Add side panels, task selection, graph animation, and project docs

- Foldable left panel (user profile) and right panel (task details)
- Clicking a task in the list or graph node selects it and shows details
- Both views (task list + graph) always mounted via absolute inset-0 for
  correct canvas dimensions; tabs toggle visibility with opacity
- Graph node selection animation: other nodes repel outward (charge -600),
  then selected node smoothly slides to center (500ms cubic ease-out),
  then charge restores to -120 and graph stabilizes
- Graph re-fits on tab switch and panel resize via ResizeObserver
- Fix UUID string IDs throughout (backend returns UUIDs, not integers)
- Add TaskDetailPanel, UserPanel components
- Add CLAUDE.md project documentation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Alvis
2026-04-08 11:23:06 +00:00
parent 5c7edd4bbc
commit f1d51b8cc8
23998 changed files with 3242708 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
/*
This is a simple promise queue that allows you to limit the number of concurrent promises
that are running at any given time. It's used to limit the number of concurrent
prefetch requests that are being made to the server but could be used for other
things as well.
*/ import { _ as _class_private_field_loose_base } from "@swc/helpers/_/_class_private_field_loose_base";
import { _ as _class_private_field_loose_key } from "@swc/helpers/_/_class_private_field_loose_key";
var _maxConcurrency = /*#__PURE__*/ _class_private_field_loose_key("_maxConcurrency"), _runningCount = /*#__PURE__*/ _class_private_field_loose_key("_runningCount"), _queue = /*#__PURE__*/ _class_private_field_loose_key("_queue"), _processNext = /*#__PURE__*/ _class_private_field_loose_key("_processNext");
export class PromiseQueue {
enqueue(promiseFn) {
let taskResolve;
let taskReject;
const taskPromise = new Promise((resolve, reject)=>{
taskResolve = resolve;
taskReject = reject;
});
const task = async ()=>{
try {
_class_private_field_loose_base(this, _runningCount)[_runningCount]++;
const result = await promiseFn();
taskResolve(result);
} catch (error) {
taskReject(error);
} finally{
_class_private_field_loose_base(this, _runningCount)[_runningCount]--;
_class_private_field_loose_base(this, _processNext)[_processNext]();
}
};
const enqueueResult = {
promiseFn: taskPromise,
task
};
// wonder if we should take a LIFO approach here
_class_private_field_loose_base(this, _queue)[_queue].push(enqueueResult);
_class_private_field_loose_base(this, _processNext)[_processNext]();
return taskPromise;
}
bump(promiseFn) {
const index = _class_private_field_loose_base(this, _queue)[_queue].findIndex((item)=>item.promiseFn === promiseFn);
if (index > -1) {
const bumpedItem = _class_private_field_loose_base(this, _queue)[_queue].splice(index, 1)[0];
_class_private_field_loose_base(this, _queue)[_queue].unshift(bumpedItem);
_class_private_field_loose_base(this, _processNext)[_processNext](true);
}
}
constructor(maxConcurrency = 5){
Object.defineProperty(this, _processNext, {
value: processNext
});
Object.defineProperty(this, _maxConcurrency, {
writable: true,
value: void 0
});
Object.defineProperty(this, _runningCount, {
writable: true,
value: void 0
});
Object.defineProperty(this, _queue, {
writable: true,
value: void 0
});
_class_private_field_loose_base(this, _maxConcurrency)[_maxConcurrency] = maxConcurrency;
_class_private_field_loose_base(this, _runningCount)[_runningCount] = 0;
_class_private_field_loose_base(this, _queue)[_queue] = [];
}
}
function processNext(forced) {
if (forced === void 0) forced = false;
if ((_class_private_field_loose_base(this, _runningCount)[_runningCount] < _class_private_field_loose_base(this, _maxConcurrency)[_maxConcurrency] || forced) && _class_private_field_loose_base(this, _queue)[_queue].length > 0) {
var _class_private_field_loose_base__queue_shift;
(_class_private_field_loose_base__queue_shift = _class_private_field_loose_base(this, _queue)[_queue].shift()) == null ? void 0 : _class_private_field_loose_base__queue_shift.task();
}
}
//# sourceMappingURL=promise-queue.js.map