@agent-native/dispatch 0.40.0 → 0.40.3
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/CHANGELOG.md +48 -19
- package/dist/actions/provider-api-register.d.ts +7 -7
- package/dist/components/app-open-actions.d.ts +1 -1
- package/dist/components/app-open-actions.d.ts.map +1 -1
- package/dist/components/app-open-actions.js +1 -1
- package/dist/components/app-open-actions.js.map +1 -1
- package/dist/components/app-row-settings.js +1 -1
- package/dist/components/app-row-settings.js.map +1 -1
- package/dist/components/automation-create-dialog.js +2 -2
- package/dist/components/automation-create-dialog.js.map +1 -1
- package/dist/components/automation-details-panel.js +1 -1
- package/dist/components/automation-details-panel.js.map +1 -1
- package/dist/components/chat-home-apps.js +1 -1
- package/dist/components/chat-home-apps.js.map +1 -1
- package/dist/components/create-app-popover.js +3 -3
- package/dist/components/create-app-popover.js.map +1 -1
- package/dist/components/dispatch-control-plane.d.ts.map +1 -1
- package/dist/components/dispatch-control-plane.js +9 -30
- package/dist/components/dispatch-control-plane.js.map +1 -1
- package/dist/components/layout/Header.js +2 -2
- package/dist/components/layout/Header.js.map +1 -1
- package/dist/components/layout/Layout.d.ts +6 -5
- package/dist/components/layout/Layout.d.ts.map +1 -1
- package/dist/components/layout/Layout.js +73 -113
- package/dist/components/layout/Layout.js.map +1 -1
- package/dist/components/layout/workspace-apps-rail.d.ts.map +1 -1
- package/dist/components/layout/workspace-apps-rail.js +7 -19
- package/dist/components/layout/workspace-apps-rail.js.map +1 -1
- package/dist/components/messaging-setup-panel.js +2 -1
- package/dist/components/messaging-setup-panel.js.map +1 -1
- package/dist/components/workspace-app-card.js +2 -2
- package/dist/components/workspace-app-card.js.map +1 -1
- package/dist/components/workspace-app-host.d.ts +1 -1
- package/dist/components/workspace-app-host.d.ts.map +1 -1
- package/dist/components/workspace-app-host.js +7 -74
- package/dist/components/workspace-app-host.js.map +1 -1
- package/dist/hooks/use-navigation-state.js +1 -1
- package/dist/hooks/use-navigation-state.js.map +1 -1
- package/dist/lib/workspace-apps.js +1 -1
- package/dist/lib/workspace-apps.js.map +1 -1
- package/dist/routes/pages/$appId.js +1 -1
- package/dist/routes/pages/$appId.js.map +1 -1
- package/dist/routes/pages/_index.js +1 -1
- package/dist/routes/pages/_index.js.map +1 -1
- package/dist/routes/pages/admin._index.js +1 -1
- package/dist/routes/pages/admin._index.js.map +1 -1
- package/dist/routes/pages/agent-integrations.js +1 -1
- package/dist/routes/pages/agent-integrations.js.map +1 -1
- package/dist/routes/pages/apps.d.ts.map +1 -1
- package/dist/routes/pages/apps.js +3 -43
- package/dist/routes/pages/apps.js.map +1 -1
- package/dist/routes/pages/browser-chat.js +1 -1
- package/dist/routes/pages/browser-chat.js.map +1 -1
- package/dist/routes/pages/chat.d.ts.map +1 -1
- package/dist/routes/pages/chat.js +24 -43
- package/dist/routes/pages/chat.js.map +1 -1
- package/dist/routes/pages/extensions.$id.js +1 -1
- package/dist/routes/pages/extensions.$id.js.map +1 -1
- package/dist/routes/pages/extensions._index.js +1 -1
- package/dist/routes/pages/extensions._index.js.map +1 -1
- package/dist/routes/pages/integrations.js +1 -1
- package/dist/routes/pages/integrations.js.map +1 -1
- package/dist/routes/pages/new-app.js +1 -1
- package/dist/routes/pages/new-app.js.map +1 -1
- package/dist/routes/pages/operations.js +2 -2
- package/dist/routes/pages/operations.js.map +1 -1
- package/dist/routes/pages/overview.d.ts +2 -2
- package/dist/routes/pages/settings-page.d.ts +10 -0
- package/dist/routes/pages/settings-page.d.ts.map +1 -0
- package/dist/routes/pages/settings-page.js +104 -0
- package/dist/routes/pages/settings-page.js.map +1 -0
- package/dist/routes/pages/settings.d.ts +4 -12
- package/dist/routes/pages/settings.d.ts.map +1 -1
- package/dist/routes/pages/settings.js +4 -88
- package/dist/routes/pages/settings.js.map +1 -1
- package/dist/routes/pages/tools.$id.js +1 -1
- package/dist/routes/pages/tools.$id.js.map +1 -1
- package/dist/routes/pages/tools._index.js +1 -1
- package/dist/routes/pages/tools._index.js.map +1 -1
- package/dist/routes/pages/vault.d.ts +1 -1
- package/dist/routes/pages/vault.js +1 -1
- package/dist/routes/pages/vault.js.map +1 -1
- package/dist/shared/app-roles.js.map +1 -1
- package/package.json +3 -3
- package/src/components/app-open-actions.tsx +1 -1
- package/src/components/app-row-settings.tsx +1 -1
- package/src/components/automation-create-dialog.tsx +7 -7
- package/src/components/automation-details-panel.tsx +1 -1
- package/src/components/chat-home-apps.tsx +1 -1
- package/src/components/create-app-popover.spec.tsx +5 -7
- package/src/components/create-app-popover.tsx +3 -3
- package/src/components/dispatch-control-plane.spec.tsx +12 -19
- package/src/components/dispatch-control-plane.tsx +10 -84
- package/src/components/layout/Header.tsx +2 -2
- package/src/components/layout/Layout.app-chat.spec.ts +1 -0
- package/src/components/layout/Layout.spec.tsx +49 -30
- package/src/components/layout/Layout.tsx +153 -205
- package/src/components/layout/workspace-apps-rail.spec.tsx +79 -0
- package/src/components/layout/workspace-apps-rail.tsx +6 -30
- package/src/components/messaging-setup-panel.tsx +1 -1
- package/src/components/workspace-app-card.tsx +2 -2
- package/src/components/workspace-app-chat-rail.spec.tsx +2 -2
- package/src/components/workspace-app-host.spec.tsx +19 -19
- package/src/components/workspace-app-host.tsx +12 -129
- package/src/hooks/use-navigation-state.ts +1 -1
- package/src/lib/workspace-apps.ts +1 -1
- package/src/routes/pages/$appId.tsx +1 -1
- package/src/routes/pages/_index.tsx +1 -1
- package/src/routes/pages/admin._index.tsx +1 -1
- package/src/routes/pages/agent-integrations.tsx +1 -1
- package/src/routes/pages/apps.tsx +2 -86
- package/src/routes/pages/automations.spec.tsx +1 -1
- package/src/routes/pages/browser-chat.spec.tsx +1 -1
- package/src/routes/pages/browser-chat.tsx +1 -1
- package/src/routes/pages/chat.spec.tsx +23 -46
- package/src/routes/pages/chat.tsx +20 -57
- package/src/routes/pages/extensions.$id.tsx +1 -1
- package/src/routes/pages/extensions._index.tsx +1 -1
- package/src/routes/pages/integrations.tsx +1 -1
- package/src/routes/pages/new-app.tsx +1 -1
- package/src/routes/pages/operations.tsx +2 -2
- package/src/routes/pages/settings-page.tsx +250 -0
- package/src/routes/pages/settings.spec.tsx +30 -8
- package/src/routes/pages/settings.tsx +4 -184
- package/src/routes/pages/tools.$id.tsx +1 -1
- package/src/routes/pages/tools._index.tsx +1 -1
- package/src/routes/pages/vault.tsx +1 -1
- package/src/shared/app-roles.ts +1 -1
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
|
-
AgentChatHome,
|
|
3
|
-
type AgentChatHomeProps,
|
|
4
2
|
insertAgentComposerReference,
|
|
5
3
|
markAgentChatHomeHandoff,
|
|
6
4
|
readChatFirstMode,
|
|
7
|
-
useActiveAgentChatRunId,
|
|
8
5
|
} from "@agent-native/core/client/agent-chat";
|
|
9
6
|
import { appBasePath, appPath } from "@agent-native/core/client/api-path";
|
|
10
|
-
import { writeClipboardText } from "@agent-native/core/client/clipboard";
|
|
11
7
|
import { useActionQuery } from "@agent-native/core/client/hooks";
|
|
12
8
|
import { useT } from "@agent-native/core/client/i18n";
|
|
13
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
AgentChatHome,
|
|
11
|
+
type AgentChatHomeProps,
|
|
12
|
+
} from "@agent-native/toolkit/app/chat";
|
|
14
13
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
15
14
|
import { useLocation, useNavigate } from "react-router";
|
|
16
15
|
|
|
17
16
|
import { ActionQueryError } from "../../components/action-query-error";
|
|
18
17
|
import { DispatchChatHomeApps } from "../../components/chat-home-apps";
|
|
19
18
|
import { useDispatchExtensions } from "../../components/layout/Layout";
|
|
20
|
-
import { Button } from "../../components/ui/button";
|
|
21
19
|
import { Skeleton } from "../../components/ui/skeleton";
|
|
22
20
|
import { submitOverviewPrompt } from "../../lib/overview-chat";
|
|
23
21
|
|
|
@@ -73,46 +71,6 @@ interface DispatchThreadUrlSync {
|
|
|
73
71
|
navigate: (path: string, options?: { replace?: boolean }) => void;
|
|
74
72
|
}
|
|
75
73
|
|
|
76
|
-
function DispatchRequestIdButton({ requestId }: { requestId: string | null }) {
|
|
77
|
-
const t = useT();
|
|
78
|
-
const [copied, setCopied] = useState(false);
|
|
79
|
-
|
|
80
|
-
const handleCopy = useCallback(() => {
|
|
81
|
-
if (!requestId) return;
|
|
82
|
-
void writeClipboardText(requestId).then((ok) => {
|
|
83
|
-
if (!ok) return;
|
|
84
|
-
setCopied(true);
|
|
85
|
-
window.setTimeout(() => setCopied(false), 1000);
|
|
86
|
-
});
|
|
87
|
-
}, [requestId]);
|
|
88
|
-
|
|
89
|
-
return (
|
|
90
|
-
<Button
|
|
91
|
-
type="button"
|
|
92
|
-
variant="outline"
|
|
93
|
-
size="sm"
|
|
94
|
-
disabled={!requestId}
|
|
95
|
-
onClick={handleCopy}
|
|
96
|
-
aria-label={t("dispatch.pages.copyRequestId", {
|
|
97
|
-
defaultValue: requestId ? "Copy request ID" : "Request ID unavailable",
|
|
98
|
-
})}
|
|
99
|
-
>
|
|
100
|
-
{copied ? (
|
|
101
|
-
<IconCheck aria-hidden="true" />
|
|
102
|
-
) : (
|
|
103
|
-
<IconCopy aria-hidden="true" />
|
|
104
|
-
)}
|
|
105
|
-
{copied
|
|
106
|
-
? t("dispatch.pages.copied", { defaultValue: "Copied" })
|
|
107
|
-
: t("dispatch.pages.copyRequestId", {
|
|
108
|
-
defaultValue: requestId
|
|
109
|
-
? "Copy request ID"
|
|
110
|
-
: "Request ID unavailable",
|
|
111
|
-
})}
|
|
112
|
-
</Button>
|
|
113
|
-
);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
74
|
interface DispatchChatLocationState {
|
|
117
75
|
dispatchPrompt?: {
|
|
118
76
|
id?: string | number;
|
|
@@ -136,7 +94,6 @@ export default function ChatRoute() {
|
|
|
136
94
|
const location = useLocation();
|
|
137
95
|
const navigate = useNavigate();
|
|
138
96
|
const routeThreadId = threadIdFromPath(location.pathname);
|
|
139
|
-
const activeRunId = useActiveAgentChatRunId(routeThreadId);
|
|
140
97
|
const agentPath = new URLSearchParams(location.search).get("agent");
|
|
141
98
|
const agentsQuery = useActionQuery<WorkspaceAgentResource[]>(
|
|
142
99
|
"list-workspace-resources",
|
|
@@ -194,6 +151,14 @@ export default function ChatRoute() {
|
|
|
194
151
|
const state = location.state as DispatchChatLocationState | null;
|
|
195
152
|
const prompt = state?.dispatchPrompt;
|
|
196
153
|
const thread = state?.dispatchThread;
|
|
154
|
+
const [pendingOverviewPrompt, setPendingOverviewPrompt] = useState<
|
|
155
|
+
DispatchChatLocationState["dispatchPrompt"] | null
|
|
156
|
+
>(null);
|
|
157
|
+
const activePrompt = prompt?.message ? prompt : pendingOverviewPrompt;
|
|
158
|
+
|
|
159
|
+
useEffect(() => {
|
|
160
|
+
if (routeThreadId) setPendingOverviewPrompt(null);
|
|
161
|
+
}, [routeThreadId]);
|
|
197
162
|
|
|
198
163
|
useEffect(() => {
|
|
199
164
|
const message = prompt?.message?.trim();
|
|
@@ -215,6 +180,7 @@ export default function ChatRoute() {
|
|
|
215
180
|
);
|
|
216
181
|
}
|
|
217
182
|
if (message) {
|
|
183
|
+
setPendingOverviewPrompt(prompt ?? null);
|
|
218
184
|
submitOverviewPrompt(message, prompt?.selectedModel, {
|
|
219
185
|
openSidebar: false,
|
|
220
186
|
selectedEngine: prompt?.selectedEngine,
|
|
@@ -303,15 +269,10 @@ export default function ChatRoute() {
|
|
|
303
269
|
|
|
304
270
|
return (
|
|
305
271
|
<div className="flex h-full min-h-0 flex-col bg-background">
|
|
306
|
-
{threadUrlSync.routeThreadId ? (
|
|
307
|
-
<div className="flex justify-end px-4 pt-4 sm:px-6">
|
|
308
|
-
<DispatchRequestIdButton requestId={activeRunId} />
|
|
309
|
-
</div>
|
|
310
|
-
) : null}
|
|
311
272
|
<AgentChatHome
|
|
312
273
|
key={agent ? `agent-${agent.id}` : "dispatch"}
|
|
313
274
|
className="flex-1 min-h-0"
|
|
314
|
-
contentClassName="max-w-
|
|
275
|
+
contentClassName="max-w-none"
|
|
315
276
|
surfaceClassName="dispatch-chat-panel px-4 sm:px-6"
|
|
316
277
|
chatViewTransition
|
|
317
278
|
defaultMode="chat"
|
|
@@ -323,7 +284,7 @@ export default function ChatRoute() {
|
|
|
323
284
|
dynamicSuggestions={false}
|
|
324
285
|
suppressInlineOpenApp={suppressInlineOpenApp}
|
|
325
286
|
suggestions={
|
|
326
|
-
agent || routeThreadId ||
|
|
287
|
+
agent || routeThreadId || activePrompt?.message
|
|
327
288
|
? []
|
|
328
289
|
: [
|
|
329
290
|
t("dispatch.pages.suggestionWorkspaceHealth"),
|
|
@@ -335,8 +296,10 @@ export default function ChatRoute() {
|
|
|
335
296
|
defaultValue:
|
|
336
297
|
"Route work, inspect status, or create something new from one place.",
|
|
337
298
|
})}
|
|
338
|
-
centerComposerWhenEmpty={!
|
|
339
|
-
composerLayoutVariant={
|
|
299
|
+
centerComposerWhenEmpty={!activePrompt?.message && !routeThreadId}
|
|
300
|
+
composerLayoutVariant={
|
|
301
|
+
activePrompt?.message || routeThreadId ? "default" : "hero"
|
|
302
|
+
}
|
|
340
303
|
composerPlaceholder={
|
|
341
304
|
agent
|
|
342
305
|
? `Ask ${agent.name}...`
|
|
@@ -350,7 +313,7 @@ export default function ChatRoute() {
|
|
|
350
313
|
<h1>{agent.name}</h1>
|
|
351
314
|
{agent.description ? <p>{agent.description}</p> : null}
|
|
352
315
|
</div>
|
|
353
|
-
) : !
|
|
316
|
+
) : !activePrompt?.message && !routeThreadId ? (
|
|
354
317
|
<div className="dispatch-chat-intro">
|
|
355
318
|
<h1>
|
|
356
319
|
{t("dispatch.pages.chatHomeTitle", {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useT } from "@agent-native/core/client/i18n";
|
|
2
|
-
import { McpIntegrationsLanding } from "@agent-native/
|
|
2
|
+
import { McpIntegrationsLanding } from "@agent-native/toolkit/app/integrations";
|
|
3
3
|
import { Link } from "react-router";
|
|
4
4
|
|
|
5
5
|
import { DispatchShell } from "../../components/dispatch-shell";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useT } from "@agent-native/core/client/i18n";
|
|
2
|
-
import { NewWorkspaceAppFlow } from "@agent-native/
|
|
2
|
+
import { NewWorkspaceAppFlow } from "@agent-native/toolkit/app/onboarding";
|
|
3
3
|
|
|
4
4
|
import { DispatchShell } from "../../components/dispatch-shell";
|
|
5
5
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { DbAdminPage } from "@agent-native/core/client/db-admin";
|
|
2
1
|
import { useT } from "@agent-native/core/client/i18n";
|
|
3
|
-
import {
|
|
2
|
+
import { DbAdminPage } from "@agent-native/toolkit/app/db-admin";
|
|
3
|
+
import { ObservabilityDashboard } from "@agent-native/toolkit/app/observability";
|
|
4
4
|
import {
|
|
5
5
|
IconActivity,
|
|
6
6
|
IconArrowUpRight,
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CHAT_FIRST_MODE_CHANGED_EVENT,
|
|
3
|
+
readChatFirstModeState,
|
|
4
|
+
writeChatFirstMode,
|
|
5
|
+
} from "@agent-native/core/client/agent-chat";
|
|
6
|
+
import {
|
|
7
|
+
useFeatureFlag,
|
|
8
|
+
useFeatureFlagState,
|
|
9
|
+
} from "@agent-native/core/client/feature-flags";
|
|
10
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
11
|
+
import { SETTINGS_REDESIGN_FLAG } from "@agent-native/core/feature-flags/registry";
|
|
12
|
+
import { ChangelogSettingsCard } from "@agent-native/toolkit/app/changelog";
|
|
13
|
+
import { OrgMembersPage, TeamPage } from "@agent-native/toolkit/app/org";
|
|
14
|
+
import {
|
|
15
|
+
AccountSettingsCard,
|
|
16
|
+
CORE_SETTINGS_PAGES,
|
|
17
|
+
registerSettingsPages,
|
|
18
|
+
SettingsGroup,
|
|
19
|
+
SettingsRow,
|
|
20
|
+
SettingsTabsPage,
|
|
21
|
+
useAgentSettingsTabs,
|
|
22
|
+
type SettingsSearchEntry,
|
|
23
|
+
} from "@agent-native/toolkit/app/settings";
|
|
24
|
+
import { LanguagePicker } from "@agent-native/toolkit/app/shared";
|
|
25
|
+
import { IconShield } from "@tabler/icons-react";
|
|
26
|
+
import { useMemo, useState } from "react";
|
|
27
|
+
import { Link } from "react-router";
|
|
28
|
+
|
|
29
|
+
import { Button } from "../../components/ui/button";
|
|
30
|
+
import { Switch } from "../../components/ui/switch";
|
|
31
|
+
import { dispatchAccessDescriptor } from "../../shared/app-roles.js";
|
|
32
|
+
import { DISPATCH_CONNECT_APPS_FLAG } from "../../shared/feature-flags.js";
|
|
33
|
+
|
|
34
|
+
const coreMembersPage = CORE_SETTINGS_PAGES.find(
|
|
35
|
+
(page) => page.id === "members",
|
|
36
|
+
);
|
|
37
|
+
if (!coreMembersPage) {
|
|
38
|
+
throw new Error("Core Settings has no members page for Dispatch app roles");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function DispatchMembersSettingsPage() {
|
|
42
|
+
return <OrgMembersPage appRoles={dispatchAccessDescriptor} />;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// The redesigned Settings shows Members from core; Dispatch's replaces it so
|
|
46
|
+
// the app-role column stays.
|
|
47
|
+
registerSettingsPages([
|
|
48
|
+
{ ...coreMembersPage, component: DispatchMembersSettingsPage },
|
|
49
|
+
]);
|
|
50
|
+
|
|
51
|
+
export function meta() {
|
|
52
|
+
return [{ title: "Settings - Dispatch" }];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface DispatchSettingsPageProps {
|
|
56
|
+
/** Raw CHANGELOG.md behind What's new. */
|
|
57
|
+
changelog: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** The template route supplies the app's own changelog. */
|
|
61
|
+
export function DispatchSettingsPage({ changelog }: DispatchSettingsPageProps) {
|
|
62
|
+
const t = useT();
|
|
63
|
+
const connectAppsEnabled = useFeatureFlag(DISPATCH_CONNECT_APPS_FLAG.key);
|
|
64
|
+
// Core Preferences owns the interface language in the redesigned Settings,
|
|
65
|
+
// whose Dispatch General page shows `generalGroups` instead of `general`.
|
|
66
|
+
const redesign = useFeatureFlagState(SETTINGS_REDESIGN_FLAG.key).enabled;
|
|
67
|
+
const agentSettingsTabs = useAgentSettingsTabs({
|
|
68
|
+
usageAppId: "dispatch",
|
|
69
|
+
usageViewAllHref: "/admin/metrics",
|
|
70
|
+
organizationContent: (
|
|
71
|
+
<div className="mx-auto w-full max-w-3xl">
|
|
72
|
+
<TeamPage
|
|
73
|
+
showTitle={false}
|
|
74
|
+
appRoles={dispatchAccessDescriptor}
|
|
75
|
+
createOrgDescription="Set up a team to share dispatch destinations and approvals with your colleagues."
|
|
76
|
+
/>
|
|
77
|
+
</div>
|
|
78
|
+
),
|
|
79
|
+
});
|
|
80
|
+
const settingsTabs = [
|
|
81
|
+
...agentSettingsTabs,
|
|
82
|
+
{
|
|
83
|
+
id: "admin",
|
|
84
|
+
label: t("dispatch.nav.admin", { defaultValue: "Admin" }),
|
|
85
|
+
icon: IconShield,
|
|
86
|
+
group: "Admin",
|
|
87
|
+
href: "/admin",
|
|
88
|
+
content: null,
|
|
89
|
+
},
|
|
90
|
+
];
|
|
91
|
+
const [chatFirstModeState] = useState(() => readChatFirstModeState());
|
|
92
|
+
const [chatFirstMode, setChatFirstMode] = useState(
|
|
93
|
+
() => chatFirstModeState.enabled,
|
|
94
|
+
);
|
|
95
|
+
const [chatFirstStorageNotice, setChatFirstStorageNotice] = useState<
|
|
96
|
+
string | null
|
|
97
|
+
>(
|
|
98
|
+
chatFirstModeState.availability === "unavailable"
|
|
99
|
+
? t("settings.chatFirstStorageUnavailable")
|
|
100
|
+
: null,
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
function updateChatFirstMode(enabled: boolean) {
|
|
104
|
+
const result = writeChatFirstMode(enabled);
|
|
105
|
+
if (!result.ok) {
|
|
106
|
+
setChatFirstStorageNotice(t("settings.chatFirstStorageBlocked"));
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
setChatFirstStorageNotice(null);
|
|
110
|
+
setChatFirstMode(enabled);
|
|
111
|
+
window.dispatchEvent(
|
|
112
|
+
new CustomEvent(CHAT_FIRST_MODE_CHANGED_EVENT, {
|
|
113
|
+
detail: { enabled },
|
|
114
|
+
}),
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const generalSearchEntries = useMemo<SettingsSearchEntry[]>(
|
|
119
|
+
() => [
|
|
120
|
+
...(redesign
|
|
121
|
+
? []
|
|
122
|
+
: [
|
|
123
|
+
{
|
|
124
|
+
id: "dispatch-language",
|
|
125
|
+
label: t("settings.languageTitle"),
|
|
126
|
+
keywords: "language locale translation i18n",
|
|
127
|
+
hash: "language",
|
|
128
|
+
},
|
|
129
|
+
]),
|
|
130
|
+
{
|
|
131
|
+
id: "dispatch-workspace",
|
|
132
|
+
label: redesign
|
|
133
|
+
? t("settings.resourcesTitle")
|
|
134
|
+
: t("settings.workspaceTitle"),
|
|
135
|
+
keywords: "workspace resources integrations vault destinations",
|
|
136
|
+
hash: "workspace-resources",
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
id: "dispatch-chat-first",
|
|
140
|
+
label: t("settings.chatFirstTitle"),
|
|
141
|
+
keywords: "chat first codex t3 apps pane navigation",
|
|
142
|
+
hash: "chat-first",
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
[redesign, t],
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
const chatFirstSwitch = (
|
|
149
|
+
<Switch
|
|
150
|
+
aria-label={t("settings.chatFirstAriaLabel")}
|
|
151
|
+
checked={chatFirstMode}
|
|
152
|
+
onCheckedChange={updateChatFirstMode}
|
|
153
|
+
/>
|
|
154
|
+
);
|
|
155
|
+
const chatFirstStorageAlert = chatFirstStorageNotice ? (
|
|
156
|
+
<p className="text-sm text-destructive" role="alert">
|
|
157
|
+
{chatFirstStorageNotice}
|
|
158
|
+
</p>
|
|
159
|
+
) : null;
|
|
160
|
+
const connectAppsRow = connectAppsEnabled ? (
|
|
161
|
+
<SettingsRow
|
|
162
|
+
id="connect-apps"
|
|
163
|
+
label={t("settings.connectApps")}
|
|
164
|
+
description={t("settings.connectAppsDescription")}
|
|
165
|
+
control={
|
|
166
|
+
<Button variant="outline" asChild>
|
|
167
|
+
<Link to="/connect">{t("settings.openConnectApps")}</Link>
|
|
168
|
+
</Button>
|
|
169
|
+
}
|
|
170
|
+
/>
|
|
171
|
+
) : null;
|
|
172
|
+
const resourceSettingsButton = (
|
|
173
|
+
<Button variant="outline" asChild>
|
|
174
|
+
<Link to="/workspace">{t("settings.openResourceSettings")}</Link>
|
|
175
|
+
</Button>
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
return (
|
|
179
|
+
<SettingsTabsPage
|
|
180
|
+
account={<AccountSettingsCard />}
|
|
181
|
+
extraTabs={settingsTabs}
|
|
182
|
+
generalSearchEntries={generalSearchEntries}
|
|
183
|
+
general={
|
|
184
|
+
<div className="mx-auto w-full max-w-2xl space-y-6">
|
|
185
|
+
<p className="text-sm leading-6 text-muted-foreground">
|
|
186
|
+
{t("settings.description")}
|
|
187
|
+
</p>
|
|
188
|
+
|
|
189
|
+
<SettingsGroup>
|
|
190
|
+
<SettingsRow
|
|
191
|
+
id="language"
|
|
192
|
+
label={t("settings.languageTitle")}
|
|
193
|
+
description={t("settings.languageDescription")}
|
|
194
|
+
control={
|
|
195
|
+
<div className="w-56">
|
|
196
|
+
<LanguagePicker label={t("settings.languageLabel")} />
|
|
197
|
+
</div>
|
|
198
|
+
}
|
|
199
|
+
/>
|
|
200
|
+
<SettingsRow
|
|
201
|
+
id="workspace-resources"
|
|
202
|
+
label={t("settings.workspaceTitle")}
|
|
203
|
+
description={t("settings.workspaceDescription")}
|
|
204
|
+
control={resourceSettingsButton}
|
|
205
|
+
/>
|
|
206
|
+
{connectAppsRow}
|
|
207
|
+
</SettingsGroup>
|
|
208
|
+
|
|
209
|
+
<SettingsGroup id="chat-first">
|
|
210
|
+
<SettingsRow
|
|
211
|
+
label={t("settings.chatFirstTitle")}
|
|
212
|
+
description={t("settings.chatFirstDescription")}
|
|
213
|
+
control={chatFirstSwitch}
|
|
214
|
+
>
|
|
215
|
+
<p className="text-sm leading-6 text-muted-foreground">
|
|
216
|
+
{t("settings.chatFirstSessionWatchDescription")}
|
|
217
|
+
</p>
|
|
218
|
+
{chatFirstStorageAlert}
|
|
219
|
+
</SettingsRow>
|
|
220
|
+
</SettingsGroup>
|
|
221
|
+
</div>
|
|
222
|
+
}
|
|
223
|
+
generalGroups={
|
|
224
|
+
<SettingsGroup id="workspace" title={t("settings.workspaceTitle")}>
|
|
225
|
+
<SettingsRow
|
|
226
|
+
id="chat-first"
|
|
227
|
+
label={t("settings.chatFirstTitle")}
|
|
228
|
+
description={t("settings.chatFirstDescription")}
|
|
229
|
+
control={chatFirstSwitch}
|
|
230
|
+
>
|
|
231
|
+
{chatFirstStorageAlert}
|
|
232
|
+
</SettingsRow>
|
|
233
|
+
<SettingsRow
|
|
234
|
+
id="workspace-resources"
|
|
235
|
+
label={t("settings.resourcesTitle")}
|
|
236
|
+
description={t("settings.workspaceDescription")}
|
|
237
|
+
control={resourceSettingsButton}
|
|
238
|
+
/>
|
|
239
|
+
{connectAppsRow}
|
|
240
|
+
</SettingsGroup>
|
|
241
|
+
}
|
|
242
|
+
whatsNew={
|
|
243
|
+
<div className="mx-auto w-full max-w-2xl">
|
|
244
|
+
<ChangelogSettingsCard markdown={changelog} />
|
|
245
|
+
</div>
|
|
246
|
+
}
|
|
247
|
+
whatsNewMarkdown={changelog}
|
|
248
|
+
/>
|
|
249
|
+
);
|
|
250
|
+
}
|
|
@@ -8,6 +8,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
8
8
|
import { dispatchAccessDescriptor } from "../../shared/app-roles.js";
|
|
9
9
|
|
|
10
10
|
const state = vi.hoisted(() => ({
|
|
11
|
+
redesign: false,
|
|
11
12
|
registered: [] as Array<{
|
|
12
13
|
id: string;
|
|
13
14
|
component: ComponentType;
|
|
@@ -16,7 +17,6 @@ const state = vi.hoisted(() => ({
|
|
|
16
17
|
membersAppRoles: undefined as unknown,
|
|
17
18
|
pageProps: null as null | {
|
|
18
19
|
general?: ReactNode;
|
|
19
|
-
account?: ReactNode;
|
|
20
20
|
generalGroups?: ReactNode;
|
|
21
21
|
generalSearchEntries?: Array<{ id: string; hash?: string }>;
|
|
22
22
|
extraTabs?: Array<{ id: string; href?: string }>;
|
|
@@ -30,7 +30,7 @@ vi.mock("@agent-native/core/client/agent-chat", () => ({
|
|
|
30
30
|
writeChatFirstMode: () => ({ ok: true }),
|
|
31
31
|
}));
|
|
32
32
|
|
|
33
|
-
vi.mock("@agent-native/
|
|
33
|
+
vi.mock("@agent-native/toolkit/app/changelog", () => ({
|
|
34
34
|
ChangelogSettingsCard: ({ markdown }: { markdown: string }) => (
|
|
35
35
|
<div data-changelog>{markdown}</div>
|
|
36
36
|
),
|
|
@@ -38,10 +38,12 @@ vi.mock("@agent-native/core/client/changelog", () => ({
|
|
|
38
38
|
|
|
39
39
|
vi.mock("@agent-native/core/client/feature-flags", () => ({
|
|
40
40
|
useFeatureFlag: () => false,
|
|
41
|
+
useFeatureFlagState: () => ({ status: "ready", enabled: state.redesign }),
|
|
41
42
|
}));
|
|
42
43
|
|
|
43
44
|
vi.mock("@agent-native/core/feature-flags/registry", () => ({
|
|
44
45
|
CONNECT_APPS_FLAG: { key: "connect-apps" },
|
|
46
|
+
SETTINGS_REDESIGN_FLAG: { key: "settings-redesign" },
|
|
45
47
|
defineFeatureFlag: (flag: { key: string }) => flag,
|
|
46
48
|
}));
|
|
47
49
|
|
|
@@ -49,7 +51,11 @@ vi.mock("@agent-native/core/client/i18n", () => ({
|
|
|
49
51
|
useT: () => (key: string) => key,
|
|
50
52
|
}));
|
|
51
53
|
|
|
52
|
-
vi.mock("@agent-native/
|
|
54
|
+
vi.mock("@agent-native/toolkit/app/shared", () => ({
|
|
55
|
+
LanguagePicker: () => null,
|
|
56
|
+
}));
|
|
57
|
+
|
|
58
|
+
vi.mock("@agent-native/toolkit/app/org", () => ({
|
|
53
59
|
TeamPage: () => null,
|
|
54
60
|
OrgMembersPage: ({ appRoles }: { appRoles?: unknown }) => {
|
|
55
61
|
state.membersAppRoles = appRoles;
|
|
@@ -57,7 +63,8 @@ vi.mock("@agent-native/core/client/org", () => ({
|
|
|
57
63
|
},
|
|
58
64
|
}));
|
|
59
65
|
|
|
60
|
-
vi.mock("@agent-native/
|
|
66
|
+
vi.mock("@agent-native/toolkit/app/settings", () => ({
|
|
67
|
+
AccountSettingsCard: () => null,
|
|
61
68
|
CORE_SETTINGS_PAGES: [
|
|
62
69
|
{ id: "profile", component: () => null },
|
|
63
70
|
{
|
|
@@ -88,7 +95,7 @@ vi.mock("@agent-native/core/client/settings", () => ({
|
|
|
88
95
|
),
|
|
89
96
|
SettingsTabsPage: (props: NonNullable<typeof state.pageProps>) => {
|
|
90
97
|
state.pageProps = props;
|
|
91
|
-
return <main>{props.generalGroups}</main>;
|
|
98
|
+
return <main>{state.redesign ? props.generalGroups : props.general}</main>;
|
|
92
99
|
},
|
|
93
100
|
useAgentSettingsTabs: () => [{ id: "organization", label: "Organization" }],
|
|
94
101
|
}));
|
|
@@ -111,6 +118,7 @@ describe("Dispatch settings route", () => {
|
|
|
111
118
|
|
|
112
119
|
beforeEach(() => {
|
|
113
120
|
vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
|
|
121
|
+
state.redesign = false;
|
|
114
122
|
state.pageProps = null;
|
|
115
123
|
state.membersAppRoles = undefined;
|
|
116
124
|
container = document.createElement("div");
|
|
@@ -137,11 +145,25 @@ describe("Dispatch settings route", () => {
|
|
|
137
145
|
expect(state.membersAppRoles).toBe(dispatchAccessDescriptor);
|
|
138
146
|
});
|
|
139
147
|
|
|
140
|
-
it("
|
|
148
|
+
it("keeps the language row and Admin link on today's General tab", () => {
|
|
149
|
+
render();
|
|
150
|
+
|
|
151
|
+
expect(container.querySelector('[data-row="language"]')).not.toBeNull();
|
|
152
|
+
expect(container.textContent).toContain(
|
|
153
|
+
"settings.chatFirstSessionWatchDescription",
|
|
154
|
+
);
|
|
155
|
+
expect(
|
|
156
|
+
state.pageProps?.generalSearchEntries?.map((entry) => entry.id),
|
|
157
|
+
).toContain("dispatch-language");
|
|
158
|
+
expect(
|
|
159
|
+
state.pageProps?.extraTabs?.find((tab) => tab.id === "admin")?.href,
|
|
160
|
+
).toBe("/admin");
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it("drops the language row in the redesigned Settings", () => {
|
|
164
|
+
state.redesign = true;
|
|
141
165
|
render();
|
|
142
166
|
|
|
143
|
-
expect(state.pageProps?.general).toBeUndefined();
|
|
144
|
-
expect(state.pageProps?.account).toBeUndefined();
|
|
145
167
|
expect(container.querySelector('[data-row="language"]')).toBeNull();
|
|
146
168
|
expect(container.querySelector('[data-row="chat-first"]')).not.toBeNull();
|
|
147
169
|
expect(
|