@elizaos/ui 2.0.3-beta.4 → 2.0.3-beta.6
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/app-navigate-view.d.ts.map +1 -1
- package/app-navigate-view.js +1 -1
- package/cloud/api-keys/ApiKeysView.d.ts +6 -3
- package/cloud/api-keys/ApiKeysView.d.ts.map +1 -1
- package/cloud/api-keys/ApiKeysView.js +21 -29
- package/cloud/api-keys/copy-api-key.d.ts +1 -8
- package/cloud/api-keys/copy-api-key.d.ts.map +1 -1
- package/cloud/api-keys/copy-api-key.js +1 -10
- package/cloud/api-keys/index.d.ts +1 -1
- package/cloud/api-keys/index.d.ts.map +1 -1
- package/cloud/api-keys/index.js +1 -1
- package/cloud/shell/CloudRouterShell.d.ts +12 -0
- package/cloud/shell/CloudRouterShell.d.ts.map +1 -1
- package/cloud/shell/CloudRouterShell.js +38 -2
- package/cloud-ui/components/data-list/api-keys-table.d.ts +1 -2
- package/cloud-ui/components/data-list/api-keys-table.d.ts.map +1 -1
- package/cloud-ui/components/data-list/api-keys-table.js +3 -9
- package/cloud-ui/components/docs/api-route-explorer-client.d.ts.map +1 -1
- package/cloud-ui/components/docs/api-route-explorer-client.js +2 -1
- package/cloud-ui/components/layout/dashboard-route-page.d.ts.map +1 -1
- package/cloud-ui/components/layout/dashboard-route-page.js +3 -1
- package/components/config-ui/config-field.js +1 -1
- package/components/pages/Springboard.d.ts.map +1 -1
- package/components/pages/Springboard.js +34 -45
- package/components/pages/SpringboardSurface.d.ts.map +1 -1
- package/components/pages/SpringboardSurface.js +116 -6
- package/components/shell/ContinuousChatOverlay.d.ts.map +1 -1
- package/components/shell/ContinuousChatOverlay.js +207 -146
- package/components/shell/HomeSpringboardSurface.d.ts.map +1 -1
- package/components/shell/HomeSpringboardSurface.js +31 -76
- package/components/shell/use-pull-gesture.d.ts +6 -0
- package/components/shell/use-pull-gesture.d.ts.map +1 -1
- package/components/shell/use-pull-gesture.js +66 -27
- package/components/shell/useShellController.d.ts.map +1 -1
- package/components/shell/useShellController.js +13 -3
- package/components/views/ViewTileImage.d.ts +8 -8
- package/components/views/ViewTileImage.d.ts.map +1 -1
- package/components/views/ViewTileImage.js +38 -9
- package/config/boot-config-store.js +1 -1
- package/hooks/useHorizontalPager.d.ts +33 -0
- package/hooks/useHorizontalPager.d.ts.map +1 -0
- package/hooks/useHorizontalPager.js +226 -0
- package/hooks/useLayoutShiftMonitor.d.ts +2 -0
- package/hooks/useLayoutShiftMonitor.d.ts.map +1 -1
- package/hooks/useLayoutShiftMonitor.js +23 -0
- package/hooks/view-catalog.d.ts +3 -4
- package/hooks/view-catalog.d.ts.map +1 -1
- package/hooks/view-catalog.js +4 -6
- package/package.json +10 -10
- package/state/startup-telemetry.d.ts +6 -0
- package/state/startup-telemetry.d.ts.map +1 -1
- package/state/startup-telemetry.js +23 -2
- package/styles/base.css +6 -6
- package/styles/brand-gold.css +6 -5
- package/testing/layout-stability.d.ts +11 -3
- package/testing/layout-stability.d.ts.map +1 -1
- package/testing/layout-stability.js +29 -4
- package/testing/run-animation-frames-immediately.d.ts +2 -0
- package/testing/run-animation-frames-immediately.d.ts.map +1 -0
- package/testing/run-animation-frames-immediately.js +8 -0
- package/themes/presets.js +14 -14
- package/utils/cloud-agent-base.d.ts.map +1 -1
- package/utils/cloud-agent-base.js +6 -0
- package/widgets/registry.d.ts.map +1 -1
- package/widgets/registry.js +7 -0
- package/components/pages/automation-conversations.d.ts +0 -16
- package/components/pages/automation-conversations.d.ts.map +0 -1
- package/components/pages/automation-conversations.js +0 -204
- package/components/pages/automations-missing-creds.d.ts +0 -25
- package/components/pages/automations-missing-creds.d.ts.map +0 -1
- package/components/pages/automations-missing-creds.js +0 -39
- package/components/settings/desktop-workspace-audit-config.d.ts +0 -3
- package/components/settings/desktop-workspace-audit-config.d.ts.map +0 -1
- package/components/settings/desktop-workspace-audit-config.js +0 -171
- package/components/shell/first-run-theme.d.ts +0 -6
- package/components/shell/first-run-theme.d.ts.map +0 -1
- package/components/shell/first-run-theme.js +0 -31
- package/genui/use-json-render-message.d.ts +0 -20
- package/genui/use-json-render-message.d.ts.map +0 -1
- package/genui/use-json-render-message.js +0 -38
- package/state/first-run-restart.d.ts +0 -8
- package/state/first-run-restart.d.ts.map +0 -1
- package/state/first-run-restart.js +0 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-navigate-view.d.ts","sourceRoot":"","sources":["../../../../src/app-navigate-view.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"app-navigate-view.d.ts","sourceRoot":"","sources":["../../../../src/app-navigate-view.ts"],"names":[],"mappings":"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"}
|
package/app-navigate-view.js
CHANGED
|
@@ -129,7 +129,7 @@ export function createNavigateViewHandler({ availableViewsForDesktopTabs, closeD
|
|
|
129
129
|
recordRecentViewId(entry.id);
|
|
130
130
|
openDesktopTab(entry, { pinned: false });
|
|
131
131
|
}
|
|
132
|
-
const primaryViewId = viewIds[0] ?? detail.viewId ?? null;
|
|
132
|
+
const primaryViewId = resolvedViewIds[0] ?? viewIds[0] ?? detail.viewId ?? null;
|
|
133
133
|
if (primaryViewId)
|
|
134
134
|
setActiveDesktopTabId(primaryViewId);
|
|
135
135
|
setViewLayout?.({
|
|
@@ -13,9 +13,12 @@
|
|
|
13
13
|
* - Mutations use the shared cloud `apiFetch` client (auth injection +
|
|
14
14
|
* structured `ApiError`) and invalidate the react-query key, replacing the
|
|
15
15
|
* raw `fetch` + manual `response.ok` plumbing.
|
|
16
|
-
* -
|
|
17
|
-
*
|
|
18
|
-
*
|
|
16
|
+
* - There is no row-level "copy key" action: the full secret is only ever
|
|
17
|
+
* shown once, in the post-create reveal dialog (copyable via `handleCopyKey`).
|
|
18
|
+
* A stored key exposes only its public prefix, so copying it is pointless.
|
|
19
|
+
* - Delete optimistically removes the row from the `["api-keys"]` cache because
|
|
20
|
+
* Hyperdrive caches the list GET, so the post-delete refetch can briefly
|
|
21
|
+
* serve the deleted key; the invalidate reconciles once the cache expires.
|
|
19
22
|
*/
|
|
20
23
|
import { type ApiKeyDisplay, type ApiKeysSummaryData } from "../../cloud-ui/components/data-list/index.js";
|
|
21
24
|
interface ApiKeysViewProps {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApiKeysView.d.ts","sourceRoot":"","sources":["../../../../../../src/cloud/api-keys/ApiKeysView.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"ApiKeysView.d.ts","sourceRoot":"","sources":["../../../../../../src/cloud/api-keys/ApiKeysView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAQH,OAAO,EACL,KAAK,aAAa,EAElB,KAAK,kBAAkB,EAExB,MAAM,qCAAqC,CAAC;AAmC7C,UAAU,gBAAgB;IACxB,IAAI,EAAE,aAAa,EAAE,CAAC;IACtB,OAAO,EAAE,kBAAkB,CAAC;CAC7B;AAoCD,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,gBAAgB,2CAkgB9D"}
|
|
@@ -14,9 +14,12 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
14
14
|
* - Mutations use the shared cloud `apiFetch` client (auth injection +
|
|
15
15
|
* structured `ApiError`) and invalidate the react-query key, replacing the
|
|
16
16
|
* raw `fetch` + manual `response.ok` plumbing.
|
|
17
|
-
* -
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* - There is no row-level "copy key" action: the full secret is only ever
|
|
18
|
+
* shown once, in the post-create reveal dialog (copyable via `handleCopyKey`).
|
|
19
|
+
* A stored key exposes only its public prefix, so copying it is pointless.
|
|
20
|
+
* - Delete optimistically removes the row from the `["api-keys"]` cache because
|
|
21
|
+
* Hyperdrive caches the list GET, so the post-delete refetch can briefly
|
|
22
|
+
* serve the deleted key; the invalidate reconciles once the cache expires.
|
|
20
23
|
*/
|
|
21
24
|
import { useQueryClient } from "@tanstack/react-query";
|
|
22
25
|
import { Copy, Plus } from "lucide-react";
|
|
@@ -34,7 +37,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "
|
|
|
34
37
|
import { Textarea } from "../../components/ui/textarea.js";
|
|
35
38
|
import { ApiError, apiFetch } from "../lib/api-client.js";
|
|
36
39
|
import { useCloudT } from "../shell/CloudI18nProvider.js";
|
|
37
|
-
import {
|
|
40
|
+
import { copyApiKeyToClipboard } from "./copy-api-key.js";
|
|
38
41
|
const rateLimitPresets = [
|
|
39
42
|
{
|
|
40
43
|
value: "standard",
|
|
@@ -133,29 +136,6 @@ export function ApiKeysView({ keys, summary }) {
|
|
|
133
136
|
}), { description: errorMessage(error) });
|
|
134
137
|
}
|
|
135
138
|
};
|
|
136
|
-
// The full secret is hashed + KMS-encrypted at rest and only returned once
|
|
137
|
-
// (on create / regenerate). For a stored key the only copyable identifier is
|
|
138
|
-
// its public prefix.
|
|
139
|
-
const handleCopyStoredKey = async (id) => {
|
|
140
|
-
const key = keys.find((k) => k.id === id);
|
|
141
|
-
if (!key)
|
|
142
|
-
return;
|
|
143
|
-
try {
|
|
144
|
-
await copyApiKeyPrefix(key.keyPrefix);
|
|
145
|
-
toast.success(t("cloud.apiKeys.prefixCopied", {
|
|
146
|
-
defaultValue: "Key prefix copied",
|
|
147
|
-
}), {
|
|
148
|
-
description: t("cloud.apiKeys.prefixCopiedDesc", {
|
|
149
|
-
defaultValue: "The full key is only shown once, when it is created. Copied the public prefix instead.",
|
|
150
|
-
}),
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
catch (error) {
|
|
154
|
-
toast.error(t("cloud.apiKeys.copyFailed", {
|
|
155
|
-
defaultValue: "Failed to copy API key",
|
|
156
|
-
}), { description: errorMessage(error) });
|
|
157
|
-
}
|
|
158
|
-
};
|
|
159
139
|
const handleDisableKey = (id) => {
|
|
160
140
|
const key = keys.find((k) => k.id === id);
|
|
161
141
|
const isCurrentlyActive = key?.status === "active";
|
|
@@ -235,12 +215,24 @@ export function ApiKeysView({ keys, summary }) {
|
|
|
235
215
|
else if (type === "delete") {
|
|
236
216
|
try {
|
|
237
217
|
await apiFetch(`/api/v1/api-keys/${id}`, { method: "DELETE" });
|
|
218
|
+
// Hyperdrive caches the list GET, so an immediate refetch can still
|
|
219
|
+
// serve the just-deleted row. Optimistically drop it from every cached
|
|
220
|
+
// `["api-keys", ...]` query (the key is partitioned per user, so match
|
|
221
|
+
// on the prefix) so it disappears immediately.
|
|
222
|
+
queryClient.setQueriesData({ queryKey: ["api-keys"] }, (existing) => existing?.filter((key) => key.id !== id));
|
|
238
223
|
toast.success(t("cloud.apiKeys.deleted", { defaultValue: "API key deleted" }), {
|
|
239
224
|
description: t("cloud.apiKeys.deletedDesc", {
|
|
240
225
|
defaultValue: "The API key has been permanently deleted.",
|
|
241
226
|
}),
|
|
242
227
|
});
|
|
243
|
-
|
|
228
|
+
// Mark the list stale WITHOUT an immediate refetch: refetching now would
|
|
229
|
+
// re-read the Hyperdrive-cached GET and clobber the optimistic removal
|
|
230
|
+
// above, making the deleted row reappear. It reconciles on the next
|
|
231
|
+
// natural refetch (mount/focus), by which point the cache has rolled over.
|
|
232
|
+
void queryClient.invalidateQueries({
|
|
233
|
+
queryKey: ["api-keys"],
|
|
234
|
+
refetchType: "none",
|
|
235
|
+
});
|
|
244
236
|
}
|
|
245
237
|
catch (error) {
|
|
246
238
|
toast.error(t("cloud.apiKeys.deleteFailed", {
|
|
@@ -301,7 +293,7 @@ export function ApiKeysView({ keys, summary }) {
|
|
|
301
293
|
defaultValue: "API key created successfully",
|
|
302
294
|
}) }), _jsx(DialogDescription, { children: t("cloud.apiKeys.createdDialogDesc", {
|
|
303
295
|
defaultValue: "Make sure to copy your API key now. You won't be able to see it again!",
|
|
304
|
-
}) })] }), _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "grid gap-2", children: [_jsx("p", { className: "text-xs font-medium text-white/70 uppercase tracking-wide", children: t("cloud.apiKeys.keyName", { defaultValue: "Key name" }) }), _jsx("div", { className: "font-mono text-sm font-semibold text-white", children: createdKey.name })] }), _jsxs("div", { className: "grid gap-2", children: [_jsx("p", { className: "text-xs font-medium text-white/70 uppercase tracking-wide", children: t("cloud.apiKeys.apiKeyLabel", { defaultValue: "API Key" }) }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Input, { value: createdKey.plainKey, readOnly: true, className: "font-mono text-sm rounded-sm border-white/10 bg-black/40 text-white" }), _jsx(BrandButton, { variant: "outline", onClick: () => void handleCopyKey(createdKey.plainKey), children: _jsx(Copy, { className: "h-4 w-4" }) })] })] })] }), _jsx(DialogFooter, { children: _jsx(BrandButton, { variant: "primary", onClick: () => setCreatedKey(null), children: t("cloud.apiKeys.done", { defaultValue: "Done" }) }) })] }) })), _jsx("div", { className: "space-y-6", children: hasKeys ? (_jsx(ApiKeysTable, { keys: keys,
|
|
296
|
+
}) })] }), _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "grid gap-2", children: [_jsx("p", { className: "text-xs font-medium text-white/70 uppercase tracking-wide", children: t("cloud.apiKeys.keyName", { defaultValue: "Key name" }) }), _jsx("div", { className: "font-mono text-sm font-semibold text-white", children: createdKey.name })] }), _jsxs("div", { className: "grid gap-2", children: [_jsx("p", { className: "text-xs font-medium text-white/70 uppercase tracking-wide", children: t("cloud.apiKeys.apiKeyLabel", { defaultValue: "API Key" }) }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Input, { value: createdKey.plainKey, readOnly: true, className: "font-mono text-sm rounded-sm border-white/10 bg-black/40 text-white" }), _jsx(BrandButton, { variant: "outline", onClick: () => void handleCopyKey(createdKey.plainKey), children: _jsx(Copy, { className: "h-4 w-4" }) })] })] })] }), _jsx(DialogFooter, { children: _jsx(BrandButton, { variant: "primary", onClick: () => setCreatedKey(null), children: t("cloud.apiKeys.done", { defaultValue: "Done" }) }) })] }) })), _jsx("div", { className: "space-y-6", children: hasKeys ? (_jsx(ApiKeysTable, { keys: keys, onDisableKey: handleDisableKey, onDeleteKey: handleDeleteKey, onRegenerateKey: handleRegenerateKey })) : (_jsx(ApiKeyEmptyState, { onCreateKey: () => setCreateDialogOpen(true) })) }), _jsx(AlertDialog, { open: pendingAction !== null, onOpenChange: (open) => !open && setPendingAction(null), children: _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: pendingAction?.title }), _jsx(AlertDialogDescription, { children: pendingAction?.description })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: t("cloud.apiKeys.cancel", { defaultValue: "Cancel" }) }), _jsx(AlertDialogAction, { onClick: () => void handleConfirmAction(), className: pendingAction?.type === "delete"
|
|
305
297
|
? "bg-red-600 hover:bg-red-700"
|
|
306
298
|
: "", children: t("cloud.apiKeys.confirm", { defaultValue: "Confirm" }) })] })] }) })] }));
|
|
307
299
|
}
|
|
@@ -12,20 +12,13 @@
|
|
|
12
12
|
* endpoint that reveals the secret of an existing key, so "copy the stored
|
|
13
13
|
* secret" is impossible by design.
|
|
14
14
|
*
|
|
15
|
-
* So this exposes
|
|
15
|
+
* So this exposes a single operation:
|
|
16
16
|
* - {@link copyApiKeyToClipboard} — copy a one-time plaintext key (the value
|
|
17
17
|
* shown in the post-create reveal dialog).
|
|
18
|
-
* - {@link copyApiKeyPrefix} — copy the public key prefix (the only visible
|
|
19
|
-
* identifier for a stored key) for the row-level "Copy key" action.
|
|
20
18
|
*/
|
|
21
19
|
/**
|
|
22
20
|
* Copy a full plaintext API key (only available in the one-time reveal dialog).
|
|
23
21
|
* Throws if the clipboard is unavailable so the caller can surface an error.
|
|
24
22
|
*/
|
|
25
23
|
export declare function copyApiKeyToClipboard(plainKey: string): Promise<void>;
|
|
26
|
-
/**
|
|
27
|
-
* Copy the public key prefix for a stored key. The full secret cannot be
|
|
28
|
-
* retrieved after creation, so the prefix is the only copyable identifier.
|
|
29
|
-
*/
|
|
30
|
-
export declare function copyApiKeyPrefix(keyPrefix: string): Promise<void>;
|
|
31
24
|
//# sourceMappingURL=copy-api-key.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copy-api-key.d.ts","sourceRoot":"","sources":["../../../../../../src/cloud/api-keys/copy-api-key.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"copy-api-key.d.ts","sourceRoot":"","sources":["../../../../../../src/cloud/api-keys/copy-api-key.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE3E"}
|
|
@@ -12,11 +12,9 @@
|
|
|
12
12
|
* endpoint that reveals the secret of an existing key, so "copy the stored
|
|
13
13
|
* secret" is impossible by design.
|
|
14
14
|
*
|
|
15
|
-
* So this exposes
|
|
15
|
+
* So this exposes a single operation:
|
|
16
16
|
* - {@link copyApiKeyToClipboard} — copy a one-time plaintext key (the value
|
|
17
17
|
* shown in the post-create reveal dialog).
|
|
18
|
-
* - {@link copyApiKeyPrefix} — copy the public key prefix (the only visible
|
|
19
|
-
* identifier for a stored key) for the row-level "Copy key" action.
|
|
20
18
|
*/
|
|
21
19
|
import { copyTextToClipboard } from "../../utils/clipboard.js";
|
|
22
20
|
/**
|
|
@@ -26,10 +24,3 @@ import { copyTextToClipboard } from "../../utils/clipboard.js";
|
|
|
26
24
|
export async function copyApiKeyToClipboard(plainKey) {
|
|
27
25
|
await copyTextToClipboard(plainKey);
|
|
28
26
|
}
|
|
29
|
-
/**
|
|
30
|
-
* Copy the public key prefix for a stored key. The full secret cannot be
|
|
31
|
-
* retrieved after creation, so the prefix is the only copyable identifier.
|
|
32
|
-
*/
|
|
33
|
-
export async function copyApiKeyPrefix(keyPrefix) {
|
|
34
|
-
await copyTextToClipboard(keyPrefix);
|
|
35
|
-
}
|
|
@@ -22,7 +22,7 @@ import { type CloudRouteDef } from "../shell/cloud-route-registry.js";
|
|
|
22
22
|
export { ApiKeysSurface, default as ApiKeysRoute } from "./ApiKeysRoute.js";
|
|
23
23
|
export { ApiKeysSection } from "./ApiKeysSection.js";
|
|
24
24
|
export { ApiKeysView } from "./ApiKeysView.js";
|
|
25
|
-
export {
|
|
25
|
+
export { copyApiKeyToClipboard } from "./copy-api-key.js";
|
|
26
26
|
export { API_KEYS_QUERY_KEY, type ApiKeyRecord, useApiKeys, } from "./use-api-keys.js";
|
|
27
27
|
/** Stable settings-section id + URL hash for the API-keys surface. */
|
|
28
28
|
export declare const API_KEYS_SECTION_ID = "api-keys";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/cloud/api-keys/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAAE,cAAc,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/cloud/api-keys/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAAE,cAAc,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EACL,kBAAkB,EAClB,KAAK,YAAY,EACjB,UAAU,GACX,MAAM,gBAAgB,CAAC;AAExB,sEAAsE;AACtE,eAAO,MAAM,mBAAmB,aAAa,CAAC;AAK9C;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,aAI/B,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAChC,IAAI,CAEN"}
|
package/cloud/api-keys/index.js
CHANGED
|
@@ -23,7 +23,7 @@ import { registerCloudRoute, } from "../shell/cloud-route-registry.js";
|
|
|
23
23
|
export { ApiKeysSurface, default as ApiKeysRoute } from "./ApiKeysRoute.js";
|
|
24
24
|
export { ApiKeysSection } from "./ApiKeysSection.js";
|
|
25
25
|
export { ApiKeysView } from "./ApiKeysView.js";
|
|
26
|
-
export {
|
|
26
|
+
export { copyApiKeyToClipboard } from "./copy-api-key.js";
|
|
27
27
|
export { API_KEYS_QUERY_KEY, useApiKeys, } from "./use-api-keys.js";
|
|
28
28
|
/** Stable settings-section id + URL hash for the API-keys surface. */
|
|
29
29
|
export const API_KEYS_SECTION_ID = "api-keys";
|
|
@@ -29,6 +29,18 @@ export interface CloudRouterShellProps {
|
|
|
29
29
|
*/
|
|
30
30
|
appElement: ReactNode;
|
|
31
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Catch-all element. Renders the agent app exactly as before, EXCEPT on an apex
|
|
34
|
+
* control-plane host where the Steward session is resolved-and-unauthenticated —
|
|
35
|
+
* there it redirects to the registered cloud `/login` page (`returnTo`
|
|
36
|
+
* preserved) instead of booting the agent shell that would 401-wall. The apex
|
|
37
|
+
* 401-wall was a router fall-through: no route registers the apex root `/`, so
|
|
38
|
+
* an unauthenticated apex visitor hit this catch-all and booted the agent
|
|
39
|
+
* runtime against a backend that isn't there.
|
|
40
|
+
*/
|
|
41
|
+
export declare function AppCatchAllRoute({ appElement, }: {
|
|
42
|
+
appElement: ReactNode;
|
|
43
|
+
}): React.JSX.Element;
|
|
32
44
|
/**
|
|
33
45
|
* The shell. Mounts the registered cloud routes + the `/dashboard/*` compat
|
|
34
46
|
* redirects, and renders {@link CloudRouterShellProps.appElement} for every
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CloudRouterShell.d.ts","sourceRoot":"","sources":["../../../../../../src/cloud/shell/CloudRouterShell.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,EAGL,KAAK,SAAS,EAEf,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"CloudRouterShell.d.ts","sourceRoot":"","sources":["../../../../../../src/cloud/shell/CloudRouterShell.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,EAGL,KAAK,SAAS,EAEf,MAAM,OAAO,CAAC;AAwHf,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,UAAU,EAAE,SAAS,CAAC;CACvB;AAsBD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,UAAU,GACX,EAAE;IACD,UAAU,EAAE,SAAS,CAAC;CACvB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAUpB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,UAAU,GACX,EAAE,qBAAqB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CA6C3C;AAED,eAAe,gBAAgB,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
3
|
* Top-level react-router shell for the Eliza web app (web build only).
|
|
4
4
|
*
|
|
@@ -24,7 +24,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
24
24
|
import { QueryClientProvider } from "@tanstack/react-query";
|
|
25
25
|
import { Suspense, } from "react";
|
|
26
26
|
import { BrowserRouter, Navigate, Route, Routes, useLocation, useParams, } from "react-router-dom";
|
|
27
|
+
import { ELIZA_CLOUD_CONTROL_PLANE_HOSTS } from "../../utils/cloud-agent-base.js";
|
|
27
28
|
import { queryClient } from "../lib/query-client.js";
|
|
29
|
+
import { useSessionAuth } from "../lib/use-session-auth.js";
|
|
28
30
|
import { CloudI18nProvider, resolveInitialCloudLang, } from "./CloudI18nProvider.js";
|
|
29
31
|
import { listCloudRoutes } from "./cloud-route-registry.js";
|
|
30
32
|
import { StewardAuthProvider } from "./StewardProvider.js";
|
|
@@ -97,6 +99,40 @@ function CloudRouteElement({ route, }) {
|
|
|
97
99
|
}
|
|
98
100
|
return _jsx(StewardAuthProvider, { children: body });
|
|
99
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Apex control-plane hosts that serve THIS console UI but have no same-origin
|
|
104
|
+
* agent backend — so an unauthenticated visitor must land on the Steward
|
|
105
|
+
* `/login` page, not the agent shell (which 401-walls on `/api/*`).
|
|
106
|
+
* `api.elizacloud.ai` is the API origin (it never serves this shell); per-agent
|
|
107
|
+
* `<id>.elizacloud.ai` subdomains are NOT in the control-plane set and boot
|
|
108
|
+
* their real runtime, so they fall through untouched.
|
|
109
|
+
*/
|
|
110
|
+
const APEX_UI_CONTROL_PLANE_HOSTS = new Set(
|
|
111
|
+
// Exclude the API origins (api. / api-staging.) — they never serve this shell.
|
|
112
|
+
[...ELIZA_CLOUD_CONTROL_PLANE_HOSTS].filter((h) => !/^api[.-]/.test(h)));
|
|
113
|
+
function isApexControlPlaneHost() {
|
|
114
|
+
if (typeof window === "undefined")
|
|
115
|
+
return false;
|
|
116
|
+
return APEX_UI_CONTROL_PLANE_HOSTS.has(window.location.hostname.toLowerCase());
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Catch-all element. Renders the agent app exactly as before, EXCEPT on an apex
|
|
120
|
+
* control-plane host where the Steward session is resolved-and-unauthenticated —
|
|
121
|
+
* there it redirects to the registered cloud `/login` page (`returnTo`
|
|
122
|
+
* preserved) instead of booting the agent shell that would 401-wall. The apex
|
|
123
|
+
* 401-wall was a router fall-through: no route registers the apex root `/`, so
|
|
124
|
+
* an unauthenticated apex visitor hit this catch-all and booted the agent
|
|
125
|
+
* runtime against a backend that isn't there.
|
|
126
|
+
*/
|
|
127
|
+
export function AppCatchAllRoute({ appElement, }) {
|
|
128
|
+
const { ready, authenticated } = useSessionAuth();
|
|
129
|
+
const location = useLocation();
|
|
130
|
+
if (isApexControlPlaneHost() && ready && !authenticated) {
|
|
131
|
+
const returnTo = encodeURIComponent(`${location.pathname}${location.search}`);
|
|
132
|
+
return _jsx(Navigate, { to: `/login?returnTo=${returnTo}`, replace: true });
|
|
133
|
+
}
|
|
134
|
+
return _jsx(_Fragment, { children: appElement });
|
|
135
|
+
}
|
|
100
136
|
/**
|
|
101
137
|
* The shell. Mounts the registered cloud routes + the `/dashboard/*` compat
|
|
102
138
|
* redirects, and renders {@link CloudRouterShellProps.appElement} for every
|
|
@@ -104,6 +140,6 @@ function CloudRouteElement({ route, }) {
|
|
|
104
140
|
*/
|
|
105
141
|
export function CloudRouterShell({ appElement, }) {
|
|
106
142
|
const cloudRoutes = listCloudRoutes();
|
|
107
|
-
return (_jsx(BrowserRouter, { children: _jsx(CloudProviders, { children: _jsxs(Routes, { children: [cloudRoutes.map((route) => (_jsx(Route, { path: route.path, element: _jsx(CloudRouteElement, { route: route }) }, route.path))), DASHBOARD_REDIRECTS.map(({ from, to }) => (_jsx(Route, { path: from, element: _jsx(ParamRedirect, { to: to }) }, from))), _jsx(Route, { path: "dashboard/*", element: _jsx(CloudNotFound, {}) }), _jsx(Route, { path: "*", element: appElement })] }) }) }));
|
|
143
|
+
return (_jsx(BrowserRouter, { children: _jsx(CloudProviders, { children: _jsxs(Routes, { children: [cloudRoutes.map((route) => (_jsx(Route, { path: route.path, element: _jsx(CloudRouteElement, { route: route }) }, route.path))), DASHBOARD_REDIRECTS.map(({ from, to }) => (_jsx(Route, { path: from, element: _jsx(ParamRedirect, { to: to }) }, from))), _jsx(Route, { path: "dashboard/*", element: _jsx(CloudNotFound, {}) }), _jsx(Route, { path: "*", element: _jsx(AppCatchAllRoute, { appElement: appElement }) })] }) }) }));
|
|
108
144
|
}
|
|
109
145
|
export default CloudRouterShell;
|
|
@@ -13,10 +13,9 @@ export interface ApiKeyDisplay {
|
|
|
13
13
|
}
|
|
14
14
|
export interface ApiKeysTableProps {
|
|
15
15
|
keys: ApiKeyDisplay[];
|
|
16
|
-
onCopyKey?: (id: string) => void;
|
|
17
16
|
onDisableKey?: (id: string) => void;
|
|
18
17
|
onDeleteKey?: (id: string) => void;
|
|
19
18
|
onRegenerateKey?: (id: string) => void;
|
|
20
19
|
}
|
|
21
|
-
export declare function ApiKeysTable({ keys,
|
|
20
|
+
export declare function ApiKeysTable({ keys, onDisableKey, onDeleteKey, onRegenerateKey, }: ApiKeysTableProps): import("react/jsx-runtime").JSX.Element | null;
|
|
22
21
|
//# sourceMappingURL=api-keys-table.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-keys-table.d.ts","sourceRoot":"","sources":["../../../../../../../src/cloud-ui/components/data-list/api-keys-table.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"api-keys-table.d.ts","sourceRoot":"","sources":["../../../../../../../src/cloud-ui/components/data-list/api-keys-table.tsx"],"names":[],"mappings":"AAiBA,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;AAE7D,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,YAAY,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,aAAa,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,eAAe,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AAwED,wBAAgB,YAAY,CAAC,EAC3B,IAAI,EACJ,YAAY,EACZ,WAAW,EACX,eAAe,GAChB,EAAE,iBAAiB,kDAoKnB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { CalendarClock,
|
|
2
|
+
import { CalendarClock, RefreshCw, ShieldOff, Trash2 } from "lucide-react";
|
|
3
3
|
import { StatusBadge } from "../../../components/ui/status-badge.js";
|
|
4
4
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "../../../components/ui/table.js";
|
|
5
5
|
import { BrandButton } from "../brand/brand-button.js";
|
|
@@ -39,11 +39,6 @@ function formatDate(value) {
|
|
|
39
39
|
}
|
|
40
40
|
function renderActions(key, handlers, triggerClassName) {
|
|
41
41
|
return (_jsx(ListActionMenu, { label: "Manage key", triggerClassName: triggerClassName, items: [
|
|
42
|
-
{
|
|
43
|
-
label: "Copy key",
|
|
44
|
-
icon: Copy,
|
|
45
|
-
onSelect: () => handlers.onCopyKey?.(key.id),
|
|
46
|
-
},
|
|
47
42
|
{
|
|
48
43
|
label: "Regenerate key",
|
|
49
44
|
icon: RefreshCw,
|
|
@@ -63,17 +58,16 @@ function renderActions(key, handlers, triggerClassName) {
|
|
|
63
58
|
},
|
|
64
59
|
] }));
|
|
65
60
|
}
|
|
66
|
-
export function ApiKeysTable({ keys,
|
|
61
|
+
export function ApiKeysTable({ keys, onDisableKey, onDeleteKey, onRegenerateKey, }) {
|
|
67
62
|
if (keys.length === 0) {
|
|
68
63
|
return null;
|
|
69
64
|
}
|
|
70
65
|
const handlers = {
|
|
71
|
-
onCopyKey,
|
|
72
66
|
onDisableKey,
|
|
73
67
|
onDeleteKey,
|
|
74
68
|
onRegenerateKey,
|
|
75
69
|
};
|
|
76
|
-
return (_jsxs(_Fragment, { children: [_jsx(DashboardDataListMobile, { className: "space-y-3", children: keys.map((key) => (_jsxs("div", { className: "space-y-3 rounded-sm border border-white/10 bg-black/40 p-4", children: [_jsxs("div", { className: "flex min-w-0 items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0 space-y-1", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx("span", { className: "truncate font-semibold text-white", children: key.name }), _jsx(StatusBadge, { status: getStatusVariant(key.status), label: getStatusLabel(key.status) })] }), key.description ? (_jsx("p", { className: "line-clamp-2 text-xs text-white/60", children: key.description })) : null] }), renderActions(key, handlers)] }), _jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-2 text-xs text-white/60", children: [_jsx("span", { className: "rounded-sm border border-white/10 bg-black/60 px-1.5 py-0.5 font-mono text-xs text-white", children: `${key.keyPrefix}.......` }), _jsxs(BrandButton, { variant: "ghost", size: "sm", className: "h-8 px-2", onClick: () =>
|
|
70
|
+
return (_jsxs(_Fragment, { children: [_jsx(DashboardDataListMobile, { className: "space-y-3", children: keys.map((key) => (_jsxs("div", { className: "space-y-3 rounded-sm border border-white/10 bg-black/40 p-4", children: [_jsxs("div", { className: "flex min-w-0 items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0 space-y-1", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx("span", { className: "truncate font-semibold text-white", children: key.name }), _jsx(StatusBadge, { status: getStatusVariant(key.status), label: getStatusLabel(key.status) })] }), key.description ? (_jsx("p", { className: "line-clamp-2 text-xs text-white/60", children: key.description })) : null] }), renderActions(key, handlers)] }), _jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-2 text-xs text-white/60", children: [_jsx("span", { className: "rounded-sm border border-white/10 bg-black/60 px-1.5 py-0.5 font-mono text-xs text-white", children: `${key.keyPrefix}.......` }), _jsxs(BrandButton, { variant: "ghost", size: "sm", className: "h-8 px-2", onClick: () => onRegenerateKey?.(key.id), children: [_jsx(RefreshCw, { className: "mr-1 h-3.5 w-3.5" }), "Regenerate"] })] }), _jsxs("div", { className: "grid grid-cols-2 gap-3 border-t border-white/10 pt-3 text-xs", children: [_jsxs("div", { children: [_jsx("p", { className: "text-white/40", children: "Usage" }), _jsxs("p", { className: "mt-1 font-medium text-white", children: [key.usageCount.toLocaleString(), " requests"] }), _jsxs("p", { className: "mt-0.5 text-white/74", children: [key.rateLimit.toLocaleString(), " / min"] })] }), _jsxs("div", { children: [_jsx("p", { className: "text-white/40", children: "Timeline" }), _jsxs("p", { className: "mt-1 text-white/60", children: ["Created ", formatDate(key.createdAt)] }), _jsxs("p", { className: "mt-0.5 text-white/60", children: ["Last used ", formatDate(key.lastUsedAt)] })] })] })] }, key.id))) }), _jsx(DashboardDataListDesktop, { className: "border-0", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Key" }), _jsx(TableHead, { children: "Usage" }), _jsx(TableHead, { children: "Timeline" }), _jsx(TableHead, { className: "text-right", children: "Actions" })] }) }), _jsx(TableBody, { children: keys.map((key) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "font-semibold text-white", children: key.name }), _jsx(StatusBadge, { status: getStatusVariant(key.status), label: getStatusLabel(key.status) })] }), key.description ? (_jsx("p", { className: "text-xs text-white/60", children: key.description })) : null, _jsxs("div", { className: "flex items-center gap-2 text-xs text-white/60", children: [_jsx("span", { className: "rounded-sm border border-white/10 bg-black/60 px-1.5 py-0.5 font-mono text-xs text-white", children: `${key.keyPrefix}.......` }), _jsxs(BrandButton, { variant: "ghost", size: "sm", className: "h-8 px-2", onClick: () => onRegenerateKey?.(key.id), children: [_jsx(RefreshCw, { className: "mr-1 h-3.5 w-3.5" }), "Regenerate"] })] })] }) }), _jsx(TableCell, { children: _jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("span", { className: "font-medium text-white", children: [key.usageCount.toLocaleString(), " requests"] }), _jsxs("p", { className: "text-xs text-white/74", children: ["Rate limit ", key.rateLimit.toLocaleString(), " / min"] })] }) }), _jsx(TableCell, { children: _jsxs("div", { className: "flex flex-col gap-2 text-xs text-white/60", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CalendarClock, { className: "h-3.5 w-3.5 text-[#FF5800]" }), _jsxs("span", { children: ["Created ", formatDate(key.createdAt)] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CalendarClock, { className: "h-3.5 w-3.5 text-[#FF5800]" }), _jsxs("span", { children: ["Last used ", formatDate(key.lastUsedAt)] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CalendarClock, { className: "h-3.5 w-3.5 text-[#FF5800]" }), _jsx("span", { children: key.expiresAt
|
|
77
71
|
? `Expires ${formatDate(key.expiresAt)}`
|
|
78
72
|
: "No expiry" })] })] }) }), _jsx(TableCell, { className: "text-right", children: renderActions(key, handlers, "h-9 w-9") })] }, key.id))) })] }) })] }));
|
|
79
73
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-route-explorer-client.d.ts","sourceRoot":"","sources":["../../../../../../../src/cloud-ui/components/docs/api-route-explorer-client.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,qBAAqB,EAAc,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"api-route-explorer-client.d.ts","sourceRoot":"","sources":["../../../../../../../src/cloud-ui/components/docs/api-route-explorer-client.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,qBAAqB,EAAc,MAAM,uBAAuB,CAAC;AAqG/E,wBAAgB,sBAAsB,CAAC,EACrC,MAAM,GACP,EAAE;IACD,MAAM,EAAE,qBAAqB,EAAE,CAAC;CACjC,2CAogBA"}
|
|
@@ -32,7 +32,8 @@ function methodBadgeClass(method) {
|
|
|
32
32
|
case "GET":
|
|
33
33
|
return `${base} bg-emerald-500/10 text-emerald-400 border-emerald-500/30 `;
|
|
34
34
|
case "POST":
|
|
35
|
-
|
|
35
|
+
// Brand rule: no blue. Slate keeps POST distinct from the amber PUT.
|
|
36
|
+
return `${base} bg-slate-500/10 text-slate-300 border-slate-500/30 `;
|
|
36
37
|
case "PUT":
|
|
37
38
|
return `${base} bg-amber-500/10 text-amber-400 border-amber-500/30 `;
|
|
38
39
|
case "PATCH":
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashboard-route-page.d.ts","sourceRoot":"","sources":["../../../../../../../src/cloud-ui/components/layout/dashboard-route-page.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,wBAAwB,EACxB,cAAc,EACd,SAAS,EACV,MAAM,OAAO,CAAC;AAEf,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAG9E,KAAK,4BAA4B,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAE7E,KAAK,gCAAgC,GAAG,IAAI,CAC1C,wBAAwB,CAAC,OAAO,sBAAsB,CAAC,EACvD,UAAU,CACX,CAAC;AAEF,KAAK,4BAA4B,GAAG,IAAI,CACtC,wBAAwB,CAAC,OAAO,kBAAkB,CAAC,EACnD,UAAU,CACX,CAAC;AAEF,UAAU,uBAAuB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,GAAG,gCAAgC,CAAC;IACvD,KAAK,CAAC,EAAE,OAAO,GAAG,4BAA4B,CAAC;IAC/C,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,UAAU,CAAC,EAAE,4BAA4B,CAAC;IAC1C,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;
|
|
1
|
+
{"version":3,"file":"dashboard-route-page.d.ts","sourceRoot":"","sources":["../../../../../../../src/cloud-ui/components/layout/dashboard-route-page.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,wBAAwB,EACxB,cAAc,EACd,SAAS,EACV,MAAM,OAAO,CAAC;AAEf,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAG9E,KAAK,4BAA4B,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAE7E,KAAK,gCAAgC,GAAG,IAAI,CAC1C,wBAAwB,CAAC,OAAO,sBAAsB,CAAC,EACvD,UAAU,CACX,CAAC;AAEF,KAAK,4BAA4B,GAAG,IAAI,CACtC,wBAAwB,CAAC,OAAO,kBAAkB,CAAC,EACnD,UAAU,CACX,CAAC;AAEF,UAAU,uBAAuB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,GAAG,gCAAgC,CAAC;IACvD,KAAK,CAAC,EAAE,OAAO,GAAG,4BAA4B,CAAC;IAC/C,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,UAAU,CAAC,EAAE,4BAA4B,CAAC;IAC1C,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAmBD,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,WAAW,EACX,OAAO,EACP,UAAe,EACf,QAAQ,EACR,SAAS,EACT,KAAK,EACL,MAAM,EACN,UAAmB,EACnB,eAAe,GAChB,EAAE,uBAAuB,2CAuCzB;AAED,YAAY,EACV,4BAA4B,EAC5B,gCAAgC,EAChC,uBAAuB,EACvB,4BAA4B,GAC7B,CAAC"}
|
|
@@ -4,7 +4,9 @@ import { cn } from "../../lib/utils.js";
|
|
|
4
4
|
import { DashboardPageContainer, DashboardPageStack } from "./dashboard-page.js";
|
|
5
5
|
import { useSetPageHeader } from "./page-header-context.hooks.js";
|
|
6
6
|
const bannerTones = {
|
|
7
|
-
|
|
7
|
+
// Brand rule: no blue. Slate reads as neutral "info" alongside the
|
|
8
|
+
// emerald/amber/red tones below.
|
|
9
|
+
info: "border-slate-400/30 bg-slate-400/10 text-slate-100",
|
|
8
10
|
success: "border-emerald-400/30 bg-emerald-400/10 text-emerald-100",
|
|
9
11
|
warning: "border-amber-400/30 bg-amber-400/10 text-amber-100",
|
|
10
12
|
error: "border-red-500/40 bg-red-500/10 text-red-400",
|
|
@@ -25,5 +25,5 @@ export function ConfigField({ renderProps, renderer, pluginId, }) {
|
|
|
25
25
|
}, children: [_jsx("span", { className: "shrink-0 mt-px", children: t("config-field.Times") }), _jsx("span", { children: err })] }, err))) })), (renderProps.hint.help || renderProps.schema.description) && (_jsxs("div", { className: "mt-1 leading-relaxed line-clamp-2", style: {
|
|
26
26
|
fontSize: "var(--plugin-help-size)",
|
|
27
27
|
color: "var(--plugin-help)",
|
|
28
|
-
}, children: [renderProps.hint.help ?? renderProps.schema.description, renderProps.schema.default != null && (_jsxs("span", { className: "opacity-
|
|
28
|
+
}, children: [renderProps.hint.help ?? renderProps.schema.description, renderProps.schema.default != null && (_jsxs("span", { className: "opacity-90", children: [" ", t("common.default", { defaultValue: "Default" }), " ", String(renderProps.schema.default), ")"] }))] }))] })] }));
|
|
29
29
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Springboard.d.ts","sourceRoot":"","sources":["../../../../../../src/components/pages/Springboard.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;
|
|
1
|
+
{"version":3,"file":"Springboard.d.ts","sourceRoot":"","sources":["../../../../../../src/components/pages/Springboard.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAc1D,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IACrC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,gBAAgB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,8EAA8E;IAC9E,aAAa,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;IACxC,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC;+CAC2C;IAC3C,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,oEAAoE;IACpE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA8JD,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,OAAe,EACf,QAAQ,EACR,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,UAAU,EACV,YAAY,EACZ,IAAI,EAAE,QAAQ,EACd,YAAY,EACZ,iBAAiB,EACjB,OAAO,EAAE,WAAW,EACpB,eAAe,EACf,YAAmB,EACnB,SAAS,GACV,EAAE,gBAAgB,2CA0UlB"}
|
|
@@ -13,8 +13,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
13
13
|
* the shared root `AppBackground` shows through, matching the home screen.
|
|
14
14
|
*/
|
|
15
15
|
import { Pencil, Trash2 } from "lucide-react";
|
|
16
|
-
import {
|
|
16
|
+
import { Reorder } from "motion/react";
|
|
17
17
|
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
18
|
+
import { useHorizontalPager } from "../../hooks/useHorizontalPager.js";
|
|
18
19
|
import { cn } from "../../lib/utils.js";
|
|
19
20
|
import { moveIcon, readSpringboardLayout, reconcileLayout, SPRINGBOARD_DOCK_LIMIT, toggleFavorite, writeSpringboardLayout, } from "../../state/springboard-layout.js";
|
|
20
21
|
import { emitViewInteraction } from "../../view-telemetry.js";
|
|
@@ -23,8 +24,6 @@ const LONG_PRESS_MS = 450;
|
|
|
23
24
|
/** Finger travel (px) that aborts a long-press — a pan/swipe is not a press, so
|
|
24
25
|
* a horizontal swipe-back can never ghost-fire edit mode mid-gesture. */
|
|
25
26
|
const LONG_PRESS_MOVE_SLOP = 10;
|
|
26
|
-
/** Horizontal drag distance (px) needed to flip to the adjacent page. */
|
|
27
|
-
const SWIPE_THRESHOLD = 60;
|
|
28
27
|
// Memoized so a layout reconcile (install/uninstall/sort) re-renders only the
|
|
29
28
|
// tiles whose props actually changed, not all ~20 on a page.
|
|
30
29
|
const IconTile = memo(function IconTile({ entry, editing, favorited, manageable, onLaunch, onToggleFavorite, onEdit, onDelete, onLongPress, }) {
|
|
@@ -62,12 +61,9 @@ const IconTile = memo(function IconTile({ entry, editing, favorited, manageable,
|
|
|
62
61
|
// gesture interrupts the press — clear the timer so a long-press never
|
|
63
62
|
// ghost-fires edit mode after the user finishes scrolling.
|
|
64
63
|
onPointerCancel: clear, className: cn(
|
|
65
|
-
// ViewTileImage
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
// fallback so a tile reads as a real app icon (not a bare glyph
|
|
69
|
-
// floating on the background) even before/without the image. Filter
|
|
70
|
-
// effects (#9281) and focus rings (#9292) were removed on develop.
|
|
64
|
+
// ViewTileImage renders this surface as an app icon, not as a
|
|
65
|
+
// cropped catalog preview. The button stays one constant hit target
|
|
66
|
+
// and owns hover/focus chrome; the inner visual owns color/glyph.
|
|
71
67
|
"h-16 w-16 overflow-hidden rounded-2xl border border-white/10 bg-black/35 text-white transition-colors hover:bg-black/45", editing && "animate-pulse"), children: _jsx(ViewTileImage, { entry: entry, source: "springboard", containerClassName: "grid h-full w-full place-items-center", glyphClassName: "h-7 w-7", imageTestId: `springboard-image-${entry.id}` }) }), editing ? (_jsx("button", { type: "button", "aria-label": favorited ? `Unpin ${entry.label}` : `Pin ${entry.label}`, "data-testid": `springboard-fav-${entry.id}`, onClick: (e) => {
|
|
72
68
|
e.stopPropagation();
|
|
73
69
|
onToggleFavorite(entry.id);
|
|
@@ -199,40 +195,33 @@ export function Springboard({ entries, loading = false, onLaunch, onEdgeSwipeRig
|
|
|
199
195
|
onDeleteView,
|
|
200
196
|
toggleEditMode,
|
|
201
197
|
]);
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
})
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
}
|
|
232
|
-
}, className: "flex min-h-0 flex-1 items-start justify-center overflow-y-auto px-6 pt-2 pb-8", children: loading && entries.length === 0 ? (_jsx("div", { className: "grid w-full max-w-2xl grid-cols-4 gap-x-4 gap-y-5 sm:grid-cols-5", children: ["a", "b", "c", "d", "e", "f", "g", "h"].map((id) => (_jsxs("div", { className: "flex flex-col items-center gap-1.5 opacity-60", children: [_jsx("div", { className: "h-16 w-16 rounded-2xl bg-bg-accent/50" }), _jsx("div", { className: "h-2.5 w-12 rounded-full bg-bg-accent/50" })] }, id))) })) : (_jsx(Reorder.Group, { axis: "y", values: pages[clampedPage] ?? [], onReorder: (next) => handleReorder(clampedPage, next), className: "grid w-full max-w-2xl grid-cols-4 gap-x-4 gap-y-5 sm:grid-cols-5", children: (pages[clampedPage] ?? []).map((id) => {
|
|
233
|
-
const entry = byId.get(id);
|
|
234
|
-
if (!entry)
|
|
235
|
-
return null;
|
|
236
|
-
return (_jsx(Reorder.Item, { value: id, drag: editing, dragListener: editing, className: "flex justify-center", children: renderTile(entry, favoriteSet.has(id)) }, id));
|
|
237
|
-
}) })) }, "springboard-page"), showPageDots && pages.length > 1 ? (_jsx("div", { className: "flex items-center justify-center gap-2 pb-3", children: pages.map((pageIds, index) => (_jsx("button", { type: "button", "aria-label": `Page ${index + 1}`, "aria-current": index === clampedPage, onClick: () => setActivePage(index), className: cn("h-2 w-2 rounded-full transition-colors", index === clampedPage ? "bg-accent" : "bg-border") }, `dot-${index}-${pageIds[0] ?? "empty"}`))) })) : null] })] }));
|
|
198
|
+
const pager = useHorizontalPager({
|
|
199
|
+
page: clampedPage,
|
|
200
|
+
pageCount: pages.length,
|
|
201
|
+
enabled: !editing && pages.length > 1,
|
|
202
|
+
edgeSwipeRightEnabled: showPageDots && onEdgeSwipeRight != null,
|
|
203
|
+
onEdgeSwipeRight,
|
|
204
|
+
onPageChange: (nextPage) => {
|
|
205
|
+
setActivePage(nextPage);
|
|
206
|
+
emitViewInteraction({
|
|
207
|
+
source: "springboard",
|
|
208
|
+
action: "page-swipe",
|
|
209
|
+
count: nextPage,
|
|
210
|
+
});
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
return (_jsxs("div", { className: cn("flex min-h-0 flex-1 flex-col", className), "data-testid": "springboard", children: [favoriteEntries.length > 0 ? (_jsx("div", { "data-testid": "springboard-dock", className: "mx-3 mt-2 mb-3 flex items-center justify-center gap-3 rounded-3xl border border-white/10 bg-black/45 px-3 py-3 sm:mx-4 sm:gap-4 sm:px-6", children: favoriteEntries.map((entry) => (_jsx("div", { children: renderTile(entry, true) }, `dock-${entry.id}`))) })) : null, _jsxs("div", { className: "relative flex min-h-0 flex-1 flex-col overflow-hidden", children: [_jsx("div", { ref: pager.viewportRef, "data-testid": "springboard-page-window", className: "relative flex min-h-0 flex-1 overflow-hidden touch-pan-y", onPointerDown: pager.handlers.onPointerDown, onPointerMove: pager.handlers.onPointerMove, onPointerUp: pager.handlers.onPointerUp, onPointerCancel: pager.handlers.onPointerCancel, onLostPointerCapture: pager.handlers.onLostPointerCapture, children: _jsx("div", { ref: pager.railRef, "data-testid": "springboard-page-rail", className: "flex h-full min-h-0 w-full motion-reduce:transition-none", children: loading && entries.length === 0 ? (_jsx("div", { className: "flex h-full min-h-0 min-w-full items-start justify-center overflow-y-auto px-6 pt-2 pb-8", children: _jsx("div", { className: "grid w-full max-w-2xl grid-cols-4 gap-x-4 gap-y-5 sm:grid-cols-5", children: ["a", "b", "c", "d", "e", "f", "g", "h"].map((id) => (_jsxs("div", { className: "flex flex-col items-center gap-1.5 opacity-60", children: [_jsx("div", { className: "h-16 w-16 rounded-2xl bg-bg-accent/50" }), _jsx("div", { className: "h-2.5 w-12 rounded-full bg-bg-accent/50" })] }, id))) }) })) : (pages.map((pageIds, pageIndex) => {
|
|
214
|
+
const active = pageIndex === clampedPage;
|
|
215
|
+
return (_jsx("div", { "data-testid": `springboard-page-${pageIndex}`, "aria-hidden": !active, inert: !active || undefined, className: cn("flex h-full min-h-0 min-w-full items-start justify-center overflow-y-auto px-6 pt-2 pb-8", !active && "pointer-events-none"), children: editing && active ? (_jsx(Reorder.Group, { axis: "y", values: pageIds, onReorder: (next) => handleReorder(pageIndex, next), className: "grid w-full max-w-2xl grid-cols-4 gap-x-4 gap-y-5 sm:grid-cols-5", children: pageIds.map((id) => {
|
|
216
|
+
const entry = byId.get(id);
|
|
217
|
+
if (!entry)
|
|
218
|
+
return null;
|
|
219
|
+
return (_jsx(Reorder.Item, { value: id, drag: editing, dragListener: editing, className: "flex justify-center", children: renderTile(entry, favoriteSet.has(id)) }, id));
|
|
220
|
+
}) })) : (_jsx("div", { className: "grid w-full max-w-2xl grid-cols-4 gap-x-4 gap-y-5 sm:grid-cols-5", children: pageIds.map((id) => {
|
|
221
|
+
const entry = byId.get(id);
|
|
222
|
+
if (!entry)
|
|
223
|
+
return null;
|
|
224
|
+
return (_jsx("div", { className: "flex justify-center", children: renderTile(entry, favoriteSet.has(id)) }, id));
|
|
225
|
+
}) })) }, `springboard-page-${pageIndex}`));
|
|
226
|
+
})) }) }), showPageDots && pages.length > 1 ? (_jsx("div", { className: "flex items-center justify-center gap-2 pb-3", children: pages.map((pageIds, index) => (_jsx("button", { type: "button", "aria-label": `Page ${index + 1}`, "aria-current": index === clampedPage, onClick: () => setActivePage(index), className: cn("h-2 w-2 rounded-full transition-colors", index === clampedPage ? "bg-accent" : "bg-border") }, `dot-${index}-${pageIds[0] ?? "empty"}`))) })) : null] })] }));
|
|
238
227
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpringboardSurface.d.ts","sourceRoot":"","sources":["../../../../../../src/components/pages/SpringboardSurface.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"SpringboardSurface.d.ts","sourceRoot":"","sources":["../../../../../../src/components/pages/SpringboardSurface.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAsI/B,MAAM,WAAW,uBAAuB;IACtC,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;CACrC;AAED,eAAO,MAAM,kBAAkB,0DAE5B,uBAAuB,KAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAmR5C,CAAC"}
|