@flanksource/clicky-ui 0.3.35 → 0.3.36
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/ai.cjs +2 -1
- package/dist/ai.cjs.map +1 -1
- package/dist/ai.js +2 -1
- package/dist/ai.js.map +1 -1
- package/dist/data/TaskHeaderExtras.cjs +35 -0
- package/dist/data/TaskHeaderExtras.cjs.map +1 -0
- package/dist/data/TaskHeaderExtras.d.ts +27 -0
- package/dist/data/TaskHeaderExtras.d.ts.map +1 -0
- package/dist/data/TaskHeaderExtras.js +35 -0
- package/dist/data/TaskHeaderExtras.js.map +1 -0
- package/dist/data/TaskManager.cjs +18 -6
- package/dist/data/TaskManager.cjs.map +1 -1
- package/dist/data/TaskManager.d.ts +13 -1
- package/dist/data/TaskManager.d.ts.map +1 -1
- package/dist/data/TaskManager.js +18 -6
- package/dist/data/TaskManager.js.map +1 -1
- package/dist/data/TaskProcessDetails.cjs +4 -1
- package/dist/data/TaskProcessDetails.cjs.map +1 -1
- package/dist/data/TaskProcessDetails.d.ts.map +1 -1
- package/dist/data/TaskProcessDetails.js +4 -1
- package/dist/data/TaskProcessDetails.js.map +1 -1
- package/dist/data/TaskProcessMetadata.cjs +50 -0
- package/dist/data/TaskProcessMetadata.cjs.map +1 -0
- package/dist/data/TaskProcessMetadata.d.ts +20 -0
- package/dist/data/TaskProcessMetadata.d.ts.map +1 -0
- package/dist/data/TaskProcessMetadata.js +50 -0
- package/dist/data/TaskProcessMetadata.js.map +1 -0
- package/dist/data/TaskProgress.cjs +22 -31
- package/dist/data/TaskProgress.cjs.map +1 -1
- package/dist/data/TaskProgress.d.ts +14 -1
- package/dist/data/TaskProgress.d.ts.map +1 -1
- package/dist/data/TaskProgress.js +22 -31
- package/dist/data/TaskProgress.js.map +1 -1
- package/dist/data/TaskSnapshot.cjs.map +1 -1
- package/dist/data/TaskSnapshot.d.ts +22 -0
- package/dist/data/TaskSnapshot.d.ts.map +1 -1
- package/dist/data/TaskSnapshot.js.map +1 -1
- package/dist/data/TaskStreamTabs.cjs +78 -0
- package/dist/data/TaskStreamTabs.cjs.map +1 -0
- package/dist/data/TaskStreamTabs.d.ts +35 -0
- package/dist/data/TaskStreamTabs.d.ts.map +1 -0
- package/dist/data/TaskStreamTabs.js +78 -0
- package/dist/data/TaskStreamTabs.js.map +1 -0
- package/dist/data/ai/SessionInspector.approvals-model.cjs +9 -0
- package/dist/data/ai/SessionInspector.approvals-model.cjs.map +1 -0
- package/dist/data/ai/SessionInspector.approvals-model.d.ts +17 -0
- package/dist/data/ai/SessionInspector.approvals-model.d.ts.map +1 -0
- package/dist/data/ai/SessionInspector.approvals-model.js +9 -0
- package/dist/data/ai/SessionInspector.approvals-model.js.map +1 -0
- package/dist/data/ai/SessionInspector.approvals.cjs +7 -11
- package/dist/data/ai/SessionInspector.approvals.cjs.map +1 -1
- package/dist/data/ai/SessionInspector.approvals.d.ts +2 -10
- package/dist/data/ai/SessionInspector.approvals.d.ts.map +1 -1
- package/dist/data/ai/SessionInspector.approvals.js +4 -8
- package/dist/data/ai/SessionInspector.approvals.js.map +1 -1
- package/dist/data/ai/SessionInspector.cjs +2 -2
- package/dist/data/ai/SessionInspector.cjs.map +1 -1
- package/dist/data/ai/SessionInspector.d.ts +1 -1
- package/dist/data/ai/SessionInspector.d.ts.map +1 -1
- package/dist/data/ai/SessionInspector.js +1 -1
- package/dist/data/ai/SessionInspector.js.map +1 -1
- package/dist/data/ai/SessionInspector.panel-parts.cjs +0 -13
- package/dist/data/ai/SessionInspector.panel-parts.cjs.map +1 -1
- package/dist/data/ai/SessionInspector.panel-parts.d.ts +4 -5
- package/dist/data/ai/SessionInspector.panel-parts.d.ts.map +1 -1
- package/dist/data/ai/SessionInspector.panel-parts.js +1 -14
- package/dist/data/ai/SessionInspector.panel-parts.js.map +1 -1
- package/dist/data/ai/SessionInspector.panel-values.cjs +18 -0
- package/dist/data/ai/SessionInspector.panel-values.cjs.map +1 -0
- package/dist/data/ai/SessionInspector.panel-values.d.ts +13 -0
- package/dist/data/ai/SessionInspector.panel-values.d.ts.map +1 -0
- package/dist/data/ai/SessionInspector.panel-values.js +18 -0
- package/dist/data/ai/SessionInspector.panel-values.js.map +1 -0
- package/dist/data/ai/SessionInspector.panels.cjs +27 -26
- package/dist/data/ai/SessionInspector.panels.cjs.map +1 -1
- package/dist/data/ai/SessionInspector.panels.d.ts.map +1 -1
- package/dist/data/ai/SessionInspector.panels.js +2 -1
- package/dist/data/ai/SessionInspector.panels.js.map +1 -1
- package/dist/data/ai/index.d.ts +2 -1
- package/dist/data/ai/index.d.ts.map +1 -1
- package/dist/data/task-metadata.cjs +36 -0
- package/dist/data/task-metadata.cjs.map +1 -0
- package/dist/data/task-metadata.d.ts +39 -0
- package/dist/data/task-metadata.d.ts.map +1 -0
- package/dist/data/task-metadata.js +36 -0
- package/dist/data/task-metadata.js.map +1 -0
- package/dist/data/task-streams.cjs +39 -0
- package/dist/data/task-streams.cjs.map +1 -0
- package/dist/data/task-streams.d.ts +60 -0
- package/dist/data/task-streams.d.ts.map +1 -0
- package/dist/data/task-streams.js +39 -0
- package/dist/data/task-streams.js.map +1 -0
- package/dist/data/version-info.cjs +3 -3
- package/dist/data/version-info.js +3 -3
- package/dist/data.cjs +14 -0
- package/dist/data.cjs.map +1 -1
- package/dist/data.d.ts +6 -1
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +14 -0
- package/dist/data.js.map +1 -1
- package/dist/hooks/use-task-run.cjs +13 -15
- package/dist/hooks/use-task-run.cjs.map +1 -1
- package/dist/hooks/use-task-run.d.ts.map +1 -1
- package/dist/hooks/use-task-run.js +14 -16
- package/dist/hooks/use-task-run.js.map +1 -1
- package/dist/index.cjs +14 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { SessionApprovalRequest } from './SessionViewer.unified';
|
|
2
|
+
/** Approve or deny one pending approval. */
|
|
3
|
+
export type ApprovalResolveAction = "approve" | "deny";
|
|
4
|
+
/** Resolves one `session.requests[]` row. Rejecting surfaces the server's
|
|
5
|
+
* refusal text inline on that row (e.g. the prompt run is no longer
|
|
6
|
+
* `waiting`) instead of leaving the Approve/Deny buttons silently inert. */
|
|
7
|
+
export type ApprovalResolveHandler = (approvalId: string, action: ApprovalResolveAction, message?: string) => void | Promise<void>;
|
|
8
|
+
/** The subset of `session.requests[]` the approvals panel surfaces: outstanding
|
|
9
|
+
* tool approvals, regardless of which surface (in-process chat or an external
|
|
10
|
+
* broker) created the request.
|
|
11
|
+
*
|
|
12
|
+
* It lives here rather than beside the panel because it is a selector, not a
|
|
13
|
+
* component, and a module that exports both loses fast refresh for everything
|
|
14
|
+
* in it. Its other caller — the SessionInspector tab badge — only ever wanted
|
|
15
|
+
* the count anyway. */
|
|
16
|
+
export declare function pendingApprovalRequests(requests: SessionApprovalRequest[] | undefined): SessionApprovalRequest[];
|
|
17
|
+
//# sourceMappingURL=SessionInspector.approvals-model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionInspector.approvals-model.d.ts","sourceRoot":"","sources":["../../../src/data/ai/SessionInspector.approvals-model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAEtE,4CAA4C;AAC5C,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,MAAM,CAAC;AAEvD;;6EAE6E;AAC7E,MAAM,MAAM,sBAAsB,GAAG,CACnC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,qBAAqB,EAC7B,OAAO,CAAC,EAAE,MAAM,KACb,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1B;;;;;;;wBAOwB;AACxB,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,sBAAsB,EAAE,GAAG,SAAS,GAC7C,sBAAsB,EAAE,CAI1B"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
function pendingApprovalRequests(requests) {
|
|
2
|
+
return (requests ?? []).filter(
|
|
3
|
+
(request) => request.state === "pending" && request.kind === "tool_approval"
|
|
4
|
+
);
|
|
5
|
+
}
|
|
6
|
+
export {
|
|
7
|
+
pendingApprovalRequests
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=SessionInspector.approvals-model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionInspector.approvals-model.js","sources":["../../../src/data/ai/SessionInspector.approvals-model.ts"],"sourcesContent":["import type { SessionApprovalRequest } from \"./SessionViewer.unified\";\n\n/** Approve or deny one pending approval. */\nexport type ApprovalResolveAction = \"approve\" | \"deny\";\n\n/** Resolves one `session.requests[]` row. Rejecting surfaces the server's\n * refusal text inline on that row (e.g. the prompt run is no longer\n * `waiting`) instead of leaving the Approve/Deny buttons silently inert. */\nexport type ApprovalResolveHandler = (\n approvalId: string,\n action: ApprovalResolveAction,\n message?: string,\n) => void | Promise<void>;\n\n/** The subset of `session.requests[]` the approvals panel surfaces: outstanding\n * tool approvals, regardless of which surface (in-process chat or an external\n * broker) created the request.\n *\n * It lives here rather than beside the panel because it is a selector, not a\n * component, and a module that exports both loses fast refresh for everything\n * in it. Its other caller — the SessionInspector tab badge — only ever wanted\n * the count anyway. */\nexport function pendingApprovalRequests(\n requests: SessionApprovalRequest[] | undefined,\n): SessionApprovalRequest[] {\n return (requests ?? []).filter(\n (request) => request.state === \"pending\" && request.kind === \"tool_approval\",\n );\n}\n"],"names":[],"mappings":"AAsBO,SAAS,wBACd,UAC0B;AAC1B,UAAQ,YAAY,CAAA,GAAI;AAAA,IACtB,CAAC,YAAY,QAAQ,UAAU,aAAa,QAAQ,SAAS;AAAA,EAAA;AAEjE;"}
|
|
@@ -7,19 +7,16 @@ const Icon = require("../Icon.cjs");
|
|
|
7
7
|
const ToolCall = require("../chat/ToolCall.cjs");
|
|
8
8
|
const SessionInspector_model = require("./SessionInspector.model.cjs");
|
|
9
9
|
const SessionInspector_panelParts = require("./SessionInspector.panel-parts.cjs");
|
|
10
|
+
const SessionInspector_panelValues = require("./SessionInspector.panel-values.cjs");
|
|
11
|
+
const SessionInspector_approvalsModel = require("./SessionInspector.approvals-model.cjs");
|
|
10
12
|
const UiClock = require("../../icons/components/UiClock.cjs");
|
|
11
|
-
function pendingApprovalRequests(requests) {
|
|
12
|
-
return (requests ?? []).filter(
|
|
13
|
-
(request) => request.state === "pending" && request.kind === "tool_approval"
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
13
|
function SessionApprovalsPanel({
|
|
17
14
|
approvals,
|
|
18
15
|
requests,
|
|
19
16
|
onResolve
|
|
20
17
|
}) {
|
|
21
18
|
var _a;
|
|
22
|
-
const pending = pendingApprovalRequests(requests);
|
|
19
|
+
const pending = SessionInspector_approvalsModel.pendingApprovalRequests(requests);
|
|
23
20
|
const hasResolvedSummary = Boolean(
|
|
24
21
|
approvals && (approvals.approved || approvals.denied || approvals.cancelled || approvals.expired || ((_a = approvals.denials) == null ? void 0 : _a.length))
|
|
25
22
|
);
|
|
@@ -46,10 +43,10 @@ function ResolvedApprovalsSummary({
|
|
|
46
43
|
KeyValueList.KeyValueList,
|
|
47
44
|
{
|
|
48
45
|
items: [
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
SessionInspector_panelValues.kv("Approved", approvals.approved ?? 0),
|
|
47
|
+
SessionInspector_panelValues.kv("Denied", approvals.denied ?? 0),
|
|
48
|
+
SessionInspector_panelValues.kv("Cancelled", approvals.cancelled ?? 0),
|
|
49
|
+
SessionInspector_panelValues.kv("Expired", approvals.expired ?? 0)
|
|
53
50
|
]
|
|
54
51
|
}
|
|
55
52
|
),
|
|
@@ -143,5 +140,4 @@ function remainingLabel(expiresAt) {
|
|
|
143
140
|
return label ? `${label} left` : "";
|
|
144
141
|
}
|
|
145
142
|
exports.SessionApprovalsPanel = SessionApprovalsPanel;
|
|
146
|
-
exports.pendingApprovalRequests = pendingApprovalRequests;
|
|
147
143
|
//# sourceMappingURL=SessionInspector.approvals.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionInspector.approvals.cjs","sources":["../../../src/data/ai/SessionInspector.approvals.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { KeyValueList } from \"../KeyValueList\";\nimport { Icon } from \"../Icon\";\nimport { UiClock } from \"../../icons\";\nimport { ToolCall } from \"../chat/ToolCall\";\nimport type { AnyToolPart } from \"../chat/types\";\nimport { durationLabel, formatDate } from \"./SessionInspector.model\";\nimport { EmptyState, SimpleList, kv } from \"./SessionInspector.panel-parts\";\nimport type {\n SessionApprovalRequest,\n SessionApprovalStats,\n} from \"./SessionViewer.unified\";\n\n/** Approve or deny one pending approval. */\nexport type ApprovalResolveAction = \"approve\" | \"deny\";\n\n/** Resolves one `session.requests[]` row. Rejecting surfaces the server's\n * refusal text inline on that row (e.g. the prompt run is no longer\n * `waiting`) instead of leaving the Approve/Deny buttons silently inert. */\nexport type ApprovalResolveHandler = (\n approvalId: string,\n action: ApprovalResolveAction,\n message?: string,\n) => void | Promise<void>;\n\n/** The subset of `session.requests[]` this panel surfaces: outstanding tool\n * approvals, regardless of which surface (in-process chat or an external\n * broker) created the request. */\nexport function pendingApprovalRequests(\n requests: SessionApprovalRequest[] | undefined,\n): SessionApprovalRequest[] {\n return (requests ?? []).filter(\n (request) => request.state === \"pending\" && request.kind === \"tool_approval\",\n );\n}\n\n/** Renders every pending tool approval directly from `session.requests[]`\n * (never from transcript parts — an approval brokered outside this session's\n * own chat has no transcript part) plus the resolved approve/deny/denial\n * summary the panel previously showed alone. */\nexport function SessionApprovalsPanel({\n approvals,\n requests,\n onResolve,\n}: {\n approvals: SessionApprovalStats | undefined;\n requests?: SessionApprovalRequest[] | undefined;\n onResolve?: ApprovalResolveHandler;\n}) {\n const pending = pendingApprovalRequests(requests);\n const hasResolvedSummary = Boolean(\n approvals &&\n (approvals.approved ||\n approvals.denied ||\n approvals.cancelled ||\n approvals.expired ||\n approvals.denials?.length),\n );\n\n if (!pending.length && !hasResolvedSummary) {\n return <EmptyState>No approval metadata.</EmptyState>;\n }\n\n return (\n <div className=\"space-y-density-4\">\n {pending.length ? (\n <PendingApprovalsList\n requests={pending}\n {...(onResolve ? { onResolve } : {})}\n />\n ) : null}\n {hasResolvedSummary ? (\n <ResolvedApprovalsSummary approvals={approvals!} />\n ) : null}\n </div>\n );\n}\n\nfunction ResolvedApprovalsSummary({\n approvals,\n}: {\n approvals: SessionApprovalStats;\n}) {\n return (\n <div className=\"space-y-density-4\">\n <KeyValueList\n items={[\n kv(\"Approved\", approvals.approved ?? 0),\n kv(\"Denied\", approvals.denied ?? 0),\n kv(\"Cancelled\", approvals.cancelled ?? 0),\n kv(\"Expired\", approvals.expired ?? 0),\n ]}\n />\n {approvals.denials?.length ? (\n <SimpleList\n title=\"Denials\"\n rows={approvals.denials.map((denial, index) => ({\n key: denial.toolUseId || `${denial.tool}-${index}`,\n title: [denial.tool, denial.toolUseId].filter(Boolean).join(\" \"),\n detail: denial.reason,\n }))}\n />\n ) : null}\n </div>\n );\n}\n\nfunction PendingApprovalsList({\n requests,\n onResolve,\n}: {\n requests: SessionApprovalRequest[];\n onResolve?: ApprovalResolveHandler;\n}) {\n return (\n <section>\n <h3 className=\"mb-density-2 flex items-center gap-1.5 text-xs font-semibold uppercase text-amber-600 dark:text-amber-400\">\n <Icon icon={UiClock} className=\"size-3.5\" />\n Awaiting approval ({requests.length})\n </h3>\n <ul className=\"space-y-density-2\">\n {requests.map((request) => (\n <li key={request.id}>\n <PendingApprovalRow\n request={request}\n {...(onResolve ? { onResolve } : {})}\n />\n </li>\n ))}\n </ul>\n </section>\n );\n}\n\nfunction PendingApprovalRow({\n request,\n onResolve,\n}: {\n request: SessionApprovalRequest;\n onResolve?: ApprovalResolveHandler;\n}) {\n const [error, setError] = useState<string | undefined>(undefined);\n const [busy, setBusy] = useState(false);\n\n const part: AnyToolPart = {\n type: \"dynamic-tool\",\n toolName: request.tool,\n toolCallId: request.toolCallId || request.id,\n state: \"approval-requested\",\n input: request.input,\n approval: { id: request.id },\n };\n\n const handleApprove = (\n approvalId: string,\n approved: boolean,\n reason?: string,\n ) => {\n if (!onResolve) return;\n setError(undefined);\n setBusy(true);\n void Promise.resolve(onResolve(approvalId, approved ? \"approve\" : \"deny\", reason))\n .catch((err: unknown) => {\n setError(err instanceof Error ? err.message : String(err));\n })\n .finally(() => setBusy(false));\n };\n\n return (\n <div className=\"rounded-md border border-amber-300/60 bg-amber-50/40 p-density-3 dark:border-amber-800/60 dark:bg-amber-950/20\">\n <div className=\"mb-1 flex flex-wrap items-center justify-between gap-2 text-[11px] text-muted-foreground\">\n <span>\n {request.requestedBy\n ? `Requested by ${request.requestedBy}`\n : \"Requested\"}\n </span>\n <span className=\"flex gap-density-3\">\n {request.createdAt ? (\n <span title={formatDate(request.createdAt)}>\n {ageLabel(request.createdAt)} ago\n </span>\n ) : null}\n {request.expiresAt ? (\n <span title={formatDate(request.expiresAt)}>\n {remainingLabel(request.expiresAt)}\n </span>\n ) : null}\n </span>\n </div>\n <ToolCall\n part={part}\n defaultOpen\n onApprove={busy ? undefined : handleApprove}\n />\n {busy ? (\n <p className=\"mt-1.5 pl-4 text-xs text-muted-foreground\">\n Submitting…\n </p>\n ) : null}\n {error ? (\n <p role=\"alert\" className=\"mt-1.5 pl-4 text-xs text-destructive\">\n {error}\n </p>\n ) : null}\n </div>\n );\n}\n\nfunction ageLabel(createdAt: string): string {\n return durationLabel(createdAt) || \"0s\";\n}\n\nfunction remainingLabel(expiresAt: string): string {\n const expiry = new Date(expiresAt).getTime();\n if (Number.isNaN(expiry)) return \"\";\n const now = Date.now();\n if (expiry <= now) return \"expired\";\n const label = durationLabel(new Date(now).toISOString(), expiresAt);\n return label ? `${label} left` : \"\";\n}\n"],"names":["jsx","EmptyState","jsxs","KeyValueList","kv","SimpleList","Icon","UiClock","useState","formatDate","ToolCall","durationLabel"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SessionInspector.approvals.cjs","sources":["../../../src/data/ai/SessionInspector.approvals.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { KeyValueList } from \"../KeyValueList\";\nimport { Icon } from \"../Icon\";\nimport { UiClock } from \"../../icons\";\nimport { ToolCall } from \"../chat/ToolCall\";\nimport type { AnyToolPart } from \"../chat/types\";\nimport { durationLabel, formatDate } from \"./SessionInspector.model\";\nimport { EmptyState, SimpleList } from \"./SessionInspector.panel-parts\";\nimport { kv } from \"./SessionInspector.panel-values\";\nimport {\n type ApprovalResolveHandler,\n pendingApprovalRequests,\n} from \"./SessionInspector.approvals-model\";\nimport type {\n SessionApprovalRequest,\n SessionApprovalStats,\n} from \"./SessionViewer.unified\";\n\nexport type {\n ApprovalResolveAction,\n ApprovalResolveHandler,\n} from \"./SessionInspector.approvals-model\";\n\n/** Renders every pending tool approval directly from `session.requests[]`\n * (never from transcript parts — an approval brokered outside this session's\n * own chat has no transcript part) plus the resolved approve/deny/denial\n * summary the panel previously showed alone. */\nexport function SessionApprovalsPanel({\n approvals,\n requests,\n onResolve,\n}: {\n approvals: SessionApprovalStats | undefined;\n requests?: SessionApprovalRequest[] | undefined;\n onResolve?: ApprovalResolveHandler;\n}) {\n const pending = pendingApprovalRequests(requests);\n const hasResolvedSummary = Boolean(\n approvals &&\n (approvals.approved ||\n approvals.denied ||\n approvals.cancelled ||\n approvals.expired ||\n approvals.denials?.length),\n );\n\n if (!pending.length && !hasResolvedSummary) {\n return <EmptyState>No approval metadata.</EmptyState>;\n }\n\n return (\n <div className=\"space-y-density-4\">\n {pending.length ? (\n <PendingApprovalsList\n requests={pending}\n {...(onResolve ? { onResolve } : {})}\n />\n ) : null}\n {hasResolvedSummary ? (\n <ResolvedApprovalsSummary approvals={approvals!} />\n ) : null}\n </div>\n );\n}\n\nfunction ResolvedApprovalsSummary({\n approvals,\n}: {\n approvals: SessionApprovalStats;\n}) {\n return (\n <div className=\"space-y-density-4\">\n <KeyValueList\n items={[\n kv(\"Approved\", approvals.approved ?? 0),\n kv(\"Denied\", approvals.denied ?? 0),\n kv(\"Cancelled\", approvals.cancelled ?? 0),\n kv(\"Expired\", approvals.expired ?? 0),\n ]}\n />\n {approvals.denials?.length ? (\n <SimpleList\n title=\"Denials\"\n rows={approvals.denials.map((denial, index) => ({\n key: denial.toolUseId || `${denial.tool}-${index}`,\n title: [denial.tool, denial.toolUseId].filter(Boolean).join(\" \"),\n detail: denial.reason,\n }))}\n />\n ) : null}\n </div>\n );\n}\n\nfunction PendingApprovalsList({\n requests,\n onResolve,\n}: {\n requests: SessionApprovalRequest[];\n onResolve?: ApprovalResolveHandler;\n}) {\n return (\n <section>\n <h3 className=\"mb-density-2 flex items-center gap-1.5 text-xs font-semibold uppercase text-amber-600 dark:text-amber-400\">\n <Icon icon={UiClock} className=\"size-3.5\" />\n Awaiting approval ({requests.length})\n </h3>\n <ul className=\"space-y-density-2\">\n {requests.map((request) => (\n <li key={request.id}>\n <PendingApprovalRow\n request={request}\n {...(onResolve ? { onResolve } : {})}\n />\n </li>\n ))}\n </ul>\n </section>\n );\n}\n\nfunction PendingApprovalRow({\n request,\n onResolve,\n}: {\n request: SessionApprovalRequest;\n onResolve?: ApprovalResolveHandler;\n}) {\n const [error, setError] = useState<string | undefined>(undefined);\n const [busy, setBusy] = useState(false);\n\n const part: AnyToolPart = {\n type: \"dynamic-tool\",\n toolName: request.tool,\n toolCallId: request.toolCallId || request.id,\n state: \"approval-requested\",\n input: request.input,\n approval: { id: request.id },\n };\n\n const handleApprove = (\n approvalId: string,\n approved: boolean,\n reason?: string,\n ) => {\n if (!onResolve) return;\n setError(undefined);\n setBusy(true);\n void Promise.resolve(onResolve(approvalId, approved ? \"approve\" : \"deny\", reason))\n .catch((err: unknown) => {\n setError(err instanceof Error ? err.message : String(err));\n })\n .finally(() => setBusy(false));\n };\n\n return (\n <div className=\"rounded-md border border-amber-300/60 bg-amber-50/40 p-density-3 dark:border-amber-800/60 dark:bg-amber-950/20\">\n <div className=\"mb-1 flex flex-wrap items-center justify-between gap-2 text-[11px] text-muted-foreground\">\n <span>\n {request.requestedBy\n ? `Requested by ${request.requestedBy}`\n : \"Requested\"}\n </span>\n <span className=\"flex gap-density-3\">\n {request.createdAt ? (\n <span title={formatDate(request.createdAt)}>\n {ageLabel(request.createdAt)} ago\n </span>\n ) : null}\n {request.expiresAt ? (\n <span title={formatDate(request.expiresAt)}>\n {remainingLabel(request.expiresAt)}\n </span>\n ) : null}\n </span>\n </div>\n <ToolCall\n part={part}\n defaultOpen\n onApprove={busy ? undefined : handleApprove}\n />\n {busy ? (\n <p className=\"mt-1.5 pl-4 text-xs text-muted-foreground\">\n Submitting…\n </p>\n ) : null}\n {error ? (\n <p role=\"alert\" className=\"mt-1.5 pl-4 text-xs text-destructive\">\n {error}\n </p>\n ) : null}\n </div>\n );\n}\n\nfunction ageLabel(createdAt: string): string {\n return durationLabel(createdAt) || \"0s\";\n}\n\nfunction remainingLabel(expiresAt: string): string {\n const expiry = new Date(expiresAt).getTime();\n if (Number.isNaN(expiry)) return \"\";\n const now = Date.now();\n if (expiry <= now) return \"expired\";\n const label = durationLabel(new Date(now).toISOString(), expiresAt);\n return label ? `${label} left` : \"\";\n}\n"],"names":["pendingApprovalRequests","jsx","EmptyState","jsxs","KeyValueList","kv","SimpleList","Icon","UiClock","useState","formatDate","ToolCall","durationLabel"],"mappings":"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"}
|
|
@@ -1,14 +1,6 @@
|
|
|
1
|
+
import { ApprovalResolveHandler } from './SessionInspector.approvals-model';
|
|
1
2
|
import { SessionApprovalRequest, SessionApprovalStats } from './SessionViewer.unified';
|
|
2
|
-
|
|
3
|
-
export type ApprovalResolveAction = "approve" | "deny";
|
|
4
|
-
/** Resolves one `session.requests[]` row. Rejecting surfaces the server's
|
|
5
|
-
* refusal text inline on that row (e.g. the prompt run is no longer
|
|
6
|
-
* `waiting`) instead of leaving the Approve/Deny buttons silently inert. */
|
|
7
|
-
export type ApprovalResolveHandler = (approvalId: string, action: ApprovalResolveAction, message?: string) => void | Promise<void>;
|
|
8
|
-
/** The subset of `session.requests[]` this panel surfaces: outstanding tool
|
|
9
|
-
* approvals, regardless of which surface (in-process chat or an external
|
|
10
|
-
* broker) created the request. */
|
|
11
|
-
export declare function pendingApprovalRequests(requests: SessionApprovalRequest[] | undefined): SessionApprovalRequest[];
|
|
3
|
+
export type { ApprovalResolveAction, ApprovalResolveHandler, } from './SessionInspector.approvals-model';
|
|
12
4
|
/** Renders every pending tool approval directly from `session.requests[]`
|
|
13
5
|
* (never from transcript parts — an approval brokered outside this session's
|
|
14
6
|
* own chat has no transcript part) plus the resolved approve/deny/denial
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionInspector.approvals.d.ts","sourceRoot":"","sources":["../../../src/data/ai/SessionInspector.approvals.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SessionInspector.approvals.d.ts","sourceRoot":"","sources":["../../../src/data/ai/SessionInspector.approvals.tsx"],"names":[],"mappings":"AASA,OAAO,EACL,KAAK,sBAAsB,EAE5B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EACV,sBAAsB,EACtB,oBAAoB,EACrB,MAAM,yBAAyB,CAAC;AAEjC,YAAY,EACV,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,oCAAoC,CAAC;AAE5C;;;iDAGiD;AACjD,wBAAgB,qBAAqB,CAAC,EACpC,SAAS,EACT,QAAQ,EACR,SAAS,GACV,EAAE;IACD,SAAS,EAAE,oBAAoB,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,EAAE,sBAAsB,EAAE,GAAG,SAAS,CAAC;IAChD,SAAS,CAAC,EAAE,sBAAsB,CAAC;CACpC,+BA4BA"}
|
|
@@ -4,13 +4,10 @@ import { KeyValueList } from "../KeyValueList.js";
|
|
|
4
4
|
import { Icon } from "../Icon.js";
|
|
5
5
|
import { ToolCall } from "../chat/ToolCall.js";
|
|
6
6
|
import { formatDate, durationLabel } from "./SessionInspector.model.js";
|
|
7
|
-
import { EmptyState,
|
|
7
|
+
import { EmptyState, SimpleList } from "./SessionInspector.panel-parts.js";
|
|
8
|
+
import { kv } from "./SessionInspector.panel-values.js";
|
|
9
|
+
import { pendingApprovalRequests } from "./SessionInspector.approvals-model.js";
|
|
8
10
|
import { UiClock } from "../../icons/components/UiClock.js";
|
|
9
|
-
function pendingApprovalRequests(requests) {
|
|
10
|
-
return (requests ?? []).filter(
|
|
11
|
-
(request) => request.state === "pending" && request.kind === "tool_approval"
|
|
12
|
-
);
|
|
13
|
-
}
|
|
14
11
|
function SessionApprovalsPanel({
|
|
15
12
|
approvals,
|
|
16
13
|
requests,
|
|
@@ -141,7 +138,6 @@ function remainingLabel(expiresAt) {
|
|
|
141
138
|
return label ? `${label} left` : "";
|
|
142
139
|
}
|
|
143
140
|
export {
|
|
144
|
-
SessionApprovalsPanel
|
|
145
|
-
pendingApprovalRequests
|
|
141
|
+
SessionApprovalsPanel
|
|
146
142
|
};
|
|
147
143
|
//# sourceMappingURL=SessionInspector.approvals.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionInspector.approvals.js","sources":["../../../src/data/ai/SessionInspector.approvals.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { KeyValueList } from \"../KeyValueList\";\nimport { Icon } from \"../Icon\";\nimport { UiClock } from \"../../icons\";\nimport { ToolCall } from \"../chat/ToolCall\";\nimport type { AnyToolPart } from \"../chat/types\";\nimport { durationLabel, formatDate } from \"./SessionInspector.model\";\nimport { EmptyState, SimpleList, kv } from \"./SessionInspector.panel-parts\";\nimport type {\n SessionApprovalRequest,\n SessionApprovalStats,\n} from \"./SessionViewer.unified\";\n\n/** Approve or deny one pending approval. */\nexport type ApprovalResolveAction = \"approve\" | \"deny\";\n\n/** Resolves one `session.requests[]` row. Rejecting surfaces the server's\n * refusal text inline on that row (e.g. the prompt run is no longer\n * `waiting`) instead of leaving the Approve/Deny buttons silently inert. */\nexport type ApprovalResolveHandler = (\n approvalId: string,\n action: ApprovalResolveAction,\n message?: string,\n) => void | Promise<void>;\n\n/** The subset of `session.requests[]` this panel surfaces: outstanding tool\n * approvals, regardless of which surface (in-process chat or an external\n * broker) created the request. */\nexport function pendingApprovalRequests(\n requests: SessionApprovalRequest[] | undefined,\n): SessionApprovalRequest[] {\n return (requests ?? []).filter(\n (request) => request.state === \"pending\" && request.kind === \"tool_approval\",\n );\n}\n\n/** Renders every pending tool approval directly from `session.requests[]`\n * (never from transcript parts — an approval brokered outside this session's\n * own chat has no transcript part) plus the resolved approve/deny/denial\n * summary the panel previously showed alone. */\nexport function SessionApprovalsPanel({\n approvals,\n requests,\n onResolve,\n}: {\n approvals: SessionApprovalStats | undefined;\n requests?: SessionApprovalRequest[] | undefined;\n onResolve?: ApprovalResolveHandler;\n}) {\n const pending = pendingApprovalRequests(requests);\n const hasResolvedSummary = Boolean(\n approvals &&\n (approvals.approved ||\n approvals.denied ||\n approvals.cancelled ||\n approvals.expired ||\n approvals.denials?.length),\n );\n\n if (!pending.length && !hasResolvedSummary) {\n return <EmptyState>No approval metadata.</EmptyState>;\n }\n\n return (\n <div className=\"space-y-density-4\">\n {pending.length ? (\n <PendingApprovalsList\n requests={pending}\n {...(onResolve ? { onResolve } : {})}\n />\n ) : null}\n {hasResolvedSummary ? (\n <ResolvedApprovalsSummary approvals={approvals!} />\n ) : null}\n </div>\n );\n}\n\nfunction ResolvedApprovalsSummary({\n approvals,\n}: {\n approvals: SessionApprovalStats;\n}) {\n return (\n <div className=\"space-y-density-4\">\n <KeyValueList\n items={[\n kv(\"Approved\", approvals.approved ?? 0),\n kv(\"Denied\", approvals.denied ?? 0),\n kv(\"Cancelled\", approvals.cancelled ?? 0),\n kv(\"Expired\", approvals.expired ?? 0),\n ]}\n />\n {approvals.denials?.length ? (\n <SimpleList\n title=\"Denials\"\n rows={approvals.denials.map((denial, index) => ({\n key: denial.toolUseId || `${denial.tool}-${index}`,\n title: [denial.tool, denial.toolUseId].filter(Boolean).join(\" \"),\n detail: denial.reason,\n }))}\n />\n ) : null}\n </div>\n );\n}\n\nfunction PendingApprovalsList({\n requests,\n onResolve,\n}: {\n requests: SessionApprovalRequest[];\n onResolve?: ApprovalResolveHandler;\n}) {\n return (\n <section>\n <h3 className=\"mb-density-2 flex items-center gap-1.5 text-xs font-semibold uppercase text-amber-600 dark:text-amber-400\">\n <Icon icon={UiClock} className=\"size-3.5\" />\n Awaiting approval ({requests.length})\n </h3>\n <ul className=\"space-y-density-2\">\n {requests.map((request) => (\n <li key={request.id}>\n <PendingApprovalRow\n request={request}\n {...(onResolve ? { onResolve } : {})}\n />\n </li>\n ))}\n </ul>\n </section>\n );\n}\n\nfunction PendingApprovalRow({\n request,\n onResolve,\n}: {\n request: SessionApprovalRequest;\n onResolve?: ApprovalResolveHandler;\n}) {\n const [error, setError] = useState<string | undefined>(undefined);\n const [busy, setBusy] = useState(false);\n\n const part: AnyToolPart = {\n type: \"dynamic-tool\",\n toolName: request.tool,\n toolCallId: request.toolCallId || request.id,\n state: \"approval-requested\",\n input: request.input,\n approval: { id: request.id },\n };\n\n const handleApprove = (\n approvalId: string,\n approved: boolean,\n reason?: string,\n ) => {\n if (!onResolve) return;\n setError(undefined);\n setBusy(true);\n void Promise.resolve(onResolve(approvalId, approved ? \"approve\" : \"deny\", reason))\n .catch((err: unknown) => {\n setError(err instanceof Error ? err.message : String(err));\n })\n .finally(() => setBusy(false));\n };\n\n return (\n <div className=\"rounded-md border border-amber-300/60 bg-amber-50/40 p-density-3 dark:border-amber-800/60 dark:bg-amber-950/20\">\n <div className=\"mb-1 flex flex-wrap items-center justify-between gap-2 text-[11px] text-muted-foreground\">\n <span>\n {request.requestedBy\n ? `Requested by ${request.requestedBy}`\n : \"Requested\"}\n </span>\n <span className=\"flex gap-density-3\">\n {request.createdAt ? (\n <span title={formatDate(request.createdAt)}>\n {ageLabel(request.createdAt)} ago\n </span>\n ) : null}\n {request.expiresAt ? (\n <span title={formatDate(request.expiresAt)}>\n {remainingLabel(request.expiresAt)}\n </span>\n ) : null}\n </span>\n </div>\n <ToolCall\n part={part}\n defaultOpen\n onApprove={busy ? undefined : handleApprove}\n />\n {busy ? (\n <p className=\"mt-1.5 pl-4 text-xs text-muted-foreground\">\n Submitting…\n </p>\n ) : null}\n {error ? (\n <p role=\"alert\" className=\"mt-1.5 pl-4 text-xs text-destructive\">\n {error}\n </p>\n ) : null}\n </div>\n );\n}\n\nfunction ageLabel(createdAt: string): string {\n return durationLabel(createdAt) || \"0s\";\n}\n\nfunction remainingLabel(expiresAt: string): string {\n const expiry = new Date(expiresAt).getTime();\n if (Number.isNaN(expiry)) return \"\";\n const now = Date.now();\n if (expiry <= now) return \"expired\";\n const label = durationLabel(new Date(now).toISOString(), expiresAt);\n return label ? `${label} left` : \"\";\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SessionInspector.approvals.js","sources":["../../../src/data/ai/SessionInspector.approvals.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { KeyValueList } from \"../KeyValueList\";\nimport { Icon } from \"../Icon\";\nimport { UiClock } from \"../../icons\";\nimport { ToolCall } from \"../chat/ToolCall\";\nimport type { AnyToolPart } from \"../chat/types\";\nimport { durationLabel, formatDate } from \"./SessionInspector.model\";\nimport { EmptyState, SimpleList } from \"./SessionInspector.panel-parts\";\nimport { kv } from \"./SessionInspector.panel-values\";\nimport {\n type ApprovalResolveHandler,\n pendingApprovalRequests,\n} from \"./SessionInspector.approvals-model\";\nimport type {\n SessionApprovalRequest,\n SessionApprovalStats,\n} from \"./SessionViewer.unified\";\n\nexport type {\n ApprovalResolveAction,\n ApprovalResolveHandler,\n} from \"./SessionInspector.approvals-model\";\n\n/** Renders every pending tool approval directly from `session.requests[]`\n * (never from transcript parts — an approval brokered outside this session's\n * own chat has no transcript part) plus the resolved approve/deny/denial\n * summary the panel previously showed alone. */\nexport function SessionApprovalsPanel({\n approvals,\n requests,\n onResolve,\n}: {\n approvals: SessionApprovalStats | undefined;\n requests?: SessionApprovalRequest[] | undefined;\n onResolve?: ApprovalResolveHandler;\n}) {\n const pending = pendingApprovalRequests(requests);\n const hasResolvedSummary = Boolean(\n approvals &&\n (approvals.approved ||\n approvals.denied ||\n approvals.cancelled ||\n approvals.expired ||\n approvals.denials?.length),\n );\n\n if (!pending.length && !hasResolvedSummary) {\n return <EmptyState>No approval metadata.</EmptyState>;\n }\n\n return (\n <div className=\"space-y-density-4\">\n {pending.length ? (\n <PendingApprovalsList\n requests={pending}\n {...(onResolve ? { onResolve } : {})}\n />\n ) : null}\n {hasResolvedSummary ? (\n <ResolvedApprovalsSummary approvals={approvals!} />\n ) : null}\n </div>\n );\n}\n\nfunction ResolvedApprovalsSummary({\n approvals,\n}: {\n approvals: SessionApprovalStats;\n}) {\n return (\n <div className=\"space-y-density-4\">\n <KeyValueList\n items={[\n kv(\"Approved\", approvals.approved ?? 0),\n kv(\"Denied\", approvals.denied ?? 0),\n kv(\"Cancelled\", approvals.cancelled ?? 0),\n kv(\"Expired\", approvals.expired ?? 0),\n ]}\n />\n {approvals.denials?.length ? (\n <SimpleList\n title=\"Denials\"\n rows={approvals.denials.map((denial, index) => ({\n key: denial.toolUseId || `${denial.tool}-${index}`,\n title: [denial.tool, denial.toolUseId].filter(Boolean).join(\" \"),\n detail: denial.reason,\n }))}\n />\n ) : null}\n </div>\n );\n}\n\nfunction PendingApprovalsList({\n requests,\n onResolve,\n}: {\n requests: SessionApprovalRequest[];\n onResolve?: ApprovalResolveHandler;\n}) {\n return (\n <section>\n <h3 className=\"mb-density-2 flex items-center gap-1.5 text-xs font-semibold uppercase text-amber-600 dark:text-amber-400\">\n <Icon icon={UiClock} className=\"size-3.5\" />\n Awaiting approval ({requests.length})\n </h3>\n <ul className=\"space-y-density-2\">\n {requests.map((request) => (\n <li key={request.id}>\n <PendingApprovalRow\n request={request}\n {...(onResolve ? { onResolve } : {})}\n />\n </li>\n ))}\n </ul>\n </section>\n );\n}\n\nfunction PendingApprovalRow({\n request,\n onResolve,\n}: {\n request: SessionApprovalRequest;\n onResolve?: ApprovalResolveHandler;\n}) {\n const [error, setError] = useState<string | undefined>(undefined);\n const [busy, setBusy] = useState(false);\n\n const part: AnyToolPart = {\n type: \"dynamic-tool\",\n toolName: request.tool,\n toolCallId: request.toolCallId || request.id,\n state: \"approval-requested\",\n input: request.input,\n approval: { id: request.id },\n };\n\n const handleApprove = (\n approvalId: string,\n approved: boolean,\n reason?: string,\n ) => {\n if (!onResolve) return;\n setError(undefined);\n setBusy(true);\n void Promise.resolve(onResolve(approvalId, approved ? \"approve\" : \"deny\", reason))\n .catch((err: unknown) => {\n setError(err instanceof Error ? err.message : String(err));\n })\n .finally(() => setBusy(false));\n };\n\n return (\n <div className=\"rounded-md border border-amber-300/60 bg-amber-50/40 p-density-3 dark:border-amber-800/60 dark:bg-amber-950/20\">\n <div className=\"mb-1 flex flex-wrap items-center justify-between gap-2 text-[11px] text-muted-foreground\">\n <span>\n {request.requestedBy\n ? `Requested by ${request.requestedBy}`\n : \"Requested\"}\n </span>\n <span className=\"flex gap-density-3\">\n {request.createdAt ? (\n <span title={formatDate(request.createdAt)}>\n {ageLabel(request.createdAt)} ago\n </span>\n ) : null}\n {request.expiresAt ? (\n <span title={formatDate(request.expiresAt)}>\n {remainingLabel(request.expiresAt)}\n </span>\n ) : null}\n </span>\n </div>\n <ToolCall\n part={part}\n defaultOpen\n onApprove={busy ? undefined : handleApprove}\n />\n {busy ? (\n <p className=\"mt-1.5 pl-4 text-xs text-muted-foreground\">\n Submitting…\n </p>\n ) : null}\n {error ? (\n <p role=\"alert\" className=\"mt-1.5 pl-4 text-xs text-destructive\">\n {error}\n </p>\n ) : null}\n </div>\n );\n}\n\nfunction ageLabel(createdAt: string): string {\n return durationLabel(createdAt) || \"0s\";\n}\n\nfunction remainingLabel(expiresAt: string): string {\n const expiry = new Date(expiresAt).getTime();\n if (Number.isNaN(expiry)) return \"\";\n const now = Date.now();\n if (expiry <= now) return \"expired\";\n const label = durationLabel(new Date(now).toISOString(), expiresAt);\n return label ? `${label} left` : \"\";\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -11,7 +11,7 @@ const SessionInspector_transcript = require("./SessionInspector.transcript.cjs")
|
|
|
11
11
|
const SessionInspector_collection = require("./SessionInspector.collection.cjs");
|
|
12
12
|
const SessionInspector_hierarchy = require("./SessionInspector.hierarchy.cjs");
|
|
13
13
|
const SessionInspector_hierarchyState = require("./SessionInspector.hierarchy-state.cjs");
|
|
14
|
-
const
|
|
14
|
+
const SessionInspector_approvalsModel = require("./SessionInspector.approvals-model.cjs");
|
|
15
15
|
const SessionViewer = require("./SessionViewer.cjs");
|
|
16
16
|
const UiChatDots = require("../../icons/components/UiChatDots.cjs");
|
|
17
17
|
const UiFileText = require("../../icons/components/UiFileText.cjs");
|
|
@@ -252,7 +252,7 @@ function tabBadge(tab, session) {
|
|
|
252
252
|
count: (((_b = (_a = session == null ? void 0 : session.files) == null ? void 0 : _a.read) == null ? void 0 : _b.length) ?? 0) + (((_d = (_c = session == null ? void 0 : session.files) == null ? void 0 : _c.written) == null ? void 0 : _d.length) ?? 0)
|
|
253
253
|
};
|
|
254
254
|
case "approvals": {
|
|
255
|
-
const pending =
|
|
255
|
+
const pending = SessionInspector_approvalsModel.pendingApprovalRequests(session == null ? void 0 : session.requests).length;
|
|
256
256
|
if (pending) return { count: pending, color: "bg-amber-500" };
|
|
257
257
|
return {
|
|
258
258
|
count: (((_e = session == null ? void 0 : session.approvals) == null ? void 0 : _e.approved) ?? 0) + (((_f = session == null ? void 0 : session.approvals) == null ? void 0 : _f.denied) ?? 0)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionInspector.cjs","sources":["../../../src/data/ai/SessionInspector.tsx"],"sourcesContent":["import { useMemo, useState, type ReactNode } from \"react\";\nimport {\n UiBraces,\n UiChatDots,\n UiCoins,\n UiFileText,\n UiListDashes,\n UiSealCheck,\n UiStrategy,\n} from \"../../icons\";\nimport { cn } from \"../../lib/utils\";\nimport { TabButton } from \"../TabButton\";\nimport { formatCost, costTotal } from \"./session-cost\";\nimport { SessionInspectorPanel } from \"./SessionInspector.panels\";\nimport {\n SessionInspectorHeader,\n SessionInspectorSidebar,\n} from \"./SessionInspector.summary\";\nimport { SessionTranscript } from \"./SessionInspector.transcript\";\nimport {\n isSessionCollectionInput,\n type SessionCollectionInput,\n type SessionCollectionItem,\n type SessionInspectorInput,\n} from \"./SessionInspector.collection\";\nimport { SessionHierarchyPicker } from \"./SessionInspector.hierarchy\";\nimport { useSessionHierarchy } from \"./SessionInspector.hierarchy-state\";\nimport {\n pendingApprovalRequests,\n type ApprovalResolveHandler,\n} from \"./SessionInspector.approvals\";\nimport { SessionViewer, type SessionViewerProps } from \"./SessionViewer\";\nimport type { SessionInput } from \"./SessionViewer.model\";\nimport type { UnifiedSessionInput } from \"./SessionViewer.unified\";\n\nexport type SessionInspectorTab =\n | \"transcript\"\n | \"files\"\n | \"plan\"\n | \"approvals\"\n | \"costs\"\n | \"metadata\"\n | \"raw\";\n\nexport interface SessionInspectorProps {\n session: SessionInspectorInput;\n className?: string;\n defaultTab?: SessionInspectorTab;\n transcriptProps?: Omit<SessionViewerProps, \"session\">;\n renderSessionActions?: (item: SessionCollectionItem) => ReactNode;\n /** Receives edits made in the Plan tab. The inspector also keeps the draft visible locally. */\n onPlanChange?: (content: string) => void;\n /** Resolves one pending tool approval from the Approvals tab. Omitted, the\n * tab still lists pending requests but renders no Approve/Deny controls. */\n onResolveApproval?: ApprovalResolveHandler;\n composer?: ReactNode;\n}\n\nconst TABS = [\n { id: \"transcript\", label: \"Transcript\", icon: UiChatDots },\n { id: \"files\", label: \"Files\", icon: UiFileText },\n { id: \"plan\", label: \"Plan\", icon: UiStrategy },\n { id: \"approvals\", label: \"Approvals\", icon: UiSealCheck },\n { id: \"costs\", label: \"Costs\", icon: UiCoins },\n { id: \"metadata\", label: \"Metadata\", icon: UiListDashes },\n { id: \"raw\", label: \"Raw\", icon: UiBraces },\n] as const;\n\nexport function SessionInspector({\n session,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n renderSessionActions,\n onPlanChange,\n onResolveApproval,\n composer,\n}: SessionInspectorProps) {\n const detail = useMemo(\n () =>\n isSessionCollectionInput(session) ? undefined : asUnifiedSession(session),\n [session],\n );\n const collection = useMemo(\n () =>\n isSessionCollectionInput(session)\n ? session\n : detail\n ? singleSessionCollection(detail)\n : undefined,\n [detail, session],\n );\n\n if (collection) {\n const optionalProps = {\n ...(className ? { className } : {}),\n ...(transcriptProps ? { transcriptProps } : {}),\n ...(renderSessionActions ? { renderSessionActions } : {}),\n ...(onPlanChange ? { onPlanChange } : {}),\n ...(onResolveApproval ? { onResolveApproval } : {}),\n ...(composer ? { composer } : {}),\n };\n return (\n <CollectionSessionInspector\n collection={collection}\n defaultTab={defaultTab}\n {...optionalProps}\n />\n );\n }\n\n return (\n <LegacySessionInspector\n session={session as SessionInput}\n defaultTab={defaultTab}\n {...(className ? { className } : {})}\n {...(transcriptProps ? { transcriptProps } : {})}\n {...(composer ? { composer } : {})}\n />\n );\n}\n\nfunction CollectionSessionInspector({\n collection,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n renderSessionActions,\n onPlanChange,\n onResolveApproval,\n composer,\n}: Omit<SessionInspectorProps, \"session\"> & {\n collection: SessionCollectionInput;\n}) {\n const hierarchy = useSessionHierarchy(collection);\n const [tab, setTab] = useState<SessionInspectorTab>(defaultTab);\n const transcriptClassName = cn(\"h-full\", transcriptProps?.className);\n const panelDetail = tab === \"costs\" ? hierarchy.filtered : hierarchy.current;\n\n return (\n <div\n className={cn(\n \"flex h-full min-h-0 w-full max-w-full flex-col overflow-hidden rounded-xl border border-border bg-background text-sm shadow-sm\",\n className,\n )}\n >\n <SessionInspectorHeader session={hierarchy.current} />\n <div\n role=\"toolbar\"\n aria-label=\"Session content controls\"\n className=\"flex shrink-0 justify-start border-b border-border px-density-2 py-density-2\"\n >\n <SessionHierarchyPicker\n collection={collection}\n state={hierarchy}\n {...(renderSessionActions ? { renderSessionActions } : {})}\n />\n </div>\n <div\n role=\"tablist\"\n aria-label=\"Session detail view\"\n className=\"flex shrink-0 overflow-x-auto border-b border-border px-density-2\"\n >\n {TABS.map((item) => {\n const badge = tabBadge(item.id, hierarchy.current);\n return (\n <TabButton\n key={item.id}\n active={tab === item.id}\n onClick={() => setTab(item.id)}\n label={tabLabel(\n item.id,\n item.label,\n item.id === \"costs\" ? hierarchy.filtered : hierarchy.current,\n )}\n icon={item.icon}\n variant=\"underline\"\n {...(badge.count === undefined ? {} : { count: badge.count })}\n {...(badge.color ? { countColor: badge.color } : {})}\n className=\"shrink-0 py-density-2 [&_svg]:text-muted-foreground\"\n />\n );\n })}\n </div>\n <div className=\"grid min-h-0 flex-1 overflow-y-auto lg:grid-cols-[minmax(0,1fr)_18rem] lg:overflow-hidden\">\n <main className=\"flex min-h-[28rem] min-w-0 flex-col lg:min-h-0\">\n <div\n className={cn(\n \"min-h-0 flex-1\",\n tab === \"transcript\"\n ? \"overflow-hidden\"\n : \"overflow-auto p-density-4\",\n )}\n >\n {tab === \"transcript\" ? (\n <SessionTranscript\n session={hierarchy.filtered}\n viewerProps={{\n ...transcriptProps,\n className: transcriptClassName,\n }}\n />\n ) : (\n <SessionInspectorPanel\n tab={tab}\n detail={panelDetail}\n session={hierarchy.current}\n {...(onPlanChange ? { onPlanChange } : {})}\n {...(onResolveApproval ? { onResolveApproval } : {})}\n />\n )}\n </div>\n {composer ? (\n <div className=\"shrink-0 border-t border-border p-density-3\">\n {composer}\n </div>\n ) : null}\n </main>\n <SessionInspectorSidebar session={hierarchy.current} />\n </div>\n </div>\n );\n}\n\nfunction LegacySessionInspector({\n session,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n composer,\n}: Pick<\n SessionInspectorProps,\n \"className\" | \"defaultTab\" | \"transcriptProps\" | \"composer\"\n> & {\n session: SessionInput;\n}) {\n const [tab, setTab] = useState<SessionInspectorTab>(defaultTab);\n const transcriptClassName = cn(\"h-full\", transcriptProps?.className);\n return (\n <div\n className={cn(\n \"flex h-full min-h-0 w-full max-w-full flex-col overflow-hidden rounded-xl border border-border bg-background text-sm shadow-sm\",\n className,\n )}\n >\n <div\n role=\"tablist\"\n aria-label=\"Session detail view\"\n className=\"flex shrink-0 overflow-x-auto border-b border-border px-density-2\"\n >\n {TABS.map((item) => (\n <TabButton\n key={item.id}\n active={tab === item.id}\n onClick={() => setTab(item.id)}\n label={item.label}\n icon={item.icon}\n variant=\"underline\"\n className=\"shrink-0 py-density-2 [&_svg]:text-muted-foreground\"\n />\n ))}\n </div>\n <div className=\"flex min-h-0 flex-1 flex-col overflow-hidden\">\n <div className=\"min-h-0 flex-1 overflow-hidden\">\n {tab === \"transcript\" ? (\n <SessionViewer\n session={session}\n scrollable\n showRowMetadata\n {...transcriptProps}\n className={transcriptClassName}\n />\n ) : (\n <SessionInspectorPanel\n tab={tab}\n detail={undefined}\n session={session}\n />\n )}\n </div>\n {composer ? (\n <div className=\"shrink-0 border-t border-border p-density-3\">\n {composer}\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n\n/** The tab's count badge and, for a pending-approvals badge, an amber\n * override so an unresolved approval reads as urgent rather than blending\n * into the neutral resolved-count badge every other tab uses. */\nfunction tabBadge(\n tab: SessionInspectorTab,\n session?: UnifiedSessionInput,\n): { count?: number; color?: string } {\n switch (tab) {\n case \"files\":\n return {\n count:\n (session?.files?.read?.length ?? 0) +\n (session?.files?.written?.length ?? 0),\n };\n case \"approvals\": {\n const pending = pendingApprovalRequests(session?.requests).length;\n if (pending) return { count: pending, color: \"bg-amber-500\" };\n return {\n count:\n (session?.approvals?.approved ?? 0) +\n (session?.approvals?.denied ?? 0),\n };\n }\n default:\n return {};\n }\n}\n\nfunction singleSessionCollection(\n session: UnifiedSessionInput,\n): SessionCollectionInput {\n const id = session.id || \"session\";\n return {\n kind: \"session-collection\",\n id,\n currentSessionId: id,\n sessions: [{ id, session }],\n };\n}\n\nfunction tabLabel(\n tab: SessionInspectorTab,\n label: string,\n session?: UnifiedSessionInput,\n) {\n if (tab !== \"costs\") return label;\n const total = costTotal(session?.cost);\n return total ? `${label} ${formatCost(total)}` : label;\n}\n\nfunction asUnifiedSession(\n session: SessionInput,\n): UnifiedSessionInput | undefined {\n if (typeof session !== \"object\" || session === null || Array.isArray(session))\n return undefined;\n return session as UnifiedSessionInput;\n}\n"],"names":["UiChatDots","UiFileText","UiStrategy","UiSealCheck","UiCoins","UiListDashes","UiBraces","useMemo","isSessionCollectionInput","jsx","useSessionHierarchy","useState","cn","jsxs","SessionInspectorHeader","SessionHierarchyPicker","TabButton","SessionTranscript","SessionInspectorPanel","SessionInspectorSidebar","SessionViewer","pendingApprovalRequests","costTotal","formatCost"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SessionInspector.cjs","sources":["../../../src/data/ai/SessionInspector.tsx"],"sourcesContent":["import { useMemo, useState, type ReactNode } from \"react\";\nimport {\n UiBraces,\n UiChatDots,\n UiCoins,\n UiFileText,\n UiListDashes,\n UiSealCheck,\n UiStrategy,\n} from \"../../icons\";\nimport { cn } from \"../../lib/utils\";\nimport { TabButton } from \"../TabButton\";\nimport { formatCost, costTotal } from \"./session-cost\";\nimport { SessionInspectorPanel } from \"./SessionInspector.panels\";\nimport {\n SessionInspectorHeader,\n SessionInspectorSidebar,\n} from \"./SessionInspector.summary\";\nimport { SessionTranscript } from \"./SessionInspector.transcript\";\nimport {\n isSessionCollectionInput,\n type SessionCollectionInput,\n type SessionCollectionItem,\n type SessionInspectorInput,\n} from \"./SessionInspector.collection\";\nimport { SessionHierarchyPicker } from \"./SessionInspector.hierarchy\";\nimport { useSessionHierarchy } from \"./SessionInspector.hierarchy-state\";\nimport {\n pendingApprovalRequests,\n type ApprovalResolveHandler,\n} from \"./SessionInspector.approvals-model\";\nimport { SessionViewer, type SessionViewerProps } from \"./SessionViewer\";\nimport type { SessionInput } from \"./SessionViewer.model\";\nimport type { UnifiedSessionInput } from \"./SessionViewer.unified\";\n\nexport type SessionInspectorTab =\n | \"transcript\"\n | \"files\"\n | \"plan\"\n | \"approvals\"\n | \"costs\"\n | \"metadata\"\n | \"raw\";\n\nexport interface SessionInspectorProps {\n session: SessionInspectorInput;\n className?: string;\n defaultTab?: SessionInspectorTab;\n transcriptProps?: Omit<SessionViewerProps, \"session\">;\n renderSessionActions?: (item: SessionCollectionItem) => ReactNode;\n /** Receives edits made in the Plan tab. The inspector also keeps the draft visible locally. */\n onPlanChange?: (content: string) => void;\n /** Resolves one pending tool approval from the Approvals tab. Omitted, the\n * tab still lists pending requests but renders no Approve/Deny controls. */\n onResolveApproval?: ApprovalResolveHandler;\n composer?: ReactNode;\n}\n\nconst TABS = [\n { id: \"transcript\", label: \"Transcript\", icon: UiChatDots },\n { id: \"files\", label: \"Files\", icon: UiFileText },\n { id: \"plan\", label: \"Plan\", icon: UiStrategy },\n { id: \"approvals\", label: \"Approvals\", icon: UiSealCheck },\n { id: \"costs\", label: \"Costs\", icon: UiCoins },\n { id: \"metadata\", label: \"Metadata\", icon: UiListDashes },\n { id: \"raw\", label: \"Raw\", icon: UiBraces },\n] as const;\n\nexport function SessionInspector({\n session,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n renderSessionActions,\n onPlanChange,\n onResolveApproval,\n composer,\n}: SessionInspectorProps) {\n const detail = useMemo(\n () =>\n isSessionCollectionInput(session) ? undefined : asUnifiedSession(session),\n [session],\n );\n const collection = useMemo(\n () =>\n isSessionCollectionInput(session)\n ? session\n : detail\n ? singleSessionCollection(detail)\n : undefined,\n [detail, session],\n );\n\n if (collection) {\n const optionalProps = {\n ...(className ? { className } : {}),\n ...(transcriptProps ? { transcriptProps } : {}),\n ...(renderSessionActions ? { renderSessionActions } : {}),\n ...(onPlanChange ? { onPlanChange } : {}),\n ...(onResolveApproval ? { onResolveApproval } : {}),\n ...(composer ? { composer } : {}),\n };\n return (\n <CollectionSessionInspector\n collection={collection}\n defaultTab={defaultTab}\n {...optionalProps}\n />\n );\n }\n\n return (\n <LegacySessionInspector\n session={session as SessionInput}\n defaultTab={defaultTab}\n {...(className ? { className } : {})}\n {...(transcriptProps ? { transcriptProps } : {})}\n {...(composer ? { composer } : {})}\n />\n );\n}\n\nfunction CollectionSessionInspector({\n collection,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n renderSessionActions,\n onPlanChange,\n onResolveApproval,\n composer,\n}: Omit<SessionInspectorProps, \"session\"> & {\n collection: SessionCollectionInput;\n}) {\n const hierarchy = useSessionHierarchy(collection);\n const [tab, setTab] = useState<SessionInspectorTab>(defaultTab);\n const transcriptClassName = cn(\"h-full\", transcriptProps?.className);\n const panelDetail = tab === \"costs\" ? hierarchy.filtered : hierarchy.current;\n\n return (\n <div\n className={cn(\n \"flex h-full min-h-0 w-full max-w-full flex-col overflow-hidden rounded-xl border border-border bg-background text-sm shadow-sm\",\n className,\n )}\n >\n <SessionInspectorHeader session={hierarchy.current} />\n <div\n role=\"toolbar\"\n aria-label=\"Session content controls\"\n className=\"flex shrink-0 justify-start border-b border-border px-density-2 py-density-2\"\n >\n <SessionHierarchyPicker\n collection={collection}\n state={hierarchy}\n {...(renderSessionActions ? { renderSessionActions } : {})}\n />\n </div>\n <div\n role=\"tablist\"\n aria-label=\"Session detail view\"\n className=\"flex shrink-0 overflow-x-auto border-b border-border px-density-2\"\n >\n {TABS.map((item) => {\n const badge = tabBadge(item.id, hierarchy.current);\n return (\n <TabButton\n key={item.id}\n active={tab === item.id}\n onClick={() => setTab(item.id)}\n label={tabLabel(\n item.id,\n item.label,\n item.id === \"costs\" ? hierarchy.filtered : hierarchy.current,\n )}\n icon={item.icon}\n variant=\"underline\"\n {...(badge.count === undefined ? {} : { count: badge.count })}\n {...(badge.color ? { countColor: badge.color } : {})}\n className=\"shrink-0 py-density-2 [&_svg]:text-muted-foreground\"\n />\n );\n })}\n </div>\n <div className=\"grid min-h-0 flex-1 overflow-y-auto lg:grid-cols-[minmax(0,1fr)_18rem] lg:overflow-hidden\">\n <main className=\"flex min-h-[28rem] min-w-0 flex-col lg:min-h-0\">\n <div\n className={cn(\n \"min-h-0 flex-1\",\n tab === \"transcript\"\n ? \"overflow-hidden\"\n : \"overflow-auto p-density-4\",\n )}\n >\n {tab === \"transcript\" ? (\n <SessionTranscript\n session={hierarchy.filtered}\n viewerProps={{\n ...transcriptProps,\n className: transcriptClassName,\n }}\n />\n ) : (\n <SessionInspectorPanel\n tab={tab}\n detail={panelDetail}\n session={hierarchy.current}\n {...(onPlanChange ? { onPlanChange } : {})}\n {...(onResolveApproval ? { onResolveApproval } : {})}\n />\n )}\n </div>\n {composer ? (\n <div className=\"shrink-0 border-t border-border p-density-3\">\n {composer}\n </div>\n ) : null}\n </main>\n <SessionInspectorSidebar session={hierarchy.current} />\n </div>\n </div>\n );\n}\n\nfunction LegacySessionInspector({\n session,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n composer,\n}: Pick<\n SessionInspectorProps,\n \"className\" | \"defaultTab\" | \"transcriptProps\" | \"composer\"\n> & {\n session: SessionInput;\n}) {\n const [tab, setTab] = useState<SessionInspectorTab>(defaultTab);\n const transcriptClassName = cn(\"h-full\", transcriptProps?.className);\n return (\n <div\n className={cn(\n \"flex h-full min-h-0 w-full max-w-full flex-col overflow-hidden rounded-xl border border-border bg-background text-sm shadow-sm\",\n className,\n )}\n >\n <div\n role=\"tablist\"\n aria-label=\"Session detail view\"\n className=\"flex shrink-0 overflow-x-auto border-b border-border px-density-2\"\n >\n {TABS.map((item) => (\n <TabButton\n key={item.id}\n active={tab === item.id}\n onClick={() => setTab(item.id)}\n label={item.label}\n icon={item.icon}\n variant=\"underline\"\n className=\"shrink-0 py-density-2 [&_svg]:text-muted-foreground\"\n />\n ))}\n </div>\n <div className=\"flex min-h-0 flex-1 flex-col overflow-hidden\">\n <div className=\"min-h-0 flex-1 overflow-hidden\">\n {tab === \"transcript\" ? (\n <SessionViewer\n session={session}\n scrollable\n showRowMetadata\n {...transcriptProps}\n className={transcriptClassName}\n />\n ) : (\n <SessionInspectorPanel\n tab={tab}\n detail={undefined}\n session={session}\n />\n )}\n </div>\n {composer ? (\n <div className=\"shrink-0 border-t border-border p-density-3\">\n {composer}\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n\n/** The tab's count badge and, for a pending-approvals badge, an amber\n * override so an unresolved approval reads as urgent rather than blending\n * into the neutral resolved-count badge every other tab uses. */\nfunction tabBadge(\n tab: SessionInspectorTab,\n session?: UnifiedSessionInput,\n): { count?: number; color?: string } {\n switch (tab) {\n case \"files\":\n return {\n count:\n (session?.files?.read?.length ?? 0) +\n (session?.files?.written?.length ?? 0),\n };\n case \"approvals\": {\n const pending = pendingApprovalRequests(session?.requests).length;\n if (pending) return { count: pending, color: \"bg-amber-500\" };\n return {\n count:\n (session?.approvals?.approved ?? 0) +\n (session?.approvals?.denied ?? 0),\n };\n }\n default:\n return {};\n }\n}\n\nfunction singleSessionCollection(\n session: UnifiedSessionInput,\n): SessionCollectionInput {\n const id = session.id || \"session\";\n return {\n kind: \"session-collection\",\n id,\n currentSessionId: id,\n sessions: [{ id, session }],\n };\n}\n\nfunction tabLabel(\n tab: SessionInspectorTab,\n label: string,\n session?: UnifiedSessionInput,\n) {\n if (tab !== \"costs\") return label;\n const total = costTotal(session?.cost);\n return total ? `${label} ${formatCost(total)}` : label;\n}\n\nfunction asUnifiedSession(\n session: SessionInput,\n): UnifiedSessionInput | undefined {\n if (typeof session !== \"object\" || session === null || Array.isArray(session))\n return undefined;\n return session as UnifiedSessionInput;\n}\n"],"names":["UiChatDots","UiFileText","UiStrategy","UiSealCheck","UiCoins","UiListDashes","UiBraces","useMemo","isSessionCollectionInput","jsx","useSessionHierarchy","useState","cn","jsxs","SessionInspectorHeader","SessionHierarchyPicker","TabButton","SessionTranscript","SessionInspectorPanel","SessionInspectorSidebar","SessionViewer","pendingApprovalRequests","costTotal","formatCost"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
import { SessionCollectionItem, SessionInspectorInput } from './SessionInspector.collection';
|
|
3
|
-
import { ApprovalResolveHandler } from './SessionInspector.approvals';
|
|
3
|
+
import { ApprovalResolveHandler } from './SessionInspector.approvals-model';
|
|
4
4
|
import { SessionViewerProps } from './SessionViewer';
|
|
5
5
|
export type SessionInspectorTab = "transcript" | "files" | "plan" | "approvals" | "costs" | "metadata" | "raw";
|
|
6
6
|
export interface SessionInspectorProps {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionInspector.d.ts","sourceRoot":"","sources":["../../../src/data/ai/SessionInspector.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAmB1D,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC3B,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,
|
|
1
|
+
{"version":3,"file":"SessionInspector.d.ts","sourceRoot":"","sources":["../../../src/data/ai/SessionInspector.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAmB1D,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC3B,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAiB,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAIzE,MAAM,MAAM,mBAAmB,GAC3B,YAAY,GACZ,OAAO,GACP,MAAM,GACN,WAAW,GACX,OAAO,GACP,UAAU,GACV,KAAK,CAAC;AAEV,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,qBAAqB,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,eAAe,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,SAAS,CAAC,CAAC;IACtD,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE,qBAAqB,KAAK,SAAS,CAAC;IAClE,+FAA+F;IAC/F,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC;iFAC6E;IAC7E,iBAAiB,CAAC,EAAE,sBAAsB,CAAC;IAC3C,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAYD,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,SAAS,EACT,UAAyB,EACzB,eAAe,EACf,oBAAoB,EACpB,YAAY,EACZ,iBAAiB,EACjB,QAAQ,GACT,EAAE,qBAAqB,+BA2CvB"}
|
|
@@ -9,7 +9,7 @@ import { SessionTranscript } from "./SessionInspector.transcript.js";
|
|
|
9
9
|
import { isSessionCollectionInput } from "./SessionInspector.collection.js";
|
|
10
10
|
import { SessionHierarchyPicker } from "./SessionInspector.hierarchy.js";
|
|
11
11
|
import { useSessionHierarchy } from "./SessionInspector.hierarchy-state.js";
|
|
12
|
-
import { pendingApprovalRequests } from "./SessionInspector.approvals.js";
|
|
12
|
+
import { pendingApprovalRequests } from "./SessionInspector.approvals-model.js";
|
|
13
13
|
import { SessionViewer } from "./SessionViewer.js";
|
|
14
14
|
import { UiChatDots } from "../../icons/components/UiChatDots.js";
|
|
15
15
|
import { UiFileText } from "../../icons/components/UiFileText.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionInspector.js","sources":["../../../src/data/ai/SessionInspector.tsx"],"sourcesContent":["import { useMemo, useState, type ReactNode } from \"react\";\nimport {\n UiBraces,\n UiChatDots,\n UiCoins,\n UiFileText,\n UiListDashes,\n UiSealCheck,\n UiStrategy,\n} from \"../../icons\";\nimport { cn } from \"../../lib/utils\";\nimport { TabButton } from \"../TabButton\";\nimport { formatCost, costTotal } from \"./session-cost\";\nimport { SessionInspectorPanel } from \"./SessionInspector.panels\";\nimport {\n SessionInspectorHeader,\n SessionInspectorSidebar,\n} from \"./SessionInspector.summary\";\nimport { SessionTranscript } from \"./SessionInspector.transcript\";\nimport {\n isSessionCollectionInput,\n type SessionCollectionInput,\n type SessionCollectionItem,\n type SessionInspectorInput,\n} from \"./SessionInspector.collection\";\nimport { SessionHierarchyPicker } from \"./SessionInspector.hierarchy\";\nimport { useSessionHierarchy } from \"./SessionInspector.hierarchy-state\";\nimport {\n pendingApprovalRequests,\n type ApprovalResolveHandler,\n} from \"./SessionInspector.approvals\";\nimport { SessionViewer, type SessionViewerProps } from \"./SessionViewer\";\nimport type { SessionInput } from \"./SessionViewer.model\";\nimport type { UnifiedSessionInput } from \"./SessionViewer.unified\";\n\nexport type SessionInspectorTab =\n | \"transcript\"\n | \"files\"\n | \"plan\"\n | \"approvals\"\n | \"costs\"\n | \"metadata\"\n | \"raw\";\n\nexport interface SessionInspectorProps {\n session: SessionInspectorInput;\n className?: string;\n defaultTab?: SessionInspectorTab;\n transcriptProps?: Omit<SessionViewerProps, \"session\">;\n renderSessionActions?: (item: SessionCollectionItem) => ReactNode;\n /** Receives edits made in the Plan tab. The inspector also keeps the draft visible locally. */\n onPlanChange?: (content: string) => void;\n /** Resolves one pending tool approval from the Approvals tab. Omitted, the\n * tab still lists pending requests but renders no Approve/Deny controls. */\n onResolveApproval?: ApprovalResolveHandler;\n composer?: ReactNode;\n}\n\nconst TABS = [\n { id: \"transcript\", label: \"Transcript\", icon: UiChatDots },\n { id: \"files\", label: \"Files\", icon: UiFileText },\n { id: \"plan\", label: \"Plan\", icon: UiStrategy },\n { id: \"approvals\", label: \"Approvals\", icon: UiSealCheck },\n { id: \"costs\", label: \"Costs\", icon: UiCoins },\n { id: \"metadata\", label: \"Metadata\", icon: UiListDashes },\n { id: \"raw\", label: \"Raw\", icon: UiBraces },\n] as const;\n\nexport function SessionInspector({\n session,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n renderSessionActions,\n onPlanChange,\n onResolveApproval,\n composer,\n}: SessionInspectorProps) {\n const detail = useMemo(\n () =>\n isSessionCollectionInput(session) ? undefined : asUnifiedSession(session),\n [session],\n );\n const collection = useMemo(\n () =>\n isSessionCollectionInput(session)\n ? session\n : detail\n ? singleSessionCollection(detail)\n : undefined,\n [detail, session],\n );\n\n if (collection) {\n const optionalProps = {\n ...(className ? { className } : {}),\n ...(transcriptProps ? { transcriptProps } : {}),\n ...(renderSessionActions ? { renderSessionActions } : {}),\n ...(onPlanChange ? { onPlanChange } : {}),\n ...(onResolveApproval ? { onResolveApproval } : {}),\n ...(composer ? { composer } : {}),\n };\n return (\n <CollectionSessionInspector\n collection={collection}\n defaultTab={defaultTab}\n {...optionalProps}\n />\n );\n }\n\n return (\n <LegacySessionInspector\n session={session as SessionInput}\n defaultTab={defaultTab}\n {...(className ? { className } : {})}\n {...(transcriptProps ? { transcriptProps } : {})}\n {...(composer ? { composer } : {})}\n />\n );\n}\n\nfunction CollectionSessionInspector({\n collection,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n renderSessionActions,\n onPlanChange,\n onResolveApproval,\n composer,\n}: Omit<SessionInspectorProps, \"session\"> & {\n collection: SessionCollectionInput;\n}) {\n const hierarchy = useSessionHierarchy(collection);\n const [tab, setTab] = useState<SessionInspectorTab>(defaultTab);\n const transcriptClassName = cn(\"h-full\", transcriptProps?.className);\n const panelDetail = tab === \"costs\" ? hierarchy.filtered : hierarchy.current;\n\n return (\n <div\n className={cn(\n \"flex h-full min-h-0 w-full max-w-full flex-col overflow-hidden rounded-xl border border-border bg-background text-sm shadow-sm\",\n className,\n )}\n >\n <SessionInspectorHeader session={hierarchy.current} />\n <div\n role=\"toolbar\"\n aria-label=\"Session content controls\"\n className=\"flex shrink-0 justify-start border-b border-border px-density-2 py-density-2\"\n >\n <SessionHierarchyPicker\n collection={collection}\n state={hierarchy}\n {...(renderSessionActions ? { renderSessionActions } : {})}\n />\n </div>\n <div\n role=\"tablist\"\n aria-label=\"Session detail view\"\n className=\"flex shrink-0 overflow-x-auto border-b border-border px-density-2\"\n >\n {TABS.map((item) => {\n const badge = tabBadge(item.id, hierarchy.current);\n return (\n <TabButton\n key={item.id}\n active={tab === item.id}\n onClick={() => setTab(item.id)}\n label={tabLabel(\n item.id,\n item.label,\n item.id === \"costs\" ? hierarchy.filtered : hierarchy.current,\n )}\n icon={item.icon}\n variant=\"underline\"\n {...(badge.count === undefined ? {} : { count: badge.count })}\n {...(badge.color ? { countColor: badge.color } : {})}\n className=\"shrink-0 py-density-2 [&_svg]:text-muted-foreground\"\n />\n );\n })}\n </div>\n <div className=\"grid min-h-0 flex-1 overflow-y-auto lg:grid-cols-[minmax(0,1fr)_18rem] lg:overflow-hidden\">\n <main className=\"flex min-h-[28rem] min-w-0 flex-col lg:min-h-0\">\n <div\n className={cn(\n \"min-h-0 flex-1\",\n tab === \"transcript\"\n ? \"overflow-hidden\"\n : \"overflow-auto p-density-4\",\n )}\n >\n {tab === \"transcript\" ? (\n <SessionTranscript\n session={hierarchy.filtered}\n viewerProps={{\n ...transcriptProps,\n className: transcriptClassName,\n }}\n />\n ) : (\n <SessionInspectorPanel\n tab={tab}\n detail={panelDetail}\n session={hierarchy.current}\n {...(onPlanChange ? { onPlanChange } : {})}\n {...(onResolveApproval ? { onResolveApproval } : {})}\n />\n )}\n </div>\n {composer ? (\n <div className=\"shrink-0 border-t border-border p-density-3\">\n {composer}\n </div>\n ) : null}\n </main>\n <SessionInspectorSidebar session={hierarchy.current} />\n </div>\n </div>\n );\n}\n\nfunction LegacySessionInspector({\n session,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n composer,\n}: Pick<\n SessionInspectorProps,\n \"className\" | \"defaultTab\" | \"transcriptProps\" | \"composer\"\n> & {\n session: SessionInput;\n}) {\n const [tab, setTab] = useState<SessionInspectorTab>(defaultTab);\n const transcriptClassName = cn(\"h-full\", transcriptProps?.className);\n return (\n <div\n className={cn(\n \"flex h-full min-h-0 w-full max-w-full flex-col overflow-hidden rounded-xl border border-border bg-background text-sm shadow-sm\",\n className,\n )}\n >\n <div\n role=\"tablist\"\n aria-label=\"Session detail view\"\n className=\"flex shrink-0 overflow-x-auto border-b border-border px-density-2\"\n >\n {TABS.map((item) => (\n <TabButton\n key={item.id}\n active={tab === item.id}\n onClick={() => setTab(item.id)}\n label={item.label}\n icon={item.icon}\n variant=\"underline\"\n className=\"shrink-0 py-density-2 [&_svg]:text-muted-foreground\"\n />\n ))}\n </div>\n <div className=\"flex min-h-0 flex-1 flex-col overflow-hidden\">\n <div className=\"min-h-0 flex-1 overflow-hidden\">\n {tab === \"transcript\" ? (\n <SessionViewer\n session={session}\n scrollable\n showRowMetadata\n {...transcriptProps}\n className={transcriptClassName}\n />\n ) : (\n <SessionInspectorPanel\n tab={tab}\n detail={undefined}\n session={session}\n />\n )}\n </div>\n {composer ? (\n <div className=\"shrink-0 border-t border-border p-density-3\">\n {composer}\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n\n/** The tab's count badge and, for a pending-approvals badge, an amber\n * override so an unresolved approval reads as urgent rather than blending\n * into the neutral resolved-count badge every other tab uses. */\nfunction tabBadge(\n tab: SessionInspectorTab,\n session?: UnifiedSessionInput,\n): { count?: number; color?: string } {\n switch (tab) {\n case \"files\":\n return {\n count:\n (session?.files?.read?.length ?? 0) +\n (session?.files?.written?.length ?? 0),\n };\n case \"approvals\": {\n const pending = pendingApprovalRequests(session?.requests).length;\n if (pending) return { count: pending, color: \"bg-amber-500\" };\n return {\n count:\n (session?.approvals?.approved ?? 0) +\n (session?.approvals?.denied ?? 0),\n };\n }\n default:\n return {};\n }\n}\n\nfunction singleSessionCollection(\n session: UnifiedSessionInput,\n): SessionCollectionInput {\n const id = session.id || \"session\";\n return {\n kind: \"session-collection\",\n id,\n currentSessionId: id,\n sessions: [{ id, session }],\n };\n}\n\nfunction tabLabel(\n tab: SessionInspectorTab,\n label: string,\n session?: UnifiedSessionInput,\n) {\n if (tab !== \"costs\") return label;\n const total = costTotal(session?.cost);\n return total ? `${label} ${formatCost(total)}` : label;\n}\n\nfunction asUnifiedSession(\n session: SessionInput,\n): UnifiedSessionInput | undefined {\n if (typeof session !== \"object\" || session === null || Array.isArray(session))\n return undefined;\n return session as UnifiedSessionInput;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SessionInspector.js","sources":["../../../src/data/ai/SessionInspector.tsx"],"sourcesContent":["import { useMemo, useState, type ReactNode } from \"react\";\nimport {\n UiBraces,\n UiChatDots,\n UiCoins,\n UiFileText,\n UiListDashes,\n UiSealCheck,\n UiStrategy,\n} from \"../../icons\";\nimport { cn } from \"../../lib/utils\";\nimport { TabButton } from \"../TabButton\";\nimport { formatCost, costTotal } from \"./session-cost\";\nimport { SessionInspectorPanel } from \"./SessionInspector.panels\";\nimport {\n SessionInspectorHeader,\n SessionInspectorSidebar,\n} from \"./SessionInspector.summary\";\nimport { SessionTranscript } from \"./SessionInspector.transcript\";\nimport {\n isSessionCollectionInput,\n type SessionCollectionInput,\n type SessionCollectionItem,\n type SessionInspectorInput,\n} from \"./SessionInspector.collection\";\nimport { SessionHierarchyPicker } from \"./SessionInspector.hierarchy\";\nimport { useSessionHierarchy } from \"./SessionInspector.hierarchy-state\";\nimport {\n pendingApprovalRequests,\n type ApprovalResolveHandler,\n} from \"./SessionInspector.approvals-model\";\nimport { SessionViewer, type SessionViewerProps } from \"./SessionViewer\";\nimport type { SessionInput } from \"./SessionViewer.model\";\nimport type { UnifiedSessionInput } from \"./SessionViewer.unified\";\n\nexport type SessionInspectorTab =\n | \"transcript\"\n | \"files\"\n | \"plan\"\n | \"approvals\"\n | \"costs\"\n | \"metadata\"\n | \"raw\";\n\nexport interface SessionInspectorProps {\n session: SessionInspectorInput;\n className?: string;\n defaultTab?: SessionInspectorTab;\n transcriptProps?: Omit<SessionViewerProps, \"session\">;\n renderSessionActions?: (item: SessionCollectionItem) => ReactNode;\n /** Receives edits made in the Plan tab. The inspector also keeps the draft visible locally. */\n onPlanChange?: (content: string) => void;\n /** Resolves one pending tool approval from the Approvals tab. Omitted, the\n * tab still lists pending requests but renders no Approve/Deny controls. */\n onResolveApproval?: ApprovalResolveHandler;\n composer?: ReactNode;\n}\n\nconst TABS = [\n { id: \"transcript\", label: \"Transcript\", icon: UiChatDots },\n { id: \"files\", label: \"Files\", icon: UiFileText },\n { id: \"plan\", label: \"Plan\", icon: UiStrategy },\n { id: \"approvals\", label: \"Approvals\", icon: UiSealCheck },\n { id: \"costs\", label: \"Costs\", icon: UiCoins },\n { id: \"metadata\", label: \"Metadata\", icon: UiListDashes },\n { id: \"raw\", label: \"Raw\", icon: UiBraces },\n] as const;\n\nexport function SessionInspector({\n session,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n renderSessionActions,\n onPlanChange,\n onResolveApproval,\n composer,\n}: SessionInspectorProps) {\n const detail = useMemo(\n () =>\n isSessionCollectionInput(session) ? undefined : asUnifiedSession(session),\n [session],\n );\n const collection = useMemo(\n () =>\n isSessionCollectionInput(session)\n ? session\n : detail\n ? singleSessionCollection(detail)\n : undefined,\n [detail, session],\n );\n\n if (collection) {\n const optionalProps = {\n ...(className ? { className } : {}),\n ...(transcriptProps ? { transcriptProps } : {}),\n ...(renderSessionActions ? { renderSessionActions } : {}),\n ...(onPlanChange ? { onPlanChange } : {}),\n ...(onResolveApproval ? { onResolveApproval } : {}),\n ...(composer ? { composer } : {}),\n };\n return (\n <CollectionSessionInspector\n collection={collection}\n defaultTab={defaultTab}\n {...optionalProps}\n />\n );\n }\n\n return (\n <LegacySessionInspector\n session={session as SessionInput}\n defaultTab={defaultTab}\n {...(className ? { className } : {})}\n {...(transcriptProps ? { transcriptProps } : {})}\n {...(composer ? { composer } : {})}\n />\n );\n}\n\nfunction CollectionSessionInspector({\n collection,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n renderSessionActions,\n onPlanChange,\n onResolveApproval,\n composer,\n}: Omit<SessionInspectorProps, \"session\"> & {\n collection: SessionCollectionInput;\n}) {\n const hierarchy = useSessionHierarchy(collection);\n const [tab, setTab] = useState<SessionInspectorTab>(defaultTab);\n const transcriptClassName = cn(\"h-full\", transcriptProps?.className);\n const panelDetail = tab === \"costs\" ? hierarchy.filtered : hierarchy.current;\n\n return (\n <div\n className={cn(\n \"flex h-full min-h-0 w-full max-w-full flex-col overflow-hidden rounded-xl border border-border bg-background text-sm shadow-sm\",\n className,\n )}\n >\n <SessionInspectorHeader session={hierarchy.current} />\n <div\n role=\"toolbar\"\n aria-label=\"Session content controls\"\n className=\"flex shrink-0 justify-start border-b border-border px-density-2 py-density-2\"\n >\n <SessionHierarchyPicker\n collection={collection}\n state={hierarchy}\n {...(renderSessionActions ? { renderSessionActions } : {})}\n />\n </div>\n <div\n role=\"tablist\"\n aria-label=\"Session detail view\"\n className=\"flex shrink-0 overflow-x-auto border-b border-border px-density-2\"\n >\n {TABS.map((item) => {\n const badge = tabBadge(item.id, hierarchy.current);\n return (\n <TabButton\n key={item.id}\n active={tab === item.id}\n onClick={() => setTab(item.id)}\n label={tabLabel(\n item.id,\n item.label,\n item.id === \"costs\" ? hierarchy.filtered : hierarchy.current,\n )}\n icon={item.icon}\n variant=\"underline\"\n {...(badge.count === undefined ? {} : { count: badge.count })}\n {...(badge.color ? { countColor: badge.color } : {})}\n className=\"shrink-0 py-density-2 [&_svg]:text-muted-foreground\"\n />\n );\n })}\n </div>\n <div className=\"grid min-h-0 flex-1 overflow-y-auto lg:grid-cols-[minmax(0,1fr)_18rem] lg:overflow-hidden\">\n <main className=\"flex min-h-[28rem] min-w-0 flex-col lg:min-h-0\">\n <div\n className={cn(\n \"min-h-0 flex-1\",\n tab === \"transcript\"\n ? \"overflow-hidden\"\n : \"overflow-auto p-density-4\",\n )}\n >\n {tab === \"transcript\" ? (\n <SessionTranscript\n session={hierarchy.filtered}\n viewerProps={{\n ...transcriptProps,\n className: transcriptClassName,\n }}\n />\n ) : (\n <SessionInspectorPanel\n tab={tab}\n detail={panelDetail}\n session={hierarchy.current}\n {...(onPlanChange ? { onPlanChange } : {})}\n {...(onResolveApproval ? { onResolveApproval } : {})}\n />\n )}\n </div>\n {composer ? (\n <div className=\"shrink-0 border-t border-border p-density-3\">\n {composer}\n </div>\n ) : null}\n </main>\n <SessionInspectorSidebar session={hierarchy.current} />\n </div>\n </div>\n );\n}\n\nfunction LegacySessionInspector({\n session,\n className,\n defaultTab = \"transcript\",\n transcriptProps,\n composer,\n}: Pick<\n SessionInspectorProps,\n \"className\" | \"defaultTab\" | \"transcriptProps\" | \"composer\"\n> & {\n session: SessionInput;\n}) {\n const [tab, setTab] = useState<SessionInspectorTab>(defaultTab);\n const transcriptClassName = cn(\"h-full\", transcriptProps?.className);\n return (\n <div\n className={cn(\n \"flex h-full min-h-0 w-full max-w-full flex-col overflow-hidden rounded-xl border border-border bg-background text-sm shadow-sm\",\n className,\n )}\n >\n <div\n role=\"tablist\"\n aria-label=\"Session detail view\"\n className=\"flex shrink-0 overflow-x-auto border-b border-border px-density-2\"\n >\n {TABS.map((item) => (\n <TabButton\n key={item.id}\n active={tab === item.id}\n onClick={() => setTab(item.id)}\n label={item.label}\n icon={item.icon}\n variant=\"underline\"\n className=\"shrink-0 py-density-2 [&_svg]:text-muted-foreground\"\n />\n ))}\n </div>\n <div className=\"flex min-h-0 flex-1 flex-col overflow-hidden\">\n <div className=\"min-h-0 flex-1 overflow-hidden\">\n {tab === \"transcript\" ? (\n <SessionViewer\n session={session}\n scrollable\n showRowMetadata\n {...transcriptProps}\n className={transcriptClassName}\n />\n ) : (\n <SessionInspectorPanel\n tab={tab}\n detail={undefined}\n session={session}\n />\n )}\n </div>\n {composer ? (\n <div className=\"shrink-0 border-t border-border p-density-3\">\n {composer}\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n\n/** The tab's count badge and, for a pending-approvals badge, an amber\n * override so an unresolved approval reads as urgent rather than blending\n * into the neutral resolved-count badge every other tab uses. */\nfunction tabBadge(\n tab: SessionInspectorTab,\n session?: UnifiedSessionInput,\n): { count?: number; color?: string } {\n switch (tab) {\n case \"files\":\n return {\n count:\n (session?.files?.read?.length ?? 0) +\n (session?.files?.written?.length ?? 0),\n };\n case \"approvals\": {\n const pending = pendingApprovalRequests(session?.requests).length;\n if (pending) return { count: pending, color: \"bg-amber-500\" };\n return {\n count:\n (session?.approvals?.approved ?? 0) +\n (session?.approvals?.denied ?? 0),\n };\n }\n default:\n return {};\n }\n}\n\nfunction singleSessionCollection(\n session: UnifiedSessionInput,\n): SessionCollectionInput {\n const id = session.id || \"session\";\n return {\n kind: \"session-collection\",\n id,\n currentSessionId: id,\n sessions: [{ id, session }],\n };\n}\n\nfunction tabLabel(\n tab: SessionInspectorTab,\n label: string,\n session?: UnifiedSessionInput,\n) {\n if (tab !== \"costs\") return label;\n const total = costTotal(session?.cost);\n return total ? `${label} ${formatCost(total)}` : label;\n}\n\nfunction asUnifiedSession(\n session: SessionInput,\n): UnifiedSessionInput | undefined {\n if (typeof session !== \"object\" || session === null || Array.isArray(session))\n return undefined;\n return session as UnifiedSessionInput;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -29,19 +29,6 @@ function SimpleList({
|
|
|
29
29
|
] }, row.key)) })
|
|
30
30
|
] });
|
|
31
31
|
}
|
|
32
|
-
function kv(label, value) {
|
|
33
|
-
return {
|
|
34
|
-
key: String(label),
|
|
35
|
-
label,
|
|
36
|
-
value: value === void 0 || value === null || value === "" ? muted("-") : value,
|
|
37
|
-
hidden: value === void 0 || value === null || value === ""
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
function muted(value) {
|
|
41
|
-
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: value });
|
|
42
|
-
}
|
|
43
32
|
exports.EmptyState = EmptyState;
|
|
44
33
|
exports.SimpleList = SimpleList;
|
|
45
|
-
exports.kv = kv;
|
|
46
|
-
exports.muted = muted;
|
|
47
34
|
//# sourceMappingURL=SessionInspector.panel-parts.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionInspector.panel-parts.cjs","sources":["../../../src/data/ai/SessionInspector.panel-parts.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils\";\
|
|
1
|
+
{"version":3,"file":"SessionInspector.panel-parts.cjs","sources":["../../../src/data/ai/SessionInspector.panel-parts.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils\";\n\n/** Small display components shared by the SessionInspector detail panels\n * (costs, metadata, approvals, …) — kept in their own module so panel files\n * can depend on them without importing each other. The value builders they are\n * used with live in SessionInspector.panel-values, which exports no components\n * so that neither module loses fast refresh to the other. */\n\nexport function EmptyState({\n children,\n compact = false,\n}: {\n children: ReactNode;\n compact?: boolean;\n}) {\n return (\n <div\n className={cn(\n \"rounded-md border border-dashed border-border text-sm text-muted-foreground\",\n compact ? \"p-density-3\" : \"p-density-6 text-center\"\n )}\n >\n {children}\n </div>\n );\n}\n\nexport function SimpleList({\n title,\n rows,\n}: {\n title: string;\n rows: Array<{ key: string; title?: ReactNode; detail?: ReactNode }>;\n}) {\n return (\n <section>\n <h3 className=\"mb-density-2 text-xs font-semibold uppercase text-muted-foreground\">\n {title}\n </h3>\n <ul className=\"divide-y divide-border rounded-md border border-border\">\n {rows.map((row) => (\n <li key={row.key} className=\"px-density-3 py-density-2\">\n <div className=\"text-sm font-medium\">{row.title || row.key}</div>\n {row.detail ? (\n <div className=\"mt-0.5 text-xs text-muted-foreground\">\n {row.detail}\n </div>\n ) : null}\n </li>\n ))}\n </ul>\n </section>\n );\n}\n\n"],"names":["jsx","cn","jsxs"],"mappings":";;;;AASO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA,UAAU;AACZ,GAGG;AACD,SACEA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWC,MAAAA;AAAAA,QACT;AAAA,QACA,UAAU,gBAAgB;AAAA,MAAA;AAAA,MAG3B;AAAA,IAAA;AAAA,EAAA;AAGP;AAEO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AACF,GAGG;AACD,yCACG,WAAA,EACC,UAAA;AAAA,IAAAD,2BAAAA,IAAC,MAAA,EAAG,WAAU,sEACX,UAAA,OACH;AAAA,IACAA,2BAAAA,IAAC,MAAA,EAAG,WAAU,0DACX,UAAA,KAAK,IAAI,CAAC,QACTE,2BAAAA,KAAC,MAAA,EAAiB,WAAU,6BAC1B,UAAA;AAAA,MAAAF,+BAAC,SAAI,WAAU,uBAAuB,UAAA,IAAI,SAAS,IAAI,KAAI;AAAA,MAC1D,IAAI,SACHA,+BAAC,OAAA,EAAI,WAAU,wCACZ,UAAA,IAAI,QACP,IACE;AAAA,IAAA,KANG,IAAI,GAOb,CACD,EAAA,CACH;AAAA,EAAA,GACF;AAEJ;;;"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
-
|
|
3
|
-
/** Small display primitives shared by the SessionInspector detail panels
|
|
2
|
+
/** Small display components shared by the SessionInspector detail panels
|
|
4
3
|
* (costs, metadata, approvals, …) — kept in their own module so panel files
|
|
5
|
-
* can depend on them without importing each other.
|
|
4
|
+
* can depend on them without importing each other. The value builders they are
|
|
5
|
+
* used with live in SessionInspector.panel-values, which exports no components
|
|
6
|
+
* so that neither module loses fast refresh to the other. */
|
|
6
7
|
export declare function EmptyState({ children, compact, }: {
|
|
7
8
|
children: ReactNode;
|
|
8
9
|
compact?: boolean;
|
|
@@ -15,6 +16,4 @@ export declare function SimpleList({ title, rows, }: {
|
|
|
15
16
|
detail?: ReactNode;
|
|
16
17
|
}>;
|
|
17
18
|
}): import("react").JSX.Element;
|
|
18
|
-
export declare function kv(label: ReactNode, value: ReactNode | undefined | null): KeyValueListItem;
|
|
19
|
-
export declare function muted(value: ReactNode): import("react").JSX.Element;
|
|
20
19
|
//# sourceMappingURL=SessionInspector.panel-parts.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionInspector.panel-parts.d.ts","sourceRoot":"","sources":["../../../src/data/ai/SessionInspector.panel-parts.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"SessionInspector.panel-parts.d.ts","sourceRoot":"","sources":["../../../src/data/ai/SessionInspector.panel-parts.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC;;;;8DAI8D;AAE9D,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,OAAe,GAChB,EAAE;IACD,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,+BAWA;AAED,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,IAAI,GACL,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,SAAS,CAAC;QAAC,MAAM,CAAC,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;CACrE,+BAoBA"}
|
|
@@ -27,21 +27,8 @@ function SimpleList({
|
|
|
27
27
|
] }, row.key)) })
|
|
28
28
|
] });
|
|
29
29
|
}
|
|
30
|
-
function kv(label, value) {
|
|
31
|
-
return {
|
|
32
|
-
key: String(label),
|
|
33
|
-
label,
|
|
34
|
-
value: value === void 0 || value === null || value === "" ? muted("-") : value,
|
|
35
|
-
hidden: value === void 0 || value === null || value === ""
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
function muted(value) {
|
|
39
|
-
return /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: value });
|
|
40
|
-
}
|
|
41
30
|
export {
|
|
42
31
|
EmptyState,
|
|
43
|
-
SimpleList
|
|
44
|
-
kv,
|
|
45
|
-
muted
|
|
32
|
+
SimpleList
|
|
46
33
|
};
|
|
47
34
|
//# sourceMappingURL=SessionInspector.panel-parts.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionInspector.panel-parts.js","sources":["../../../src/data/ai/SessionInspector.panel-parts.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils\";\
|
|
1
|
+
{"version":3,"file":"SessionInspector.panel-parts.js","sources":["../../../src/data/ai/SessionInspector.panel-parts.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils\";\n\n/** Small display components shared by the SessionInspector detail panels\n * (costs, metadata, approvals, …) — kept in their own module so panel files\n * can depend on them without importing each other. The value builders they are\n * used with live in SessionInspector.panel-values, which exports no components\n * so that neither module loses fast refresh to the other. */\n\nexport function EmptyState({\n children,\n compact = false,\n}: {\n children: ReactNode;\n compact?: boolean;\n}) {\n return (\n <div\n className={cn(\n \"rounded-md border border-dashed border-border text-sm text-muted-foreground\",\n compact ? \"p-density-3\" : \"p-density-6 text-center\"\n )}\n >\n {children}\n </div>\n );\n}\n\nexport function SimpleList({\n title,\n rows,\n}: {\n title: string;\n rows: Array<{ key: string; title?: ReactNode; detail?: ReactNode }>;\n}) {\n return (\n <section>\n <h3 className=\"mb-density-2 text-xs font-semibold uppercase text-muted-foreground\">\n {title}\n </h3>\n <ul className=\"divide-y divide-border rounded-md border border-border\">\n {rows.map((row) => (\n <li key={row.key} className=\"px-density-3 py-density-2\">\n <div className=\"text-sm font-medium\">{row.title || row.key}</div>\n {row.detail ? (\n <div className=\"mt-0.5 text-xs text-muted-foreground\">\n {row.detail}\n </div>\n ) : null}\n </li>\n ))}\n </ul>\n </section>\n );\n}\n\n"],"names":[],"mappings":";;AASO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA,UAAU;AACZ,GAGG;AACD,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,UAAU,gBAAgB;AAAA,MAAA;AAAA,MAG3B;AAAA,IAAA;AAAA,EAAA;AAGP;AAEO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AACF,GAGG;AACD,8BACG,WAAA,EACC,UAAA;AAAA,IAAA,oBAAC,MAAA,EAAG,WAAU,sEACX,UAAA,OACH;AAAA,IACA,oBAAC,MAAA,EAAG,WAAU,0DACX,UAAA,KAAK,IAAI,CAAC,QACT,qBAAC,MAAA,EAAiB,WAAU,6BAC1B,UAAA;AAAA,MAAA,oBAAC,SAAI,WAAU,uBAAuB,UAAA,IAAI,SAAS,IAAI,KAAI;AAAA,MAC1D,IAAI,SACH,oBAAC,OAAA,EAAI,WAAU,wCACZ,UAAA,IAAI,QACP,IACE;AAAA,IAAA,KANG,IAAI,GAOb,CACD,EAAA,CACH;AAAA,EAAA,GACF;AAEJ;"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
function muted(value) {
|
|
5
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: value });
|
|
6
|
+
}
|
|
7
|
+
function kv(label, value) {
|
|
8
|
+
const absent = value === void 0 || value === null || value === "";
|
|
9
|
+
return {
|
|
10
|
+
key: String(label),
|
|
11
|
+
label,
|
|
12
|
+
value: absent ? muted("-") : value,
|
|
13
|
+
hidden: absent
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
exports.kv = kv;
|
|
17
|
+
exports.muted = muted;
|
|
18
|
+
//# sourceMappingURL=SessionInspector.panel-values.cjs.map
|