work-graph-simple/graph/graph.js

232 lines
6.7 KiB
JavaScript

/** @import * as TYPES from "./types.ts" */
/** @type {TYPES.GraphBuilder} */
function Builder({user, role, part, desk, pass}, folderName)
{
// mutate users
/** @type {Record<string, TYPES.User>} */
//@ts-ignore
const UserList = user;
for(let userId in user)
{
const name = user[userId];
UserList[userId] = {name, desk:new Set()};
}
// mutate roles
/** @type {Record<string, TYPES.Role>} */
//@ts-ignore
const RoleList = role;
for(let roleId in role)
{
const [name, ...userIds] = role[roleId];
RoleList[roleId] = {name, user:userIds.map(uId=>UserList[/**@type{string}*/(uId)])};
}
// mutate parts
/** @type {Record<string, TYPES.Part>} */
//@ts-ignore
const PartList = part;
for(let partId in part)
{
const name = part[partId];
PartList[partId] = /** @type {TYPES.Part} */({name, need:[], make:[], pass:new Map()});
}
// mutate desks
/** @type {Record<string, TYPES.Desk>} */
//@ts-ignore
const DeskList = desk;
for(let deskId in desk)
{
const [name, roleIDs, mode, needObj, ...makePartIDs] = desk[deskId];
/** @type {TYPES.Part[]}*/ const need =[];
/** @type {number[]}*/ const time =[];
/** @type {TYPES.Desk} */
const deskObj = {
name,
mode,
need,
time,
make:[],
role:[],
pass:new Map()
};
for(const partId in needObj)
{
const part = PartList[partId];
need.push(part);
part.need.push(deskObj);
time.push(needObj[partId]);
}
deskObj.role = roleIDs.map(roleId=>
{
const role = RoleList[/**@type{string}*/(roleId)];
role.user.forEach(u =>u.desk.add(deskObj));
return role;
});
deskObj.make = makePartIDs.map( partId=>
{
const part = PartList[/**@type{string}*/(partId)];
part.make.push(deskObj);
return part;
} )
DeskList[deskId] = deskObj;
}
// Apply passes
/** @type {Record<string, TYPES.Pass>} */
//@ts-ignore
const PassList = pass;
for(let passID in pass)
{
/** @type {TYPES.Pass} */
const passObj = {
name: pass[passID][0],
path:passID,
async load(){
// make room for this pass to each part and desk
Object.values(PartList).forEach((partObj)=>
{
partObj.pass.set(passObj, {time:0, work:[], make(user, data)
{
this.time = Date.now();
this.work.push(/** @type {TYPES.Work}*/([this.time, data, user]));
partObj.make.forEach((arg)=>{Scan(arg, passObj)});
partObj.need.forEach((arg)=>{Scan(arg, passObj)});
}});
});
Object.values(DeskList).forEach((deskObj)=>
{
deskObj.pass.set(passObj, {need:[], make:[]});
});
// actually load the pass
const userData = Object.entries(UserList);
for(let i=0; i<userData.length; i++)
{
const [userID, userObject] = userData[i];
try
{
const resp = await fetch(`./room/${folderName}/${passID}/${userID}.json`);
/** @type {TYPES.UserPassFile} */
const json = await resp.json();
Object.entries(json).forEach(([partID, payload])=>{
let latest = 0;
payload.forEach((condensedWork)=>{
if(condensedWork[0] > latest)
{
latest = condensedWork[0];
}
condensedWork[2] = userObject;
});
const passCheck = PartList[partID].pass.get(this);
if(passCheck)
{
if(latest > passCheck.time)
{
passCheck.time = latest;
}
passCheck.work = /** @type {TYPES.Work[]}*/(payload);
}
})
}
catch(e)
{
console.warn(`No data for user ${userID} on pass ${passID} yet.`)
continue;
}
}
console.log("load complete", PartList);
// update the graph
Object.values(DeskList).forEach((deskObj)=>Scan(deskObj, passObj));
this.live = true;
},
dump(){
Object.values(PartList).forEach((partObj)=>partObj.pass.delete(passObj));
Object.values(DeskList).forEach((deskObj)=>deskObj.pass.delete(passObj));
this.live = false;
},
live:false
};
PassList[passID] = passObj;
}
return {
Desk:DeskList,
Part:PartList,
User:UserList,
Role:RoleList,
Pass:PassList
};
}
/** @type {TYPES.MassDscription} */
export default function Graph(params)
{
return ()=>{
Object.entries(params).forEach( ([roomFolderName, roomData])=>
{
params[roomFolderName] = Builder(roomData, roomFolderName);
});
return params;
}
}
/** @type {TYPES.Scanner} */
const Scan =(desk, pass)=>
{
const dirtyNeed = [];
const dirtyMake = [];
let makeMin = Infinity;
let needMax = -Infinity;
for(let i=0; i<desk.need.length; i++)
{
const part = desk.need[i];
const partPassTime = part.pass.get(pass)?.time || 0;
if(partPassTime > needMax) needMax = partPassTime;
}
for(let i=0; i<desk.make.length; i++)
{
const part = desk.make[i];
const partPassTime = part.pass.get(pass)?.time || 0;
if(partPassTime < makeMin) makeMin = partPassTime;
if(partPassTime < needMax)
{
dirtyMake.push(i);
}
}
for(let i=0; i<desk.need.length; i++)
{
const part = desk.need[i];
const partPassTime = part.pass.get(pass)?.time || 0;
if(partPassTime > makeMin)
{
dirtyNeed.push(i);
}
}
desk.pass.set(pass, {need:dirtyNeed, make:dirtyMake})
};