@agimon-ai/po-template-elegant 0.0.0-alpha.2 → 0.0.0-alpha.20
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/extensions/web.mjs +649 -78
- package/dist/extensions/web.mjs.map +1 -1
- package/package.json +12 -12
package/dist/extensions/web.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { defineWebPlugin, defineWebTemplate } from "@agimon-ai/po-core/web";
|
|
2
|
-
import { DEFAULT_REPOSITORY_SETTINGS_SECTION, DEFAULT_SETTINGS_SECTION, DashboardRendererProvider, HOST_SLOTS, findTransientTab, pluginActivityGroups, refreshWebPluginCompositions, sessionsStore, setDockOpen, settingsSection, transientTabsStore, uiStore, updateWorkspaceAdmission, useActiveSession, useActiveSessionMeta, useDashboardRoute, useDashboardState, useNoSessions, usePluginSlotProps, useSessionMcp, useWebPluginRegistry, watchDashboardTranscript, webTabs, workspaceAdmissionStore, workspacesStore } from "@agimon-ai/po-web-dashboard";
|
|
3
|
-
import { ActivityDock, AppearanceSettings, CommandPalette, Composer, ContributedSettings, DialogOverlay, ImageSettings, NotificationSettings, PairingApprovalDialog, PluginSettings, PluginSurface, ProviderSettings, RefusedCard, RemoteAccessDialog, RemoteControlSettings, RepositoryWorkspace, SelectionBar, SessionActivity, SessionMcp, SessionRailDialogs, SessionTranscriptView, SettingsMenu, SettingsPanelHost, ThreadView, Timeline, TopBar, WelcomePanel, useSessionRail } from "@agimon-ai/po-web-dashboard/views";
|
|
2
|
+
import { DEFAULT_REPOSITORY_SETTINGS_SECTION, DEFAULT_SETTINGS_SECTION, DashboardRendererProvider, HOST_SLOTS, admitDashboardWorkspace, answerLogin, cancelLogin, createPlainSession, findTransientTab, hasSessionProtocol, listDirectory, listPoFolders, listProviders, pluginActivityGroups, readLogin, refreshWebPluginCompositions, sessionsStore, setDockOpen, settingsSection, startLogin, submitComposerDraft, transientTabsStore, uiStore, updateComposerState, updateWorkspaceAdmission, useActiveSession, useActiveSessionMeta, useDashboardRoute, useDashboardState, useNoSessions, usePluginSlotProps, useSessionMcp, useWebPluginRegistry, watchDashboardTranscript, webTabs, workspaceAdmissionStore, workspacesStore } from "@agimon-ai/po-web-dashboard";
|
|
3
|
+
import { ActivityDock, AppearanceSettings, CommandPalette, Composer, ContributedSettings, DialogOverlay, ImageSettings, LoginFlowDialog, NotificationSettings, PairingApprovalDialog, PluginSettings, PluginSurface, ProviderSettings, RefusedCard, RemoteAccessDialog, RemoteControlSettings, RepositoryWorkspace, SelectionBar, SessionActivity, SessionMcp, SessionRailDialogs, SessionTranscriptView, SettingsMenu, SettingsPanelHost, ThreadView, Timeline, TopBar, WelcomePanel, useSessionRail } from "@agimon-ai/po-web-dashboard/views";
|
|
4
4
|
import { useStore } from "@tanstack/react-store";
|
|
5
|
-
import { useEffect, useRef, useState } from "react";
|
|
6
|
-
import { ActivityIcon, AlertIcon, Avatar, AvatarFallback, AvatarImage, BranchIcon, Button, ChevronUpIcon, CloseIcon, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, Dot, Drawer, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, FolderIcon, ForkIcon, GearIcon, Input, Kbd, KebabIcon, LoaderIcon, NavTab, OptionRow, PlusIcon, ShieldIcon, cn } from "@agimon-ai/po-web-components";
|
|
5
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
6
|
+
import { ActivityIcon, AlertIcon, ArrowRightIcon, Avatar, AvatarFallback, AvatarImage, BranchIcon, Button, Checkbox, ChevronUpIcon, CloseIcon, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, Dot, Drawer, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, FolderIcon, ForkIcon, GearIcon, Input, Kbd, KebabIcon, LoaderIcon, LockIcon, NavTab, OptionRow, PlusIcon, RadioGroup, RadioGroupItem, SendIcon, ShieldIcon, Skeleton, Textarea, cn } from "@agimon-ai/po-web-components";
|
|
7
7
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
import { Link, useNavigate } from "@tanstack/react-router";
|
|
9
9
|
//#region src/extensions/(frontend)/template/_components/ElegantFolderBrowser.tsx
|
|
10
|
-
function folderName$
|
|
10
|
+
function folderName$2(path) {
|
|
11
11
|
return path.slice(path.lastIndexOf("/") + 1) || path;
|
|
12
12
|
}
|
|
13
13
|
/** Walks the server's folders inline: up, into a child, or pick the current folder. */
|
|
@@ -31,7 +31,7 @@ function ElegantFolderBrowser({ start, listDirectory, onSelect }) {
|
|
|
31
31
|
}, [target, listDirectory]);
|
|
32
32
|
return /* @__PURE__ */ jsxs("div", {
|
|
33
33
|
"data-testid": "folder-browser",
|
|
34
|
-
className: "flex flex-col gap-1 rounded-lg border border-
|
|
34
|
+
className: "flex flex-col gap-1 rounded-lg border border-po-border-soft bg-po-panel/40 p-1.5",
|
|
35
35
|
children: [
|
|
36
36
|
/* @__PURE__ */ jsxs("div", {
|
|
37
37
|
className: "flex items-center gap-1 px-1",
|
|
@@ -47,7 +47,7 @@ function ElegantFolderBrowser({ start, listDirectory, onSelect }) {
|
|
|
47
47
|
children: /* @__PURE__ */ jsx(ChevronUpIcon, { className: "h-3 w-3" })
|
|
48
48
|
}),
|
|
49
49
|
/* @__PURE__ */ jsx("span", {
|
|
50
|
-
className: "min-w-0 flex-1 truncate text-sm text-
|
|
50
|
+
className: "min-w-0 flex-1 truncate text-sm text-po-dim",
|
|
51
51
|
title: listing?.path,
|
|
52
52
|
children: listing?.path ?? "loading…"
|
|
53
53
|
}),
|
|
@@ -62,7 +62,7 @@ function ElegantFolderBrowser({ start, listDirectory, onSelect }) {
|
|
|
62
62
|
]
|
|
63
63
|
}),
|
|
64
64
|
error ? /* @__PURE__ */ jsx("p", {
|
|
65
|
-
className: "px-2 py-1 text-sm text-
|
|
65
|
+
className: "px-2 py-1 text-sm text-po-red",
|
|
66
66
|
children: error
|
|
67
67
|
}) : null,
|
|
68
68
|
/* @__PURE__ */ jsxs("div", {
|
|
@@ -70,14 +70,14 @@ function ElegantFolderBrowser({ start, listDirectory, onSelect }) {
|
|
|
70
70
|
"aria-label": "folders",
|
|
71
71
|
className: "max-h-40 overflow-y-auto",
|
|
72
72
|
children: [listing !== null && listing.directories.length === 0 ? /* @__PURE__ */ jsx("p", {
|
|
73
|
-
className: "px-2 py-1 text-sm text-
|
|
73
|
+
className: "px-2 py-1 text-sm text-po-dim",
|
|
74
74
|
children: "no folders here"
|
|
75
75
|
}) : null, listing?.directories.map((directory) => /* @__PURE__ */ jsx(OptionRow, {
|
|
76
76
|
density: "compact",
|
|
77
77
|
"data-testid": "folder-browser-entry",
|
|
78
78
|
onClick: () => setTarget(directory),
|
|
79
79
|
className: "w-full px-2.5 py-1 ",
|
|
80
|
-
children: folderName$
|
|
80
|
+
children: folderName$2(directory)
|
|
81
81
|
}, directory))]
|
|
82
82
|
})
|
|
83
83
|
]
|
|
@@ -87,9 +87,9 @@ function ElegantFolderBrowser({ start, listDirectory, onSelect }) {
|
|
|
87
87
|
//#region src/extensions/(frontend)/template/_components/ElegantAddWorkspaceDialog.tsx
|
|
88
88
|
const SUGGESTION_DEBOUNCE_MS = 120;
|
|
89
89
|
const NO_HIGHLIGHT = -1;
|
|
90
|
-
const TRAILING_SEPARATORS = /\/+$/u;
|
|
91
|
-
function folderName(path) {
|
|
92
|
-
const trimmed = path.trim().replace(TRAILING_SEPARATORS, "");
|
|
90
|
+
const TRAILING_SEPARATORS$1 = /\/+$/u;
|
|
91
|
+
function folderName$1(path) {
|
|
92
|
+
const trimmed = path.trim().replace(TRAILING_SEPARATORS$1, "");
|
|
93
93
|
return trimmed.slice(trimmed.lastIndexOf("/") + 1);
|
|
94
94
|
}
|
|
95
95
|
/** Adds a workspace by name, by folder, or both; a name alone gets a new default folder. */
|
|
@@ -104,7 +104,7 @@ function ElegantAddWorkspaceDialog({ suggestedPaths, actions }) {
|
|
|
104
104
|
const [suggestions, setSuggestions] = useState([]);
|
|
105
105
|
const [highlight, setHighlight] = useState(NO_HIGHLIGHT);
|
|
106
106
|
const pathInput = useRef(null);
|
|
107
|
-
const shownName = nameEdited ? name : folderName(path);
|
|
107
|
+
const shownName = nameEdited ? name : folderName$1(path);
|
|
108
108
|
useEffect(() => {
|
|
109
109
|
const typed = path.trim();
|
|
110
110
|
if (typed === "") return;
|
|
@@ -128,7 +128,7 @@ function ElegantAddWorkspaceDialog({ suggestedPaths, actions }) {
|
|
|
128
128
|
changePath(`${directory}/`);
|
|
129
129
|
pathInput.current?.focus();
|
|
130
130
|
};
|
|
131
|
-
const trimmedPath = path.trim().replace(TRAILING_SEPARATORS, "") || (path.trim() === "" ? "" : "/");
|
|
131
|
+
const trimmedPath = path.trim().replace(TRAILING_SEPARATORS$1, "") || (path.trim() === "" ? "" : "/");
|
|
132
132
|
const canSubmit = !busy && (trimmedPath !== "" || shownName.trim() !== "");
|
|
133
133
|
const submit = async () => {
|
|
134
134
|
if (!canSubmit) return;
|
|
@@ -149,7 +149,7 @@ function ElegantAddWorkspaceDialog({ suggestedPaths, actions }) {
|
|
|
149
149
|
htmlFor: "add-workspace-name",
|
|
150
150
|
className: "flex flex-col gap-1",
|
|
151
151
|
children: [/* @__PURE__ */ jsx("span", {
|
|
152
|
-
className: "text-base font-medium text-
|
|
152
|
+
className: "text-base font-medium text-po-dim",
|
|
153
153
|
children: "name"
|
|
154
154
|
}), /* @__PURE__ */ jsx(Input, {
|
|
155
155
|
id: "add-workspace-name",
|
|
@@ -170,9 +170,9 @@ function ElegantAddWorkspaceDialog({ suggestedPaths, actions }) {
|
|
|
170
170
|
htmlFor: "add-workspace-root",
|
|
171
171
|
className: "flex flex-col gap-1",
|
|
172
172
|
children: [/* @__PURE__ */ jsxs("span", {
|
|
173
|
-
className: "text-base font-medium text-
|
|
173
|
+
className: "text-base font-medium text-po-dim",
|
|
174
174
|
children: ["folder ", /* @__PURE__ */ jsx("span", {
|
|
175
|
-
className: "text-
|
|
175
|
+
className: "text-po-dim",
|
|
176
176
|
children: "(optional; type a path or browse)"
|
|
177
177
|
})]
|
|
178
178
|
}), /* @__PURE__ */ jsxs("span", {
|
|
@@ -219,7 +219,7 @@ function ElegantAddWorkspaceDialog({ suggestedPaths, actions }) {
|
|
|
219
219
|
role: "listbox",
|
|
220
220
|
"aria-label": "matching directories",
|
|
221
221
|
"data-testid": "add-workspace-suggestions",
|
|
222
|
-
className: "max-h-40 overflow-y-auto rounded-lg border border-
|
|
222
|
+
className: "max-h-40 overflow-y-auto rounded-lg border border-po-border-soft bg-po-panel/40 p-1.5",
|
|
223
223
|
children: suggestions.map((directory, index) => /* @__PURE__ */ jsx(OptionRow, {
|
|
224
224
|
density: "compact",
|
|
225
225
|
active: index === highlight,
|
|
@@ -242,11 +242,11 @@ function ElegantAddWorkspaceDialog({ suggestedPaths, actions }) {
|
|
|
242
242
|
}) : null,
|
|
243
243
|
trimmedPath === "" && shownName.trim() !== "" ? /* @__PURE__ */ jsxs("p", {
|
|
244
244
|
"data-testid": "add-workspace-default-hint",
|
|
245
|
-
className: "text-sm text-
|
|
245
|
+
className: "text-sm text-po-dim",
|
|
246
246
|
children: ["creates ~/.po/workspace/", shownName.trim()]
|
|
247
247
|
}) : null,
|
|
248
248
|
error ? /* @__PURE__ */ jsx("pre", {
|
|
249
|
-
className: "max-h-28 overflow-y-auto rounded border border-
|
|
249
|
+
className: "max-h-28 overflow-y-auto rounded border border-po-edge-red bg-po-tint-red/40 px-2.5 py-2 text-sm whitespace-pre-wrap text-po-red",
|
|
250
250
|
children: error
|
|
251
251
|
}) : null,
|
|
252
252
|
/* @__PURE__ */ jsxs(DialogFooter, { children: [/* @__PURE__ */ jsx(Button, {
|
|
@@ -286,12 +286,12 @@ function ElegantPendingSetup({ sessionId, setup, actions }) {
|
|
|
286
286
|
};
|
|
287
287
|
return /* @__PURE__ */ jsxs("div", {
|
|
288
288
|
"data-testid": `pending-session-${setup.id}`,
|
|
289
|
-
className: "ml-9 flex flex-col gap-0.5 rounded-lg border border-dashed border-
|
|
289
|
+
className: "ml-9 flex flex-col gap-0.5 rounded-lg border border-dashed border-po-border-soft px-3 py-2",
|
|
290
290
|
children: [
|
|
291
291
|
/* @__PURE__ */ jsxs("div", {
|
|
292
292
|
className: "flex items-center justify-between gap-2",
|
|
293
293
|
children: [/* @__PURE__ */ jsx("span", {
|
|
294
|
-
className: "truncate text-base font-semibold text-
|
|
294
|
+
className: "truncate text-base font-semibold text-po-hi",
|
|
295
295
|
children: setup.name
|
|
296
296
|
}), /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
|
|
297
297
|
asChild: true,
|
|
@@ -310,17 +310,17 @@ function ElegantPendingSetup({ sessionId, setup, actions }) {
|
|
|
310
310
|
}) })] })]
|
|
311
311
|
}),
|
|
312
312
|
/* @__PURE__ */ jsx("p", {
|
|
313
|
-
className: setup.failed ? "text-sm text-
|
|
313
|
+
className: setup.failed ? "text-sm text-po-red" : "text-sm text-po-dim",
|
|
314
314
|
children: setup.status
|
|
315
315
|
}),
|
|
316
316
|
setup.recovery ? /* @__PURE__ */ jsx("p", {
|
|
317
317
|
role: setup.failed ? "alert" : void 0,
|
|
318
|
-
className: "text-sm text-
|
|
318
|
+
className: "text-sm text-po-dim",
|
|
319
319
|
children: setup.recovery
|
|
320
320
|
}) : null,
|
|
321
321
|
error ? /* @__PURE__ */ jsx("p", {
|
|
322
322
|
role: "alert",
|
|
323
|
-
className: "text-sm text-
|
|
323
|
+
className: "text-sm text-po-red",
|
|
324
324
|
children: error
|
|
325
325
|
}) : null
|
|
326
326
|
]
|
|
@@ -342,7 +342,7 @@ function ElegantSessionCard({ session, actions }) {
|
|
|
342
342
|
};
|
|
343
343
|
const { active } = session;
|
|
344
344
|
const error = removeError || session.error;
|
|
345
|
-
const tileClass = active ? "rounded-lg border border-
|
|
345
|
+
const tileClass = active ? "rounded-lg border border-po-edge-green bg-po-tint-green px-3 hover:bg-po-tint-green" : "rounded-lg border border-transparent px-3 hover:bg-po-panel";
|
|
346
346
|
const failed = session.status.startsWith("failed") || session.status.includes(" failed");
|
|
347
347
|
const running = session.status.startsWith("running");
|
|
348
348
|
const commitRename = () => {
|
|
@@ -370,7 +370,7 @@ function ElegantSessionCard({ session, actions }) {
|
|
|
370
370
|
src: session.profile.avatarUrl,
|
|
371
371
|
alt: ""
|
|
372
372
|
}) : null, /* @__PURE__ */ jsx(AvatarFallback, {
|
|
373
|
-
className: "bg-
|
|
373
|
+
className: "bg-po-tint-green text-xs font-semibold text-po-green",
|
|
374
374
|
children: session.profile?.initials ?? "PO"
|
|
375
375
|
})]
|
|
376
376
|
}), /* @__PURE__ */ jsxs("span", {
|
|
@@ -380,27 +380,27 @@ function ElegantSessionCard({ session, actions }) {
|
|
|
380
380
|
children: [
|
|
381
381
|
session.nested && session.provenance === "workflow-session" ? /* @__PURE__ */ jsx(ActivityIcon, {
|
|
382
382
|
"aria-label": "workflow session",
|
|
383
|
-
className: `mt-1 size-3 shrink-0 ${active ? "text-
|
|
383
|
+
className: `mt-1 size-3 shrink-0 ${active ? "text-po-green" : "text-po-faint"}`
|
|
384
384
|
}) : session.nested && session.provenance ? /* @__PURE__ */ jsx(ForkIcon, {
|
|
385
385
|
"aria-label": session.provenance === "worktree" ? "automatic per-conversation worktree" : session.provenance,
|
|
386
|
-
className: `mt-1 size-3 shrink-0 ${active ? "text-
|
|
386
|
+
className: `mt-1 size-3 shrink-0 ${active ? "text-po-green" : "text-po-faint"}`
|
|
387
387
|
}) : null,
|
|
388
388
|
/* @__PURE__ */ jsx("span", {
|
|
389
|
-
className: "min-w-0 flex-1 text-base font-semibold break-words text-
|
|
389
|
+
className: "min-w-0 flex-1 text-base font-semibold break-words text-po-hi",
|
|
390
390
|
children: session.name || "Untitled"
|
|
391
391
|
}),
|
|
392
392
|
session.ordinal <= 9 ? /* @__PURE__ */ jsx("span", {
|
|
393
393
|
title: `press ${String(session.ordinal)} to focus`,
|
|
394
|
-
className: "grid size-5 shrink-0 place-items-center rounded-full bg-
|
|
394
|
+
className: "grid size-5 shrink-0 place-items-center rounded-full bg-po-panel text-2xs text-po-dim transition-opacity group-focus-within:opacity-0 group-hover:opacity-0",
|
|
395
395
|
children: session.ordinal
|
|
396
396
|
}) : null
|
|
397
397
|
]
|
|
398
398
|
}), /* @__PURE__ */ jsxs("span", {
|
|
399
|
-
className: `flex min-w-0 items-start gap-1.5 text-sm leading-snug ${failed ? "text-
|
|
399
|
+
className: `flex min-w-0 items-start gap-1.5 text-sm leading-snug ${failed ? "text-po-red" : running ? "text-po-yellow" : active ? "text-po-text" : "text-po-dim"}`,
|
|
400
400
|
children: [session.awaitingInput ? /* @__PURE__ */ jsx(AlertIcon, {
|
|
401
401
|
"data-testid": "session-awaiting-input",
|
|
402
402
|
"aria-label": "Waiting for your input",
|
|
403
|
-
className: "mt-0.5 size-3 shrink-0 text-
|
|
403
|
+
className: "mt-0.5 size-3 shrink-0 text-po-magenta"
|
|
404
404
|
}) : running ? /* @__PURE__ */ jsx(LoaderIcon, {
|
|
405
405
|
"aria-hidden": true,
|
|
406
406
|
className: "mt-0.5 size-3 shrink-0 animate-spin"
|
|
@@ -417,22 +417,22 @@ function ElegantSessionCard({ session, actions }) {
|
|
|
417
417
|
}),
|
|
418
418
|
session.git ? /* @__PURE__ */ jsxs("span", {
|
|
419
419
|
"data-testid": "session-branch",
|
|
420
|
-
className: "flex min-w-0 items-center gap-1.5 pl-10.5 text-sm text-
|
|
420
|
+
className: "flex min-w-0 items-center gap-1.5 pl-10.5 text-sm text-po-dim",
|
|
421
421
|
children: [
|
|
422
|
-
/* @__PURE__ */ jsx(BranchIcon, { className: `size-3 shrink-0 ${active ? "text-
|
|
422
|
+
/* @__PURE__ */ jsx(BranchIcon, { className: `size-3 shrink-0 ${active ? "text-po-green" : ""}` }),
|
|
423
423
|
/* @__PURE__ */ jsx("span", {
|
|
424
424
|
className: "truncate font-mono",
|
|
425
425
|
children: session.git.branch
|
|
426
426
|
}),
|
|
427
427
|
session.git.dirty ? /* @__PURE__ */ jsx("span", {
|
|
428
|
-
className: "shrink-0 text-
|
|
428
|
+
className: "shrink-0 text-po-yellow",
|
|
429
429
|
children: "modified"
|
|
430
430
|
}) : null
|
|
431
431
|
]
|
|
432
432
|
}) : null,
|
|
433
433
|
error ? /* @__PURE__ */ jsx("span", {
|
|
434
434
|
"data-testid": "session-error",
|
|
435
|
-
className: "line-clamp-3 text-sm break-words text-
|
|
435
|
+
className: "line-clamp-3 text-sm break-words text-po-red",
|
|
436
436
|
children: error
|
|
437
437
|
}) : null
|
|
438
438
|
] });
|
|
@@ -466,7 +466,7 @@ function ElegantSessionCard({ session, actions }) {
|
|
|
466
466
|
size: "icon",
|
|
467
467
|
"data-testid": `session-menu-${session.id}`,
|
|
468
468
|
title: "session actions",
|
|
469
|
-
className: "text-
|
|
469
|
+
className: "text-po-dim hover:text-po-hi",
|
|
470
470
|
children: /* @__PURE__ */ jsx(KebabIcon, { className: "h-3 w-3" })
|
|
471
471
|
})
|
|
472
472
|
}), /* @__PURE__ */ jsxs(DropdownMenuContent, {
|
|
@@ -552,7 +552,7 @@ function ElegantSessionCard({ session, actions }) {
|
|
|
552
552
|
children: [/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: "remove session" }) }), /* @__PURE__ */ jsxs(DialogBody, { children: [/* @__PURE__ */ jsxs(DialogDescription, { children: [
|
|
553
553
|
"this stops ",
|
|
554
554
|
/* @__PURE__ */ jsx("span", {
|
|
555
|
-
className: "font-semibold text-
|
|
555
|
+
className: "font-semibold text-po-hi",
|
|
556
556
|
children: session.name || "untitled"
|
|
557
557
|
}),
|
|
558
558
|
" and removes it from the list. anything it is running ends now, but its saved history remains available to resume."
|
|
@@ -603,19 +603,19 @@ function ElegantWorkspaceGroup({ workspace, actions }) {
|
|
|
603
603
|
className: "flex flex-col gap-1.5",
|
|
604
604
|
children: [
|
|
605
605
|
/* @__PURE__ */ jsxs("div", {
|
|
606
|
-
className: "flex min-w-0 items-start gap-2.5 rounded-md px-2 py-1 transition-colors hover:bg-
|
|
606
|
+
className: "flex min-w-0 items-start gap-2.5 rounded-md px-2 py-1 transition-colors hover:bg-po-panel/60",
|
|
607
607
|
children: [
|
|
608
608
|
/* @__PURE__ */ jsx(FolderIcon, {
|
|
609
609
|
"aria-hidden": true,
|
|
610
|
-
className: "mt-0.5 size-4 shrink-0 text-
|
|
610
|
+
className: "mt-0.5 size-4 shrink-0 text-po-dim"
|
|
611
611
|
}),
|
|
612
612
|
/* @__PURE__ */ jsxs("div", {
|
|
613
613
|
className: "flex min-w-0 flex-1 flex-col",
|
|
614
614
|
children: [/* @__PURE__ */ jsx("p", {
|
|
615
|
-
className: "truncate text-base font-semibold text-
|
|
615
|
+
className: "truncate text-base font-semibold text-po-hi",
|
|
616
616
|
children: name
|
|
617
617
|
}), /* @__PURE__ */ jsx("p", {
|
|
618
|
-
className: "truncate font-mono text-sm text-
|
|
618
|
+
className: "truncate font-mono text-sm text-po-dim",
|
|
619
619
|
title: root,
|
|
620
620
|
children: root
|
|
621
621
|
})]
|
|
@@ -630,7 +630,7 @@ function ElegantWorkspaceGroup({ workspace, actions }) {
|
|
|
630
630
|
"aria-label": `New session in ${name}`,
|
|
631
631
|
disabled: !available,
|
|
632
632
|
onClick: () => actions.createSession(id),
|
|
633
|
-
className: "text-
|
|
633
|
+
className: "text-po-faint hover:text-po-hi",
|
|
634
634
|
children: /* @__PURE__ */ jsx(PlusIcon, { className: "size-3.5" })
|
|
635
635
|
}), /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
|
|
636
636
|
asChild: true,
|
|
@@ -640,7 +640,7 @@ function ElegantWorkspaceGroup({ workspace, actions }) {
|
|
|
640
640
|
"data-testid": `workspace-menu-${id}`,
|
|
641
641
|
title: "Workspace actions",
|
|
642
642
|
"aria-label": `${name} actions`,
|
|
643
|
-
className: "text-
|
|
643
|
+
className: "text-po-faint hover:text-po-hi",
|
|
644
644
|
children: /* @__PURE__ */ jsx(KebabIcon, { className: "size-3.5" })
|
|
645
645
|
})
|
|
646
646
|
}), /* @__PURE__ */ jsxs(DropdownMenuContent, { children: [
|
|
@@ -668,7 +668,7 @@ function ElegantWorkspaceGroup({ workspace, actions }) {
|
|
|
668
668
|
]
|
|
669
669
|
}),
|
|
670
670
|
!available ? /* @__PURE__ */ jsx("p", {
|
|
671
|
-
className: "px-9 text-sm text-
|
|
671
|
+
className: "px-9 text-sm text-po-red",
|
|
672
672
|
children: "Workspace unavailable"
|
|
673
673
|
}) : null,
|
|
674
674
|
workspace.sessions.length > 0 ? /* @__PURE__ */ jsx("div", {
|
|
@@ -678,7 +678,7 @@ function ElegantWorkspaceGroup({ workspace, actions }) {
|
|
|
678
678
|
actions
|
|
679
679
|
}, session.id))
|
|
680
680
|
}) : available ? /* @__PURE__ */ jsx("p", {
|
|
681
|
-
className: "px-9 pb-1 text-sm text-
|
|
681
|
+
className: "px-9 pb-1 text-sm text-po-dim",
|
|
682
682
|
children: "No sessions yet. Start or resume one."
|
|
683
683
|
}) : null,
|
|
684
684
|
/* @__PURE__ */ jsx(Dialog, {
|
|
@@ -692,7 +692,7 @@ function ElegantWorkspaceGroup({ workspace, actions }) {
|
|
|
692
692
|
/* @__PURE__ */ jsxs(DialogDescription, { children: [
|
|
693
693
|
"this unregisters ",
|
|
694
694
|
/* @__PURE__ */ jsx("span", {
|
|
695
|
-
className: "font-semibold text-
|
|
695
|
+
className: "font-semibold text-po-hi",
|
|
696
696
|
children: name
|
|
697
697
|
}),
|
|
698
698
|
" from Po only. files at",
|
|
@@ -702,7 +702,7 @@ function ElegantWorkspaceGroup({ workspace, actions }) {
|
|
|
702
702
|
] }),
|
|
703
703
|
removeError ? /* @__PURE__ */ jsx("p", {
|
|
704
704
|
"data-testid": `workspace-delete-error-${id}`,
|
|
705
|
-
className: "text-sm text-
|
|
705
|
+
className: "text-sm text-po-red",
|
|
706
706
|
children: removeError
|
|
707
707
|
}) : null,
|
|
708
708
|
/* @__PURE__ */ jsxs(DialogFooter, { children: [/* @__PURE__ */ jsx(Button, {
|
|
@@ -748,7 +748,7 @@ function ElegantRail({ rail, onClose }) {
|
|
|
748
748
|
className: "size-9 rounded-lg"
|
|
749
749
|
}), /* @__PURE__ */ jsx("span", {
|
|
750
750
|
"aria-hidden": "true",
|
|
751
|
-
className: "text-2xl font-semibold text-
|
|
751
|
+
className: "text-2xl font-semibold text-po-hi",
|
|
752
752
|
children: "Po"
|
|
753
753
|
})]
|
|
754
754
|
}), /* @__PURE__ */ jsxs("span", {
|
|
@@ -759,7 +759,7 @@ function ElegantRail({ rail, onClose }) {
|
|
|
759
759
|
"data-testid": "remote-access-open",
|
|
760
760
|
"aria-label": `Remote access is ${remote.status}`,
|
|
761
761
|
onClick: actions.openRemoteAccess,
|
|
762
|
-
className: `gap-1.5 rounded-md ${remote.status === "failed" ? "" : "bg-
|
|
762
|
+
className: `gap-1.5 rounded-md ${remote.status === "failed" ? "" : "bg-po-panel"}`,
|
|
763
763
|
children: [live ? /* @__PURE__ */ jsx(Dot, {
|
|
764
764
|
tone: "yellow",
|
|
765
765
|
pulse: true,
|
|
@@ -772,7 +772,7 @@ function ElegantRail({ rail, onClose }) {
|
|
|
772
772
|
title: "Hide sessions",
|
|
773
773
|
"aria-label": "Hide sessions",
|
|
774
774
|
onClick: onClose,
|
|
775
|
-
className: "text-
|
|
775
|
+
className: "text-po-dim",
|
|
776
776
|
children: /* @__PURE__ */ jsx(CloseIcon, { className: "size-3.5" })
|
|
777
777
|
})]
|
|
778
778
|
})]
|
|
@@ -780,7 +780,7 @@ function ElegantRail({ rail, onClose }) {
|
|
|
780
780
|
/* @__PURE__ */ jsxs("div", {
|
|
781
781
|
className: "flex items-center justify-between px-5 pt-3 pb-2",
|
|
782
782
|
children: [/* @__PURE__ */ jsx("h2", {
|
|
783
|
-
className: "text-lg font-semibold text-
|
|
783
|
+
className: "text-lg font-semibold text-po-hi",
|
|
784
784
|
children: "Workspaces"
|
|
785
785
|
}), /* @__PURE__ */ jsx(Button, {
|
|
786
786
|
variant: "ghost",
|
|
@@ -789,7 +789,7 @@ function ElegantRail({ rail, onClose }) {
|
|
|
789
789
|
title: "Add workspace",
|
|
790
790
|
"aria-label": "Add workspace",
|
|
791
791
|
onClick: actions.openAddWorkspace,
|
|
792
|
-
className: "text-
|
|
792
|
+
className: "text-po-faint hover:text-po-hi",
|
|
793
793
|
children: /* @__PURE__ */ jsx(PlusIcon, { className: "size-3.5" })
|
|
794
794
|
})]
|
|
795
795
|
}),
|
|
@@ -799,16 +799,16 @@ function ElegantRail({ rail, onClose }) {
|
|
|
799
799
|
workspace,
|
|
800
800
|
actions
|
|
801
801
|
}, workspace.id)), rail.workspaces.length === 0 ? /* @__PURE__ */ jsxs("div", {
|
|
802
|
-
className: "flex flex-col gap-3 rounded-lg border border-dashed border-
|
|
802
|
+
className: "flex flex-col gap-3 rounded-lg border border-dashed border-po-border px-4 py-5",
|
|
803
803
|
children: [/* @__PURE__ */ jsx("p", {
|
|
804
|
-
className: "text-sm text-
|
|
804
|
+
className: "text-sm text-po-dim",
|
|
805
805
|
children: "Add a folder to start working with Po."
|
|
806
806
|
}), /* @__PURE__ */ jsxs(Button, {
|
|
807
807
|
variant: "outline",
|
|
808
808
|
size: "md",
|
|
809
809
|
"data-testid": "add-workspace-empty",
|
|
810
810
|
onClick: actions.openAddWorkspace,
|
|
811
|
-
className: "justify-start gap-2 bg-
|
|
811
|
+
className: "justify-start gap-2 bg-po-panel",
|
|
812
812
|
children: [/* @__PURE__ */ jsx(PlusIcon, { className: "size-3.5" }), "Add workspace"]
|
|
813
813
|
})]
|
|
814
814
|
}) : null]
|
|
@@ -816,10 +816,10 @@ function ElegantRail({ rail, onClose }) {
|
|
|
816
816
|
rail.pluginContent,
|
|
817
817
|
/* @__PURE__ */ jsx("div", { className: "flex-1" }),
|
|
818
818
|
/* @__PURE__ */ jsxs("div", {
|
|
819
|
-
className: "sticky bottom-0 mt-auto shrink-0 bg-
|
|
819
|
+
className: "sticky bottom-0 mt-auto shrink-0 bg-po-rail",
|
|
820
820
|
children: [remote.status === "off" ? null : /* @__PURE__ */ jsxs("div", {
|
|
821
821
|
"data-testid": "remote-banner",
|
|
822
|
-
className: `flex items-center gap-2 border-t border-
|
|
822
|
+
className: `flex items-center gap-2 border-t border-po-border-soft px-4 py-2 text-sm ${remote.status === "failed" ? "bg-po-tint-red text-po-red" : "bg-po-tint-yellow text-po-yellow"}`,
|
|
823
823
|
children: [
|
|
824
824
|
/* @__PURE__ */ jsx(Dot, { tone: remote.status === "failed" ? "red" : "yellow" }),
|
|
825
825
|
/* @__PURE__ */ jsx("span", {
|
|
@@ -842,24 +842,24 @@ function ElegantRail({ rail, onClose }) {
|
|
|
842
842
|
})
|
|
843
843
|
]
|
|
844
844
|
}), /* @__PURE__ */ jsxs("div", {
|
|
845
|
-
className: "flex flex-col gap-1 border-t border-
|
|
845
|
+
className: "flex flex-col gap-1 border-t border-po-border-soft px-3 py-3",
|
|
846
846
|
children: [/* @__PURE__ */ jsxs(Button, {
|
|
847
847
|
variant: "ghost",
|
|
848
848
|
size: "md",
|
|
849
849
|
"data-testid": "settings-open",
|
|
850
850
|
onClick: actions.openSettings,
|
|
851
|
-
className: "justify-start gap-2.5 px-2 text-
|
|
852
|
-
children: [/* @__PURE__ */ jsx(GearIcon, { className: "size-4 text-
|
|
851
|
+
className: "justify-start gap-2.5 px-2 text-po-text",
|
|
852
|
+
children: [/* @__PURE__ */ jsx(GearIcon, { className: "size-4 text-po-dim" }), "Settings"]
|
|
853
853
|
}), /* @__PURE__ */ jsxs("span", {
|
|
854
|
-
className: "px-2 text-sm text-
|
|
854
|
+
className: "px-2 text-sm text-po-dim max-sm:hidden",
|
|
855
855
|
children: [
|
|
856
856
|
/* @__PURE__ */ jsx(Kbd, {
|
|
857
|
-
className: "bg-
|
|
857
|
+
className: "bg-po-panel",
|
|
858
858
|
children: "ctrl+k"
|
|
859
859
|
}),
|
|
860
860
|
" commands · ",
|
|
861
861
|
/* @__PURE__ */ jsx(Kbd, {
|
|
862
|
-
className: "bg-
|
|
862
|
+
className: "bg-po-panel",
|
|
863
863
|
children: "ctrl+t"
|
|
864
864
|
}),
|
|
865
865
|
" new session"
|
|
@@ -876,7 +876,7 @@ function ElegantRail({ rail, onClose }) {
|
|
|
876
876
|
function ElegantLayout({ view, slots, rail, navigationOpen, mobileActivityOpen, onNavigationOpenChange, onMobileActivityOpenChange }) {
|
|
877
877
|
const conversation = view === "conversation" || view === "welcome";
|
|
878
878
|
return /* @__PURE__ */ jsxs("div", {
|
|
879
|
-
className: "relative flex h-full min-w-0 flex-col overflow-hidden bg-
|
|
879
|
+
className: "relative flex h-full min-w-0 flex-col overflow-hidden bg-po-bg",
|
|
880
880
|
children: [
|
|
881
881
|
/* @__PURE__ */ jsx(Drawer, {
|
|
882
882
|
open: navigationOpen,
|
|
@@ -886,7 +886,7 @@ function ElegantLayout({ view, slots, rail, navigationOpen, mobileActivityOpen,
|
|
|
886
886
|
showHeader: false,
|
|
887
887
|
"data-testid": "session-rail-panel",
|
|
888
888
|
backdropTestId: "mobile-drawer-backdrop",
|
|
889
|
-
className: "w-[min(340px,calc(100vw-48px))] border-
|
|
889
|
+
className: "w-[min(340px,calc(100vw-48px))] border-po-border-soft",
|
|
890
890
|
children: /* @__PURE__ */ jsx(ElegantRail, {
|
|
891
891
|
rail,
|
|
892
892
|
onClose: () => onNavigationOpenChange(false)
|
|
@@ -909,10 +909,10 @@ function ElegantLayout({ view, slots, rail, navigationOpen, mobileActivityOpen,
|
|
|
909
909
|
children: slots.composer
|
|
910
910
|
}),
|
|
911
911
|
slots.controls == null ? null : /* @__PURE__ */ jsxs("details", {
|
|
912
|
-
className: "shrink-0 px-3 pb-3 text-sm text-
|
|
912
|
+
className: "shrink-0 px-3 pb-3 text-sm text-po-dim",
|
|
913
913
|
children: [/* @__PURE__ */ jsx("summary", {
|
|
914
914
|
"data-testid": "template-controls-toggle",
|
|
915
|
-
className: "cursor-pointer rounded-sm px-1 py-1 focus-visible:outline focus-visible:outline-
|
|
915
|
+
className: "cursor-pointer rounded-sm px-1 py-1 focus-visible:outline focus-visible:outline-po-blue",
|
|
916
916
|
children: "Session controls"
|
|
917
917
|
}), slots.controls]
|
|
918
918
|
})
|
|
@@ -937,6 +937,576 @@ function ElegantLayout({ view, slots, rail, navigationOpen, mobileActivityOpen,
|
|
|
937
937
|
});
|
|
938
938
|
}
|
|
939
939
|
//#endregion
|
|
940
|
+
//#region src/extensions/(frontend)/template/_components/ElegantOnboarding.tsx
|
|
941
|
+
function StepFrame({ step, pending, children, testId }) {
|
|
942
|
+
return /* @__PURE__ */ jsx("div", {
|
|
943
|
+
"data-testid": testId,
|
|
944
|
+
className: "flex min-h-0 flex-1 items-center justify-center overflow-y-auto px-4 py-10",
|
|
945
|
+
children: /* @__PURE__ */ jsxs("section", {
|
|
946
|
+
className: "flex w-full max-w-xl flex-col gap-6",
|
|
947
|
+
children: [children, pending.length > 1 ? /* @__PURE__ */ jsx("ol", {
|
|
948
|
+
"aria-label": "Setup steps",
|
|
949
|
+
className: "flex justify-center gap-2",
|
|
950
|
+
children: pending.map((entry) => /* @__PURE__ */ jsx("li", {
|
|
951
|
+
"aria-current": entry === step ? "step" : void 0,
|
|
952
|
+
className: `size-1.5 rounded-full ${entry === step ? "bg-po-selected" : "bg-po-border-soft"}`
|
|
953
|
+
}, entry))
|
|
954
|
+
}) : null]
|
|
955
|
+
})
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
function Heading({ title, description }) {
|
|
959
|
+
return /* @__PURE__ */ jsxs("header", {
|
|
960
|
+
className: "flex flex-col gap-1.5 text-center",
|
|
961
|
+
children: [/* @__PURE__ */ jsx("h1", {
|
|
962
|
+
className: "text-xl font-semibold text-po-hi",
|
|
963
|
+
children: title
|
|
964
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
965
|
+
className: "text-base text-po-dim",
|
|
966
|
+
children: description
|
|
967
|
+
})]
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
function ErrorLine({ error }) {
|
|
971
|
+
return error ? /* @__PURE__ */ jsx("p", {
|
|
972
|
+
role: "alert",
|
|
973
|
+
className: "text-sm text-po-red",
|
|
974
|
+
children: error
|
|
975
|
+
}) : null;
|
|
976
|
+
}
|
|
977
|
+
const STEP_COUNT_WORDS = [
|
|
978
|
+
"",
|
|
979
|
+
"One quick step",
|
|
980
|
+
"Two quick steps"
|
|
981
|
+
];
|
|
982
|
+
/** The first thing a new person sees, only while a setup step is still missing. */
|
|
983
|
+
function ElegantOnboardingWelcome({ pending, onBegin }) {
|
|
984
|
+
return /* @__PURE__ */ jsx(StepFrame, {
|
|
985
|
+
pending: [],
|
|
986
|
+
testId: "onboarding-welcome",
|
|
987
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
988
|
+
className: "flex flex-col items-center gap-5 py-4 text-center",
|
|
989
|
+
children: [
|
|
990
|
+
/* @__PURE__ */ jsxs("span", {
|
|
991
|
+
className: "flex items-center gap-2.5",
|
|
992
|
+
"aria-label": "Po",
|
|
993
|
+
children: [/* @__PURE__ */ jsx("img", {
|
|
994
|
+
src: "/favicon.svg",
|
|
995
|
+
alt: "",
|
|
996
|
+
"aria-hidden": "true",
|
|
997
|
+
className: "size-10 rounded-lg"
|
|
998
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
999
|
+
"aria-hidden": "true",
|
|
1000
|
+
className: "text-2xl font-semibold text-po-hi",
|
|
1001
|
+
children: "Po"
|
|
1002
|
+
})]
|
|
1003
|
+
}),
|
|
1004
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1005
|
+
className: "flex flex-col gap-1.5",
|
|
1006
|
+
children: [/* @__PURE__ */ jsx("h1", {
|
|
1007
|
+
className: "text-2xl font-semibold text-po-hi",
|
|
1008
|
+
children: "Hi, I'm Po. I'll handle the busywork."
|
|
1009
|
+
}), /* @__PURE__ */ jsxs("p", {
|
|
1010
|
+
className: "text-base text-po-dim",
|
|
1011
|
+
children: [STEP_COUNT_WORDS[pending.length] ?? `${pending.length} quick steps`, " and you can hand me your first task."]
|
|
1012
|
+
})]
|
|
1013
|
+
}),
|
|
1014
|
+
/* @__PURE__ */ jsxs(Button, {
|
|
1015
|
+
variant: "primary",
|
|
1016
|
+
size: "lg",
|
|
1017
|
+
"data-testid": "onboarding-begin",
|
|
1018
|
+
onClick: onBegin,
|
|
1019
|
+
className: "px-6",
|
|
1020
|
+
children: ["Let's begin", /* @__PURE__ */ jsx(ArrowRightIcon, { className: "size-3.5" })]
|
|
1021
|
+
})
|
|
1022
|
+
]
|
|
1023
|
+
})
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
/** Choose and sign in to the provider that runs the models. */
|
|
1027
|
+
function ElegantOnboardingModel({ pending, providers, selectedId, busy, error, onSelect, onConnect, onShowAll }) {
|
|
1028
|
+
return /* @__PURE__ */ jsxs(StepFrame, {
|
|
1029
|
+
step: "model",
|
|
1030
|
+
pending,
|
|
1031
|
+
testId: "onboarding-model",
|
|
1032
|
+
children: [
|
|
1033
|
+
/* @__PURE__ */ jsx(Heading, {
|
|
1034
|
+
title: "Choose who does the thinking",
|
|
1035
|
+
description: "You can connect more providers later in settings."
|
|
1036
|
+
}),
|
|
1037
|
+
/* @__PURE__ */ jsx(RadioGroup, {
|
|
1038
|
+
"aria-label": "Model provider",
|
|
1039
|
+
value: selectedId ?? "",
|
|
1040
|
+
onValueChange: onSelect,
|
|
1041
|
+
className: "flex flex-col gap-2",
|
|
1042
|
+
children: providers.map((provider) => /* @__PURE__ */ jsxs("label", {
|
|
1043
|
+
htmlFor: `onboarding-provider-${provider.id}`,
|
|
1044
|
+
"data-testid": `onboarding-provider-${provider.id}`,
|
|
1045
|
+
className: `flex cursor-pointer items-center gap-3 rounded-lg border px-4 py-3 transition-colors ${provider.id === selectedId ? "border-po-selected bg-po-selected/5" : "border-po-border-soft hover:border-po-green/50"}`,
|
|
1046
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
1047
|
+
className: "flex min-w-0 flex-1 flex-col",
|
|
1048
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
1049
|
+
className: "text-base font-semibold text-po-hi",
|
|
1050
|
+
children: provider.name
|
|
1051
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
1052
|
+
className: "text-sm text-po-dim",
|
|
1053
|
+
children: provider.note
|
|
1054
|
+
})]
|
|
1055
|
+
}), /* @__PURE__ */ jsx(RadioGroupItem, {
|
|
1056
|
+
id: `onboarding-provider-${provider.id}`,
|
|
1057
|
+
value: provider.id
|
|
1058
|
+
})]
|
|
1059
|
+
}, provider.id))
|
|
1060
|
+
}),
|
|
1061
|
+
/* @__PURE__ */ jsx(Button, {
|
|
1062
|
+
variant: "ghost",
|
|
1063
|
+
size: "sm",
|
|
1064
|
+
onClick: onShowAll,
|
|
1065
|
+
className: "self-start",
|
|
1066
|
+
children: "Show every provider"
|
|
1067
|
+
}),
|
|
1068
|
+
/* @__PURE__ */ jsx(ErrorLine, { error }),
|
|
1069
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1070
|
+
className: "flex items-center justify-between gap-3",
|
|
1071
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
1072
|
+
className: "flex items-center gap-1.5 text-sm text-po-dim",
|
|
1073
|
+
children: [/* @__PURE__ */ jsx(LockIcon, { className: "size-3.5" }), "Your keys stay on this machine."]
|
|
1074
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
1075
|
+
variant: "primary",
|
|
1076
|
+
size: "lg",
|
|
1077
|
+
"data-testid": "onboarding-connect",
|
|
1078
|
+
disabled: selectedId === null || busy,
|
|
1079
|
+
onClick: onConnect,
|
|
1080
|
+
children: busy ? "Connecting…" : "Connect"
|
|
1081
|
+
})]
|
|
1082
|
+
})
|
|
1083
|
+
]
|
|
1084
|
+
});
|
|
1085
|
+
}
|
|
1086
|
+
function addLabel(count) {
|
|
1087
|
+
if (count === 0) return "Add workspace";
|
|
1088
|
+
return count === 1 ? "Add 1 workspace" : `Add ${count} workspaces`;
|
|
1089
|
+
}
|
|
1090
|
+
/** Admit folders Po found, a new named workspace, or a browsed folder. */
|
|
1091
|
+
function ElegantOnboardingWorkspace({ pending, scanning, found, name, busy, error, browser, onToggle, onNameChange, onBrowse, onAdd }) {
|
|
1092
|
+
const count = found.filter((folder) => folder.checked).length + (name.trim() === "" ? 0 : 1);
|
|
1093
|
+
const showFound = scanning || found.length > 0;
|
|
1094
|
+
return /* @__PURE__ */ jsxs(StepFrame, {
|
|
1095
|
+
step: "workspace",
|
|
1096
|
+
pending,
|
|
1097
|
+
testId: "onboarding-workspace",
|
|
1098
|
+
children: [
|
|
1099
|
+
/* @__PURE__ */ jsx(Heading, {
|
|
1100
|
+
title: "Where should I work?",
|
|
1101
|
+
description: found.length > 0 ? "I found these folders with Po settings on this machine." : "Name a new workspace, or pick a folder you already have."
|
|
1102
|
+
}),
|
|
1103
|
+
showFound ? /* @__PURE__ */ jsxs("div", {
|
|
1104
|
+
className: "flex flex-col rounded-lg border border-po-border-soft",
|
|
1105
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
1106
|
+
className: "border-b border-po-border-soft px-4 py-2 text-sm text-po-dim",
|
|
1107
|
+
children: scanning ? "Looking for folders with Po settings…" : "Found on this machine"
|
|
1108
|
+
}), scanning ? /* @__PURE__ */ jsxs("output", {
|
|
1109
|
+
"aria-busy": true,
|
|
1110
|
+
className: "flex flex-col gap-3 px-4 py-3",
|
|
1111
|
+
children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-56" }), /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-44" })]
|
|
1112
|
+
}) : /* @__PURE__ */ jsx("ul", {
|
|
1113
|
+
"data-testid": "onboarding-found",
|
|
1114
|
+
children: found.map((folder) => /* @__PURE__ */ jsx("li", {
|
|
1115
|
+
className: "border-b border-po-border-soft last:border-b-0",
|
|
1116
|
+
children: /* @__PURE__ */ jsxs("label", {
|
|
1117
|
+
className: "flex cursor-pointer items-center gap-3 px-4 py-2.5",
|
|
1118
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
1119
|
+
className: "min-w-0 flex-1 truncate font-mono text-sm text-po-text",
|
|
1120
|
+
children: folder.path
|
|
1121
|
+
}), /* @__PURE__ */ jsx(Checkbox, {
|
|
1122
|
+
"aria-label": `Add ${folder.path}`,
|
|
1123
|
+
checked: folder.checked,
|
|
1124
|
+
onCheckedChange: (checked) => onToggle(folder.path, checked === true)
|
|
1125
|
+
})]
|
|
1126
|
+
})
|
|
1127
|
+
}, folder.path))
|
|
1128
|
+
})]
|
|
1129
|
+
}) : null,
|
|
1130
|
+
showFound ? /* @__PURE__ */ jsxs("div", {
|
|
1131
|
+
className: "flex items-center gap-3 text-sm text-po-dim",
|
|
1132
|
+
children: [
|
|
1133
|
+
/* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-po-border-soft" }),
|
|
1134
|
+
"or",
|
|
1135
|
+
/* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-po-border-soft" })
|
|
1136
|
+
]
|
|
1137
|
+
}) : null,
|
|
1138
|
+
/* @__PURE__ */ jsxs("label", {
|
|
1139
|
+
htmlFor: "onboarding-workspace-name",
|
|
1140
|
+
className: "flex flex-col gap-1.5",
|
|
1141
|
+
children: [
|
|
1142
|
+
/* @__PURE__ */ jsx("span", {
|
|
1143
|
+
className: "text-base font-medium text-po-text",
|
|
1144
|
+
children: "Name a new workspace"
|
|
1145
|
+
}),
|
|
1146
|
+
/* @__PURE__ */ jsxs("span", {
|
|
1147
|
+
className: "flex items-center gap-2",
|
|
1148
|
+
children: [/* @__PURE__ */ jsx(Input, {
|
|
1149
|
+
id: "onboarding-workspace-name",
|
|
1150
|
+
"data-testid": "onboarding-workspace-name",
|
|
1151
|
+
value: name,
|
|
1152
|
+
placeholder: "Notes",
|
|
1153
|
+
onChange: (event) => onNameChange(event.target.value),
|
|
1154
|
+
className: "min-w-0 flex-1"
|
|
1155
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
1156
|
+
variant: "outline",
|
|
1157
|
+
size: "md",
|
|
1158
|
+
"data-testid": "onboarding-browse",
|
|
1159
|
+
onClick: onBrowse,
|
|
1160
|
+
children: "Browse folders"
|
|
1161
|
+
})]
|
|
1162
|
+
}),
|
|
1163
|
+
/* @__PURE__ */ jsxs("span", {
|
|
1164
|
+
className: "font-mono text-sm text-po-dim",
|
|
1165
|
+
children: ["~/.po/workspace/", name.trim() || "Notes"]
|
|
1166
|
+
})
|
|
1167
|
+
]
|
|
1168
|
+
}),
|
|
1169
|
+
browser,
|
|
1170
|
+
/* @__PURE__ */ jsx(ErrorLine, { error }),
|
|
1171
|
+
/* @__PURE__ */ jsx(Button, {
|
|
1172
|
+
variant: "primary",
|
|
1173
|
+
size: "lg",
|
|
1174
|
+
"data-testid": "onboarding-add-workspaces",
|
|
1175
|
+
disabled: count === 0 || busy,
|
|
1176
|
+
onClick: onAdd,
|
|
1177
|
+
className: "self-end",
|
|
1178
|
+
children: busy ? "Adding…" : addLabel(count)
|
|
1179
|
+
})
|
|
1180
|
+
]
|
|
1181
|
+
});
|
|
1182
|
+
}
|
|
1183
|
+
/** Setup is done and nothing has started yet: the first task goes straight into a new session. */
|
|
1184
|
+
function ElegantOnboardingReady({ model, root, draft, busy, error, suggestions, onDraftChange, onSend }) {
|
|
1185
|
+
return /* @__PURE__ */ jsxs(StepFrame, {
|
|
1186
|
+
pending: [],
|
|
1187
|
+
testId: "welcome",
|
|
1188
|
+
children: [
|
|
1189
|
+
/* @__PURE__ */ jsxs("header", {
|
|
1190
|
+
className: "flex flex-col gap-1.5",
|
|
1191
|
+
children: [/* @__PURE__ */ jsx("h1", {
|
|
1192
|
+
className: "text-2xl font-semibold text-po-hi",
|
|
1193
|
+
children: "Ready when you are."
|
|
1194
|
+
}), /* @__PURE__ */ jsxs("p", {
|
|
1195
|
+
className: "text-base text-po-dim",
|
|
1196
|
+
children: [
|
|
1197
|
+
"Po is connected to ",
|
|
1198
|
+
model,
|
|
1199
|
+
" and working in ",
|
|
1200
|
+
/* @__PURE__ */ jsx("span", {
|
|
1201
|
+
className: "font-mono text-po-text",
|
|
1202
|
+
children: root
|
|
1203
|
+
}),
|
|
1204
|
+
"."
|
|
1205
|
+
]
|
|
1206
|
+
})]
|
|
1207
|
+
}),
|
|
1208
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1209
|
+
className: "flex flex-col gap-2 rounded-lg border border-po-border bg-po-bg p-3 focus-within:border-po-green/60",
|
|
1210
|
+
children: [/* @__PURE__ */ jsx(Textarea, {
|
|
1211
|
+
"data-testid": "onboarding-first-task",
|
|
1212
|
+
"aria-label": "Your first task",
|
|
1213
|
+
value: draft,
|
|
1214
|
+
placeholder: "Tell Po what you'd like done…",
|
|
1215
|
+
onChange: (event) => onDraftChange(event.target.value),
|
|
1216
|
+
onKeyDown: (event) => {
|
|
1217
|
+
if (event.key === "Enter" && !event.shiftKey && draft.trim() !== "") {
|
|
1218
|
+
event.preventDefault();
|
|
1219
|
+
onSend();
|
|
1220
|
+
}
|
|
1221
|
+
},
|
|
1222
|
+
className: "min-h-20 resize-none border-0 bg-transparent p-1 text-lg focus-visible:ring-0"
|
|
1223
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
1224
|
+
variant: "primary",
|
|
1225
|
+
size: "icon-md",
|
|
1226
|
+
"aria-label": "Start this task",
|
|
1227
|
+
"data-testid": "onboarding-send",
|
|
1228
|
+
disabled: draft.trim() === "" || busy,
|
|
1229
|
+
onClick: onSend,
|
|
1230
|
+
className: "self-end",
|
|
1231
|
+
children: /* @__PURE__ */ jsx(SendIcon, { className: "size-4" })
|
|
1232
|
+
})]
|
|
1233
|
+
}),
|
|
1234
|
+
/* @__PURE__ */ jsx("div", {
|
|
1235
|
+
className: "grid gap-2 sm:grid-cols-3",
|
|
1236
|
+
children: suggestions.map((suggestion) => /* @__PURE__ */ jsx(Button, {
|
|
1237
|
+
variant: "outline",
|
|
1238
|
+
size: "card",
|
|
1239
|
+
onClick: () => onDraftChange(suggestion),
|
|
1240
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
1241
|
+
className: "text-base text-po-text",
|
|
1242
|
+
children: suggestion
|
|
1243
|
+
})
|
|
1244
|
+
}, suggestion))
|
|
1245
|
+
}),
|
|
1246
|
+
/* @__PURE__ */ jsx(ErrorLine, { error }),
|
|
1247
|
+
/* @__PURE__ */ jsxs("span", {
|
|
1248
|
+
className: "flex flex-wrap items-center justify-end gap-1.5 border-t border-po-border-soft pt-4 text-sm text-po-dim",
|
|
1249
|
+
children: [
|
|
1250
|
+
/* @__PURE__ */ jsx(Kbd, { children: "ctrl+t" }),
|
|
1251
|
+
" new session · ",
|
|
1252
|
+
/* @__PURE__ */ jsx(Kbd, { children: "ctrl+k" }),
|
|
1253
|
+
" commands"
|
|
1254
|
+
]
|
|
1255
|
+
})
|
|
1256
|
+
]
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
//#endregion
|
|
1260
|
+
//#region src/extensions/(frontend)/template/_components/ElegantOnboardingFlow.tsx
|
|
1261
|
+
/** Shown first, in this order; every other provider waits behind "Show every provider". */
|
|
1262
|
+
const FEATURED_PROVIDERS = [
|
|
1263
|
+
"anthropic",
|
|
1264
|
+
"openai-codex",
|
|
1265
|
+
"github-copilot",
|
|
1266
|
+
"google",
|
|
1267
|
+
"openrouter"
|
|
1268
|
+
];
|
|
1269
|
+
const SUGGESTIONS = [
|
|
1270
|
+
"Tour this codebase for me",
|
|
1271
|
+
"Find and fix failing tests",
|
|
1272
|
+
"Draft a README update"
|
|
1273
|
+
];
|
|
1274
|
+
const FLOW_POLL_MS = 500;
|
|
1275
|
+
const ATTACH_TIMEOUT_MS = 3e4;
|
|
1276
|
+
const TRAILING_SEPARATORS = /\/+$/u;
|
|
1277
|
+
function folderName(path) {
|
|
1278
|
+
const trimmed = path.trim().replace(TRAILING_SEPARATORS, "");
|
|
1279
|
+
return trimmed.slice(trimmed.lastIndexOf("/") + 1);
|
|
1280
|
+
}
|
|
1281
|
+
/**
|
|
1282
|
+
* Sends the session's composer draft once the session is attached and its protocol is bound,
|
|
1283
|
+
* which only happens after the session page takes focus. Sends once, never retries, so an
|
|
1284
|
+
* unacknowledged send cannot repeat. A session that never gets ready keeps the text in its
|
|
1285
|
+
* composer for the person to send.
|
|
1286
|
+
*/
|
|
1287
|
+
function submitWhenReady(sessionId) {
|
|
1288
|
+
const started = Date.now();
|
|
1289
|
+
const timer = setInterval(() => {
|
|
1290
|
+
const ready = sessionsStore.state.byId[sessionId]?.attach === "attached" && hasSessionProtocol(sessionId);
|
|
1291
|
+
if (!ready && Date.now() - started < ATTACH_TIMEOUT_MS) return;
|
|
1292
|
+
clearInterval(timer);
|
|
1293
|
+
if (ready) submitComposerDraft(sessionId, "submit");
|
|
1294
|
+
}, FLOW_POLL_MS);
|
|
1295
|
+
}
|
|
1296
|
+
function ModelStep({ pending, models, onConnected }) {
|
|
1297
|
+
const [showAll, setShowAll] = useState(false);
|
|
1298
|
+
const signable = models.filter((provider) => provider.methods.length > 0);
|
|
1299
|
+
const featured = FEATURED_PROVIDERS.flatMap((id) => signable.filter((provider) => provider.id === id));
|
|
1300
|
+
const shown = showAll || featured.length === 0 ? signable : featured;
|
|
1301
|
+
const [selectedId, setSelectedId] = useState(shown[0]?.id ?? null);
|
|
1302
|
+
const [flow, setFlow] = useState(null);
|
|
1303
|
+
const [starting, setStarting] = useState(false);
|
|
1304
|
+
const [error, setError] = useState("");
|
|
1305
|
+
const flowId = flow?.id;
|
|
1306
|
+
const running = flow?.status === "running";
|
|
1307
|
+
useEffect(() => {
|
|
1308
|
+
if (flowId === void 0 || !running) return;
|
|
1309
|
+
let stopped = false;
|
|
1310
|
+
let timer;
|
|
1311
|
+
const poll = async () => {
|
|
1312
|
+
const result = await readLogin(flowId);
|
|
1313
|
+
if (stopped) return;
|
|
1314
|
+
if ("error" in result) {
|
|
1315
|
+
setFlow((current) => current?.id === flowId ? {
|
|
1316
|
+
...current,
|
|
1317
|
+
status: "failed",
|
|
1318
|
+
error: result.error
|
|
1319
|
+
} : current);
|
|
1320
|
+
return;
|
|
1321
|
+
}
|
|
1322
|
+
setFlow(result.flow);
|
|
1323
|
+
if (result.flow.status === "succeeded") onConnected();
|
|
1324
|
+
else if (result.flow.status === "running") timer = setTimeout(() => void poll(), FLOW_POLL_MS);
|
|
1325
|
+
};
|
|
1326
|
+
timer = setTimeout(() => void poll(), FLOW_POLL_MS);
|
|
1327
|
+
return () => {
|
|
1328
|
+
stopped = true;
|
|
1329
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
1330
|
+
};
|
|
1331
|
+
}, [
|
|
1332
|
+
flowId,
|
|
1333
|
+
running,
|
|
1334
|
+
onConnected
|
|
1335
|
+
]);
|
|
1336
|
+
const connect = async () => {
|
|
1337
|
+
const provider = signable.find((candidate) => candidate.id === selectedId);
|
|
1338
|
+
const method = provider?.methods.find((candidate) => candidate.type === "oauth") ?? provider?.methods[0];
|
|
1339
|
+
if (provider === void 0 || method === void 0 || starting || running) return;
|
|
1340
|
+
setError("");
|
|
1341
|
+
setStarting(true);
|
|
1342
|
+
const result = await startLogin(provider.id, method.type);
|
|
1343
|
+
setStarting(false);
|
|
1344
|
+
if ("flow" in result) setFlow(result.flow);
|
|
1345
|
+
else setError(result.error);
|
|
1346
|
+
};
|
|
1347
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ElegantOnboardingModel, {
|
|
1348
|
+
pending,
|
|
1349
|
+
providers: shown.map((provider) => ({
|
|
1350
|
+
id: provider.id,
|
|
1351
|
+
name: provider.name,
|
|
1352
|
+
note: provider.methods.map((method) => method.label).join(" or ")
|
|
1353
|
+
})),
|
|
1354
|
+
selectedId,
|
|
1355
|
+
busy: starting || running,
|
|
1356
|
+
...error === "" ? {} : { error },
|
|
1357
|
+
onSelect: setSelectedId,
|
|
1358
|
+
onConnect: () => void connect(),
|
|
1359
|
+
onShowAll: () => setShowAll(true)
|
|
1360
|
+
}), flow ? /* @__PURE__ */ jsx(LoginFlowDialog, {
|
|
1361
|
+
flow,
|
|
1362
|
+
onAnswer: (promptId, value) => void answerLogin(flow.id, promptId, value).then((result) => {
|
|
1363
|
+
if ("flow" in result) setFlow(result.flow);
|
|
1364
|
+
else setError(result.error);
|
|
1365
|
+
}),
|
|
1366
|
+
onCancel: () => void cancelLogin(flow.id).then((result) => setFlow("flow" in result ? result.flow : null)),
|
|
1367
|
+
onClose: () => {
|
|
1368
|
+
if (flow.status === "failed") setError(flow.error ?? "The sign-in did not finish. Try again whenever you like.");
|
|
1369
|
+
setFlow(null);
|
|
1370
|
+
}
|
|
1371
|
+
}) : null] });
|
|
1372
|
+
}
|
|
1373
|
+
function WorkspaceStep({ pending }) {
|
|
1374
|
+
const [scanning, setScanning] = useState(true);
|
|
1375
|
+
const [found, setFound] = useState([]);
|
|
1376
|
+
const [name, setName] = useState("");
|
|
1377
|
+
const [browsing, setBrowsing] = useState(false);
|
|
1378
|
+
const [error, setError] = useState("");
|
|
1379
|
+
const busy = useStore(workspaceAdmissionStore, (state) => state.pending);
|
|
1380
|
+
useEffect(() => {
|
|
1381
|
+
let stale = false;
|
|
1382
|
+
listPoFolders().then((paths) => {
|
|
1383
|
+
if (stale) return;
|
|
1384
|
+
setFound(paths.map((path, index) => ({
|
|
1385
|
+
path,
|
|
1386
|
+
checked: index === 0
|
|
1387
|
+
})));
|
|
1388
|
+
setScanning(false);
|
|
1389
|
+
});
|
|
1390
|
+
return () => {
|
|
1391
|
+
stale = true;
|
|
1392
|
+
};
|
|
1393
|
+
}, []);
|
|
1394
|
+
const pick = (path) => {
|
|
1395
|
+
setFound((current) => current.some((folder) => folder.path === path) ? current.map((folder) => folder.path === path ? {
|
|
1396
|
+
...folder,
|
|
1397
|
+
checked: true
|
|
1398
|
+
} : folder) : [...current, {
|
|
1399
|
+
path,
|
|
1400
|
+
checked: true
|
|
1401
|
+
}]);
|
|
1402
|
+
setBrowsing(false);
|
|
1403
|
+
};
|
|
1404
|
+
const add = async () => {
|
|
1405
|
+
setError("");
|
|
1406
|
+
const admissions = [...found.filter((folder) => folder.checked).map((folder) => ({
|
|
1407
|
+
name: folderName(folder.path),
|
|
1408
|
+
path: folder.path
|
|
1409
|
+
})), ...name.trim() === "" ? [] : [{ name: name.trim() }]];
|
|
1410
|
+
for (const admission of admissions) {
|
|
1411
|
+
const result = await admitDashboardWorkspace(admission);
|
|
1412
|
+
if (result !== void 0) {
|
|
1413
|
+
setError(result.error);
|
|
1414
|
+
return;
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
};
|
|
1418
|
+
return /* @__PURE__ */ jsx(ElegantOnboardingWorkspace, {
|
|
1419
|
+
pending,
|
|
1420
|
+
scanning,
|
|
1421
|
+
found,
|
|
1422
|
+
name,
|
|
1423
|
+
busy,
|
|
1424
|
+
...error === "" ? {} : { error },
|
|
1425
|
+
...browsing ? { browser: /* @__PURE__ */ jsx(ElegantFolderBrowser, {
|
|
1426
|
+
listDirectory,
|
|
1427
|
+
onSelect: pick
|
|
1428
|
+
}) } : {},
|
|
1429
|
+
onToggle: (path, checked) => setFound((current) => current.map((folder) => folder.path === path ? {
|
|
1430
|
+
...folder,
|
|
1431
|
+
checked
|
|
1432
|
+
} : folder)),
|
|
1433
|
+
onNameChange: setName,
|
|
1434
|
+
onBrowse: () => setBrowsing((open) => !open),
|
|
1435
|
+
onAdd: () => void add()
|
|
1436
|
+
});
|
|
1437
|
+
}
|
|
1438
|
+
function ReadyStep({ model }) {
|
|
1439
|
+
const navigate = useNavigate();
|
|
1440
|
+
const workspace = useStore(workspacesStore, (state) => state.byId[state.selectedId ?? state.order[0] ?? ""]);
|
|
1441
|
+
const [draft, setDraft] = useState("");
|
|
1442
|
+
const [busy, setBusy] = useState(false);
|
|
1443
|
+
const [error, setError] = useState("");
|
|
1444
|
+
if (workspace === void 0) return null;
|
|
1445
|
+
const send = async () => {
|
|
1446
|
+
const text = draft.trim();
|
|
1447
|
+
if (text === "" || busy) return;
|
|
1448
|
+
setError("");
|
|
1449
|
+
setBusy(true);
|
|
1450
|
+
const outcome = await createPlainSession(workspace.id);
|
|
1451
|
+
if (!("sessionId" in outcome)) {
|
|
1452
|
+
setBusy(false);
|
|
1453
|
+
setError(outcome.error);
|
|
1454
|
+
return;
|
|
1455
|
+
}
|
|
1456
|
+
updateComposerState(outcome.sessionId, (state) => ({
|
|
1457
|
+
...state,
|
|
1458
|
+
draft: text,
|
|
1459
|
+
caret: text.length
|
|
1460
|
+
}));
|
|
1461
|
+
submitWhenReady(outcome.sessionId);
|
|
1462
|
+
await navigate({
|
|
1463
|
+
to: "/session/$sessionId",
|
|
1464
|
+
params: { sessionId: outcome.sessionId }
|
|
1465
|
+
});
|
|
1466
|
+
};
|
|
1467
|
+
return /* @__PURE__ */ jsx(ElegantOnboardingReady, {
|
|
1468
|
+
model,
|
|
1469
|
+
root: workspace.root,
|
|
1470
|
+
draft,
|
|
1471
|
+
busy,
|
|
1472
|
+
...error === "" ? {} : { error },
|
|
1473
|
+
suggestions: SUGGESTIONS,
|
|
1474
|
+
onDraftChange: setDraft,
|
|
1475
|
+
onSend: () => void send()
|
|
1476
|
+
});
|
|
1477
|
+
}
|
|
1478
|
+
/**
|
|
1479
|
+
* First run in place of the empty welcome: only the setup steps still missing, then the
|
|
1480
|
+
* first task. Finished steps are read from the hub, so nothing new is persisted.
|
|
1481
|
+
*/
|
|
1482
|
+
function ElegantOnboardingFlow() {
|
|
1483
|
+
const updateRequired = useStore(sessionsStore, (state) => state.updateRequired);
|
|
1484
|
+
const hydrated = useStore(workspacesStore, (state) => state.hydrated);
|
|
1485
|
+
const hasWorkspace = useStore(workspacesStore, (state) => state.order.length > 0);
|
|
1486
|
+
const [providers, setProviders] = useState(null);
|
|
1487
|
+
const [steps, setSteps] = useState(null);
|
|
1488
|
+
const reload = useCallback(() => {
|
|
1489
|
+
listProviders().then((result) => setProviders("providers" in result ? result.providers : "unavailable"));
|
|
1490
|
+
}, []);
|
|
1491
|
+
useEffect(reload, [reload]);
|
|
1492
|
+
if (updateRequired) return /* @__PURE__ */ jsx(WelcomePanel, {});
|
|
1493
|
+
if (providers === null || !hydrated) return null;
|
|
1494
|
+
const models = providers === "unavailable" ? [] : providers.filter((provider) => provider.kind !== "po-feature");
|
|
1495
|
+
const connected = models.find((provider) => provider.authenticated !== void 0);
|
|
1496
|
+
const pending = [...providers === "unavailable" || connected !== void 0 ? [] : ["model"], ...hasWorkspace ? [] : ["workspace"]];
|
|
1497
|
+
if (steps === null && pending.length > 0) return /* @__PURE__ */ jsx(ElegantOnboardingWelcome, {
|
|
1498
|
+
pending,
|
|
1499
|
+
onBegin: () => setSteps(pending)
|
|
1500
|
+
});
|
|
1501
|
+
if (pending[0] === "model") return /* @__PURE__ */ jsx(ModelStep, {
|
|
1502
|
+
pending: steps ?? pending,
|
|
1503
|
+
models,
|
|
1504
|
+
onConnected: reload
|
|
1505
|
+
});
|
|
1506
|
+
if (pending[0] === "workspace") return /* @__PURE__ */ jsx(WorkspaceStep, { pending: steps ?? pending });
|
|
1507
|
+
return /* @__PURE__ */ jsx(ReadyStep, { model: connected?.name ?? "your model" });
|
|
1508
|
+
}
|
|
1509
|
+
//#endregion
|
|
940
1510
|
//#region src/extensions/(frontend)/template/_components/ElegantConversation.tsx
|
|
941
1511
|
function ElegantConversation() {
|
|
942
1512
|
useWebPluginRegistry();
|
|
@@ -1010,18 +1580,19 @@ function ElegantConversation() {
|
|
|
1010
1580
|
}),
|
|
1011
1581
|
notices: transferLabel === null ? null : /* @__PURE__ */ jsxs("output", {
|
|
1012
1582
|
"data-testid": "voice-transfer-transition",
|
|
1013
|
-
className: "border-b border-
|
|
1583
|
+
className: "border-b border-po-cyan/30 bg-po-cyan/10 px-4 py-2 text-center text-base font-medium text-po-cyan",
|
|
1014
1584
|
children: [
|
|
1015
1585
|
"Transferring voice to ",
|
|
1016
1586
|
transferLabel,
|
|
1017
1587
|
"..."
|
|
1018
1588
|
]
|
|
1019
1589
|
}),
|
|
1020
|
-
content: mcpView ? /* @__PURE__ */ jsx(SessionMcp, { state: mcp }, sessionId) : tab ? /* @__PURE__ */ jsx(tab.panel, { ...slotProps }) : noSessions ? /* @__PURE__ */ jsx(
|
|
1590
|
+
content: mcpView ? /* @__PURE__ */ jsx(SessionMcp, { state: mcp }, sessionId) : tab ? /* @__PURE__ */ jsx(tab.panel, { ...slotProps }) : noSessions ? /* @__PURE__ */ jsx(ElegantOnboardingFlow, {}) : /* @__PURE__ */ jsx(Timeline, {}),
|
|
1021
1591
|
composer: mcpView ? null : tab ? tab.retainComposer === true ? /* @__PURE__ */ jsx(Composer, { composerContext }) : null : noSessions ? null : /* @__PURE__ */ jsx(Composer, {}),
|
|
1022
1592
|
controls: !mcpView && !tab && !noSessions && dormantMeta === null ? /* @__PURE__ */ jsx(SelectionBar, {}) : null,
|
|
1023
1593
|
activity: /* @__PURE__ */ jsx(ActivityDock, {
|
|
1024
1594
|
mcp,
|
|
1595
|
+
tabId,
|
|
1025
1596
|
onClose: closeActivity,
|
|
1026
1597
|
onOpenContent: () => setMobileActivityOpen(false)
|
|
1027
1598
|
})
|
|
@@ -1070,21 +1641,21 @@ function ElegantSettings() {
|
|
|
1070
1641
|
]);
|
|
1071
1642
|
return /* @__PURE__ */ jsxs("div", {
|
|
1072
1643
|
"data-testid": "settings",
|
|
1073
|
-
className: "flex h-full min-h-0 min-w-0 flex-col overflow-hidden bg-
|
|
1644
|
+
className: "flex h-full min-h-0 min-w-0 flex-col overflow-hidden bg-po-bg",
|
|
1074
1645
|
children: [/* @__PURE__ */ jsxs("header", {
|
|
1075
|
-
className: "grid shrink-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-x-2 gap-y-2 border-b border-
|
|
1646
|
+
className: "grid shrink-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-x-2 gap-y-2 border-b border-po-border px-3 py-2 sm:h-14 sm:grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] sm:px-6 sm:py-0",
|
|
1076
1647
|
children: [
|
|
1077
1648
|
/* @__PURE__ */ jsx("h1", {
|
|
1078
|
-
className: "order-1 min-w-0 truncate text-xl font-semibold text-
|
|
1649
|
+
className: "order-1 min-w-0 truncate text-xl font-semibold text-po-hi sm:order-none",
|
|
1079
1650
|
children: "Settings"
|
|
1080
1651
|
}),
|
|
1081
1652
|
/* @__PURE__ */ jsxs("nav", {
|
|
1082
|
-
className: "order-3 col-span-2 flex w-full items-center gap-1 rounded-lg bg-
|
|
1653
|
+
className: "order-3 col-span-2 flex w-full items-center gap-1 rounded-lg bg-po-panel p-1 sm:order-none sm:col-span-1 sm:w-auto",
|
|
1083
1654
|
"aria-label": "settings workspace",
|
|
1084
1655
|
children: [/* @__PURE__ */ jsx(NavTab, {
|
|
1085
1656
|
asChild: true,
|
|
1086
1657
|
active: workspace === "general",
|
|
1087
|
-
className: "min-h-8 flex-1 justify-center rounded-md px-4 focus-visible:ring-2 focus-visible:ring-
|
|
1658
|
+
className: "min-h-8 flex-1 justify-center rounded-md px-4 focus-visible:ring-2 focus-visible:ring-po-green sm:flex-none",
|
|
1088
1659
|
"aria-current": workspace === "general" ? "true" : void 0,
|
|
1089
1660
|
children: /* @__PURE__ */ jsx(Link, {
|
|
1090
1661
|
to: "/settings/$section",
|
|
@@ -1096,7 +1667,7 @@ function ElegantSettings() {
|
|
|
1096
1667
|
}), /* @__PURE__ */ jsx(NavTab, {
|
|
1097
1668
|
asChild: true,
|
|
1098
1669
|
active: workspace === "repository",
|
|
1099
|
-
className: "min-h-8 flex-1 justify-center rounded-md px-4 focus-visible:ring-2 focus-visible:ring-
|
|
1670
|
+
className: "min-h-8 flex-1 justify-center rounded-md px-4 focus-visible:ring-2 focus-visible:ring-po-green sm:flex-none",
|
|
1100
1671
|
"aria-current": workspace === "repository" ? "true" : void 0,
|
|
1101
1672
|
children: /* @__PURE__ */ jsx(Link, {
|
|
1102
1673
|
to: "/settings/$section",
|