254 lines
7.4 KiB
JavaScript
254 lines
7.4 KiB
JavaScript
/** @import * as TYPES from "./graph/types.ts" */
|
|
import * as FSHandle from "./store-directory-handle.js";
|
|
|
|
const {Div, DOM} = Gale({
|
|
Title:{
|
|
padding:"2rem",
|
|
background: "blue",
|
|
color:"white"
|
|
},
|
|
Plain:{},
|
|
PartGroup:{
|
|
display: `flex`,
|
|
flexWrap: `wrap`
|
|
},
|
|
Part:{
|
|
border: `1px solid black`,
|
|
borderRadius: `5px`,
|
|
padding: `1rem`
|
|
}
|
|
});
|
|
|
|
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<string, TYPES.GraphParts>} */
|
|
const read = module.default();
|
|
rooms.val = read;
|
|
}
|
|
catch(_e)
|
|
{
|
|
console.log("the handle exists, but the request failed. the service work must not be ready yet.")
|
|
rooms.val = {};
|
|
}
|
|
}
|
|
else
|
|
{
|
|
console.log("no fs handle has been set, cannot get room graph")
|
|
rooms.val = {};
|
|
}
|
|
}
|
|
|
|
|
|
/** @type {Van.State<Record<string, TYPES.GraphParts>>} */
|
|
const rooms = van.state({});
|
|
let handle = await FSHandle.getDirectoryHandle();
|
|
await LoadHandleFiles();
|
|
|
|
/** @type {(path:string[], part:string, time:number, data:string)=>void} */
|
|
async function WRITE(path, part, time, data)
|
|
{
|
|
const fileHandle = await FSHandle.Dig(handle, path, true);
|
|
if(fileHandle)
|
|
{
|
|
const file = await fileHandle.getFile();
|
|
const text = await file.text();
|
|
let json = {};
|
|
if(text)
|
|
{
|
|
json = JSON.parse(text);
|
|
}
|
|
let partProp = json[part];
|
|
if(!partProp)
|
|
{
|
|
partProp = [];
|
|
json[part] = partProp;
|
|
}
|
|
partProp.push([time, data]);
|
|
|
|
const writeable = await fileHandle.createWritable();
|
|
await writeable.write(JSON.stringify(json, null, 2));
|
|
await writeable.close();
|
|
}
|
|
|
|
}
|
|
|
|
/** @type {Van.State<TYPES.User|false>} */
|
|
const loggedIn = van.state(false);
|
|
|
|
/** @type {(room_id:string, graphParts:TYPES.GraphParts)=>HTMLElement} */
|
|
function Room(room_id, graphParts)
|
|
{
|
|
const rerender = van.state(0);
|
|
|
|
return Div.Plain(
|
|
|
|
Div.Plain("Users:"),
|
|
Div.PartGroup(
|
|
Object.entries(graphParts.User).map(([user_id, user])=>{
|
|
return ()=>{
|
|
|
|
rerender.val;
|
|
|
|
return Div.Part(
|
|
DOM.div.Plain(user.name),
|
|
()=>{
|
|
return DOM.button.Plain(
|
|
{async onclick(){
|
|
rerender.val++
|
|
loggedIn.val = 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"
|
|
)
|
|
},
|
|
)
|
|
}
|
|
})
|
|
),
|
|
|
|
Div.Plain("Parts"),
|
|
Div.PartGroup(
|
|
Object.entries(graphParts.Part).map(([part_id, part])=>{
|
|
|
|
return ()=>{
|
|
|
|
rerender.val;
|
|
|
|
const work = []
|
|
for(const [pass, data] of part.pass)
|
|
{
|
|
|
|
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({async onclick(){
|
|
if(loggedIn.val)
|
|
{
|
|
await data.make(loggedIn.val, "NEW");
|
|
rerender.val++;
|
|
}
|
|
}}, "Add work!")
|
|
: null
|
|
)
|
|
))
|
|
}
|
|
|
|
return Div.Part(
|
|
DOM.h3(part.name),
|
|
...work,
|
|
);
|
|
}
|
|
|
|
}),
|
|
),
|
|
|
|
Div.Plain("Desks"),
|
|
Div.PartGroup(
|
|
Object.entries(graphParts.Desk).map(([desk_id, desk])=>{
|
|
|
|
return ()=>{
|
|
|
|
rerender.val;
|
|
|
|
/** @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 Div.Plain(
|
|
part.name,
|
|
DOM.p( dirty.includes(index) ? "Dirty" : "Good!" ),
|
|
Div.Part(
|
|
time, " ", latest?.[1] || ""
|
|
)
|
|
);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
const work = [];
|
|
for(const [pass, dirty] of desk.pass)
|
|
{
|
|
|
|
work.push(Div.Part(
|
|
DOM.h5(pass.name),
|
|
Div.Part(
|
|
DOM.h4("Need:"),
|
|
desk.need.map((part, index)=>Iterator(part, index, pass, dirty.need))
|
|
),
|
|
Div.Part(
|
|
DOM.h4("Make:"),
|
|
desk.make.map((part, index)=>Iterator(part, index, pass, dirty.make))
|
|
)
|
|
))
|
|
}
|
|
|
|
return Div.Part(
|
|
DOM.h3(desk.name),
|
|
work
|
|
)
|
|
}
|
|
|
|
}),
|
|
),
|
|
|
|
)
|
|
}
|
|
|
|
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);
|