@tangle-network/agent-app 0.60.184 → 0.60.185
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/agent-profiles/d1.js +3 -3
- package/dist/agent-profiles/index.js +3 -3
- package/dist/assistant/index.js +9 -9
- package/dist/channels/index.js +1 -1
- package/dist/chat-react/index.js +4 -4
- package/dist/chat-routes/index.js +4 -4
- package/dist/{chunk-YXLN4PXK.js → chunk-2RCPPOQ4.js} +2 -2
- package/dist/{chunk-YESFGM56.js → chunk-5IS3GCMR.js} +3 -3
- package/dist/{chunk-3RHAF2P5.js → chunk-A3CUVYRZ.js} +3 -3
- package/dist/{chunk-LN5RBVGP.js → chunk-AVP5SNIG.js} +4 -4
- package/dist/{chunk-LN5RBVGP.js.map → chunk-AVP5SNIG.js.map} +1 -1
- package/dist/{chunk-7BYY7QKC.js → chunk-E65YV7VV.js} +5 -5
- package/dist/{chunk-7BYY7QKC.js.map → chunk-E65YV7VV.js.map} +1 -1
- package/dist/chunk-EZFBGW23.js +179 -0
- package/dist/chunk-EZFBGW23.js.map +1 -0
- package/dist/{chunk-UDLA3NGY.js → chunk-GNBBY3KN.js} +3 -3
- package/dist/{chunk-KOTNMTHV.js → chunk-HCFVEJQL.js} +3 -3
- package/dist/{chunk-YGBEGBJY.js → chunk-HEPEGY6Q.js} +2 -2
- package/dist/{chunk-AJZ3EJB5.js → chunk-IJAXOQJU.js} +2 -2
- package/dist/{chunk-EQRVOMMS.js → chunk-KMIDRUUH.js} +2 -2
- package/dist/{chunk-BBHVV37T.js → chunk-MSAGTFN4.js} +4 -4
- package/dist/chunk-OBKVNZPH.js +70 -0
- package/dist/chunk-OBKVNZPH.js.map +1 -0
- package/dist/{chunk-75ZIWV4U.js → chunk-QAF7ZTO3.js} +4 -4
- package/dist/{chunk-TJ4DYKF2.js → chunk-XG6FODYO.js} +3 -2
- package/dist/chunk-XG6FODYO.js.map +1 -0
- package/dist/{chunk-6O2NQ7WD.js → chunk-Y2SOQOJE.js} +3 -3
- package/dist/integrations-react/index.js +1 -1
- package/dist/{mention-editor-ZJAOUDEE.js → mention-editor-NOS5R3AU.js} +2 -2
- package/dist/preset-cloudflare/index.js +2 -2
- package/dist/sandbox/index.js +4 -4
- package/dist/settings-react/confirm-action.d.ts +51 -0
- package/dist/settings-react/delete-workspace-section.d.ts +31 -0
- package/dist/settings-react/export-section.d.ts +26 -0
- package/dist/settings-react/index.d.ts +20 -0
- package/dist/settings-react/index.js +1438 -0
- package/dist/settings-react/index.js.map +1 -0
- package/dist/settings-react/members-section.d.ts +66 -0
- package/dist/settings-react/save-status.d.ts +24 -0
- package/dist/settings-react/setting-outcome.d.ts +33 -0
- package/dist/settings-react/settings-layout.d.ts +71 -0
- package/dist/settings-react/settings-save-bar.d.ts +26 -0
- package/dist/settings-react/timezone-picker.d.ts +17 -0
- package/dist/settings-react/use-setting-field.d.ts +70 -0
- package/dist/stories/settings/settings-backend.d.ts +66 -0
- package/dist/stories/settings/settings-demo.d.ts +16 -0
- package/dist/stories/settings/team-panels-demo.d.ts +21 -0
- package/dist/studio-react/index.js +2 -2
- package/dist/teams-react/components/InviteForm.d.ts +2 -2
- package/dist/teams-react/components/MembersPanel.d.ts +9 -5
- package/dist/teams-react/components/RoleSelect.d.ts +10 -8
- package/dist/teams-react/components/invitation-detail.d.ts +8 -0
- package/dist/teams-react/components/member-access.d.ts +17 -0
- package/dist/teams-react/contracts.d.ts +2 -0
- package/dist/teams-react/index.js +119 -242
- package/dist/teams-react/index.js.map +1 -1
- package/dist/theme/tokens.css +43 -2
- package/dist/tools/index.js +4 -4
- package/dist/web-react/agent-profile-editor.js +4 -4
- package/dist/web-react/async/index.js +1 -1
- package/dist/web-react/controls.d.ts +4 -5
- package/dist/web-react/index.js +12 -12
- package/dist/work-product/index.js +2 -2
- package/dist/workspace-export/react.d.ts +26 -0
- package/dist/workspace-export/react.js +6 -169
- package/dist/workspace-export/react.js.map +1 -1
- package/dist/workspace-react/index.js +3 -3
- package/package.json +9 -4
- package/dist/chunk-TJ4DYKF2.js.map +0 -1
- /package/dist/{chunk-YXLN4PXK.js.map → chunk-2RCPPOQ4.js.map} +0 -0
- /package/dist/{chunk-YESFGM56.js.map → chunk-5IS3GCMR.js.map} +0 -0
- /package/dist/{chunk-3RHAF2P5.js.map → chunk-A3CUVYRZ.js.map} +0 -0
- /package/dist/{chunk-UDLA3NGY.js.map → chunk-GNBBY3KN.js.map} +0 -0
- /package/dist/{chunk-KOTNMTHV.js.map → chunk-HCFVEJQL.js.map} +0 -0
- /package/dist/{chunk-YGBEGBJY.js.map → chunk-HEPEGY6Q.js.map} +0 -0
- /package/dist/{chunk-AJZ3EJB5.js.map → chunk-IJAXOQJU.js.map} +0 -0
- /package/dist/{chunk-EQRVOMMS.js.map → chunk-KMIDRUUH.js.map} +0 -0
- /package/dist/{chunk-BBHVV37T.js.map → chunk-MSAGTFN4.js.map} +0 -0
- /package/dist/{chunk-75ZIWV4U.js.map → chunk-QAF7ZTO3.js.map} +0 -0
- /package/dist/{chunk-6O2NQ7WD.js.map → chunk-Y2SOQOJE.js.map} +0 -0
- /package/dist/{mention-editor-ZJAOUDEE.js.map → mention-editor-NOS5R3AU.js.map} +0 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
// src/workspace-export/react.tsx
|
|
2
|
+
import { Button, Card, StatusPill } from "@tangle-network/ui/primitives";
|
|
3
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
var DEFAULT_DESCRIPTION = "Everything in one zip. Credentials are never included.";
|
|
6
|
+
var BYTE_UNITS = ["B", "KB", "MB", "GB", "TB"];
|
|
7
|
+
function formatBytes(bytes) {
|
|
8
|
+
let value = bytes;
|
|
9
|
+
let unit = 0;
|
|
10
|
+
while (value >= 1024 && unit < BYTE_UNITS.length - 1) {
|
|
11
|
+
value /= 1024;
|
|
12
|
+
unit += 1;
|
|
13
|
+
}
|
|
14
|
+
return `${value < 10 && unit ? value.toFixed(1) : Math.round(value)} ${BYTE_UNITS[unit]}`;
|
|
15
|
+
}
|
|
16
|
+
var TONE = { running: "info", complete: "success", failed: "danger" };
|
|
17
|
+
var LABEL = { running: "Preparing", complete: "Ready", failed: "Failed" };
|
|
18
|
+
async function readJson(response) {
|
|
19
|
+
const body = await response.json().catch(() => null);
|
|
20
|
+
if (!response.ok) throw new Error(body?.error?.message ?? `Request failed (${response.status})`);
|
|
21
|
+
return body;
|
|
22
|
+
}
|
|
23
|
+
function useWorkspaceExport({ endpoint, enabled, fetcher }) {
|
|
24
|
+
const doFetch = fetcher ?? fetch;
|
|
25
|
+
const [exports, setExports] = useState([]);
|
|
26
|
+
const [error, setError] = useState(null);
|
|
27
|
+
const [loading, setLoading] = useState(true);
|
|
28
|
+
const [starting, setStarting] = useState(false);
|
|
29
|
+
const driving = useRef(null);
|
|
30
|
+
const mounted = useRef(true);
|
|
31
|
+
useEffect(() => () => {
|
|
32
|
+
mounted.current = false;
|
|
33
|
+
}, []);
|
|
34
|
+
const upsert = useCallback((next) => {
|
|
35
|
+
setExports((current) => [next, ...current.filter((e) => e.id !== next.id)]);
|
|
36
|
+
}, []);
|
|
37
|
+
const drive = useCallback(async (id) => {
|
|
38
|
+
if (driving.current === id) return;
|
|
39
|
+
driving.current = id;
|
|
40
|
+
const retired = () => !mounted.current || driving.current !== id;
|
|
41
|
+
let failures = 0;
|
|
42
|
+
try {
|
|
43
|
+
for (; ; ) {
|
|
44
|
+
if (retired()) return;
|
|
45
|
+
try {
|
|
46
|
+
const next = await readJson(await doFetch(`${endpoint}/${id}/advance`, { method: "POST", credentials: "same-origin" }));
|
|
47
|
+
if (retired()) return;
|
|
48
|
+
failures = 0;
|
|
49
|
+
setError(null);
|
|
50
|
+
upsert(next);
|
|
51
|
+
if (next.status !== "running") return;
|
|
52
|
+
} catch (err) {
|
|
53
|
+
failures += 1;
|
|
54
|
+
if (failures >= 6) throw err;
|
|
55
|
+
if (mounted.current) setError(`Still working; retrying (${failures})`);
|
|
56
|
+
}
|
|
57
|
+
await new Promise((resolve) => setTimeout(resolve, failures ? 3e3 * failures : 1500));
|
|
58
|
+
}
|
|
59
|
+
} catch (err) {
|
|
60
|
+
if (mounted.current) setError(err instanceof Error ? err.message : String(err));
|
|
61
|
+
} finally {
|
|
62
|
+
if (driving.current === id) driving.current = null;
|
|
63
|
+
}
|
|
64
|
+
}, [doFetch, endpoint, upsert]);
|
|
65
|
+
const refresh = useCallback(async () => {
|
|
66
|
+
setLoading(true);
|
|
67
|
+
setError(null);
|
|
68
|
+
try {
|
|
69
|
+
const body = await readJson(await doFetch(endpoint, { credentials: "same-origin" }));
|
|
70
|
+
if (!mounted.current) return;
|
|
71
|
+
setExports(body.exports);
|
|
72
|
+
const running2 = body.exports.find((e) => e.status === "running");
|
|
73
|
+
if (running2) void drive(running2.id);
|
|
74
|
+
} catch (err) {
|
|
75
|
+
if (mounted.current) setError(err instanceof Error ? err.message : String(err));
|
|
76
|
+
} finally {
|
|
77
|
+
if (mounted.current) setLoading(false);
|
|
78
|
+
}
|
|
79
|
+
}, [doFetch, drive, endpoint]);
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
if (enabled) void refresh();
|
|
82
|
+
}, [enabled, refresh]);
|
|
83
|
+
const start = async () => {
|
|
84
|
+
setStarting(true);
|
|
85
|
+
setError(null);
|
|
86
|
+
try {
|
|
87
|
+
const job = await readJson(await doFetch(endpoint, { method: "POST", credentials: "same-origin" }));
|
|
88
|
+
upsert(job);
|
|
89
|
+
void drive(job.id);
|
|
90
|
+
} catch (err) {
|
|
91
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
92
|
+
} finally {
|
|
93
|
+
setStarting(false);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
const latest = exports[0];
|
|
97
|
+
const running = latest?.status === "running";
|
|
98
|
+
const retry = () => latest?.status === "running" ? void drive(latest.id) : void refresh();
|
|
99
|
+
return { latest, error, loading, starting, running, start, retry };
|
|
100
|
+
}
|
|
101
|
+
function WorkspaceExportPanel({ endpoint, canExport, title = "Export workspace data", description = DEFAULT_DESCRIPTION, className, fetcher, continuesInBackground = false }) {
|
|
102
|
+
const { latest, error, loading, starting, running, start, retry } = useWorkspaceExport({ endpoint, enabled: canExport, fetcher });
|
|
103
|
+
if (!canExport) return null;
|
|
104
|
+
return /* @__PURE__ */ jsxs(Card, { className: ["min-w-0 space-y-4 p-5 shadow-none", className].filter(Boolean).join(" "), "aria-busy": running || loading || void 0, children: [
|
|
105
|
+
/* @__PURE__ */ jsxs("header", { className: "flex flex-wrap items-start justify-between gap-3", children: [
|
|
106
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
107
|
+
/* @__PURE__ */ jsx("h2", { className: "text-base font-semibold", children: title }),
|
|
108
|
+
description != null && description !== false ? /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: description }) : null
|
|
109
|
+
] }),
|
|
110
|
+
/* @__PURE__ */ jsx(Button, { type: "button", onClick: start, disabled: starting || running, children: running ? "Exporting\u2026" : starting ? "Starting\u2026" : "Export" })
|
|
111
|
+
] }),
|
|
112
|
+
error ? /* @__PURE__ */ jsxs("div", { role: "alert", className: "flex flex-wrap items-center gap-3 rounded-xl border border-destructive/40 p-3 text-sm text-destructive", children: [
|
|
113
|
+
/* @__PURE__ */ jsx("p", { className: "min-w-0 flex-1 break-words", children: error }),
|
|
114
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: retry, children: "Retry" })
|
|
115
|
+
] }) : null,
|
|
116
|
+
latest ? /* @__PURE__ */ jsxs("section", { "aria-label": "Latest export", className: "space-y-3 rounded-xl border border-border p-4", children: [
|
|
117
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
|
|
118
|
+
/* @__PURE__ */ jsx(StatusPill, { tone: TONE[latest.status], size: "sm", children: LABEL[latest.status] }),
|
|
119
|
+
/* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
|
|
120
|
+
latest.unitsDone,
|
|
121
|
+
" of ",
|
|
122
|
+
latest.unitsTotal,
|
|
123
|
+
" sources",
|
|
124
|
+
latest.unitsFailed ? ` \xB7 ${latest.unitsFailed} failed` : "",
|
|
125
|
+
" \xB7 ",
|
|
126
|
+
formatBytes(latest.bytes)
|
|
127
|
+
] }),
|
|
128
|
+
latest.current ? /* @__PURE__ */ jsxs("span", { className: "min-w-0 truncate text-sm text-muted-foreground", children: [
|
|
129
|
+
"Now: ",
|
|
130
|
+
latest.current
|
|
131
|
+
] }) : null
|
|
132
|
+
] }),
|
|
133
|
+
running && continuesInBackground ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "You can close this page. The export keeps going, and the download is here when you return." }) : null,
|
|
134
|
+
/* @__PURE__ */ jsx(
|
|
135
|
+
"div",
|
|
136
|
+
{
|
|
137
|
+
role: "progressbar",
|
|
138
|
+
"aria-label": "Export progress",
|
|
139
|
+
"aria-valuemin": 0,
|
|
140
|
+
"aria-valuemax": latest.unitsTotal,
|
|
141
|
+
"aria-valuenow": latest.unitsDone,
|
|
142
|
+
className: "h-2 overflow-hidden rounded-full bg-muted",
|
|
143
|
+
children: /* @__PURE__ */ jsx(
|
|
144
|
+
"div",
|
|
145
|
+
{
|
|
146
|
+
className: `h-full rounded-full ${latest.status === "failed" ? "bg-destructive" : "bg-primary"} transition-[width] duration-300 motion-reduce:transition-none`,
|
|
147
|
+
style: { width: `${latest.unitsTotal ? Math.round(latest.unitsDone / latest.unitsTotal * 100) : 0}%` }
|
|
148
|
+
}
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
),
|
|
152
|
+
latest.status === "failed" ? /* @__PURE__ */ jsxs("p", { className: "text-sm text-destructive [overflow-wrap:anywhere]", children: [
|
|
153
|
+
latest.error ?? "The export failed.",
|
|
154
|
+
" Start a new export to try again."
|
|
155
|
+
] }) : null,
|
|
156
|
+
latest.downloadUrl ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
|
|
157
|
+
/* @__PURE__ */ jsx(Button, { asChild: true, children: /* @__PURE__ */ jsx("a", { href: latest.downloadUrl, download: true, children: "Download zip" }) }),
|
|
158
|
+
/* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
|
|
159
|
+
"Link expires ",
|
|
160
|
+
latest.downloadExpiresAt ? new Date(latest.downloadExpiresAt).toLocaleTimeString() : "soon",
|
|
161
|
+
"; refresh the page for a new one."
|
|
162
|
+
] })
|
|
163
|
+
] }) : null,
|
|
164
|
+
/* @__PURE__ */ jsxs("details", { className: "text-sm", children: [
|
|
165
|
+
/* @__PURE__ */ jsx("summary", { className: "cursor-pointer text-muted-foreground", children: "Sources" }),
|
|
166
|
+
/* @__PURE__ */ jsx("ul", { className: "mt-2 divide-y divide-border", children: latest.units.map((unit) => /* @__PURE__ */ jsxs("li", { className: "flex flex-wrap items-center justify-between gap-2 py-1.5", children: [
|
|
167
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 [overflow-wrap:anywhere]", children: unit.name }),
|
|
168
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: unit.status === "pending" ? "waiting" : unit.status === "empty" ? "nothing to export" : unit.status === "failed" ? "failed" : unit.rows !== void 0 ? `${unit.rows} rows` : unit.files !== void 0 ? `${unit.files} files \xB7 ${formatBytes(unit.bytes)}` : formatBytes(unit.bytes) })
|
|
169
|
+
] }, unit.name)) })
|
|
170
|
+
] })
|
|
171
|
+
] }) : loading ? /* @__PURE__ */ jsx("p", { role: "status", className: "text-sm text-muted-foreground", children: "Loading exports\u2026" }) : null
|
|
172
|
+
] });
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export {
|
|
176
|
+
useWorkspaceExport,
|
|
177
|
+
WorkspaceExportPanel
|
|
178
|
+
};
|
|
179
|
+
//# sourceMappingURL=chunk-EZFBGW23.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/workspace-export/react.tsx"],"sourcesContent":["/**\n * Export panel for a workspace settings page. Starts an export, drives it to\n * completion by calling `advance` while the page is open, shows each source as\n * it finishes, and offers the signed download link. Reopening the page resumes\n * a running export.\n */\n\nimport { Button, Card, StatusPill, type StatusTone } from '@tangle-network/ui/primitives'\nimport { useCallback, useEffect, useRef, useState, type ReactNode } from 'react'\nimport type { ExportProgress } from './types'\n\nexport interface WorkspaceExportPanelProps {\n /** The mount path of the product's export routes, e.g. `/api/workspaces/ws-1/exports`. */\n endpoint: string\n /** Hidden for non-owners; the server refuses them regardless. */\n canExport: boolean\n title?: string\n /** One short muted line under the title. Pass `null` to render none. */\n description?: ReactNode\n className?: string\n fetcher?: typeof fetch\n /** True when the product runs `continueRunning` on a cron, so the export finishes after the page closes. */\n continuesInBackground?: boolean\n}\n\nconst DEFAULT_DESCRIPTION = 'Everything in one zip. Credentials are never included.'\n\nconst BYTE_UNITS = ['B', 'KB', 'MB', 'GB', 'TB']\n\nfunction formatBytes(bytes: number): string {\n let value = bytes\n let unit = 0\n while (value >= 1024 && unit < BYTE_UNITS.length - 1) {\n value /= 1024\n unit += 1\n }\n return `${value < 10 && unit ? value.toFixed(1) : Math.round(value)} ${BYTE_UNITS[unit]}`\n}\n\nconst TONE: Record<ExportProgress['status'], StatusTone> = { running: 'info', complete: 'success', failed: 'danger' }\nconst LABEL: Record<ExportProgress['status'], string> = { running: 'Preparing', complete: 'Ready', failed: 'Failed' }\n\nasync function readJson<T>(response: Response): Promise<T> {\n const body = (await response.json().catch(() => null)) as { error?: { message?: string } } | null\n if (!response.ok) throw new Error(body?.error?.message ?? `Request failed (${response.status})`)\n return body as T\n}\n\nexport interface UseWorkspaceExportOptions {\n /** The mount path of the product's export routes. */\n endpoint: string\n /** False skips loading; the server refuses non-owners regardless. */\n enabled: boolean\n fetcher?: typeof fetch\n}\n\nexport interface WorkspaceExportState {\n /** The newest export, if any. */\n latest: ExportProgress | undefined\n /** The last request failure, as a sentence. */\n error: string | null\n loading: boolean\n starting: boolean\n running: boolean\n start: () => Promise<void>\n /** Resumes a running export, or reloads the list. */\n retry: () => void\n}\n\n/**\n * Starts an export, drives it to completion by calling `advance` while the\n * page is open, and resumes a running one on mount. `WorkspaceExportPanel`\n * and the settings `ExportSection` both draw from it.\n */\nexport function useWorkspaceExport({ endpoint, enabled, fetcher }: UseWorkspaceExportOptions): WorkspaceExportState {\n const doFetch = fetcher ?? fetch\n const [exports, setExports] = useState<ExportProgress[]>([])\n const [error, setError] = useState<string | null>(null)\n const [loading, setLoading] = useState(true)\n const [starting, setStarting] = useState(false)\n const driving = useRef<string | null>(null)\n const mounted = useRef(true)\n\n useEffect(() => () => {\n mounted.current = false\n }, [])\n\n const upsert = useCallback((next: ExportProgress) => {\n setExports((current) => [next, ...current.filter((e) => e.id !== next.id)])\n }, [])\n\n const drive = useCallback(async (id: string) => {\n // One driver at a time: starting another export retires the old loop, so a\n // stale running job and a new one are never advanced together.\n if (driving.current === id) return\n driving.current = id\n const retired = () => !mounted.current || driving.current !== id\n // A failed request is retried: the server records each attempt and fails\n // the export itself once a source cannot finish.\n let failures = 0\n try {\n for (;;) {\n if (retired()) return\n try {\n const next = await readJson<ExportProgress>(await doFetch(`${endpoint}/${id}/advance`, { method: 'POST', credentials: 'same-origin' }))\n if (retired()) return\n failures = 0\n setError(null)\n upsert(next)\n if (next.status !== 'running') return\n } catch (err) {\n failures += 1\n if (failures >= 6) throw err\n if (mounted.current) setError(`Still working; retrying (${failures})`)\n }\n // Another tab may hold the lease, or the last request failed; wait before asking again.\n await new Promise((resolve) => setTimeout(resolve, failures ? 3000 * failures : 1500))\n }\n } catch (err) {\n if (mounted.current) setError(err instanceof Error ? err.message : String(err))\n } finally {\n if (driving.current === id) driving.current = null\n }\n }, [doFetch, endpoint, upsert])\n\n const refresh = useCallback(async () => {\n setLoading(true)\n setError(null)\n try {\n const body = await readJson<{ exports: ExportProgress[] }>(await doFetch(endpoint, { credentials: 'same-origin' }))\n if (!mounted.current) return\n setExports(body.exports)\n const running = body.exports.find((e) => e.status === 'running')\n if (running) void drive(running.id)\n } catch (err) {\n if (mounted.current) setError(err instanceof Error ? err.message : String(err))\n } finally {\n if (mounted.current) setLoading(false)\n }\n }, [doFetch, drive, endpoint])\n\n useEffect(() => {\n if (enabled) void refresh()\n }, [enabled, refresh])\n\n const start = async () => {\n setStarting(true)\n setError(null)\n try {\n const job = await readJson<ExportProgress>(await doFetch(endpoint, { method: 'POST', credentials: 'same-origin' }))\n upsert(job)\n void drive(job.id)\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err))\n } finally {\n setStarting(false)\n }\n }\n\n const latest = exports[0]\n const running = latest?.status === 'running'\n const retry = () => (latest?.status === 'running' ? void drive(latest.id) : void refresh())\n return { latest, error, loading, starting, running, start, retry }\n}\n\nexport function WorkspaceExportPanel({ endpoint, canExport, title = 'Export workspace data', description = DEFAULT_DESCRIPTION, className, fetcher, continuesInBackground = false }: WorkspaceExportPanelProps) {\n const { latest, error, loading, starting, running, start, retry } = useWorkspaceExport({ endpoint, enabled: canExport, fetcher })\n if (!canExport) return null\n\n return (\n <Card className={['min-w-0 space-y-4 p-5 shadow-none', className].filter(Boolean).join(' ')} aria-busy={running || loading || undefined}>\n <header className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <h2 className=\"text-base font-semibold\">{title}</h2>\n {description != null && description !== false ? (\n <p className=\"mt-1 text-sm text-muted-foreground\">{description}</p>\n ) : null}\n </div>\n <Button type=\"button\" onClick={start} disabled={starting || running}>\n {running ? 'Exporting…' : starting ? 'Starting…' : 'Export'}\n </Button>\n </header>\n\n {error ? (\n <div role=\"alert\" className=\"flex flex-wrap items-center gap-3 rounded-xl border border-destructive/40 p-3 text-sm text-destructive\">\n <p className=\"min-w-0 flex-1 break-words\">{error}</p>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={retry}>\n Retry\n </Button>\n </div>\n ) : null}\n\n {latest ? (\n <section aria-label=\"Latest export\" className=\"space-y-3 rounded-xl border border-border p-4\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <StatusPill tone={TONE[latest.status]} size=\"sm\">{LABEL[latest.status]}</StatusPill>\n <span className=\"text-sm text-muted-foreground\">\n {latest.unitsDone} of {latest.unitsTotal} sources{latest.unitsFailed ? ` · ${latest.unitsFailed} failed` : ''} · {formatBytes(latest.bytes)}\n </span>\n {latest.current ? <span className=\"min-w-0 truncate text-sm text-muted-foreground\">Now: {latest.current}</span> : null}\n </div>\n {running && continuesInBackground ? (\n <p className=\"text-sm text-muted-foreground\">You can close this page. The export keeps going, and the download is here when you return.</p>\n ) : null}\n <div\n role=\"progressbar\"\n aria-label=\"Export progress\"\n aria-valuemin={0}\n aria-valuemax={latest.unitsTotal}\n aria-valuenow={latest.unitsDone}\n className=\"h-2 overflow-hidden rounded-full bg-muted\"\n >\n <div\n className={`h-full rounded-full ${latest.status === 'failed' ? 'bg-destructive' : 'bg-primary'} transition-[width] duration-300 motion-reduce:transition-none`}\n style={{ width: `${latest.unitsTotal ? Math.round((latest.unitsDone / latest.unitsTotal) * 100) : 0}%` }}\n />\n </div>\n {latest.status === 'failed' ? (\n <p className=\"text-sm text-destructive [overflow-wrap:anywhere]\">{latest.error ?? 'The export failed.'} Start a new export to try again.</p>\n ) : null}\n {latest.downloadUrl ? (\n <div className=\"flex flex-wrap items-center gap-3\">\n <Button asChild>\n <a href={latest.downloadUrl} download>Download zip</a>\n </Button>\n <span className=\"text-sm text-muted-foreground\">\n Link expires {latest.downloadExpiresAt ? new Date(latest.downloadExpiresAt).toLocaleTimeString() : 'soon'}; refresh the page for a new one.\n </span>\n </div>\n ) : null}\n <details className=\"text-sm\">\n <summary className=\"cursor-pointer text-muted-foreground\">Sources</summary>\n <ul className=\"mt-2 divide-y divide-border\">\n {latest.units.map((unit) => (\n <li key={unit.name} className=\"flex flex-wrap items-center justify-between gap-2 py-1.5\">\n <span className=\"min-w-0 [overflow-wrap:anywhere]\">{unit.name}</span>\n <span className=\"text-sm text-muted-foreground\">\n {unit.status === 'pending' ? 'waiting' : unit.status === 'empty' ? 'nothing to export' : unit.status === 'failed' ? 'failed' : unit.rows !== undefined ? `${unit.rows} rows` : unit.files !== undefined ? `${unit.files} files · ${formatBytes(unit.bytes)}` : formatBytes(unit.bytes)}\n </span>\n </li>\n ))}\n </ul>\n </details>\n </section>\n ) : loading ? (\n <p role=\"status\" className=\"text-sm text-muted-foreground\">Loading exports…</p>\n ) : null}\n </Card>\n )\n}\n"],"mappings":"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","names":["running"]}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
usePopoverDialog
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-HEPEGY6Q.js";
|
|
4
4
|
import {
|
|
5
5
|
CheckGlyph,
|
|
6
6
|
OVERLAY_SHADOW,
|
|
7
7
|
PopoverSurface
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-XG6FODYO.js";
|
|
9
9
|
|
|
10
10
|
// src/web-react/workspace-switcher.tsx
|
|
11
11
|
import { useCallback, useState } from "react";
|
|
@@ -116,4 +116,4 @@ export {
|
|
|
116
116
|
WorkspaceSwitcher,
|
|
117
117
|
WorkspaceInitial
|
|
118
118
|
};
|
|
119
|
-
//# sourceMappingURL=chunk-
|
|
119
|
+
//# sourceMappingURL=chunk-GNBBY3KN.js.map
|
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
} from "./chunk-I6BZVIRH.js";
|
|
5
5
|
import {
|
|
6
6
|
defineAppTool
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-IJAXOQJU.js";
|
|
8
8
|
import {
|
|
9
9
|
ToolInputError
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-E65YV7VV.js";
|
|
11
11
|
|
|
12
12
|
// src/agent-profiles/index.ts
|
|
13
13
|
import {
|
|
@@ -772,4 +772,4 @@ export {
|
|
|
772
772
|
PROFILE_MEMORY_PREFIX,
|
|
773
773
|
profileTools
|
|
774
774
|
};
|
|
775
|
-
//# sourceMappingURL=chunk-
|
|
775
|
+
//# sourceMappingURL=chunk-HCFVEJQL.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
usePopover
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-XG6FODYO.js";
|
|
4
4
|
|
|
5
5
|
// src/web-react/popover-dialog.ts
|
|
6
6
|
import { useEffect, useId } from "react";
|
|
@@ -45,4 +45,4 @@ function usePopoverDialog(open, onOpenChange) {
|
|
|
45
45
|
export {
|
|
46
46
|
usePopoverDialog
|
|
47
47
|
};
|
|
48
|
-
//# sourceMappingURL=chunk-
|
|
48
|
+
//# sourceMappingURL=chunk-HEPEGY6Q.js.map
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
OPENUI_NODE_JSON_SCHEMA,
|
|
6
6
|
OPENUI_NODE_TYPES
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-E65YV7VV.js";
|
|
8
8
|
|
|
9
9
|
// src/tools/openai.ts
|
|
10
10
|
var APP_TOOL_NAMES = ["submit_proposal", "schedule_followup", "render_ui", "add_citation"];
|
|
@@ -112,4 +112,4 @@ export {
|
|
|
112
112
|
customToolToOpenAI,
|
|
113
113
|
findCustomTool
|
|
114
114
|
};
|
|
115
|
-
//# sourceMappingURL=chunk-
|
|
115
|
+
//# sourceMappingURL=chunk-IJAXOQJU.js.map
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
OVERLAY_SHADOW,
|
|
12
12
|
PopoverSurface,
|
|
13
13
|
usePopover
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-XG6FODYO.js";
|
|
15
15
|
|
|
16
16
|
// src/web-react/session-history.tsx
|
|
17
17
|
import {
|
|
@@ -746,4 +746,4 @@ export {
|
|
|
746
746
|
formatSessionTimestamp,
|
|
747
747
|
SessionHistoryPanel
|
|
748
748
|
};
|
|
749
|
-
//# sourceMappingURL=chunk-
|
|
749
|
+
//# sourceMappingURL=chunk-KMIDRUUH.js.map
|
|
@@ -10,12 +10,12 @@ import {
|
|
|
10
10
|
filterAcceptedFiles,
|
|
11
11
|
isAcceptedFileType,
|
|
12
12
|
renamePastedImages
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-5IS3GCMR.js";
|
|
14
14
|
import {
|
|
15
15
|
OVERLAY_SHADOW,
|
|
16
16
|
POPOVER_OPTION_FOCUS,
|
|
17
17
|
PopoverSurface
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-XG6FODYO.js";
|
|
19
19
|
import {
|
|
20
20
|
ATTACHMENT_ACCEPT,
|
|
21
21
|
ATTACHMENT_MAX_COUNT,
|
|
@@ -267,7 +267,7 @@ import {
|
|
|
267
267
|
import { focusFieldWithin } from "@tangle-network/ui/utils";
|
|
268
268
|
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
269
269
|
function createLazyMentionEditor() {
|
|
270
|
-
return lazy2(() => import("./mention-editor-
|
|
270
|
+
return lazy2(() => import("./mention-editor-NOS5R3AU.js").then((m) => m.loadMentionEditor()));
|
|
271
271
|
}
|
|
272
272
|
var IS_APPLE_PLATFORM = typeof navigator !== "undefined" && /Mac|iPhone|iPad|iPod/i.test(navigator.platform);
|
|
273
273
|
function SendGlyph({ className }) {
|
|
@@ -1552,4 +1552,4 @@ export {
|
|
|
1552
1552
|
ComposerModeControls,
|
|
1553
1553
|
EntryComposer
|
|
1554
1554
|
};
|
|
1555
|
-
//# sourceMappingURL=chunk-
|
|
1555
|
+
//# sourceMappingURL=chunk-MSAGTFN4.js.map
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ASSIGNABLE_WORKSPACE_ROLES,
|
|
3
|
+
hasWorkspaceRole
|
|
4
|
+
} from "./chunk-6XIAPIW6.js";
|
|
5
|
+
|
|
6
|
+
// src/teams-react/components/RoleSelect.tsx
|
|
7
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@tangle-network/ui/primitives";
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
var ROLE_CAPABILITY = {
|
|
10
|
+
viewer: "Can view",
|
|
11
|
+
editor: "Can edit",
|
|
12
|
+
admin: "Can manage settings and people",
|
|
13
|
+
owner: "Owner"
|
|
14
|
+
};
|
|
15
|
+
var ROLE_DESCRIPTION = {
|
|
16
|
+
viewer: "Reads everything; can\u2019t chat or edit",
|
|
17
|
+
editor: "Also chats with the agent and edits",
|
|
18
|
+
admin: "Also invites people and sets roles"
|
|
19
|
+
};
|
|
20
|
+
function RoleSelect({ value, onChange, ariaLabel, id, disabled }) {
|
|
21
|
+
return /* @__PURE__ */ jsxs(Select, { value, onValueChange: (role) => onChange(role), disabled, children: [
|
|
22
|
+
/* @__PURE__ */ jsx(SelectTrigger, { id, "aria-label": ariaLabel, children: /* @__PURE__ */ jsx(SelectValue, { children: ROLE_CAPABILITY[value] }) }),
|
|
23
|
+
/* @__PURE__ */ jsx(SelectContent, { children: ASSIGNABLE_WORKSPACE_ROLES.map((role) => /* @__PURE__ */ jsxs(SelectItem, { value: role, textValue: ROLE_CAPABILITY[role], children: [
|
|
24
|
+
/* @__PURE__ */ jsx("span", { className: "block", children: ROLE_CAPABILITY[role] }),
|
|
25
|
+
/* @__PURE__ */ jsx("span", { className: "block font-normal text-muted-foreground", "data-role-description": true, children: ROLE_DESCRIPTION[role] })
|
|
26
|
+
] }, role)) })
|
|
27
|
+
] });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// src/teams-react/components/member-access.ts
|
|
31
|
+
function canManageMember(member, currentRole, currentUserId) {
|
|
32
|
+
if (!hasWorkspaceRole(currentRole, "admin") || member.role === "owner" || member.inherited) return false;
|
|
33
|
+
return !isCurrentMember(member, currentUserId);
|
|
34
|
+
}
|
|
35
|
+
function isCurrentMember(member, currentUserId) {
|
|
36
|
+
return currentUserId != null && member.userId === currentUserId;
|
|
37
|
+
}
|
|
38
|
+
function memberRoleLabel(member) {
|
|
39
|
+
if (member.role === "owner") return member.inherited ? "Organization admin" : "Owner";
|
|
40
|
+
return ROLE_CAPABILITY[member.role];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// src/teams-react/components/invitation-detail.ts
|
|
44
|
+
function shortDate(value) {
|
|
45
|
+
return new Date(value).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
|
|
46
|
+
}
|
|
47
|
+
function invitationDetail(invitation) {
|
|
48
|
+
const role = ROLE_CAPABILITY[invitation.permissions];
|
|
49
|
+
switch (invitation.status) {
|
|
50
|
+
case "accepted":
|
|
51
|
+
return invitation.acceptedAt ? `${role} \xB7 joined ${shortDate(invitation.acceptedAt)}` : `${role} \xB7 joined`;
|
|
52
|
+
case "pending": {
|
|
53
|
+
const delivery = invitation.emailStatus === "sent" ? "email sent" : invitation.emailStatus === "not_sent" ? "email not sent yet" : null;
|
|
54
|
+
return [role, delivery, `expires ${shortDate(invitation.expiresAt)}`].filter(Boolean).join(" \xB7 ");
|
|
55
|
+
}
|
|
56
|
+
case "expired":
|
|
57
|
+
return `${role} \xB7 expired ${shortDate(invitation.expiresAt)}`;
|
|
58
|
+
case "revoked":
|
|
59
|
+
return `${role} \xB7 revoked`;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export {
|
|
64
|
+
RoleSelect,
|
|
65
|
+
canManageMember,
|
|
66
|
+
isCurrentMember,
|
|
67
|
+
memberRoleLabel,
|
|
68
|
+
invitationDetail
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=chunk-OBKVNZPH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/teams-react/components/RoleSelect.tsx","../src/teams-react/components/member-access.ts","../src/teams-react/components/invitation-detail.ts"],"sourcesContent":["/**\n * The role picker both team panels and the settings sections share: the ui\n * `Select`, with each role named by what it lets a person do and, in the open\n * list, one line on what it adds, so choosing one never needs a help page.\n * The trigger shows the name alone and fills its container; give the\n * container the width.\n */\n\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@tangle-network/ui/primitives'\nimport { ASSIGNABLE_WORKSPACE_ROLES, type AssignableWorkspaceRole, type WorkspaceRole } from '../../teams/roles'\n\n/** Each workspace role in the words a person decides by. */\nexport const ROLE_CAPABILITY: Record<WorkspaceRole, string> = {\n viewer: 'Can view',\n editor: 'Can edit',\n admin: 'Can manage settings and people',\n owner: 'Owner',\n}\n\n// What each assignable role adds, under its name in the open list; chatting\n// with the agent is what a viewer cannot do. Each line fits a phone-width\n// trigger, so the open list is never wider than the screen.\nconst ROLE_DESCRIPTION: Record<AssignableWorkspaceRole, string> = {\n viewer: 'Reads everything; can’t chat or edit',\n editor: 'Also chats with the agent and edits',\n admin: 'Also invites people and sets roles',\n}\n\nexport interface RoleSelectProps {\n value: WorkspaceRole\n onChange(role: WorkspaceRole): void\n /** Accessible name (no visible label — the panels label the row). */\n ariaLabel: string\n id?: string\n disabled?: boolean\n}\n\nexport function RoleSelect({ value, onChange, ariaLabel, id, disabled }: RoleSelectProps) {\n return (\n <Select value={value} onValueChange={(role) => onChange(role as WorkspaceRole)} disabled={disabled}>\n <SelectTrigger id={id} aria-label={ariaLabel}>\n <SelectValue>{ROLE_CAPABILITY[value]}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {ASSIGNABLE_WORKSPACE_ROLES.map((role) => (\n <SelectItem key={role} value={role} textValue={ROLE_CAPABILITY[role]}>\n <span className=\"block\">{ROLE_CAPABILITY[role]}</span>\n <span className=\"block font-normal text-muted-foreground\" data-role-description>{ROLE_DESCRIPTION[role]}</span>\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )\n}\n","/**\n * Who may change a member's access, and the words for a role shown as text.\n * `MembersPanel` and the settings `MembersSection` both read these, so the two\n * member lists apply one rule.\n */\n\nimport { hasWorkspaceRole, type WorkspaceRole } from '../../teams/roles'\nimport type { MemberView } from '../contracts'\nimport { ROLE_CAPABILITY } from './RoleSelect'\n\n/**\n * Whether the viewer can change this member's role or remove them: an admin\n * can, except for an owner, an inherited organization admin, or their own row,\n * so no one demotes or removes themselves from a list.\n */\nexport function canManageMember(member: MemberView, currentRole: WorkspaceRole, currentUserId?: string | null): boolean {\n if (!hasWorkspaceRole(currentRole, 'admin') || member.role === 'owner' || member.inherited) return false\n return !isCurrentMember(member, currentUserId)\n}\n\n/** True on the viewer's own row. */\nexport function isCurrentMember(member: MemberView, currentUserId?: string | null): boolean {\n return currentUserId != null && member.userId === currentUserId\n}\n\n/** A role shown as text rather than a picker. */\nexport function memberRoleLabel(member: MemberView): string {\n if (member.role === 'owner') return member.inherited ? 'Organization admin' : 'Owner'\n return ROLE_CAPABILITY[member.role]\n}\n","/** The line under an invitation's address, shared by `InvitationsPanel` and the settings `InvitationsSection`. */\n\nimport type { InvitationView } from '../contracts'\nimport { ROLE_CAPABILITY } from './RoleSelect'\n\nfunction shortDate(value: Date | number | string): string {\n return new Date(value).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })\n}\n\n/**\n * The line under the address: what the invitee can do, then only what is true\n * of this invitation now. Every status says itself in words, so a past\n * invitation reads as joined, expired or revoked without a badge.\n */\nexport function invitationDetail(invitation: InvitationView): string {\n const role = ROLE_CAPABILITY[invitation.permissions]\n switch (invitation.status) {\n case 'accepted':\n return invitation.acceptedAt ? `${role} · joined ${shortDate(invitation.acceptedAt)}` : `${role} · joined`\n case 'pending': {\n const delivery = invitation.emailStatus === 'sent' ? 'email sent' : invitation.emailStatus === 'not_sent' ? 'email not sent yet' : null\n return [role, delivery, `expires ${shortDate(invitation.expiresAt)}`].filter(Boolean).join(' · ')\n }\n case 'expired':\n return `${role} · expired ${shortDate(invitation.expiresAt)}`\n case 'revoked':\n return `${role} · revoked`\n }\n}\n"],"mappings":";;;;;;AAQA,SAAS,QAAQ,eAAe,YAAY,eAAe,mBAAmB;AAiCtE,cAIE,YAJF;AA7BD,IAAM,kBAAiD;AAAA,EAC5D,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,OAAO;AACT;AAKA,IAAM,mBAA4D;AAAA,EAChE,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AACT;AAWO,SAAS,WAAW,EAAE,OAAO,UAAU,WAAW,IAAI,SAAS,GAAoB;AACxF,SACE,qBAAC,UAAO,OAAc,eAAe,CAAC,SAAS,SAAS,IAAqB,GAAG,UAC9E;AAAA,wBAAC,iBAAc,IAAQ,cAAY,WACjC,8BAAC,eAAa,0BAAgB,KAAK,GAAE,GACvC;AAAA,IACA,oBAAC,iBACE,qCAA2B,IAAI,CAAC,SAC/B,qBAAC,cAAsB,OAAO,MAAM,WAAW,gBAAgB,IAAI,GACjE;AAAA,0BAAC,UAAK,WAAU,SAAS,0BAAgB,IAAI,GAAE;AAAA,MAC/C,oBAAC,UAAK,WAAU,2CAA0C,yBAAqB,MAAE,2BAAiB,IAAI,GAAE;AAAA,SAFzF,IAGjB,CACD,GACH;AAAA,KACF;AAEJ;;;ACtCO,SAAS,gBAAgB,QAAoB,aAA4B,eAAwC;AACtH,MAAI,CAAC,iBAAiB,aAAa,OAAO,KAAK,OAAO,SAAS,WAAW,OAAO,UAAW,QAAO;AACnG,SAAO,CAAC,gBAAgB,QAAQ,aAAa;AAC/C;AAGO,SAAS,gBAAgB,QAAoB,eAAwC;AAC1F,SAAO,iBAAiB,QAAQ,OAAO,WAAW;AACpD;AAGO,SAAS,gBAAgB,QAA4B;AAC1D,MAAI,OAAO,SAAS,QAAS,QAAO,OAAO,YAAY,uBAAuB;AAC9E,SAAO,gBAAgB,OAAO,IAAI;AACpC;;;ACxBA,SAAS,UAAU,OAAuC;AACxD,SAAO,IAAI,KAAK,KAAK,EAAE,mBAAmB,SAAS,EAAE,OAAO,SAAS,KAAK,WAAW,MAAM,UAAU,CAAC;AACxG;AAOO,SAAS,iBAAiB,YAAoC;AACnE,QAAM,OAAO,gBAAgB,WAAW,WAAW;AACnD,UAAQ,WAAW,QAAQ;AAAA,IACzB,KAAK;AACH,aAAO,WAAW,aAAa,GAAG,IAAI,gBAAa,UAAU,WAAW,UAAU,CAAC,KAAK,GAAG,IAAI;AAAA,IACjG,KAAK,WAAW;AACd,YAAM,WAAW,WAAW,gBAAgB,SAAS,eAAe,WAAW,gBAAgB,aAAa,uBAAuB;AACnI,aAAO,CAAC,MAAM,UAAU,WAAW,UAAU,WAAW,SAAS,CAAC,EAAE,EAAE,OAAO,OAAO,EAAE,KAAK,QAAK;AAAA,IAClG;AAAA,IACA,KAAK;AACH,aAAO,GAAG,IAAI,iBAAc,UAAU,WAAW,SAAS,CAAC;AAAA,IAC7D,KAAK;AACH,aAAO,GAAG,IAAI;AAAA,EAClB;AACF;","names":[]}
|
|
@@ -10,15 +10,15 @@ import {
|
|
|
10
10
|
} from "./chunk-S5SRJJQG.js";
|
|
11
11
|
import {
|
|
12
12
|
assertRenderUiSchema
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-2RCPPOQ4.js";
|
|
14
14
|
import {
|
|
15
15
|
buildAppToolOpenAITools,
|
|
16
16
|
findCustomTool,
|
|
17
17
|
isAppToolName
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-IJAXOQJU.js";
|
|
19
19
|
import {
|
|
20
20
|
ToolInputError
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-E65YV7VV.js";
|
|
22
22
|
|
|
23
23
|
// src/tools/capability.ts
|
|
24
24
|
async function createCapabilityToken(userId, opts) {
|
|
@@ -270,4 +270,4 @@ export {
|
|
|
270
270
|
createAppToolRuntimeExecutor,
|
|
271
271
|
handleAppToolRequest
|
|
272
272
|
};
|
|
273
|
-
//# sourceMappingURL=chunk-
|
|
273
|
+
//# sourceMappingURL=chunk-QAF7ZTO3.js.map
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
} from "react";
|
|
19
19
|
import { createPortal } from "react-dom";
|
|
20
20
|
import { StatusPill } from "@tangle-network/ui/primitives";
|
|
21
|
+
import { fieldPresentation, fieldSizes, fieldTouchText } from "@tangle-network/ui/presentation";
|
|
21
22
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
22
23
|
function ChevronDown({ className }) {
|
|
23
24
|
return /* @__PURE__ */ jsx("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "m6 9 6 6 6-6" }) });
|
|
@@ -187,7 +188,7 @@ function pickerRootClass(fullWidth) {
|
|
|
187
188
|
return `relative ${fullWidth ? "flex w-full" : "inline-flex"}`;
|
|
188
189
|
}
|
|
189
190
|
function fieldPickerTriggerClass({ interactive = true } = {}) {
|
|
190
|
-
return
|
|
191
|
+
return `${fieldPresentation} ${fieldSizes.md} ${fieldTouchText} inline-flex w-full min-w-0 items-center justify-between gap-2 whitespace-nowrap border text-left font-normal text-foreground disabled:cursor-not-allowed disabled:opacity-50 ${interactive ? "data-[state=open]:border-[var(--ix-hover-border)] data-[state=open]:shadow-[var(--ix-after)]" : "cursor-default"}`;
|
|
191
192
|
}
|
|
192
193
|
var CHIP_PICKER_TRIGGER = "inline-flex h-[var(--control-height-sm,2rem)] items-center gap-1.5 whitespace-nowrap rounded-full border border-border bg-card px-3 text-sm font-medium text-foreground transition";
|
|
193
194
|
var QUIET_PICKER_TRIGGER_BASE = "inline-flex h-[var(--control-height-sm,2rem)] shrink-0 items-center gap-1.5 whitespace-nowrap rounded-md bg-transparent px-2 text-sm font-normal text-muted-foreground transition focus:outline-none focus-visible:ring-2 focus-visible:ring-ring";
|
|
@@ -728,4 +729,4 @@ export {
|
|
|
728
729
|
EffortMeter,
|
|
729
730
|
EffortPicker
|
|
730
731
|
};
|
|
731
|
-
//# sourceMappingURL=chunk-
|
|
732
|
+
//# sourceMappingURL=chunk-XG6FODYO.js.map
|