feat-WIP: Adds update to trunk-size form, currently height / width is not working though.
This commit is contained in:
@@ -11,6 +11,9 @@ extension DatabaseClient {
|
||||
public var delete: @Sendable (DuctSizing.TrunkSize.ID) async throws -> Void
|
||||
public var fetch: @Sendable (Project.ID) async throws -> [DuctSizing.TrunkSize]
|
||||
public var get: @Sendable (DuctSizing.TrunkSize.ID) async throws -> DuctSizing.TrunkSize?
|
||||
public var update:
|
||||
@Sendable (DuctSizing.TrunkSize.ID, DuctSizing.TrunkSize.Update) async throws ->
|
||||
DuctSizing.TrunkSize
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +85,21 @@ extension DatabaseClient.TrunkSizes: TestDependencyKey {
|
||||
return nil
|
||||
}
|
||||
return try await model.toDTO(on: database)
|
||||
},
|
||||
update: { id, updates in
|
||||
guard
|
||||
let model =
|
||||
try await TrunkModel
|
||||
.query(on: database)
|
||||
.with(\.$rooms)
|
||||
.filter(\.$id == id)
|
||||
.first()
|
||||
else {
|
||||
throw NotFoundError()
|
||||
}
|
||||
try updates.validate()
|
||||
try await model.applyUpdates(updates, on: database)
|
||||
return try await model.toDTO(on: database)
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -107,7 +125,21 @@ extension DuctSizing.TrunkSize.Create {
|
||||
height: height
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension DuctSizing.TrunkSize.Update {
|
||||
func validate() throws(ValidationError) {
|
||||
if let rooms {
|
||||
guard rooms.count > 0 else {
|
||||
throw ValidationError("Trunk size should have associated rooms / registers.")
|
||||
}
|
||||
}
|
||||
if let height {
|
||||
guard height > 0 else {
|
||||
throw ValidationError("Trunk size height should be greater than 0.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension DuctSizing.TrunkSize {
|
||||
@@ -250,4 +282,62 @@ final class TrunkModel: Model, @unchecked Sendable {
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
func applyUpdates(
|
||||
_ updates: DuctSizing.TrunkSize.Update,
|
||||
on database: any Database
|
||||
) async throws {
|
||||
if let type = updates.type, type.rawValue != self.type {
|
||||
self.type = type.rawValue
|
||||
}
|
||||
if let height = updates.height, height != self.height {
|
||||
self.height = height
|
||||
}
|
||||
if hasChanges {
|
||||
try await self.save(on: database)
|
||||
}
|
||||
|
||||
guard let updateRooms = updates.rooms else {
|
||||
return
|
||||
}
|
||||
|
||||
// Update rooms.
|
||||
let rooms = try await TrunkRoomModel.query(on: database)
|
||||
.with(\.$room)
|
||||
.filter(\.$trunk.$id == requireID())
|
||||
.all()
|
||||
|
||||
for (roomID, registers) in updateRooms {
|
||||
if let currRoom = rooms.first(where: { $0.$room.id == roomID }) {
|
||||
database.logger.debug("CURRENT ROOM: \(currRoom.room.name)")
|
||||
if registers != currRoom.registers {
|
||||
database.logger.debug("Updating registers for: \(currRoom.room.name)")
|
||||
currRoom.registers = registers
|
||||
}
|
||||
if currRoom.hasChanges {
|
||||
try await currRoom.save(on: database)
|
||||
}
|
||||
} else {
|
||||
database.logger.debug("CREATING NEW TrunkRoomModel")
|
||||
let newModel = try TrunkRoomModel(
|
||||
trunkID: requireID(),
|
||||
roomID: roomID,
|
||||
registers: registers,
|
||||
type: .init(rawValue: type)!
|
||||
)
|
||||
try await newModel.save(on: database)
|
||||
}
|
||||
}
|
||||
|
||||
let roomsToDelete = rooms.filter {
|
||||
!updateRooms.keys.contains($0.$room.id)
|
||||
}
|
||||
|
||||
for room in roomsToDelete {
|
||||
try await room.delete(on: database)
|
||||
}
|
||||
|
||||
database.logger.debug("DONE WITH UPDATES")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +126,8 @@ public enum DuctSizing {
|
||||
|
||||
extension DuctSizing {
|
||||
|
||||
// Represents the database model that the duct sizes have been calculated
|
||||
// for.
|
||||
public struct TrunkContainer: Codable, Equatable, Identifiable, Sendable {
|
||||
public var id: TrunkSize.ID { trunk.id }
|
||||
|
||||
@@ -141,6 +143,7 @@ extension DuctSizing {
|
||||
}
|
||||
}
|
||||
|
||||
// Represents the database model.
|
||||
public struct TrunkSize: Codable, Equatable, Identifiable, Sendable {
|
||||
|
||||
public let id: UUID
|
||||
@@ -187,6 +190,23 @@ extension DuctSizing.TrunkSize {
|
||||
}
|
||||
}
|
||||
|
||||
public struct Update: Codable, Equatable, Sendable {
|
||||
|
||||
public let type: TrunkType?
|
||||
public let rooms: [Room.ID: [Int]]?
|
||||
public let height: Int?
|
||||
|
||||
public init(
|
||||
type: DuctSizing.TrunkSize.TrunkType? = nil,
|
||||
rooms: [Room.ID: [Int]]? = nil,
|
||||
height: Int? = nil
|
||||
) {
|
||||
self.type = type
|
||||
self.rooms = rooms
|
||||
self.height = height
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Make registers non-optional
|
||||
public struct RoomProxy: Codable, Equatable, Identifiable, Sendable {
|
||||
|
||||
|
||||
@@ -13,6 +13,14 @@ extension SiteRoute.View.ProjectRoute.DuctSizingRoute.TrunkSizeForm {
|
||||
)
|
||||
}
|
||||
|
||||
func toUpdate(logger: Logger? = nil) throws -> DuctSizing.TrunkSize.Update {
|
||||
try .init(
|
||||
type: type,
|
||||
rooms: makeRooms(logger: logger),
|
||||
height: height
|
||||
)
|
||||
}
|
||||
|
||||
func makeRooms(logger: Logger?) throws -> [Room.ID: [Int]] {
|
||||
var retval = [Room.ID: [Int]]()
|
||||
for room in rooms {
|
||||
|
||||
@@ -581,8 +581,9 @@ extension SiteRoute.View.ProjectRoute.DuctSizingRoute {
|
||||
}
|
||||
|
||||
case .update(let id, let form):
|
||||
// FIX:
|
||||
fatalError()
|
||||
return await view(on: request, projectID: projectID) {
|
||||
_ = try await database.trunkSizes.update(id, form.toUpdate())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,6 +176,7 @@ struct DuctSizingView: HTML, Sendable {
|
||||
}
|
||||
|
||||
struct TrunkTable: HTML, Sendable {
|
||||
|
||||
let trunks: [DuctSizing.TrunkContainer]
|
||||
let rooms: [DuctSizing.RoomContainer]
|
||||
|
||||
@@ -196,86 +197,89 @@ struct DuctSizingView: HTML, Sendable {
|
||||
}
|
||||
tbody {
|
||||
for trunk in trunks {
|
||||
tr {
|
||||
td(.class("space-x-2")) {
|
||||
// div(.class("flex flex-wrap space-x-2 max-w-1/3")) {
|
||||
for id in registerIDS(trunk.trunk) {
|
||||
Badge { id }
|
||||
}
|
||||
// }
|
||||
}
|
||||
td {
|
||||
Number(trunk.ductSize.designCFM.value, digits: 0)
|
||||
}
|
||||
td {
|
||||
Number(trunk.ductSize.roundSize, digits: 1)
|
||||
}
|
||||
td {
|
||||
Number(trunk.ductSize.velocity)
|
||||
}
|
||||
td {
|
||||
Badge(number: trunk.ductSize.finalSize)
|
||||
.attributes(.class("badge-secondary"))
|
||||
}
|
||||
td {
|
||||
Badge(number: trunk.ductSize.flexSize)
|
||||
.attributes(.class("badge-primary"))
|
||||
}
|
||||
td {
|
||||
if let width = trunk.ductSize.width {
|
||||
Number(width)
|
||||
}
|
||||
|
||||
}
|
||||
td {
|
||||
|
||||
div(.class("flex justify-between items-center space-x-4")) {
|
||||
div {
|
||||
if let height = trunk.ductSize.height {
|
||||
Number(height)
|
||||
}
|
||||
}
|
||||
|
||||
div {
|
||||
div(.class("join")) {
|
||||
TrashButton()
|
||||
.attributes(.class("join-item btn-ghost"))
|
||||
.attributes(
|
||||
// .hx.delete(
|
||||
// route: .project(
|
||||
// .detail(
|
||||
// projectID,
|
||||
// .ductSizing(
|
||||
// .deleteRectangularSize(
|
||||
// room.roomID,
|
||||
// room.rectangularSize?.id ?? .init())
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
// ),
|
||||
.hx.target("closest tr"),
|
||||
.hx.swap(.outerHTML)
|
||||
// when: room.rectangularSize != nil
|
||||
)
|
||||
|
||||
EditButton()
|
||||
.attributes(
|
||||
.class("join-item btn-ghost"),
|
||||
// .showModal(id: RectangularSizeForm.id(room))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
// FIX: Add Trunk form.
|
||||
}
|
||||
}
|
||||
TrunkRow(trunk: trunk, rooms: rooms)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func registerIDS(_ trunk: DuctSizing.TrunkSize) -> [String] {
|
||||
}
|
||||
|
||||
struct TrunkRow: HTML, Sendable {
|
||||
|
||||
@Environment(ProjectViewValue.$projectID) var projectID
|
||||
|
||||
let trunk: DuctSizing.TrunkContainer
|
||||
let rooms: [DuctSizing.RoomContainer]
|
||||
|
||||
var body: some HTML<HTMLTag.tr> {
|
||||
tr {
|
||||
td(.class("space-x-2")) {
|
||||
for id in registerIDS(trunk.trunk) {
|
||||
Badge { id }
|
||||
}
|
||||
}
|
||||
td {
|
||||
Number(trunk.ductSize.designCFM.value, digits: 0)
|
||||
}
|
||||
td {
|
||||
Number(trunk.ductSize.roundSize, digits: 1)
|
||||
}
|
||||
td {
|
||||
Number(trunk.ductSize.velocity)
|
||||
}
|
||||
td {
|
||||
Badge(number: trunk.ductSize.finalSize)
|
||||
.attributes(.class("badge-secondary"))
|
||||
}
|
||||
td {
|
||||
Badge(number: trunk.ductSize.flexSize)
|
||||
.attributes(.class("badge-primary"))
|
||||
}
|
||||
td {
|
||||
if let width = trunk.ductSize.width {
|
||||
Number(width)
|
||||
}
|
||||
|
||||
}
|
||||
td {
|
||||
|
||||
div(.class("flex justify-between items-center space-x-4")) {
|
||||
div {
|
||||
if let height = trunk.ductSize.height {
|
||||
Number(height)
|
||||
}
|
||||
}
|
||||
|
||||
div {
|
||||
div(.class("join")) {
|
||||
TrashButton()
|
||||
.attributes(.class("join-item btn-ghost"))
|
||||
.attributes(
|
||||
.hx.delete(route: deleteRoute),
|
||||
.hx.target("closest tr"),
|
||||
.hx.swap(.outerHTML)
|
||||
)
|
||||
|
||||
EditButton()
|
||||
.attributes(
|
||||
.class("join-item btn-ghost"),
|
||||
.showModal(id: TrunkSizeForm.id(trunk))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
TrunkSizeForm(trunk: trunk, rooms: rooms, dismiss: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var deleteRoute: SiteRoute.View {
|
||||
.project(.detail(projectID, .ductSizing(.trunk(.delete(trunk.id)))))
|
||||
}
|
||||
|
||||
private func registerIDS(_ trunk: DuctSizing.TrunkSize) -> [String] {
|
||||
trunk.rooms.reduce(into: []) { array, room in
|
||||
array = room.registers.reduce(into: array) { array, register in
|
||||
if let room =
|
||||
|
||||
@@ -5,27 +5,47 @@ import Styleguide
|
||||
|
||||
struct TrunkSizeForm: HTML, Sendable {
|
||||
|
||||
static func id() -> String {
|
||||
"trunkSizeForm"
|
||||
static func id(_ trunk: DuctSizing.TrunkContainer? = nil) -> String {
|
||||
let base = "trunkSizeForm"
|
||||
guard let trunk else { return base }
|
||||
return "\(base)_\(trunk.id.idString)"
|
||||
}
|
||||
|
||||
@Environment(ProjectViewValue.$projectID) var projectID
|
||||
|
||||
let container: DuctSizing.TrunkContainer?
|
||||
let rooms: [DuctSizing.RoomContainer]
|
||||
let dismiss: Bool
|
||||
|
||||
var trunk: DuctSizing.TrunkSize? {
|
||||
container?.trunk
|
||||
}
|
||||
|
||||
init(
|
||||
trunk: DuctSizing.TrunkContainer? = nil,
|
||||
rooms: [DuctSizing.RoomContainer],
|
||||
dismiss: Bool = true
|
||||
) {
|
||||
self.container = trunk
|
||||
self.rooms = rooms
|
||||
self.dismiss = dismiss
|
||||
}
|
||||
|
||||
var route: String {
|
||||
SiteRoute.View.router
|
||||
.path(for: .project(.detail(projectID, .ductSizing(.index))))
|
||||
.appendingPath(SiteRoute.View.ProjectRoute.DuctSizingRoute.TrunkRoute.rootPath)
|
||||
.appendingPath(trunk?.id)
|
||||
}
|
||||
|
||||
var body: some HTML {
|
||||
ModalForm(id: Self.id(), dismiss: dismiss) {
|
||||
ModalForm(id: Self.id(container), dismiss: dismiss) {
|
||||
h1(.class("text-lg font-bold mb-4")) { "Trunk Size" }
|
||||
form(
|
||||
.class("space-y-4"),
|
||||
.hx.post(route),
|
||||
trunk == nil
|
||||
? .hx.post(route)
|
||||
: .hx.patch(route),
|
||||
.hx.target("body"),
|
||||
.hx.swap(.outerHTML)
|
||||
) {
|
||||
@@ -38,6 +58,7 @@ struct TrunkSizeForm: HTML, Sendable {
|
||||
select(.name("type")) {
|
||||
for type in DuctSizing.TrunkSize.TrunkType.allCases {
|
||||
option(.value(type.rawValue)) { type.rawValue.capitalized }
|
||||
.attributes(.selected, when: trunk?.type == type)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,6 +67,7 @@ struct TrunkSizeForm: HTML, Sendable {
|
||||
"Height",
|
||||
.type(.text),
|
||||
.name("height"),
|
||||
.value(trunk?.height),
|
||||
.placeholder("8 (Optional)"),
|
||||
)
|
||||
}
|
||||
@@ -63,6 +85,10 @@ struct TrunkSizeForm: HTML, Sendable {
|
||||
.name("rooms"),
|
||||
.value("\(room.roomID)_\(room.roomRegister)")
|
||||
)
|
||||
.attributes(
|
||||
.checked,
|
||||
when: trunk == nil ? false : trunk!.rooms.hasRoom(room)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,3 +101,12 @@ struct TrunkSizeForm: HTML, Sendable {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Array where Element == DuctSizing.TrunkSize.RoomProxy {
|
||||
func hasRoom(_ room: DuctSizing.RoomContainer) -> Bool {
|
||||
first {
|
||||
$0.id == room.roomID
|
||||
&& $0.registers.contains(room.roomRegister)
|
||||
} != nil
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user