WIP: Updates test html snapshots, working on validation when delegating airflow to a different room.
Some checks failed
CI / Linux Tests (push) Has been cancelled
Some checks failed
CI / Linux Tests (push) Has been cancelled
This commit is contained in:
@@ -84,6 +84,14 @@ extension DatabaseClient.Rooms: TestDependencyKey {
|
||||
extension Room.Create {
|
||||
|
||||
func toModel(projectID: Project.ID) throws -> RoomModel {
|
||||
var registerCount = registerCount
|
||||
// Set register count appropriately when delegatedTo is set / changes.
|
||||
if delegatedTo != nil {
|
||||
registerCount = 0
|
||||
} else if registerCount == 0 {
|
||||
registerCount = 1
|
||||
}
|
||||
|
||||
return .init(
|
||||
name: name,
|
||||
heatingLoad: heatingLoad,
|
||||
@@ -229,13 +237,28 @@ final class RoomModel: Model, @unchecked Sendable, Validatable {
|
||||
Validator.validate(\.coolingLoad)
|
||||
.errorLabel("Cooling Load", inline: true)
|
||||
|
||||
Validator.validate(\.registerCount, with: .greaterThanOrEquals(1))
|
||||
Validator.validate(\.registerCount, with: .greaterThanOrEquals($room.id == nil ? 1 : 0))
|
||||
.errorLabel("Register Count", inline: true)
|
||||
|
||||
Validator.validate(\.rectangularSizes)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func validateAndSave(on database: Database) async throws {
|
||||
try self.validate()
|
||||
if let delegateTo = $room.id {
|
||||
guard let parent = try await RoomModel.find(delegateTo, on: database) else {
|
||||
throw ValidationError("Can not find room: \(delegateTo), to delegate airflow to.")
|
||||
}
|
||||
guard parent.$room.id == nil else {
|
||||
throw ValidationError(
|
||||
"Can not delegate airflow to a room that also delegates it's own airflow."
|
||||
)
|
||||
}
|
||||
}
|
||||
try await save(on: database)
|
||||
}
|
||||
}
|
||||
|
||||
extension Room.CoolingLoad: Validatable {
|
||||
|
||||
@@ -59,3 +59,24 @@ extension Select where Element: Identifiable, Element.ID == UUID, Element: Senda
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Select
|
||||
where Element: Identifiable, Element.ID == UUID, Element: Sendable, Label == HTMLText {
|
||||
|
||||
public init(
|
||||
_ items: [Element],
|
||||
label keyPath: KeyPath<Element, String>,
|
||||
placeholder: String? = nil,
|
||||
selected: @escaping @Sendable (Element) -> Bool = { _ in false }
|
||||
) {
|
||||
self.init(
|
||||
items,
|
||||
placeholder: placeholder,
|
||||
value: { $0.id.uuidString },
|
||||
selected: selected,
|
||||
label: { HTMLText($0[keyPath: keyPath]) }
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,13 +30,17 @@ struct RoomForm: HTML, Sendable {
|
||||
self.room = room
|
||||
}
|
||||
|
||||
var route: String {
|
||||
private var route: String {
|
||||
SiteRoute.View.router.path(
|
||||
for: .project(.detail(projectID, .rooms(.index)))
|
||||
)
|
||||
.appendingPath(room?.id)
|
||||
}
|
||||
|
||||
private var selectableRooms: [Room] {
|
||||
rooms.filter { $0.delegatedTo == nil }
|
||||
}
|
||||
|
||||
var body: some HTML {
|
||||
ModalForm(id: Self.id(room), dismiss: dismiss) {
|
||||
h1(.class("text-3xl font-bold pb-6")) { "Room" }
|
||||
@@ -104,28 +108,15 @@ struct RoomForm: HTML, Sendable {
|
||||
.id("registerCount")
|
||||
)
|
||||
|
||||
label(.class("select w-full"), .id("delegateToSelect")) {
|
||||
label(.class("select w-full")) {
|
||||
span(.class("label")) { "Room" }
|
||||
Select(rooms, placeholder: "Delegate Airflow") {
|
||||
$0.name
|
||||
}
|
||||
Select(selectableRooms, label: \.name, placeholder: "Delegate Airflow")
|
||||
.attributes(.name("delegatedTo"))
|
||||
}
|
||||
|
||||
SubmitButton()
|
||||
.attributes(.class("btn-block"))
|
||||
}
|
||||
}
|
||||
|
||||
script {
|
||||
"""
|
||||
function myClick() {
|
||||
console.log('clicked');
|
||||
const simple = document.getElementById('simple');
|
||||
console.log(simple.style.display);
|
||||
simple.style.display = 'block';
|
||||
console.log(simple.style.display);
|
||||
}
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,6 @@ struct RoomsView: HTML, Sendable {
|
||||
|
||||
var body: some HTML {
|
||||
div(.class("flex w-full flex-col")) {
|
||||
input(.type(.checkbox), .name("delegateToCheckbox"), .on(.click, "showElement('simple');"))
|
||||
div(.style("display: none;"), .id("simple"), .class("hidden")) {
|
||||
"This is hidden"
|
||||
}
|
||||
|
||||
PageTitleRow {
|
||||
div(.class("flex grid grid-cols-3 w-full gap-y-4")) {
|
||||
|
||||
@@ -107,6 +102,11 @@ struct RoomsView: HTML, Sendable {
|
||||
"Register Count"
|
||||
}
|
||||
}
|
||||
th {
|
||||
div(.class("flex justify-center")) {
|
||||
"Delegated To"
|
||||
}
|
||||
}
|
||||
th {
|
||||
div(.class("flex justify-end me-2 space-x-4")) {
|
||||
|
||||
@@ -151,10 +151,11 @@ struct RoomsView: HTML, Sendable {
|
||||
|
||||
var coolingSensible: Double {
|
||||
try! room.coolingLoad.ensured(shr: shr).sensible
|
||||
// guard let value = room.coolingSensible else {
|
||||
// return room.coolingTotal * shr
|
||||
// }
|
||||
// return value
|
||||
}
|
||||
|
||||
var delegatedToRoomName: String? {
|
||||
guard let delegatedToID = room.delegatedTo else { return nil }
|
||||
return rooms.first(where: { $0.id == delegatedToID })?.name
|
||||
}
|
||||
|
||||
init(room: Room, shr: Double?, rooms: [Room]) {
|
||||
@@ -186,7 +187,14 @@ struct RoomsView: HTML, Sendable {
|
||||
}
|
||||
td {
|
||||
div(.class("flex justify-center")) {
|
||||
Number(room.registerCount)
|
||||
Number(delegatedToRoomName != nil ? 0 : room.registerCount)
|
||||
}
|
||||
}
|
||||
td {
|
||||
if let name = delegatedToRoomName {
|
||||
div(.class("flex justify-center")) {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
td {
|
||||
|
||||
@@ -11,9 +11,9 @@ struct CSVParsingTests {
|
||||
let parser = CSVParser.liveValue
|
||||
|
||||
let input = """
|
||||
Name,Heating Load,Cooling Total,Cooling Sensible,Register Count
|
||||
Bed-1,12345,12345,,2
|
||||
Bed-2,1223,,1123,1
|
||||
Name,Heating Load,Cooling Total,Cooling Sensible,Register Count,Delegated To
|
||||
Bed-1,12345,12345,,2,
|
||||
Bed-2,1223,,1123,1,
|
||||
"""
|
||||
let rooms = try await parser.parseRooms(.init(file: Data(input.utf8)))
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ p-6 w-full">
|
||||
<div class="col-span-2">
|
||||
<h1 class="text-3xl font-bold">Room Loads</h1>
|
||||
</div>
|
||||
<div class="flex justify-end grow">
|
||||
<div class="flex justify-end grow space-x-4">
|
||||
<div class="tooltip tooltip-left" data-tip="Set sensible heat ratio">
|
||||
<button class="btn btn-primary text-lg font-bold py-2 " onclick="shrForm.showModal()">
|
||||
<div class="flex grow justify-end items-end space-x-4">
|
||||
@@ -63,12 +63,6 @@ p-6 w-full">
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="tooltip tooltip-left" data-tip="Upload csv file">
|
||||
<form hx-post="/projects/00000000-0000-0000-0000-000000000000/rooms/csv" hx-target="body" hx-swap="outerHTML" enctype="multipart/form-data">
|
||||
<input type="file" name="file" accept=".csv">
|
||||
<button class="btn btn-secondary" type="submit">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-end space-x-4 font-bold">
|
||||
<span class="text-lg">Heating Total</span>
|
||||
@@ -113,7 +107,13 @@ p-6 w-full">
|
||||
<div class="flex justify-center">Register Count</div>
|
||||
</th>
|
||||
<th>
|
||||
<div class="flex justify-end me-2">
|
||||
<div class="flex justify-center">Delegated To</div>
|
||||
</th>
|
||||
<th>
|
||||
<div class="flex justify-end me-2 space-x-4">
|
||||
<div class="tooltip tooltip-left" data-tip="Upload CSV">
|
||||
<button class="btn btn-secondary" onclick="uploadCSV.showModal()"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-file-plus-corner-icon lucide-file-plus-corner"><path d="M11.35 22H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.706.706l3.588 3.588A2.4 2.4 0 0 1 20 8v5.35"/><path d="M14 2v5a1 1 0 0 0 1 1h5"/><path d="M14 19h6"/><path d="M17 16v6"/></svg></button>
|
||||
</div>
|
||||
<div class="tooltip tooltip-left" data-tip="Add Room">
|
||||
<button type="button" class="btn btn-primary mx-auto tooltip-left" onclick="roomForm.showModal()"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-plus-icon lucide-circle-plus"><circle cx="12" cy="12" r="10"/><path d="M8 12h8"/><path d="M12 8v8"/></svg></button>
|
||||
</div>
|
||||
@@ -136,6 +136,7 @@ p-6 w-full">
|
||||
<td>
|
||||
<div class="flex justify-center"><span>1</span></div>
|
||||
</td>
|
||||
<td></td>
|
||||
<td>
|
||||
<div class="flex justify-end">
|
||||
<div class="join">
|
||||
@@ -167,7 +168,17 @@ p-6 w-full">
|
||||
Cooling Sensible</label><label class="input w-full"><span class="label"></span>
|
||||
<input name="coolingSensible" type="number" placeholder="1234 (Optional)" min="0" value="">
|
||||
Registers</label><label class="input w-full"><span class="label"></span>
|
||||
<input name="registerCount" type="number" min="1" required value="1"></label>
|
||||
<input name="registerCount" type="number" min="1" required value="1" id="registerCount">
|
||||
Room</label><label class="select w-full"><span class="label"></span>
|
||||
<select name="delegatedTo">
|
||||
<option selected disabled>Delegate Airflow</option>
|
||||
<option value="00000000-0000-0000-0000-000000000001">Bed-1</option>
|
||||
<option value="00000000-0000-0000-0000-000000000002">Entry</option>
|
||||
<option value="00000000-0000-0000-0000-000000000003">Family Room</option>
|
||||
<option value="00000000-0000-0000-0000-000000000004">Kitchen</option>
|
||||
<option value="00000000-0000-0000-0000-000000000005">Living Room</option>
|
||||
<option value="00000000-0000-0000-0000-000000000006">Master</option>
|
||||
</select></label>
|
||||
<button class="btn btn-secondary btn-block" type="submit">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -188,6 +199,7 @@ p-6 w-full">
|
||||
<td>
|
||||
<div class="flex justify-center"><span>2</span></div>
|
||||
</td>
|
||||
<td></td>
|
||||
<td>
|
||||
<div class="flex justify-end">
|
||||
<div class="join">
|
||||
@@ -219,7 +231,17 @@ p-6 w-full">
|
||||
Cooling Sensible</label><label class="input w-full"><span class="label"></span>
|
||||
<input name="coolingSensible" type="number" placeholder="1234 (Optional)" min="0" value="">
|
||||
Registers</label><label class="input w-full"><span class="label"></span>
|
||||
<input name="registerCount" type="number" min="1" required value="2"></label>
|
||||
<input name="registerCount" type="number" min="1" required value="2" id="registerCount">
|
||||
Room</label><label class="select w-full"><span class="label"></span>
|
||||
<select name="delegatedTo">
|
||||
<option selected disabled>Delegate Airflow</option>
|
||||
<option value="00000000-0000-0000-0000-000000000001">Bed-1</option>
|
||||
<option value="00000000-0000-0000-0000-000000000002">Entry</option>
|
||||
<option value="00000000-0000-0000-0000-000000000003">Family Room</option>
|
||||
<option value="00000000-0000-0000-0000-000000000004">Kitchen</option>
|
||||
<option value="00000000-0000-0000-0000-000000000005">Living Room</option>
|
||||
<option value="00000000-0000-0000-0000-000000000006">Master</option>
|
||||
</select></label>
|
||||
<button class="btn btn-secondary btn-block" type="submit">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -240,6 +262,7 @@ p-6 w-full">
|
||||
<td>
|
||||
<div class="flex justify-center"><span>3</span></div>
|
||||
</td>
|
||||
<td></td>
|
||||
<td>
|
||||
<div class="flex justify-end">
|
||||
<div class="join">
|
||||
@@ -271,7 +294,17 @@ p-6 w-full">
|
||||
Cooling Sensible</label><label class="input w-full"><span class="label"></span>
|
||||
<input name="coolingSensible" type="number" placeholder="1234 (Optional)" min="0" value="">
|
||||
Registers</label><label class="input w-full"><span class="label"></span>
|
||||
<input name="registerCount" type="number" min="1" required value="3"></label>
|
||||
<input name="registerCount" type="number" min="1" required value="3" id="registerCount">
|
||||
Room</label><label class="select w-full"><span class="label"></span>
|
||||
<select name="delegatedTo">
|
||||
<option selected disabled>Delegate Airflow</option>
|
||||
<option value="00000000-0000-0000-0000-000000000001">Bed-1</option>
|
||||
<option value="00000000-0000-0000-0000-000000000002">Entry</option>
|
||||
<option value="00000000-0000-0000-0000-000000000003">Family Room</option>
|
||||
<option value="00000000-0000-0000-0000-000000000004">Kitchen</option>
|
||||
<option value="00000000-0000-0000-0000-000000000005">Living Room</option>
|
||||
<option value="00000000-0000-0000-0000-000000000006">Master</option>
|
||||
</select></label>
|
||||
<button class="btn btn-secondary btn-block" type="submit">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -292,6 +325,7 @@ p-6 w-full">
|
||||
<td>
|
||||
<div class="flex justify-center"><span>2</span></div>
|
||||
</td>
|
||||
<td></td>
|
||||
<td>
|
||||
<div class="flex justify-end">
|
||||
<div class="join">
|
||||
@@ -323,7 +357,17 @@ p-6 w-full">
|
||||
Cooling Sensible</label><label class="input w-full"><span class="label"></span>
|
||||
<input name="coolingSensible" type="number" placeholder="1234 (Optional)" min="0" value="">
|
||||
Registers</label><label class="input w-full"><span class="label"></span>
|
||||
<input name="registerCount" type="number" min="1" required value="2"></label>
|
||||
<input name="registerCount" type="number" min="1" required value="2" id="registerCount">
|
||||
Room</label><label class="select w-full"><span class="label"></span>
|
||||
<select name="delegatedTo">
|
||||
<option selected disabled>Delegate Airflow</option>
|
||||
<option value="00000000-0000-0000-0000-000000000001">Bed-1</option>
|
||||
<option value="00000000-0000-0000-0000-000000000002">Entry</option>
|
||||
<option value="00000000-0000-0000-0000-000000000003">Family Room</option>
|
||||
<option value="00000000-0000-0000-0000-000000000004">Kitchen</option>
|
||||
<option value="00000000-0000-0000-0000-000000000005">Living Room</option>
|
||||
<option value="00000000-0000-0000-0000-000000000006">Master</option>
|
||||
</select></label>
|
||||
<button class="btn btn-secondary btn-block" type="submit">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -344,6 +388,7 @@ p-6 w-full">
|
||||
<td>
|
||||
<div class="flex justify-center"><span>2</span></div>
|
||||
</td>
|
||||
<td></td>
|
||||
<td>
|
||||
<div class="flex justify-end">
|
||||
<div class="join">
|
||||
@@ -375,7 +420,17 @@ p-6 w-full">
|
||||
Cooling Sensible</label><label class="input w-full"><span class="label"></span>
|
||||
<input name="coolingSensible" type="number" placeholder="1234 (Optional)" min="0" value="">
|
||||
Registers</label><label class="input w-full"><span class="label"></span>
|
||||
<input name="registerCount" type="number" min="1" required value="2"></label>
|
||||
<input name="registerCount" type="number" min="1" required value="2" id="registerCount">
|
||||
Room</label><label class="select w-full"><span class="label"></span>
|
||||
<select name="delegatedTo">
|
||||
<option selected disabled>Delegate Airflow</option>
|
||||
<option value="00000000-0000-0000-0000-000000000001">Bed-1</option>
|
||||
<option value="00000000-0000-0000-0000-000000000002">Entry</option>
|
||||
<option value="00000000-0000-0000-0000-000000000003">Family Room</option>
|
||||
<option value="00000000-0000-0000-0000-000000000004">Kitchen</option>
|
||||
<option value="00000000-0000-0000-0000-000000000005">Living Room</option>
|
||||
<option value="00000000-0000-0000-0000-000000000006">Master</option>
|
||||
</select></label>
|
||||
<button class="btn btn-secondary btn-block" type="submit">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -396,6 +451,7 @@ p-6 w-full">
|
||||
<td>
|
||||
<div class="flex justify-center"><span>2</span></div>
|
||||
</td>
|
||||
<td></td>
|
||||
<td>
|
||||
<div class="flex justify-end">
|
||||
<div class="join">
|
||||
@@ -427,7 +483,17 @@ p-6 w-full">
|
||||
Cooling Sensible</label><label class="input w-full"><span class="label"></span>
|
||||
<input name="coolingSensible" type="number" placeholder="1234 (Optional)" min="0" value="">
|
||||
Registers</label><label class="input w-full"><span class="label"></span>
|
||||
<input name="registerCount" type="number" min="1" required value="2"></label>
|
||||
<input name="registerCount" type="number" min="1" required value="2" id="registerCount">
|
||||
Room</label><label class="select w-full"><span class="label"></span>
|
||||
<select name="delegatedTo">
|
||||
<option selected disabled>Delegate Airflow</option>
|
||||
<option value="00000000-0000-0000-0000-000000000001">Bed-1</option>
|
||||
<option value="00000000-0000-0000-0000-000000000002">Entry</option>
|
||||
<option value="00000000-0000-0000-0000-000000000003">Family Room</option>
|
||||
<option value="00000000-0000-0000-0000-000000000004">Kitchen</option>
|
||||
<option value="00000000-0000-0000-0000-000000000005">Living Room</option>
|
||||
<option value="00000000-0000-0000-0000-000000000006">Master</option>
|
||||
</select></label>
|
||||
<button class="btn btn-secondary btn-block" type="submit">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -450,11 +516,34 @@ p-6 w-full">
|
||||
Cooling Sensible</label><label class="input w-full"><span class="label"></span>
|
||||
<input name="coolingSensible" type="number" placeholder="1234 (Optional)" min="0" value="">
|
||||
Registers</label><label class="input w-full"><span class="label"></span>
|
||||
<input name="registerCount" type="number" min="1" required value="1"></label>
|
||||
<input name="registerCount" type="number" min="1" required value="1" id="registerCount">
|
||||
Room</label><label class="select w-full"><span class="label"></span>
|
||||
<select name="delegatedTo">
|
||||
<option selected disabled>Delegate Airflow</option>
|
||||
<option value="00000000-0000-0000-0000-000000000001">Bed-1</option>
|
||||
<option value="00000000-0000-0000-0000-000000000002">Entry</option>
|
||||
<option value="00000000-0000-0000-0000-000000000003">Family Room</option>
|
||||
<option value="00000000-0000-0000-0000-000000000004">Kitchen</option>
|
||||
<option value="00000000-0000-0000-0000-000000000005">Living Room</option>
|
||||
<option value="00000000-0000-0000-0000-000000000006">Master</option>
|
||||
</select></label>
|
||||
<button class="btn btn-secondary btn-block" type="submit">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
</dialog>
|
||||
<dialog id="uploadCSV" class="modal">
|
||||
<div class="modal-box">
|
||||
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2" onclick="uploadCSV.close()"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-x-icon lucide-x"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg></button>
|
||||
<div class="pb-6 space-y-3">
|
||||
<h1 class="text-3xl font-bold">Upload CSV</h1>
|
||||
<p class="text-sm italic">Drag and drop, or click to upload</p>
|
||||
</div>
|
||||
<form hx-post="/projects/00000000-0000-0000-0000-000000000000/rooms/csv" hx-target="body" hx-swap="outerHTML" enctype="multipart/form-data">
|
||||
<input type="file" name="file" accept=".csv">
|
||||
<button class="btn btn-secondary btn-block mt-6" type="submit">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
</dialog>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user