dawlad-paperclip-direction 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/manifest.js +1 -1
- package/dist/ui/index.js +266 -60
- package/dist/ui/index.js.map +3 -3
- package/package.json +1 -1
package/dist/manifest.js
CHANGED
|
@@ -11,7 +11,7 @@ var route = (routeKey, method, path) => ({
|
|
|
11
11
|
var manifest = {
|
|
12
12
|
id: "dawlad.direction",
|
|
13
13
|
apiVersion: 1,
|
|
14
|
-
version: "0.2.
|
|
14
|
+
version: "0.2.2",
|
|
15
15
|
displayName: "Direction",
|
|
16
16
|
description: "Horizon, campaigns, milestones and one queue of decisions: where Dawlad is heading and what's in the way.",
|
|
17
17
|
author: "Aly Solamon",
|
package/dist/ui/index.js
CHANGED
|
@@ -216,8 +216,31 @@ html:has([data-dx-page="decisions"]) ol[data-slot="breadcrumb-list"]:has(a[href$
|
|
|
216
216
|
.dx-err { color: var(--dx-red); font-size: 13px; }
|
|
217
217
|
.dx-tabs-line { display: flex; gap: 6px; }
|
|
218
218
|
/* Decisions: documents beside the card */
|
|
219
|
-
.dx-dq.beside { grid-template-columns:
|
|
220
|
-
.dx-dq.beside.wide { grid-template-columns: minmax(
|
|
219
|
+
.dx-dq.beside { grid-template-columns: 250px minmax(0, 1fr) minmax(0, 1.05fr); }
|
|
220
|
+
.dx-dq.beside.wide { grid-template-columns: minmax(0, .8fr) minmax(0, 1.6fr); }
|
|
221
|
+
.dx-dq.beside.closed { grid-template-columns: 250px minmax(0, 1fr) 44px; }
|
|
222
|
+
.dx-dq-main { min-width: 0; }
|
|
223
|
+
.dx-pane-rail { border-left: 1px solid var(--dx-line); display: flex; flex-direction: column; align-items: center; gap: 10px; padding-top: 12px; position: sticky; top: 0; height: calc(100vh - 60px); }
|
|
224
|
+
.dx-pane-rail-t { writing-mode: vertical-rl; font-size: 12px; color: var(--dx-muted); cursor: pointer; letter-spacing: .04em; }
|
|
225
|
+
.dx-pane-rail-t:hover { color: var(--dx-fg); }
|
|
226
|
+
.dx-menu-anchor { position: relative; flex: none; }
|
|
227
|
+
.dx-menu.right { left: auto; right: 0; }
|
|
228
|
+
.dx-menu { position: absolute; top: calc(100% + 6px); left: 0; z-index: 30; width: 340px; max-width: calc(100vw - 32px); background: var(--dx-card); border: 1px solid var(--dx-line); border-radius: 10px; box-shadow: 0 8px 28px rgb(0 0 0 / .14); display: flex; flex-direction: column; max-height: 70vh; }
|
|
229
|
+
.dx-menu-search { display: flex; align-items: center; gap: 8px; padding: 10px 12px; border-bottom: 1px solid var(--dx-line); color: var(--dx-muted); }
|
|
230
|
+
.dx-menu-search input { border: 0; outline: none; background: transparent; color: var(--dx-fg); font-size: 13.5px; flex: 1; min-width: 0; }
|
|
231
|
+
.dx-menu-body { overflow: auto; padding: 4px 6px 8px; }
|
|
232
|
+
.dx-menu-label { font-size: 12px; color: var(--dx-muted); padding: 10px 8px 4px; }
|
|
233
|
+
.dx-menu-item { display: flex; align-items: flex-start; gap: 10px; width: 100%; text-align: left; border: 0; background: transparent; color: var(--dx-fg); padding: 7px 8px; border-radius: 6px; cursor: pointer; font-size: 13.5px; }
|
|
234
|
+
.dx-menu-item:hover, .dx-menu-item:focus-visible { background: var(--dx-soft2); outline: none; }
|
|
235
|
+
.dx-menu-item svg { margin-top: 3px; flex: none; }
|
|
236
|
+
.dx-menu-item .t { display: flex; flex-direction: column; min-width: 0; flex: 1; }
|
|
237
|
+
.dx-menu-item .t > span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
238
|
+
.dx-menu-item .s { font-size: 11.5px; color: var(--dx-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
239
|
+
.dx-menu-item .ck { color: var(--dx-fg); font-size: 12px; }
|
|
240
|
+
.dx-run-stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; border-top: 1px solid var(--dx-line); border-bottom: 1px solid var(--dx-line); padding: 12px 0; margin-bottom: 16px; }
|
|
241
|
+
.dx-run-stats b { display: block; font-size: 16px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
242
|
+
.dx-run-stats span { font-size: 12px; color: var(--dx-muted); }
|
|
243
|
+
.dx-run-h { font-size: 14px; font-weight: 600; margin: 0 0 8px; }
|
|
221
244
|
.dx-dq.beside.wide .dx-dq-list { display: none; }
|
|
222
245
|
.dx-dq-foot { margin-top: 10px; border-top: 1px solid var(--dx-line); padding: 10px 8px 0; font-size: 12px; color: var(--dx-muted); cursor: pointer; }
|
|
223
246
|
.dx-dq-foot:hover { color: var(--dx-fg); }
|
|
@@ -227,7 +250,8 @@ html:has([data-dx-page="decisions"]) ol[data-slot="breadcrumb-list"]:has(a[href$
|
|
|
227
250
|
.dx-pill.lane-this-week { color: var(--dx-amber); background: var(--dx-amber-bg); border-color: transparent; }
|
|
228
251
|
.dx-pill.lane-needs-work { color: var(--dx-amber); border-color: var(--dx-amber-line); }
|
|
229
252
|
.dx-pane { border-left: 1px solid var(--dx-line); display: flex; flex-direction: column; min-width: 0; position: sticky; top: 0; height: calc(100vh - 60px); background: var(--dx-bg); }
|
|
230
|
-
.dx-pane-
|
|
253
|
+
.dx-pane-head { display: flex; align-items: center; gap: 4px; padding: 10px 12px; border-bottom: 1px solid var(--dx-line); flex: none; min-width: 0; }
|
|
254
|
+
.dx-pane-tabs { display: flex; align-items: center; gap: 4px; overflow-x: auto; min-width: 0; flex: 0 1 auto; scrollbar-width: none; }
|
|
231
255
|
.dx-pane-tab { display: inline-flex; align-items: center; gap: 6px; padding: 5px 6px 5px 9px; border-radius: 6px; font-size: 13px; color: var(--dx-muted); cursor: pointer; max-width: 220px; flex: none; }
|
|
232
256
|
.dx-pane-tab .t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
233
257
|
.dx-pane-tab.on { background: var(--dx-soft2); color: var(--dx-fg); }
|
|
@@ -236,7 +260,7 @@ html:has([data-dx-page="decisions"]) ol[data-slot="breadcrumb-list"]:has(a[href$
|
|
|
236
260
|
.dx-icon { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: 6px; border: 0; background: transparent; color: var(--dx-muted); cursor: pointer; flex: none; }
|
|
237
261
|
.dx-icon:hover, .dx-icon.on { background: var(--dx-soft2); color: var(--dx-fg); }
|
|
238
262
|
.dx-icon:focus-visible, .dx-pane-tab:focus-visible { outline: 2px solid var(--dx-blue); outline-offset: 1px; }
|
|
239
|
-
.dx-pane-add { border-bottom: 1px solid var(--dx-line); padding: 6px 14px 10px; max-height: 40%; overflow: auto; flex: none; }
|
|
263
|
+
.dx-pane-add-unused { border-bottom: 1px solid var(--dx-line); padding: 6px 14px 10px; max-height: 40%; overflow: auto; flex: none; }
|
|
240
264
|
.dx-pane-pick { display: flex; align-items: center; gap: 8px; padding: 6px 6px; border-radius: 6px; cursor: pointer; font-size: 13px; }
|
|
241
265
|
.dx-pane-pick:hover { background: var(--dx-soft); }
|
|
242
266
|
.dx-pane-pick .t { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
@@ -249,13 +273,15 @@ html:has([data-dx-page="decisions"]) ol[data-slot="breadcrumb-list"]:has(a[href$
|
|
|
249
273
|
.dx-convo { padding: 2px 0 12px 22px; display: grid; gap: 12px; }
|
|
250
274
|
.dx-convo-c { border-left: 2px solid var(--dx-line); padding-left: 10px; }
|
|
251
275
|
@media (max-width: 1200px) {
|
|
252
|
-
.dx-dq.beside, .dx-dq.beside.wide { grid-template-columns: 240px minmax(0, 1fr); }
|
|
276
|
+
.dx-dq.beside, .dx-dq.beside.wide, .dx-dq.beside.closed { grid-template-columns: 240px minmax(0, 1fr); }
|
|
277
|
+
.dx-pane-rail { grid-column: 1 / -1; flex-direction: row; height: auto; position: static; border-left: 0; border-top: 1px solid var(--dx-line); padding: 8px 12px; }
|
|
278
|
+
.dx-pane-rail-t { writing-mode: horizontal-tb; }
|
|
253
279
|
.dx-dq.beside.wide .dx-dq-list { display: flex; }
|
|
254
280
|
.dx-pane { grid-column: 1 / -1; position: static; height: 75vh; border-left: 0; border-top: 1px solid var(--dx-line); }
|
|
255
281
|
.dx-wide-btn { display: none; }
|
|
256
282
|
}
|
|
257
283
|
@media (max-width: 760px) {
|
|
258
|
-
.dx-dq.beside, .dx-dq.beside.wide { grid-template-columns: minmax(0, 1fr); margin: -16px; }
|
|
284
|
+
.dx-dq.beside, .dx-dq.beside.wide, .dx-dq.beside.closed { grid-template-columns: minmax(0, 1fr); margin: -16px; }
|
|
259
285
|
.dx-dq-list { border-right: 0; border-bottom: 1px solid var(--dx-line); max-height: 40vh; }
|
|
260
286
|
.dx-dq-main { padding: 16px; }
|
|
261
287
|
}
|
|
@@ -2147,7 +2173,7 @@ import { useEffect as useEffect4, useMemo as useMemo4, useState as useState7 } f
|
|
|
2147
2173
|
import { MarkdownBlock as MarkdownBlock2, usePluginAction as usePluginAction2, usePluginData as usePluginData2 } from "@paperclipai/plugin-sdk/ui";
|
|
2148
2174
|
|
|
2149
2175
|
// src/ui/beside.tsx
|
|
2150
|
-
import { useEffect as useEffect3, useMemo as useMemo3, useState as useState6 } from "react";
|
|
2176
|
+
import { useEffect as useEffect3, useMemo as useMemo3, useRef as useRef2, useState as useState6 } from "react";
|
|
2151
2177
|
import { MarkdownBlock } from "@paperclipai/plugin-sdk/ui";
|
|
2152
2178
|
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2153
2179
|
var get = async (path) => {
|
|
@@ -2223,30 +2249,76 @@ var Ico = {
|
|
|
2223
2249
|
out: /* @__PURE__ */ jsx7("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx7("path", { d: "M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5" }) }),
|
|
2224
2250
|
doc: /* @__PURE__ */ jsx7("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx7("path", { d: "M14 3H6a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V8z M14 3v5h5 M8 13h8M8 17h6" }) }),
|
|
2225
2251
|
file: /* @__PURE__ */ jsx7("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx7("path", { d: "M4 5h16v14H4z M4 9h16 M9 9v10" }) }),
|
|
2252
|
+
search: /* @__PURE__ */ jsxs7("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
2253
|
+
/* @__PURE__ */ jsx7("circle", { cx: "11", cy: "11", r: "7" }),
|
|
2254
|
+
/* @__PURE__ */ jsx7("path", { d: "m20 20-3.5-3.5" })
|
|
2255
|
+
] }),
|
|
2256
|
+
run: /* @__PURE__ */ jsx7("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx7("path", { d: "M3 12h4l3-8 4 16 3-8h4" }) }),
|
|
2226
2257
|
phone: /* @__PURE__ */ jsx7("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", children: /* @__PURE__ */ jsx7("path", { d: "M22 16.9v3a2 2 0 0 1-2.2 2 19.8 19.8 0 0 1-8.6-3.1 19.5 19.5 0 0 1-6-6A19.8 19.8 0 0 1 2.1 4.2 2 2 0 0 1 4.1 2h3a2 2 0 0 1 2 1.7c.1 1 .4 1.9.7 2.8a2 2 0 0 1-.5 2.1L8.1 9.9a16 16 0 0 0 6 6l1.3-1.3a2 2 0 0 1 2.1-.4c.9.3 1.8.6 2.8.7a2 2 0 0 1 1.7 2z" }) })
|
|
2227
2258
|
};
|
|
2228
|
-
function
|
|
2259
|
+
function useRuns(issueId, companyId) {
|
|
2260
|
+
const [runs, setRuns] = useState6([]);
|
|
2261
|
+
const [agents, setAgents] = useState6([]);
|
|
2262
|
+
useEffect3(() => {
|
|
2263
|
+
if (!issueId) return;
|
|
2264
|
+
let live = true;
|
|
2265
|
+
get(`/issues/${issueId}/runs`).then((r) => live && setRuns(r.filter((x) => !["queued"].includes(x.status)).slice(0, 4))).catch(() => {
|
|
2266
|
+
});
|
|
2267
|
+
if (companyId) get(`/companies/${companyId}/agents`).then((a) => live && setAgents(a)).catch(() => {
|
|
2268
|
+
});
|
|
2269
|
+
return () => {
|
|
2270
|
+
live = false;
|
|
2271
|
+
};
|
|
2272
|
+
}, [issueId, companyId]);
|
|
2273
|
+
return { runs, agentName: (id) => agents.find((a) => a.id === id)?.name ?? "Agent" };
|
|
2274
|
+
}
|
|
2275
|
+
var minutes = (a, b) => a && b ? Math.max(1, Math.round((Date.parse(b) - Date.parse(a)) / 6e4)) : null;
|
|
2276
|
+
function BesidePane({ d, wide, setWide, onClose }) {
|
|
2229
2277
|
const go = useGo("decide");
|
|
2230
2278
|
const { all, issue, linked, loading, error } = useResources(d);
|
|
2279
|
+
const { runs, agentName } = useRuns(d.issueId, issue?.companyId ?? null);
|
|
2231
2280
|
const [open, setOpen] = useState6([]);
|
|
2232
2281
|
const [active, setActive] = useState6(null);
|
|
2233
|
-
const [
|
|
2282
|
+
const [menu, setMenu] = useState6(false);
|
|
2283
|
+
const [right, setRight] = useState6(false);
|
|
2284
|
+
const [q, setQ] = useState6("");
|
|
2234
2285
|
const [asked, setAsked] = useState6(false);
|
|
2286
|
+
const menuRef = useRef2(null);
|
|
2235
2287
|
useEffect3(() => {
|
|
2236
2288
|
if (loading) return;
|
|
2237
2289
|
const have = new Set(all.map((r) => r.key));
|
|
2238
2290
|
let first = [...linked.docs, ...linked.files].filter((k) => have.has(k));
|
|
2239
2291
|
if (!first.length) {
|
|
2240
2292
|
const own = all.filter((r) => r.where === "task");
|
|
2241
|
-
const
|
|
2242
|
-
first =
|
|
2293
|
+
const pick2 = own.find((r) => r.primary) ?? own.find((r) => r.kind === "file" && /html/.test(r.file?.contentType ?? "")) ?? own.find((r) => r.kind === "doc");
|
|
2294
|
+
first = pick2 ? [pick2.key] : [];
|
|
2243
2295
|
}
|
|
2244
2296
|
setOpen([...new Set(first)]);
|
|
2245
2297
|
setActive(first[0] ?? null);
|
|
2246
2298
|
}, [loading, d.key]);
|
|
2247
|
-
|
|
2248
|
-
|
|
2299
|
+
useEffect3(() => {
|
|
2300
|
+
if (!menu) return;
|
|
2301
|
+
const away = (e) => {
|
|
2302
|
+
if (menuRef.current && !menuRef.current.contains(e.target)) setMenu(false);
|
|
2303
|
+
};
|
|
2304
|
+
const esc = (e) => {
|
|
2305
|
+
if (e.key === "Escape") setMenu(false);
|
|
2306
|
+
};
|
|
2307
|
+
document.addEventListener("mousedown", away);
|
|
2308
|
+
document.addEventListener("keydown", esc);
|
|
2309
|
+
return () => {
|
|
2310
|
+
document.removeEventListener("mousedown", away);
|
|
2311
|
+
document.removeEventListener("keydown", esc);
|
|
2312
|
+
};
|
|
2313
|
+
}, [menu]);
|
|
2314
|
+
const runRes = runs.map((r) => {
|
|
2315
|
+
const id = r.runId ?? r.id ?? "";
|
|
2316
|
+
const took = minutes(r.startedAt ?? r.createdAt, r.finishedAt);
|
|
2317
|
+
return { key: `run:${id}`, kind: "run", title: `${agentName(r.agentId)}'s run ${id.slice(0, 8)}`, sub: `${ago(r.createdAt)} \xB7 ${r.status}${took ? ` \xB7 ${took} min` : ""} \xB7 read, made, changed`, issue, where: "task", run: { ...r, id, agentName: agentName(r.agentId) } };
|
|
2318
|
+
});
|
|
2319
|
+
const byKey = useMemo3(() => new Map([...all, ...runRes].map((r) => [r.key, r])), [all, runs]);
|
|
2249
2320
|
const cur = active ? byKey.get(active) : void 0;
|
|
2321
|
+
const missingLinks = [...linked.docs, ...linked.files].filter((k) => !all.some((r) => r.key === k));
|
|
2250
2322
|
const toggle = (k) => {
|
|
2251
2323
|
if (open.includes(k)) {
|
|
2252
2324
|
const rest = open.filter((x) => x !== k);
|
|
@@ -2257,6 +2329,12 @@ function BesidePane({ d, wide, setWide }) {
|
|
|
2257
2329
|
setActive(k);
|
|
2258
2330
|
}
|
|
2259
2331
|
};
|
|
2332
|
+
const pick = (k) => {
|
|
2333
|
+
if (!open.includes(k)) setOpen([...open, k]);
|
|
2334
|
+
setActive(k);
|
|
2335
|
+
setMenu(false);
|
|
2336
|
+
setQ("");
|
|
2337
|
+
};
|
|
2260
2338
|
const askForEvidence = async () => {
|
|
2261
2339
|
if (!issue) return;
|
|
2262
2340
|
await fetch(`/api/issues/${issue.id}/comments`, {
|
|
@@ -2269,59 +2347,78 @@ function BesidePane({ d, wide, setWide }) {
|
|
|
2269
2347
|
});
|
|
2270
2348
|
setAsked(true);
|
|
2271
2349
|
};
|
|
2350
|
+
const match = (r) => !q || `${r.title} ${r.sub}`.toLowerCase().includes(q.toLowerCase());
|
|
2272
2351
|
const groups = [
|
|
2273
|
-
{ label:
|
|
2274
|
-
{ label: "
|
|
2275
|
-
{ label: "
|
|
2276
|
-
|
|
2352
|
+
{ label: "Open", list: open.map((k) => byKey.get(k)).filter((r) => !!r) },
|
|
2353
|
+
{ label: issue ? `Task documents \xB7 ${issue.identifier}` : "Task documents", list: all.filter((r) => r.where === "task" && !open.includes(r.key)) },
|
|
2354
|
+
{ label: "Parent task", list: all.filter((r) => r.where === "parent" && !open.includes(r.key)) },
|
|
2355
|
+
{ label: "Linked from the card", list: all.filter((r) => r.where === "linked" && !open.includes(r.key)) },
|
|
2356
|
+
{ label: "Runs", list: runRes.filter((r) => !open.includes(r.key)) }
|
|
2357
|
+
].map((g) => ({ ...g, list: g.list.filter(match) })).filter((g) => g.list.length);
|
|
2358
|
+
const icon = (r) => r.kind === "doc" ? Ico.doc : r.kind === "run" ? Ico.run : Ico.file;
|
|
2359
|
+
const talkTo = d.waitingAgentId && d.waitingName && d.waitingName !== "Jev" ? { id: d.waitingAgentId, name: d.waitingName } : null;
|
|
2277
2360
|
return /* @__PURE__ */ jsxs7("aside", { className: "dx-pane", children: [
|
|
2278
|
-
/* @__PURE__ */ jsxs7("div", { className: "dx-pane-
|
|
2279
|
-
open.map((k) => {
|
|
2361
|
+
/* @__PURE__ */ jsxs7("div", { className: "dx-pane-head", children: [
|
|
2362
|
+
/* @__PURE__ */ jsx7("div", { className: "dx-pane-tabs", children: open.map((k) => {
|
|
2280
2363
|
const r = byKey.get(k);
|
|
2281
2364
|
return r && /* @__PURE__ */ jsxs7("span", { className: `dx-pane-tab${k === active ? " on" : ""}`, onClick: () => setActive(k), title: r.title, children: [
|
|
2282
|
-
r
|
|
2365
|
+
icon(r),
|
|
2283
2366
|
/* @__PURE__ */ jsx7("span", { className: "t", children: r.title }),
|
|
2284
2367
|
/* @__PURE__ */ jsx7("button", { "aria-label": `Close ${r.title}`, onClick: (e) => {
|
|
2285
2368
|
e.stopPropagation();
|
|
2286
2369
|
toggle(k);
|
|
2287
2370
|
}, children: Ico.x })
|
|
2288
2371
|
] }, k);
|
|
2289
|
-
}),
|
|
2372
|
+
}) }),
|
|
2373
|
+
/* @__PURE__ */ jsxs7("div", { className: "dx-menu-anchor", ref: menuRef, children: [
|
|
2374
|
+
/* @__PURE__ */ jsx7("button", { className: `dx-icon${menu ? " on" : ""}`, "aria-label": "Add a tab", "aria-expanded": menu, title: "Add a document, file or run", onClick: (e) => {
|
|
2375
|
+
const x = e.currentTarget.getBoundingClientRect();
|
|
2376
|
+
setRight(x.left + 360 > window.innerWidth - 16);
|
|
2377
|
+
setMenu(!menu);
|
|
2378
|
+
}, children: Ico.plus }),
|
|
2379
|
+
menu && /* @__PURE__ */ jsxs7("div", { className: `dx-menu${right ? " right" : ""}`, role: "menu", children: [
|
|
2380
|
+
/* @__PURE__ */ jsxs7("label", { className: "dx-menu-search", children: [
|
|
2381
|
+
Ico.search,
|
|
2382
|
+
/* @__PURE__ */ jsx7("input", { autoFocus: true, placeholder: "Search tabs and resources\u2026", value: q, onChange: (e) => setQ(e.target.value) })
|
|
2383
|
+
] }),
|
|
2384
|
+
/* @__PURE__ */ jsxs7("div", { className: "dx-menu-body", children: [
|
|
2385
|
+
groups.map((g) => /* @__PURE__ */ jsxs7("div", { children: [
|
|
2386
|
+
/* @__PURE__ */ jsx7("div", { className: "dx-menu-label", children: g.label }),
|
|
2387
|
+
g.list.map((r) => /* @__PURE__ */ jsxs7("button", { className: "dx-menu-item", role: "menuitem", onClick: () => g.label === "Open" ? (setActive(r.key), setMenu(false)) : pick(r.key), children: [
|
|
2388
|
+
icon(r),
|
|
2389
|
+
/* @__PURE__ */ jsxs7("span", { className: "t", children: [
|
|
2390
|
+
/* @__PURE__ */ jsx7("span", { children: r.title }),
|
|
2391
|
+
/* @__PURE__ */ jsx7("span", { className: "s", children: r.sub })
|
|
2392
|
+
] }),
|
|
2393
|
+
g.label === "Open" && /* @__PURE__ */ jsx7("span", { className: "ck", children: "\u2713" })
|
|
2394
|
+
] }, r.key))
|
|
2395
|
+
] }, g.label)),
|
|
2396
|
+
(!q || /talk|ask|call|jev/i.test(q) || talkTo && talkTo.name.toLowerCase().includes(q.toLowerCase())) && /* @__PURE__ */ jsxs7("div", { children: [
|
|
2397
|
+
/* @__PURE__ */ jsx7("div", { className: "dx-menu-label", children: "Talk" }),
|
|
2398
|
+
talkTo && /* @__PURE__ */ jsx7(TalkMenuItem, { d, agentId: talkTo.id, label: `Talk it through with ${talkTo.name}`, sub: "a call \xB7 knows this decision, its documents and runs", onDone: () => setMenu(false) }),
|
|
2399
|
+
/* @__PURE__ */ jsx7(TalkMenuItem, { d, agentId: null, label: "Ask Jev about this decision", sub: "a call \xB7 the bigger picture", onDone: () => setMenu(false) })
|
|
2400
|
+
] }),
|
|
2401
|
+
!groups.length && q && /* @__PURE__ */ jsxs7("div", { className: "dx-muted dx-small", style: { padding: "8px 10px" }, children: [
|
|
2402
|
+
'Nothing matches "',
|
|
2403
|
+
q,
|
|
2404
|
+
'".'
|
|
2405
|
+
] })
|
|
2406
|
+
] })
|
|
2407
|
+
] })
|
|
2408
|
+
] }),
|
|
2290
2409
|
/* @__PURE__ */ jsx7("span", { style: { flex: 1 } }),
|
|
2291
|
-
/* @__PURE__ */ jsx7("button", { className: `dx-icon${adding ? " on" : ""}`, "aria-label": "Add a tab", title: "Add a document or file", onClick: () => setAdding(!adding), children: Ico.plus }),
|
|
2292
2410
|
/* @__PURE__ */ jsx7("button", { className: "dx-icon dx-wide-btn", "aria-label": wide ? "Narrow the panel" : "Widen the panel", title: wide ? "Narrow" : "Widen", onClick: () => setWide(!wide), children: wide ? Ico.narrow : Ico.wide }),
|
|
2293
|
-
cur && /* @__PURE__ */ jsx7("a", { className: "dx-icon", title: "Open in the task", ...go.hostLink(cur.kind === "doc" ? `/issues/${cur.issue.identifier}#document-${cur.doc.key}` : `/issues/${cur.issue.identifier}`), children: Ico.out })
|
|
2294
|
-
|
|
2295
|
-
adding && /* @__PURE__ */ jsxs7("div", { className: "dx-pane-add", children: [
|
|
2296
|
-
groups.map((g) => /* @__PURE__ */ jsxs7("div", { children: [
|
|
2297
|
-
/* @__PURE__ */ jsx7("div", { className: "dx-group-label", style: { margin: "6px 0 2px" }, children: g.label }),
|
|
2298
|
-
g.list.map((r) => /* @__PURE__ */ jsxs7("div", { className: "dx-pane-pick", onClick: () => {
|
|
2299
|
-
toggle(r.key);
|
|
2300
|
-
setAdding(false);
|
|
2301
|
-
}, children: [
|
|
2302
|
-
r.kind === "doc" ? Ico.doc : Ico.file,
|
|
2303
|
-
/* @__PURE__ */ jsx7("span", { className: "t", children: r.title }),
|
|
2304
|
-
/* @__PURE__ */ jsx7("span", { className: "dx-muted dx-xs", children: r.sub }),
|
|
2305
|
-
open.includes(r.key) && /* @__PURE__ */ jsx7("span", { className: "dx-xs", children: "\u2713" })
|
|
2306
|
-
] }, r.key))
|
|
2307
|
-
] }, g.label)),
|
|
2308
|
-
!groups.length && /* @__PURE__ */ jsx7("div", { className: "dx-muted dx-small", children: "Nothing on this task or its parent yet." })
|
|
2411
|
+
cur && /* @__PURE__ */ jsx7("a", { className: "dx-icon", title: "Open in the task", ...go.hostLink(cur.kind === "doc" ? `/issues/${cur.issue.identifier}#document-${cur.doc.key}` : cur.kind === "run" ? `/agents/${cur.run.agentId}/runs/${cur.run.id}` : `/issues/${cur.issue.identifier}`), children: Ico.out }),
|
|
2412
|
+
/* @__PURE__ */ jsx7("button", { className: "dx-icon", "aria-label": "Hide the panel", title: "Hide the panel", onClick: onClose, children: Ico.x })
|
|
2309
2413
|
] }),
|
|
2310
2414
|
/* @__PURE__ */ jsxs7("div", { className: `dx-pane-body${cur?.kind === "file" && /html|pdf/.test(cur.file.contentType) ? " flush" : ""}`, children: [
|
|
2311
2415
|
loading ? /* @__PURE__ */ jsx7("div", { className: "dx-muted dx-small", children: "Loading what this rests on\u2026" }) : error ? /* @__PURE__ */ jsxs7("div", { className: "dx-err", children: [
|
|
2312
2416
|
"Couldn't load the task's documents: ",
|
|
2313
2417
|
error
|
|
2314
|
-
] }) : cur ? /* @__PURE__ */ jsx7(Viewer, { r: cur }) : /* @__PURE__ */ jsxs7("div", { className: "dx-pane-empty", children: [
|
|
2315
|
-
/* @__PURE__ */
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
"."
|
|
2319
|
-
] }),
|
|
2320
|
-
/* @__PURE__ */ jsxs7("span", { className: "dx-muted dx-small", children: [
|
|
2321
|
-
"The card should link the documents it rests on. ",
|
|
2322
|
-
d.waitingName ? `${d.waitingName} gets a note on the task.` : ""
|
|
2323
|
-
] }),
|
|
2324
|
-
issue && (asked ? /* @__PURE__ */ jsx7("span", { className: "dx-small", children: "Asked. The agent wakes with your note." }) : /* @__PURE__ */ jsxs7("button", { className: "dx-btn", onClick: askForEvidence, children: [
|
|
2418
|
+
] }) : cur ? cur.kind === "run" ? /* @__PURE__ */ jsx7(RunView, { r: cur }) : /* @__PURE__ */ jsx7(Viewer, { r: cur }) : /* @__PURE__ */ jsxs7("div", { className: "dx-pane-empty", children: [
|
|
2419
|
+
/* @__PURE__ */ jsx7("b", { children: "Nothing is open." }),
|
|
2420
|
+
/* @__PURE__ */ jsx7("span", { className: "dx-muted dx-small", children: all.length ? "Use + to open a document, file or run from this task." : `Nothing is attached to ${issue?.identifier ?? "this decision"}. The card should link the documents it rests on.` }),
|
|
2421
|
+
!all.length && issue && (asked ? /* @__PURE__ */ jsx7("span", { className: "dx-small", children: "Asked. The agent wakes with your note." }) : /* @__PURE__ */ jsxs7("button", { className: "dx-btn", onClick: askForEvidence, children: [
|
|
2325
2422
|
"Ask ",
|
|
2326
2423
|
d.waitingName ?? "the agent",
|
|
2327
2424
|
" to attach the evidence"
|
|
@@ -2339,6 +2436,86 @@ function BesidePane({ d, wide, setWide }) {
|
|
|
2339
2436
|
] })
|
|
2340
2437
|
] });
|
|
2341
2438
|
}
|
|
2439
|
+
function PaneRail({ onOpen }) {
|
|
2440
|
+
return /* @__PURE__ */ jsxs7("aside", { className: "dx-pane-rail", children: [
|
|
2441
|
+
/* @__PURE__ */ jsx7("button", { className: "dx-icon", "aria-label": "Show the documents panel", title: "Show documents, files and runs", onClick: onOpen, children: Ico.doc }),
|
|
2442
|
+
/* @__PURE__ */ jsx7("span", { className: "dx-pane-rail-t", onClick: onOpen, children: "Documents" })
|
|
2443
|
+
] });
|
|
2444
|
+
}
|
|
2445
|
+
function TalkMenuItem({ d, agentId, label, sub, onDone }) {
|
|
2446
|
+
const start = useTalk(d, agentId);
|
|
2447
|
+
return /* @__PURE__ */ jsxs7("button", { className: "dx-menu-item", role: "menuitem", onClick: () => {
|
|
2448
|
+
void start();
|
|
2449
|
+
onDone();
|
|
2450
|
+
}, children: [
|
|
2451
|
+
Ico.phone,
|
|
2452
|
+
/* @__PURE__ */ jsxs7("span", { className: "t", children: [
|
|
2453
|
+
/* @__PURE__ */ jsx7("span", { children: label }),
|
|
2454
|
+
/* @__PURE__ */ jsx7("span", { className: "s", children: sub })
|
|
2455
|
+
] })
|
|
2456
|
+
] });
|
|
2457
|
+
}
|
|
2458
|
+
function RunView({ r }) {
|
|
2459
|
+
const run = r.run;
|
|
2460
|
+
const [detail, setDetail] = useState6(null);
|
|
2461
|
+
const [posted, setPosted] = useState6(null);
|
|
2462
|
+
const go = useGo("decide");
|
|
2463
|
+
useEffect3(() => {
|
|
2464
|
+
let live = true;
|
|
2465
|
+
get(`/heartbeat-runs/${run.id}`).then((x) => live && setDetail(x)).catch(() => {
|
|
2466
|
+
});
|
|
2467
|
+
get(`/issues/${r.issue.id}/comments`).then((c) => live && setPosted(c.filter((x) => x.createdByRunId === run.id))).catch(() => live && setPosted([]));
|
|
2468
|
+
return () => {
|
|
2469
|
+
live = false;
|
|
2470
|
+
};
|
|
2471
|
+
}, [run.id]);
|
|
2472
|
+
const u = detail?.usageJson ?? null;
|
|
2473
|
+
const took = minutes(detail?.startedAt ?? run.createdAt, detail?.finishedAt ?? run.finishedAt);
|
|
2474
|
+
const k = (n) => n == null ? "\u2014" : n >= 1e3 ? `${Math.round(n / 1e3)}k` : String(n);
|
|
2475
|
+
const verb = run.status === "succeeded" ? "finished" : run.status;
|
|
2476
|
+
return /* @__PURE__ */ jsxs7("article", { children: [
|
|
2477
|
+
/* @__PURE__ */ jsxs7("h2", { style: { fontSize: 18, fontWeight: 600, margin: "0 0 2px" }, children: [
|
|
2478
|
+
run.agentName,
|
|
2479
|
+
"'s run ",
|
|
2480
|
+
verb,
|
|
2481
|
+
took ? ` in ${took} min` : ""
|
|
2482
|
+
] }),
|
|
2483
|
+
/* @__PURE__ */ jsxs7("div", { className: "dx-muted dx-xs", style: { marginBottom: 14 }, children: [
|
|
2484
|
+
"Run ",
|
|
2485
|
+
run.id.slice(0, 8),
|
|
2486
|
+
" \xB7 ",
|
|
2487
|
+
new Date(run.createdAt).toLocaleString(),
|
|
2488
|
+
run.errorCode ? ` \xB7 ${run.errorCode}` : ""
|
|
2489
|
+
] }),
|
|
2490
|
+
/* @__PURE__ */ jsxs7("div", { className: "dx-run-stats", children: [
|
|
2491
|
+
/* @__PURE__ */ jsxs7("div", { children: [
|
|
2492
|
+
/* @__PURE__ */ jsx7("b", { children: u?.model ?? "\u2014" }),
|
|
2493
|
+
/* @__PURE__ */ jsx7("span", { children: "model" })
|
|
2494
|
+
] }),
|
|
2495
|
+
/* @__PURE__ */ jsxs7("div", { children: [
|
|
2496
|
+
/* @__PURE__ */ jsx7("b", { children: k((u?.inputTokens ?? 0) + (u?.cachedInputTokens ?? 0) || void 0) }),
|
|
2497
|
+
/* @__PURE__ */ jsx7("span", { children: "tokens read" })
|
|
2498
|
+
] }),
|
|
2499
|
+
/* @__PURE__ */ jsxs7("div", { children: [
|
|
2500
|
+
/* @__PURE__ */ jsx7("b", { children: k(u?.outputTokens) }),
|
|
2501
|
+
/* @__PURE__ */ jsx7("span", { children: "tokens written" })
|
|
2502
|
+
] }),
|
|
2503
|
+
/* @__PURE__ */ jsxs7("div", { children: [
|
|
2504
|
+
/* @__PURE__ */ jsx7("b", { children: u?.costUsd != null ? `$${u.costUsd.toFixed(2)}` : u?.billingType === "subscription_included" ? "$0" : "\u2014" }),
|
|
2505
|
+
/* @__PURE__ */ jsx7("span", { children: u?.billingType === "subscription_included" ? "on your subscription" : "cost" })
|
|
2506
|
+
] })
|
|
2507
|
+
] }),
|
|
2508
|
+
/* @__PURE__ */ jsx7("h3", { className: "dx-run-h", children: "What it posted" }),
|
|
2509
|
+
posted == null ? /* @__PURE__ */ jsx7("div", { className: "dx-muted dx-small", children: "Loading\u2026" }) : posted.length ? posted.map((c) => /* @__PURE__ */ jsx7("div", { className: "dx-doc", children: /* @__PURE__ */ jsx7(MarkdownBlock, { content: c.body }) }, c.id)) : /* @__PURE__ */ jsxs7("div", { className: "dx-muted dx-small", children: [
|
|
2510
|
+
"Nothing on this task from this run.",
|
|
2511
|
+
run.status !== "succeeded" ? " It did not finish." : ""
|
|
2512
|
+
] }),
|
|
2513
|
+
/* @__PURE__ */ jsx7("div", { className: "dx-row", style: { gap: 8, marginTop: 16 }, children: /* @__PURE__ */ jsxs7("a", { className: "dx-btn", ...go.hostLink(`/agents/${run.agentId}/runs/${run.id}`), children: [
|
|
2514
|
+
Ico.run,
|
|
2515
|
+
" Open the full log"
|
|
2516
|
+
] }) })
|
|
2517
|
+
] });
|
|
2518
|
+
}
|
|
2342
2519
|
function Viewer({ r }) {
|
|
2343
2520
|
if (r.kind === "doc") {
|
|
2344
2521
|
const doc = r.doc;
|
|
@@ -2479,24 +2656,29 @@ function askDock(timeoutMs = 250) {
|
|
|
2479
2656
|
b.postMessage({ type: "ping" });
|
|
2480
2657
|
});
|
|
2481
2658
|
}
|
|
2482
|
-
function
|
|
2659
|
+
function useTalk(d, agentId) {
|
|
2483
2660
|
const go = useGo("decide");
|
|
2484
|
-
|
|
2485
|
-
const start = async () => {
|
|
2486
|
-
setBusy(true);
|
|
2661
|
+
return async () => {
|
|
2487
2662
|
const decision = { issueId: d.issueId, interactionId: d.source === "interaction" ? d.id : null, approvalId: d.source === "approval" ? d.id : null };
|
|
2488
2663
|
const m = { type: "start", ...agentId ? { entityType: "agent", entityId: agentId } : {}, path: d.identifier ? `/issues/${d.identifier}` : void 0, decision };
|
|
2489
2664
|
if (await askDock()) {
|
|
2490
2665
|
const b = new BroadcastChannel(BUS);
|
|
2491
2666
|
b.postMessage(m);
|
|
2492
2667
|
b.close();
|
|
2493
|
-
|
|
2494
|
-
const q = new URLSearchParams({ start: "1", ...agentId ? { entityType: "agent", entityId: agentId } : {}, ...d.issueId ? { decisionIssue: d.issueId } : {}, ...decision.interactionId ? { decisionInteraction: decision.interactionId } : {}, ...decision.approvalId ? { decisionApproval: decision.approvalId } : {} });
|
|
2495
|
-
go.host(`/call?${q}`);
|
|
2668
|
+
return;
|
|
2496
2669
|
}
|
|
2497
|
-
|
|
2670
|
+
const q = new URLSearchParams({ start: "1", ...agentId ? { entityType: "agent", entityId: agentId } : {}, ...d.issueId ? { decisionIssue: d.issueId } : {}, ...decision.interactionId ? { decisionInteraction: decision.interactionId } : {}, ...decision.approvalId ? { decisionApproval: decision.approvalId } : {} });
|
|
2671
|
+
go.host(`/call?${q}`);
|
|
2498
2672
|
};
|
|
2499
|
-
|
|
2673
|
+
}
|
|
2674
|
+
function TalkButton({ d, agentId, label }) {
|
|
2675
|
+
const start = useTalk(d, agentId);
|
|
2676
|
+
const [busy, setBusy] = useState6(false);
|
|
2677
|
+
return /* @__PURE__ */ jsxs7("button", { className: "dx-btn", disabled: busy, onClick: async () => {
|
|
2678
|
+
setBusy(true);
|
|
2679
|
+
await start();
|
|
2680
|
+
setTimeout(() => setBusy(false), 1500);
|
|
2681
|
+
}, children: [
|
|
2500
2682
|
Ico.phone,
|
|
2501
2683
|
" ",
|
|
2502
2684
|
label
|
|
@@ -2527,6 +2709,20 @@ function DecisionsPage({ companyId }) {
|
|
|
2527
2709
|
const [filter, setFilter] = useState7("waiting");
|
|
2528
2710
|
const [answered, setAnswered] = useState7([]);
|
|
2529
2711
|
const [wide, setWide] = useState7(false);
|
|
2712
|
+
const [pane, setPaneState] = useState7(() => {
|
|
2713
|
+
try {
|
|
2714
|
+
return localStorage.getItem("dx-decisions-pane") !== "closed";
|
|
2715
|
+
} catch {
|
|
2716
|
+
return true;
|
|
2717
|
+
}
|
|
2718
|
+
});
|
|
2719
|
+
const setPane = (v) => {
|
|
2720
|
+
setPaneState(v);
|
|
2721
|
+
try {
|
|
2722
|
+
localStorage.setItem("dx-decisions-pane", v ? "open" : "closed");
|
|
2723
|
+
} catch {
|
|
2724
|
+
}
|
|
2725
|
+
};
|
|
2530
2726
|
const alarms = useAlarms(companyId);
|
|
2531
2727
|
const forget = usePluginAction2("refresh-decisions");
|
|
2532
2728
|
const items = (data?.items ?? []).filter((x) => !answered.includes(x.key)).filter((x) => !q || `${x.title} ${x.identifier} ${x.kindLabel}`.toLowerCase().includes(q.toLowerCase()));
|
|
@@ -2537,7 +2733,7 @@ function DecisionsPage({ companyId }) {
|
|
|
2537
2733
|
if (error) return /* @__PURE__ */ jsx8(ErrorBox, { error });
|
|
2538
2734
|
const groups = ["now", "this week", "whenever", "needs work"].map((b) => ({ b, list: items.filter((x) => (x.lane ?? (x.bucket === "today" ? "now" : x.bucket)) === b) }));
|
|
2539
2735
|
const pick = (k) => go.to(`/${encodeURIComponent(k)}`);
|
|
2540
|
-
return /* @__PURE__ */ jsxs8("div", { className: `dx-dq beside${wide ? " wide" : ""}`, children: [
|
|
2736
|
+
return /* @__PURE__ */ jsxs8("div", { className: `dx-dq beside${pane ? wide ? " wide" : "" : " closed"}`, children: [
|
|
2541
2737
|
/* @__PURE__ */ jsxs8("div", { className: "dx-dq-list", children: [
|
|
2542
2738
|
/* @__PURE__ */ jsxs8("div", { className: "dx-row", style: { padding: "0 4px 10px" }, children: [
|
|
2543
2739
|
/* @__PURE__ */ jsx8("b", { style: { fontSize: 15 }, children: "Queue" }),
|
|
@@ -2580,7 +2776,10 @@ function DecisionsPage({ companyId }) {
|
|
|
2580
2776
|
setAnswered((a) => [...a, sel.key]);
|
|
2581
2777
|
void forget({}).then(() => refresh());
|
|
2582
2778
|
} }, sel.key) : /* @__PURE__ */ jsx8("div", { className: "dx-empty", style: { marginTop: 40 }, children: "Nothing is waiting on you. New decisions from the team land here." }) }),
|
|
2583
|
-
sel && /* @__PURE__ */ jsx8(BesidePane, { d: sel, wide, setWide
|
|
2779
|
+
sel && (pane ? /* @__PURE__ */ jsx8(BesidePane, { d: sel, wide, setWide, onClose: () => {
|
|
2780
|
+
setPane(false);
|
|
2781
|
+
setWide(false);
|
|
2782
|
+
} }, sel.key) : /* @__PURE__ */ jsx8(PaneRail, { onOpen: () => setPane(true) }))
|
|
2584
2783
|
] });
|
|
2585
2784
|
}
|
|
2586
2785
|
function Decision({ d, companyId, pos, total, onPrev, onNext, onDone }) {
|
|
@@ -3221,6 +3420,13 @@ function DecisionsLink({ context }) {
|
|
|
3221
3420
|
const t = setInterval(refresh, 6e4);
|
|
3222
3421
|
return () => clearInterval(t);
|
|
3223
3422
|
}, [refresh]);
|
|
3423
|
+
useEffect5(() => {
|
|
3424
|
+
if (document.getElementById("dx-one-decisions")) return;
|
|
3425
|
+
const st = document.createElement("style");
|
|
3426
|
+
st.id = "dx-one-decisions";
|
|
3427
|
+
st.textContent = 'aside nav a[href$="/decisions"] { display: none !important; }';
|
|
3428
|
+
document.head.appendChild(st);
|
|
3429
|
+
}, []);
|
|
3224
3430
|
return /* @__PURE__ */ jsx9(SideLink, { base: "decide", label: "Decisions", icon: Icon.list, badge: data?.items.length ?? null });
|
|
3225
3431
|
}
|
|
3226
3432
|
function CampaignTab({ context }) {
|