From f47ab32d68025d6566f1f830da938a406233013d Mon Sep 17 00:00:00 2001 From: Seth Trowbridge Date: Sun, 2 Nov 2025 13:47:12 -0500 Subject: [PATCH] input controls --- app.js | 272 +++++++++++++++++++-------------- mock-user-folder/graph/room.js | 20 ++- mock-user-folder/graph/user.js | 5 - styles.js | 8 + 4 files changed, 181 insertions(+), 124 deletions(-) delete mode 100644 mock-user-folder/graph/user.js diff --git a/app.js b/app.js index 32461fd..48bacd3 100644 --- a/app.js +++ b/app.js @@ -20,11 +20,21 @@ async function LoadHandleFiles() const module = await import("./graph/room.js"+"?bust="+Math.random()); /** @type {Record} */ const read = module.default(); + + for(const roomKey in read) + { + const room = read[roomKey] + for(const pass in room.Pass) + { + await room.Pass[pass].load(); + } + } + rooms.val = read; } - catch(_e) + catch(e) { - console.log("the handle exists, but the request failed. the service work must not be ready yet.") + console.log("the handle exists, but the request failed. the service work must not be ready yet.", e) rooms.val = {}; } } @@ -49,115 +59,153 @@ const blocking = van.state(false); const showDesks = van.state(true, "desks"); -/** @type {(inParts:Record)=>HTMLElement} */ -function Parts(inParts) +function Input(handler=(str)=>{}) { - return Div.Plain( - Div.Plain("Parts"), - Div.PartGroup( - Object.entries(inParts).map(([part_id, part])=>{ + const input = DOM.textarea({style:"vertical-align:text-top; width:500px; height:200px;"}); + + let submitButton = Div.Plain(DOM.button({onclick(){ + handler(input.value); + input.value = ""; + mountPoint.remove(); + }}, "submit value")); - const work = [] - for(const [pass, data] of part.pass) - { + let cancelButton = DOM.button({onclick(){ + input.value = ""; + mountPoint.remove(); + }}, "cancel") - work.push(Div.Part( - DOM.h5(pass.name), - DOM.p(data.time), - data.work.map(([time, data, user])=>Div.Plain( - DOM.span(time), - " ", - DOM.strong(data), - )), - Div.Plain( - loggedIn.val ? DOM.button({onclick(){ - blocking.val = true; - loggedIn.val && data.make(loggedIn.val, "NEW").then(()=>{ - blocking.val = false; - }); - }}, "Add work!") - : null - ) - )) - } - - return Div.Part( - DOM.h3(part.name), - ...work, - ); - - }), - ) - ) + const mountPoint = Div.Plain({onclick(e){e.stopPropagation();}}, input, cancelButton, submitButton); + return mountPoint; } +/** @type {(inParts:Record, inPasses:Record)=>HTMLElement} */ +function Parts(inParts, inPasses) +{ + const rows = []; + + const row = [DOM.th()] + for(const pass in inPasses) + { + row.push(DOM.th(inPasses[pass].name)); + } + rows.push(DOM.thead(row)); + + Object.entries(inParts).map(([part_id, part])=>{ + + const row = [DOM.th(part.name)]; + for(const [pass, data] of part.pass) + { + row.push(DOM.td.Part(data.work.map(w=>Div.Plain(w[1]) ))) + } + rows.push(DOM.tr(row)) + }); + + return DOM.table.GapVertical(rows); +} + +const deskRender = van.state(0); + /** @type {(inDesks:Record)=>HTMLElement} */ function Desks(inDesks) { - return Div.Plain( - Div.Plain("Desks"), - Div.PartGroup( - Object.entries(inDesks).map(([desk_id, desk])=>{ - loggedIn.val; + - if(loggedIn.val) + return Div.PartGroup( + Object.entries(inDesks).map(([desk_id, desk])=>{ + + loggedIn.val; + + deskRender.val; + console.log("reredering desk", desk.name); + + if (loggedIn.val) + { + let userInRole = false; + for(const role of desk.role) { - for(const role of desk.role) + if(role.user.includes(loggedIn.val)) { - if(!role.user.includes(loggedIn.val)) - { - return null; - } + userInRole = true; } } - - /** @type {(part:TYPES.Part, index:number, pass:TYPES.Pass, dirty:number[])=>HTMLElement|null} */ - const Iterator = (part, index, pass, dirty)=>{ - - const partPass = part.pass.get(pass); - if(partPass) - { - const time = partPass.time; - const latest = partPass.work.find(t=>t[0] == time); - - return DOM.td( - Div.Part( - {class: dirty.includes(index) ? Tag("DeskDirty") : ""}, - latest?.[1] || "" - ) - ); - } + if(!userInRole) + { return null; } + } - const work = []; - for(const [pass, dirty] of desk.pass) + + /** @type {(part:TYPES.Part, index:number, pass:TYPES.Pass, dirty:number[], type:"need"|"make")=>HTMLElement|null} */ + const Iterator = (part, index, pass, dirty, type)=>{ + + const partPass = part.pass.get(pass); + if(partPass) { - work.push(DOM.tr( - DOM.td(pass.name), - desk.need.map((part, index)=>Iterator(part, index, pass, dirty.need)), - DOM.td("->"), - desk.make.map((part, index)=>Iterator(part, index, pass, dirty.make)) - )) + const time = partPass.time; + const latest = partPass.work.find(t=>t[0] == time); + + const attributes = { + class: dirty.includes(index) ? Tag("DeskDirty") : "", + }; + + if(type == "make") + { + attributes.onclick=function(){ + loggedIn.rawVal && van.add(this, Input((str)=>{ + if(loggedIn.rawVal) + { + blocking.val = true; + partPass.make(loggedIn.rawVal, str).then(()=>{ + deskRender.val++; + blocking.val = false; + }) + } + else + { + return false; + } + + })); + } + } + + return DOM.td( + Div.Part( + attributes, + latest?.[1] || "" + ) + ); } + return null; + } - return Div.DeskContainer( - DOM.h3(desk.name), - DOM.table( - DOM.thead( - DOM.th(), - desk.need.map((part, index)=>DOM.th(part.name)), - DOM.th(), - desk.make.map((part, index)=>DOM.th(part.name)) - ), - work - ) + const work = []; + for(const [pass, dirty] of desk.pass) + { + work.push(DOM.tr( + DOM.td(pass.name), + desk.need.map((part, index)=>Iterator(part, index, pass, dirty.need, "need")), + DOM.td("->"), + desk.make.map((part, index)=>Iterator(part, index, pass, dirty.make, "make")) + )) + } + + return Div.DeskContainer( + DOM.h3(desk.name), + DOM.table.GapHorizontal( + DOM.thead( + DOM.th(), + desk.need.map((part, index)=>DOM.th(part.name)), + DOM.th(), + desk.make.map((part, index)=>DOM.th(part.name)) + ), + work ) + ) - }), - ) + }), ) } @@ -189,29 +237,29 @@ function Room(room_id, graphParts) ), - Div.Plain("Passes:"), - Div.PartGroup( - Object.entries(graphParts.Pass).map(([pass_id, pass])=>{ - return ()=>{ - console.log("rerendering...", rerender.rawVal); - - rerender.val; - - return Div.Part( - DOM.div.Plain(pass.name), - ()=>{ - return DOM.button.Plain( - {async onclick(){ - await pass[pass.live ? "dump" : "load"](); - rerender.val++ - }}, - pass.live ? "Dump" : "Load" - ) - }, - ) - } - }) - ), +// Div.Plain("Passes:"), +// Div.PartGroup( +// Object.entries(graphParts.Pass).map(([pass_id, pass])=>{ +// return ()=>{ +// console.log("rerendering...", rerender.rawVal); +// +// rerender.val; +// +// return Div.Part( +// DOM.div.Plain(pass.name), +// ()=>{ +// return DOM.button.Plain( +// {async onclick(){ +// await pass[pass.live ? "dump" : "load"](); +// rerender.val++ +// }}, +// pass.live ? "Dump" : "Load" +// ) +// }, +// ) +// } +// }) +// ), ()=>{ return DOM.button({onclick(){ @@ -221,7 +269,7 @@ function Room(room_id, graphParts) ()=>{ rerender.val; - return showDesks.val ? Desks(graphParts.Desk) : Parts(graphParts.Part); + return showDesks.val ? Desks(graphParts.Desk) : Parts(graphParts.Part, graphParts.Pass); }, diff --git a/mock-user-folder/graph/room.js b/mock-user-folder/graph/room.js index a830e3d..19a1053 100644 --- a/mock-user-folder/graph/room.js +++ b/mock-user-folder/graph/room.js @@ -1,13 +1,19 @@ //@ts-check -import Rooms, {Room} from "../../graph/graph.js"; -import User from "./user.js"; +import CreateAllRooms, {Room} from "../../graph/graph.js"; -export default Rooms({ +const user = { + u1:"Seth Trowbridge", + u4:"Sarah Sharp", + u5:"Adam Marshall", +} + +export default CreateAllRooms({ room_01:Room({ - user:User, + user, role:{ dev:["Development", "u1"], - write:["Writing", "u2", "u3"], + write:["Writing", "u5"], + admin:["Admin", "u4"] }, part:{ p1:"Page title", @@ -15,8 +21,8 @@ export default Rooms({ p3:"Page preview", }, desk:{ - d1:["Write page metas", ["write"], "all", {}, "p1", "p2"], - d2:["Build Page preview", ["dev"], "all", {p1:1, p2:1}, "p3"] + d1:["Write page metas", ["admin", "write"], "all", {}, "p1", "p2"], + d2:["Build Page preview", ["admin", "dev"], "all", {p1:1, p2:1}, "p3" ] }, pass:{ pass_01:["January"], diff --git a/mock-user-folder/graph/user.js b/mock-user-folder/graph/user.js deleted file mode 100644 index 5523c18..0000000 --- a/mock-user-folder/graph/user.js +++ /dev/null @@ -1,5 +0,0 @@ -export default { - u1:"seth", - u2:"seth2", - u3:"seth3" -} \ No newline at end of file diff --git a/styles.js b/styles.js index a9d6d9c..e14cca2 100644 --- a/styles.js +++ b/styles.js @@ -31,5 +31,13 @@ export default Gale({ DeskDirty:{ background:"tomato", color:"white" + }, + GapHorizontal:{ + borderCollapse:"separate", + borderSpacing:"0 2rem" + }, + GapVertical:{ + borderCollapse:"separate", + borderSpacing:"2rem 0.2rem" } }); \ No newline at end of file