2026-10-14 09:40:12 -07:00
|
|
|
import { get, put, subscribe } from "./api.js";
|
2026-10-14 22:42:46 -07:00
|
|
|
import { errorText, h, replace, showAlert } from "./dom.js";
|
2026-10-16 08:42:48 -07:00
|
|
|
import { loadDrafts } from "./drafts.js";
|
2026-10-15 09:40:30 -07:00
|
|
|
import { leadPane, taskPane } from "./panes.js";
|
2026-10-15 18:55:38 -07:00
|
|
|
import { handleEvent, loadFocus, loadInbox, loadLeadSessions, loadMe, loadProjects, notify, on, selectTask, setFocus, startLeadStream, state, tabs } from "./state.js";
|
2026-10-15 22:21:20 -07:00
|
|
|
import { bindShortcuts } from "./switcher.js";
|
2026-10-14 09:40:12 -07:00
|
|
|
function identityBanner(root) {
|
|
|
|
|
const render = () => {
|
|
|
|
|
const me = state.me;
|
|
|
|
|
if (!me || (me.git_name && me.git_email)) {
|
|
|
|
|
replace(root);
|
|
|
|
|
root.hidden = true;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const name = h("input", { placeholder: "Git name", value: me.display_name, required: true });
|
|
|
|
|
const email = h("input", { type: "email", placeholder: "Git email", required: true });
|
|
|
|
|
const form = h("form", { class: "inline-form" }, "Set the identity agents commit as: ", name, email, h("button", { type: "submit" }, "Save"));
|
|
|
|
|
form.onsubmit = async (e) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
try {
|
|
|
|
|
state.me = await put("/api/me", { body: { git_name: name.value, git_email: email.value } });
|
|
|
|
|
render();
|
|
|
|
|
}
|
|
|
|
|
catch (err) {
|
2026-10-14 22:42:46 -07:00
|
|
|
void showAlert(errorText(err));
|
2026-10-14 09:40:12 -07:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
root.hidden = false;
|
|
|
|
|
replace(root, form);
|
|
|
|
|
};
|
|
|
|
|
on("me", render);
|
|
|
|
|
render();
|
|
|
|
|
}
|
|
|
|
|
function route() {
|
2026-10-15 18:55:38 -07:00
|
|
|
const match = /^#\/(task|project)\/(\w+)(?:\/(\w+))?$/.exec(location.hash);
|
2026-10-15 09:59:13 -07:00
|
|
|
const taskId = match?.[1] === "task" ? match[2] : undefined;
|
|
|
|
|
const projectId = match?.[1] === "project" ? match[2] : undefined;
|
2026-10-15 18:55:38 -07:00
|
|
|
const tab = tabs.find((t) => t === match?.[3]);
|
2026-10-15 09:59:13 -07:00
|
|
|
if (taskId) {
|
2026-10-15 18:55:38 -07:00
|
|
|
if (taskId !== state.focus.task_id || (tab && tab !== state.focus.tab)) {
|
|
|
|
|
setFocus({ task_id: taskId, tab }).catch((err) => console.error("set focus", err));
|
2026-10-15 09:59:13 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (state.focus.task_id || projectId !== state.focus.project_id) {
|
|
|
|
|
setFocus({ task_id: null, project_id: projectId ?? null }).catch((err) => console.error("set focus", err));
|
2026-10-15 09:40:30 -07:00
|
|
|
}
|
2026-10-14 09:40:12 -07:00
|
|
|
if (taskId !== state.selectedTaskId) {
|
2026-10-14 23:53:17 -07:00
|
|
|
selectTask(taskId);
|
2026-10-14 09:40:12 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
async function main() {
|
|
|
|
|
const banner = h("div", { class: "banner", hidden: true });
|
2026-10-15 09:40:30 -07:00
|
|
|
const status = await get("/api/admin/status");
|
|
|
|
|
await Promise.all([loadMe(), loadProjects(), loadInbox(), loadLeadSessions()]);
|
2026-10-16 08:42:48 -07:00
|
|
|
loadDrafts();
|
2026-10-15 09:40:30 -07:00
|
|
|
const linked = location.hash;
|
|
|
|
|
await loadFocus();
|
2026-10-15 18:55:38 -07:00
|
|
|
if (/^#\/(task|project)\/\w+(\/\w+)?$/.test(linked)) {
|
2026-10-15 09:40:30 -07:00
|
|
|
location.hash = linked;
|
|
|
|
|
}
|
|
|
|
|
startLeadStream();
|
2026-10-15 22:21:20 -07:00
|
|
|
replace(document.body, banner, h("div", { class: "panes" }, leadPane(), taskPane()));
|
|
|
|
|
bindShortcuts();
|
2026-10-14 09:40:12 -07:00
|
|
|
identityBanner(banner);
|
2026-10-14 23:34:39 -07:00
|
|
|
addEventListener("keydown", (e) => {
|
|
|
|
|
if (e.key !== "Escape") {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
document.querySelector("dialog[open]")?.close();
|
|
|
|
|
}, { capture: true });
|
2026-10-15 09:40:30 -07:00
|
|
|
subscribe(status.last_event_seq, {}, handleEvent, (connected) => {
|
2026-10-14 09:40:12 -07:00
|
|
|
state.connected = connected;
|
|
|
|
|
notify("connection");
|
2026-10-16 10:45:38 -07:00
|
|
|
}, () => undefined);
|
2026-10-14 09:40:12 -07:00
|
|
|
addEventListener("hashchange", route);
|
|
|
|
|
route();
|
2026-10-15 18:34:53 -07:00
|
|
|
}
|
|
|
|
|
async function start() {
|
2026-10-14 21:25:01 -07:00
|
|
|
if ("serviceWorker" in navigator) {
|
2026-10-15 18:34:53 -07:00
|
|
|
for (const reg of await navigator.serviceWorker.getRegistrations()) {
|
|
|
|
|
await reg.unregister();
|
|
|
|
|
}
|
|
|
|
|
if (navigator.serviceWorker.controller) {
|
|
|
|
|
location.reload();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-10-14 21:25:01 -07:00
|
|
|
}
|
2026-10-15 18:34:53 -07:00
|
|
|
await main();
|
2026-10-14 09:40:12 -07:00
|
|
|
}
|
2026-10-15 18:34:53 -07:00
|
|
|
start().catch((err) => {
|
2026-10-14 09:40:12 -07:00
|
|
|
replace(document.body, h("pre", { class: "fatal" }, `byre failed to start: ${errorText(err)}`));
|
|
|
|
|
});
|
|
|
|
|
//# sourceMappingURL=app.js.map
|