input controls

This commit is contained in:
Seth Trowbridge 2025-11-02 13:47:12 -05:00
parent 396ad5b3c9
commit f47ab32d68
4 changed files with 181 additions and 124 deletions

272
app.js
View File

@ -20,11 +20,21 @@ async function LoadHandleFiles()
const module = await import("./graph/room.js"+"?bust="+Math.random());
/** @type {Record<string, TYPES.GraphParts>} */
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<string, TYPES.Part>)=>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<string, TYPES.Part>, inPasses:Record<string, TYPES.Pass>)=>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<string, TYPES.Desk>)=>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);
},

View File

@ -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"],

View File

@ -1,5 +0,0 @@
export default {
u1:"seth",
u2:"seth2",
u3:"seth3"
}

View File

@ -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"
}
});