/** @import * as TYPES from "./graph/types.ts" */ import * as FSHandle from "./store-directory-handle.js"; import Styles from "./styles.js"; const {DOM, Div, Tag} = Styles; async function PickHandle() { handle = await showDirectoryPicker(); await FSHandle.setDirectoryHandle(handle); await LoadHandleFiles(); } async function LoadHandleFiles() { console.log("fetching room.js", handle); if(handle) { try { 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) { console.log("the handle exists, but the request failed. the service work must not be ready yet.", e) rooms.val = {}; } } else { console.log("no fs handle has been set, cannot get room graph") rooms.val = {}; } } /** @type {Van.State>} */ const rooms = van.state({}); let handle = await FSHandle.getDirectoryHandle(); await LoadHandleFiles(); /** @type {Van.State} */ const loggedIn = van.state(false); const blocking = van.state(false); const showDesks = van.state(true, "desks"); function Input(handler=(str)=>{}) { 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")); let cancelButton = DOM.button({onclick(){ input.value = ""; mountPoint.remove(); }}, "cancel") 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.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) { if(role.user.includes(loggedIn.val)) { userInRole = true; } } if(!userInRole) { return null; } } const work = []; for(const [pass, scan] of desk.pass) { // at least one but not all need fields are empty const caution = scan.need_empty.length>0 && scan.need_empty.length { const partPass = part.pass.get(pass); if(!partPass){ return null } const latest = partPass.work.find(t=>t[0] == partPass.time)?.[1]; const attributes = {}; if(latest) { attributes.class = Tag("PartGood") } else { attributes.class = caution ? Tag("PartCaution") : Tag("PartEmpty") } if(scan.need_dirty.includes(index)) { attributes.class = Tag("PartDirty") } return DOM.td( Div.Part( attributes, latest ) ); }), DOM.td(Div.Icon("⇉")), desk.make.map((part, index, array)=> { const partPass = part.pass.get(pass); if(!partPass){ return null } const latest = partPass.work.find(t=>t[0] == partPass.time)?.[1]; const attributes = { onclick(){ 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; } })); } }; if(latest) { attributes.class = Tag("PartGood") } else { attributes.class = Tag("PartEmpty") } if( (desk.need.length==0 && !latest) || scan.make_dirty.includes(index)) { if(!latest && caution) { attributes.class = Tag("PartCaution") } else { attributes.class = Tag("PartDirty"); } } return DOM.td( Div.Part( attributes, latest ) ); }), )) } return Div.DeskContainer( DOM.h3(desk.name), DOM.table.GapHorizontal( DOM.thead( DOM.tr( DOM.th(), desk.need.map((part, index)=>DOM.th(part.name)), DOM.th("→"), desk.make.map((part, index)=>DOM.th(part.name)) ) ), work ) ) }), ) } /** @type {(room_id:string, graphParts:TYPES.GraphParts)=>HTMLElement} */ function Room(room_id, graphParts) { const rerender = van.state(0); blocking.val; return Div.Plain( Div.Plain("Users:"), Div.PartGroup( Object.entries(graphParts.User).map(([user_id, user])=>{ return ()=>{ return Div.Part( DOM.div.Plain(user.name), ()=>{ return DOM.button.Plain( {onclick(){ loggedIn.val = (loggedIn.val == user) ? false : user; }}, loggedIn.val == user ? "this is me" : "impersonate" ) }, ) } }) ), // 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(){ showDesks.val = !showDesks.val; }}, showDesks.val ? "Show Parts" : "Show Desks") }, ()=>{ rerender.val; return showDesks.val ? Desks(graphParts.Desk) : Parts(graphParts.Part, graphParts.Pass); }, ()=>{ return blocking.val ? Div.BlockScreen() : null } ) } function App() { return Div.Plain( DOM.button({onclick:PickHandle}, "Pick Directory"), Object.entries(rooms.val).map(([room_id, graphParts])=> Room(room_id, graphParts) ) ) } van.add(document.body, App);