@elizaos/ui 2.0.3-beta.3 → 2.0.3-beta.5
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.d.ts.map +1 -1
- package/App.js +3 -4
- 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/chat/widgets/home-widget-card.d.ts.map +1 -1
- package/components/chat/widgets/home-widget-card.js +1 -3
- package/components/config-ui/config-field.js +1 -1
- package/components/pages/Springboard.d.ts.map +1 -1
- package/components/pages/Springboard.js +37 -48
- 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/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
|
@@ -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,20 +61,17 @@ 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);
|
|
74
70
|
}, className: cn(
|
|
75
71
|
// Filled chips stay legible across image and dark tile backgrounds.
|
|
76
|
-
"absolute -right-1.5 -top-1.5 grid h-5 w-5 place-items-center rounded-full text-[11px] font-bold shadow-md
|
|
77
|
-
? "bg-accent text-white
|
|
78
|
-
: "bg-white text-neutral-900
|
|
72
|
+
"absolute -right-1.5 -top-1.5 grid h-5 w-5 place-items-center rounded-full border text-[11px] font-bold shadow-md", favorited
|
|
73
|
+
? "border-black/20 bg-accent text-white"
|
|
74
|
+
: "border-black/15 bg-white text-neutral-900"), children: favorited ? "★" : "+" })) : null, editing && manageable ? (_jsxs("div", { className: "absolute -left-1.5 -top-1.5 flex gap-1", children: [onEdit ? (_jsx("button", { type: "button", "aria-label": `Edit ${entry.label}`, "data-testid": `springboard-edit-${entry.id}`, onClick: (e) => {
|
|
79
75
|
e.stopPropagation();
|
|
80
76
|
onEdit(entry.id);
|
|
81
77
|
}, className: "grid h-5 w-5 place-items-center rounded-full bg-bg-accent text-foreground", children: _jsx(Pencil, { className: "h-3 w-3", "aria-hidden": "true" }) })) : null, onDelete ? (_jsx("button", { type: "button", "aria-label": `Delete ${entry.label}`, "data-testid": `springboard-delete-${entry.id}`, onClick: (e) => {
|
|
@@ -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"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { isViewVisible } from "@elizaos/core";
|
|
3
3
|
import * as React from "react";
|
|
4
|
+
import { getElectrobunRendererRpc, registerDynamicView, unregisterDynamicView, } from "../../bridge/electrobun-rpc.js";
|
|
4
5
|
import { useRoutableViews } from "../../hooks/useAvailableViews.js";
|
|
5
6
|
import { useViewCatalog } from "../../hooks/useViewCatalog.js";
|
|
6
7
|
import { viewToEntry } from "../../hooks/view-catalog.js";
|
|
7
8
|
import { getActiveViewModality, } from "../../platform/platform-guards.js";
|
|
8
9
|
import { setSpringboardEditing, setSpringboardPage, setSpringboardPageCount, useShellSurface, } from "../../state/shell-surface-store.js";
|
|
10
|
+
import { useIsDeveloperMode } from "../../state/useDeveloperMode.js";
|
|
9
11
|
import { useEnabledViewKinds } from "../../state/useViewKinds.js";
|
|
10
12
|
import { recordRecentViewId } from "../../view-recents.js";
|
|
11
13
|
import { Springboard } from "./Springboard.js";
|
|
@@ -17,8 +19,14 @@ const HIDDEN_SPRINGBOARD_VIEW_IDS = new Set([
|
|
|
17
19
|
"character",
|
|
18
20
|
"character-select",
|
|
19
21
|
"voice",
|
|
22
|
+
"background",
|
|
23
|
+
]);
|
|
24
|
+
const HIDDEN_SPRINGBOARD_PATHS = new Set([
|
|
25
|
+
"/chat",
|
|
26
|
+
"/views",
|
|
27
|
+
"/apps",
|
|
28
|
+
"/background",
|
|
20
29
|
]);
|
|
21
|
-
const HIDDEN_SPRINGBOARD_PATHS = new Set(["/chat", "/views", "/apps"]);
|
|
22
30
|
const SPRINGBOARD_SYSTEM_ENTRY_IDS = new Set([
|
|
23
31
|
"settings",
|
|
24
32
|
"tasks",
|
|
@@ -37,7 +45,6 @@ const SPRINGBOARD_SYSTEM_ENTRY_IDS = new Set([
|
|
|
37
45
|
"runtime",
|
|
38
46
|
"database",
|
|
39
47
|
"logs",
|
|
40
|
-
"background",
|
|
41
48
|
"stream",
|
|
42
49
|
"desktop",
|
|
43
50
|
]);
|
|
@@ -74,15 +81,36 @@ function dedupeEntries(entries) {
|
|
|
74
81
|
}
|
|
75
82
|
return out;
|
|
76
83
|
}
|
|
84
|
+
const EMPTY_DYNAMIC_VIEW_FORM = {
|
|
85
|
+
id: "",
|
|
86
|
+
title: "",
|
|
87
|
+
entrypoint: "",
|
|
88
|
+
description: "",
|
|
89
|
+
};
|
|
90
|
+
function dynamicViewBridgeAvailable() {
|
|
91
|
+
const request = getElectrobunRendererRpc()?.request;
|
|
92
|
+
return (typeof request?.dynamicViewRegister === "function" &&
|
|
93
|
+
typeof request?.dynamicViewUnregister === "function");
|
|
94
|
+
}
|
|
95
|
+
function editableEntrypointFor(entry) {
|
|
96
|
+
return (entry.view?.bundleUrl ??
|
|
97
|
+
entry.view?.path ??
|
|
98
|
+
entry.path ??
|
|
99
|
+
`/apps/${entry.id}`);
|
|
100
|
+
}
|
|
77
101
|
export const SpringboardSurface = React.memo(function SpringboardSurface({ onNavigateHomeFromEdge, }) {
|
|
78
|
-
const { views, loading } = useRoutableViews();
|
|
79
|
-
const { entries: catalogEntries, get: getCatalogEntry } = useViewCatalog();
|
|
102
|
+
const { views, loading, refresh: refreshViews } = useRoutableViews();
|
|
103
|
+
const { entries: catalogEntries, get: getCatalogEntry, refresh: refreshCatalog, } = useViewCatalog();
|
|
80
104
|
const enabledKinds = useEnabledViewKinds();
|
|
105
|
+
const developerMode = useIsDeveloperMode();
|
|
81
106
|
const activeModality = React.useMemo(() => getActiveViewModality(), []);
|
|
107
|
+
const [dynamicViewForm, setDynamicViewForm] = React.useState(EMPTY_DYNAMIC_VIEW_FORM);
|
|
108
|
+
const [dynamicViewStatus, setDynamicViewStatus] = React.useState(null);
|
|
82
109
|
// Page index + edit mode come from the single shell-surface store, so the
|
|
83
110
|
// springboard, the rail, and its one indicator can never disagree (and edit
|
|
84
111
|
// mode is auto-reset by the store when the user leaves the springboard).
|
|
85
112
|
const { springboardPage, springboardEditing } = useShellSurface();
|
|
113
|
+
const showDynamicViewControls = developerMode && dynamicViewBridgeAvailable();
|
|
86
114
|
const loadedEntries = React.useMemo(() => views
|
|
87
115
|
.filter((view) => isVisibleSpringboardView(view, enabledKinds, activeModality))
|
|
88
116
|
.map(viewToEntry), [activeModality, enabledKinds, views]);
|
|
@@ -92,6 +120,10 @@ export const SpringboardSurface = React.memo(function SpringboardSurface({ onNav
|
|
|
92
120
|
.sort(compareEntryLabels), [activeModality, catalogEntries]);
|
|
93
121
|
const entries = React.useMemo(() => dedupeEntries([...loadedEntries, ...availableEntries]), [availableEntries, loadedEntries]);
|
|
94
122
|
const entryById = React.useMemo(() => new Map(entries.map((entry) => [entry.id, entry])), [entries]);
|
|
123
|
+
const refreshDynamicViews = React.useCallback(() => {
|
|
124
|
+
refreshViews();
|
|
125
|
+
refreshCatalog();
|
|
126
|
+
}, [refreshCatalog, refreshViews]);
|
|
95
127
|
const handleLaunch = React.useCallback((entry) => {
|
|
96
128
|
if (entry.state !== "loaded") {
|
|
97
129
|
void getCatalogEntry(entry).catch(() => {
|
|
@@ -116,5 +148,83 @@ export const SpringboardSurface = React.memo(function SpringboardSurface({ onNav
|
|
|
116
148
|
// Sandboxed navigation is best-effort.
|
|
117
149
|
}
|
|
118
150
|
}, [getCatalogEntry]);
|
|
119
|
-
|
|
151
|
+
const canManageView = React.useCallback((id) => {
|
|
152
|
+
if (!showDynamicViewControls)
|
|
153
|
+
return false;
|
|
154
|
+
const entry = entryById.get(id);
|
|
155
|
+
return (entry?.state === "loaded" && entry.kind === "view" && !entry.builtin);
|
|
156
|
+
}, [entryById, showDynamicViewControls]);
|
|
157
|
+
const updateDynamicField = React.useCallback((field, value) => {
|
|
158
|
+
setDynamicViewForm((current) => ({ ...current, [field]: value }));
|
|
159
|
+
}, []);
|
|
160
|
+
const handleEditDynamicView = React.useCallback((id) => {
|
|
161
|
+
const entry = entryById.get(id);
|
|
162
|
+
if (!entry)
|
|
163
|
+
return;
|
|
164
|
+
setDynamicViewForm({
|
|
165
|
+
id: entry.id,
|
|
166
|
+
title: entry.label,
|
|
167
|
+
entrypoint: editableEntrypointFor(entry),
|
|
168
|
+
description: entry.description ?? "",
|
|
169
|
+
});
|
|
170
|
+
setDynamicViewStatus(null);
|
|
171
|
+
}, [entryById]);
|
|
172
|
+
const handleSaveDynamicView = React.useCallback(async (event) => {
|
|
173
|
+
event.preventDefault();
|
|
174
|
+
const id = dynamicViewForm.id.trim();
|
|
175
|
+
const title = dynamicViewForm.title.trim();
|
|
176
|
+
const entrypoint = dynamicViewForm.entrypoint.trim();
|
|
177
|
+
const description = dynamicViewForm.description.trim();
|
|
178
|
+
if (!id || !title || !entrypoint) {
|
|
179
|
+
setDynamicViewStatus("Dynamic view ID, title, and entrypoint are required.");
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const manifest = {
|
|
183
|
+
id,
|
|
184
|
+
title,
|
|
185
|
+
source: "developer",
|
|
186
|
+
entrypoint,
|
|
187
|
+
placement: "canvas",
|
|
188
|
+
};
|
|
189
|
+
if (description)
|
|
190
|
+
manifest.description = description;
|
|
191
|
+
try {
|
|
192
|
+
const saved = await registerDynamicView(manifest, { update: true });
|
|
193
|
+
if (!saved) {
|
|
194
|
+
setDynamicViewStatus("Dynamic view bridge is unavailable.");
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
setDynamicViewStatus(`Saved ${saved.title}.`);
|
|
198
|
+
refreshDynamicViews();
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
setDynamicViewStatus(error instanceof Error ? error.message : String(error));
|
|
202
|
+
}
|
|
203
|
+
}, [dynamicViewForm, refreshDynamicViews]);
|
|
204
|
+
const handleDeleteDynamicView = React.useCallback(async (id) => {
|
|
205
|
+
const entry = entryById.get(id);
|
|
206
|
+
if (!entry)
|
|
207
|
+
return;
|
|
208
|
+
try {
|
|
209
|
+
const result = await unregisterDynamicView(id);
|
|
210
|
+
if (!result) {
|
|
211
|
+
setDynamicViewStatus("Dynamic view bridge is unavailable.");
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (!result.removed) {
|
|
215
|
+
setDynamicViewStatus(`${entry.label} was not registered.`);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
setDynamicViewStatus(`Deleted ${entry.label}.`);
|
|
219
|
+
setDynamicViewForm((current) => current.id === id ? { ...EMPTY_DYNAMIC_VIEW_FORM } : current);
|
|
220
|
+
refreshDynamicViews();
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
setDynamicViewStatus(error instanceof Error ? error.message : String(error));
|
|
224
|
+
}
|
|
225
|
+
}, [entryById, refreshDynamicViews]);
|
|
226
|
+
return (_jsxs("div", { className: "absolute inset-0 flex min-h-0 flex-col px-0 pb-[calc(var(--eliza-mobile-nav-offset,0px)+var(--safe-area-bottom,0px)+var(--eliza-continuous-chat-clearance,5.25rem)+1.75rem)]", children: [showDynamicViewControls ? (_jsxs("form", { "aria-label": "Dynamic view management", onSubmit: handleSaveDynamicView, className: "mx-3 mb-2 grid flex-none gap-2 rounded-lg border border-white/10 bg-black/55 p-3 text-white sm:mx-4", children: [_jsxs("div", { className: "grid gap-2 sm:grid-cols-2", children: [_jsxs("label", { className: "grid gap-1 text-xs font-medium", children: ["Dynamic view ID", _jsx("input", { className: "h-9 rounded-md border border-white/15 bg-black/40 px-2 text-sm text-white outline-none", value: dynamicViewForm.id, onChange: (event) => updateDynamicField("id", event.currentTarget.value) })] }), _jsxs("label", { className: "grid gap-1 text-xs font-medium", children: ["Dynamic view title", _jsx("input", { className: "h-9 rounded-md border border-white/15 bg-black/40 px-2 text-sm text-white outline-none", value: dynamicViewForm.title, onChange: (event) => updateDynamicField("title", event.currentTarget.value) })] }), _jsxs("label", { className: "grid gap-1 text-xs font-medium", children: ["Dynamic view entrypoint", _jsx("input", { className: "h-9 rounded-md border border-white/15 bg-black/40 px-2 text-sm text-white outline-none", value: dynamicViewForm.entrypoint, onChange: (event) => updateDynamicField("entrypoint", event.currentTarget.value) })] }), _jsxs("label", { className: "grid gap-1 text-xs font-medium", children: ["Dynamic view description", _jsx("input", { className: "h-9 rounded-md border border-white/15 bg-black/40 px-2 text-sm text-white outline-none", value: dynamicViewForm.description, onChange: (event) => updateDynamicField("description", event.currentTarget.value) })] })] }), _jsxs("div", { className: "flex min-h-9 flex-wrap items-center gap-2", children: [_jsx("button", { type: "submit", className: "h-8 rounded-md bg-accent px-3 text-sm font-semibold text-white hover:bg-accent/85", children: "Save" }), _jsx("button", { type: "button", className: "h-8 rounded-md border border-white/15 px-3 text-sm font-semibold text-white hover:bg-white/10", onClick: () => {
|
|
227
|
+
setDynamicViewForm({ ...EMPTY_DYNAMIC_VIEW_FORM });
|
|
228
|
+
setDynamicViewStatus(null);
|
|
229
|
+
}, children: "Clear" }), dynamicViewStatus ? (_jsx("p", { role: "status", className: "text-sm text-white/80", children: dynamicViewStatus })) : null] })] })) : null, _jsx(Springboard, { entries: entries, loading: loading, onLaunch: (entry) => handleLaunch(entryById.get(entry.id) ?? entry), onEdgeSwipeRight: onNavigateHomeFromEdge, canManageView: showDynamicViewControls ? canManageView : undefined, onEditView: showDynamicViewControls ? handleEditDynamicView : undefined, onDeleteView: showDynamicViewControls ? handleDeleteDynamicView : undefined, page: springboardPage, onPageChange: setSpringboardPage, onPageCountChange: setSpringboardPageCount, editing: springboardEditing, onEditingChange: setSpringboardEditing, showPageDots: false })] }));
|
|
120
230
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContinuousChatOverlay.d.ts","sourceRoot":"","sources":["../../../../../../src/components/shell/ContinuousChatOverlay.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAc/B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;
|
|
1
|
+
{"version":3,"file":"ContinuousChatOverlay.d.ts","sourceRoot":"","sources":["../../../../../../src/components/shell/ContinuousChatOverlay.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAc/B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAqCnF,OAAO,KAAK,EAAmB,eAAe,EAAE,MAAM,sBAAsB,CAAC;AA8D7E;;+CAE+C;AAC/C,MAAM,MAAM,SAAS,GACjB,QAAQ,GACR,OAAO,GACP,iBAAiB,GACjB,mBAAmB,GACnB,WAAW,CAAC;AAEhB;;;;;;;;GAQG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAw0B1D,wBAAgB,qBAAqB,CAAC,EACpC,UAAU,EACV,SAAmB,EACnB,KAAK,EAAE,SAAS,GACjB,EAAE;IACD,UAAU,EAAE,eAAe,CAAC;IAC5B,qFAAqF;IACrF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,sBAAsB,CAAC;CAChC,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAknFpB"}
|