@agent-native/dispatch 0.40.2 → 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 CHANGED
@@ -1,5 +1,15 @@
1
1
  # @agent-native/dispatch
2
2
 
3
+ ## 0.40.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 181ca1d: Keep the package changelog in Dispatch's route wrapper so generated workspaces can render the shared Settings page during SSR.
8
+ - Release all public npm packages with a patch version bump.
9
+ - Updated dependencies
10
+ - Updated dependencies [63c4c02]
11
+ - @agent-native/toolkit@0.198.2
12
+
3
13
  ## 0.40.2
4
14
 
5
15
  ### Patch Changes
@@ -1078,11 +1088,4 @@
1078
1088
  - Updated dependencies [89f194f]
1079
1089
  - @agent-native/toolkit@0.14.3
1080
1090
 
1081
- ## 0.24.6
1082
-
1083
- ### Patch Changes
1084
-
1085
- - Updated dependencies [2db503b]
1086
- - @agent-native/toolkit@0.14.2
1087
-
1088
1091
  For the full list of releases, see the [changelog archive](./changelog/archive/CHANGELOG.md).
@@ -0,0 +1,10 @@
1
+ export declare function meta(): {
2
+ title: string;
3
+ }[];
4
+ export interface DispatchSettingsPageProps {
5
+ /** Raw CHANGELOG.md behind What's new. */
6
+ changelog: string;
7
+ }
8
+ /** The template route supplies the app's own changelog. */
9
+ export declare function DispatchSettingsPage({ changelog }: DispatchSettingsPageProps): import("node_modules/@types/react").JSX.Element;
10
+ //# sourceMappingURL=settings-page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-page.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/settings-page.tsx"],"names":[],"mappings":"AAkDA,wBAAgB,IAAI;;IAEnB;AAED,MAAM,WAAW,yBAAyB;IACxC,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,2DAA2D;AAC3D,wBAAgB,oBAAoB,CAAC,EAAE,SAAS,EAAE,EAAE,yBAAyB,mDA6L5E"}
@@ -0,0 +1,104 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { CHAT_FIRST_MODE_CHANGED_EVENT, readChatFirstModeState, writeChatFirstMode, } from "@agent-native/core/client/agent-chat";
3
+ import { useFeatureFlag, useFeatureFlagState, } from "@agent-native/core/client/feature-flags";
4
+ import { useT } from "@agent-native/core/client/i18n";
5
+ import { SETTINGS_REDESIGN_FLAG } from "@agent-native/core/feature-flags/registry";
6
+ import { ChangelogSettingsCard } from "@agent-native/toolkit/app/changelog";
7
+ import { OrgMembersPage, TeamPage } from "@agent-native/toolkit/app/org";
8
+ import { AccountSettingsCard, CORE_SETTINGS_PAGES, registerSettingsPages, SettingsGroup, SettingsRow, SettingsTabsPage, useAgentSettingsTabs, } from "@agent-native/toolkit/app/settings";
9
+ import { LanguagePicker } from "@agent-native/toolkit/app/shared";
10
+ import { IconShield } from "@tabler/icons-react";
11
+ import { useMemo, useState } from "react";
12
+ import { Link } from "react-router";
13
+ import { Button } from "../../components/ui/button.js";
14
+ import { Switch } from "../../components/ui/switch.js";
15
+ import { dispatchAccessDescriptor } from "../../shared/app-roles.js";
16
+ import { DISPATCH_CONNECT_APPS_FLAG } from "../../shared/feature-flags.js";
17
+ const coreMembersPage = CORE_SETTINGS_PAGES.find((page) => page.id === "members");
18
+ if (!coreMembersPage) {
19
+ throw new Error("Core Settings has no members page for Dispatch app roles");
20
+ }
21
+ function DispatchMembersSettingsPage() {
22
+ return _jsx(OrgMembersPage, { appRoles: dispatchAccessDescriptor });
23
+ }
24
+ // The redesigned Settings shows Members from core; Dispatch's replaces it so
25
+ // the app-role column stays.
26
+ registerSettingsPages([
27
+ { ...coreMembersPage, component: DispatchMembersSettingsPage },
28
+ ]);
29
+ export function meta() {
30
+ return [{ title: "Settings - Dispatch" }];
31
+ }
32
+ /** The template route supplies the app's own changelog. */
33
+ export function DispatchSettingsPage({ changelog }) {
34
+ const t = useT();
35
+ const connectAppsEnabled = useFeatureFlag(DISPATCH_CONNECT_APPS_FLAG.key);
36
+ // Core Preferences owns the interface language in the redesigned Settings,
37
+ // whose Dispatch General page shows `generalGroups` instead of `general`.
38
+ const redesign = useFeatureFlagState(SETTINGS_REDESIGN_FLAG.key).enabled;
39
+ const agentSettingsTabs = useAgentSettingsTabs({
40
+ usageAppId: "dispatch",
41
+ usageViewAllHref: "/admin/metrics",
42
+ organizationContent: (_jsx("div", { className: "mx-auto w-full max-w-3xl", children: _jsx(TeamPage, { showTitle: false, appRoles: dispatchAccessDescriptor, createOrgDescription: "Set up a team to share dispatch destinations and approvals with your colleagues." }) })),
43
+ });
44
+ const settingsTabs = [
45
+ ...agentSettingsTabs,
46
+ {
47
+ id: "admin",
48
+ label: t("dispatch.nav.admin", { defaultValue: "Admin" }),
49
+ icon: IconShield,
50
+ group: "Admin",
51
+ href: "/admin",
52
+ content: null,
53
+ },
54
+ ];
55
+ const [chatFirstModeState] = useState(() => readChatFirstModeState());
56
+ const [chatFirstMode, setChatFirstMode] = useState(() => chatFirstModeState.enabled);
57
+ const [chatFirstStorageNotice, setChatFirstStorageNotice] = useState(chatFirstModeState.availability === "unavailable"
58
+ ? t("settings.chatFirstStorageUnavailable")
59
+ : null);
60
+ function updateChatFirstMode(enabled) {
61
+ const result = writeChatFirstMode(enabled);
62
+ if (!result.ok) {
63
+ setChatFirstStorageNotice(t("settings.chatFirstStorageBlocked"));
64
+ return;
65
+ }
66
+ setChatFirstStorageNotice(null);
67
+ setChatFirstMode(enabled);
68
+ window.dispatchEvent(new CustomEvent(CHAT_FIRST_MODE_CHANGED_EVENT, {
69
+ detail: { enabled },
70
+ }));
71
+ }
72
+ const generalSearchEntries = useMemo(() => [
73
+ ...(redesign
74
+ ? []
75
+ : [
76
+ {
77
+ id: "dispatch-language",
78
+ label: t("settings.languageTitle"),
79
+ keywords: "language locale translation i18n",
80
+ hash: "language",
81
+ },
82
+ ]),
83
+ {
84
+ id: "dispatch-workspace",
85
+ label: redesign
86
+ ? t("settings.resourcesTitle")
87
+ : t("settings.workspaceTitle"),
88
+ keywords: "workspace resources integrations vault destinations",
89
+ hash: "workspace-resources",
90
+ },
91
+ {
92
+ id: "dispatch-chat-first",
93
+ label: t("settings.chatFirstTitle"),
94
+ keywords: "chat first codex t3 apps pane navigation",
95
+ hash: "chat-first",
96
+ },
97
+ ], [redesign, t]);
98
+ const chatFirstSwitch = (_jsx(Switch, { "aria-label": t("settings.chatFirstAriaLabel"), checked: chatFirstMode, onCheckedChange: updateChatFirstMode }));
99
+ const chatFirstStorageAlert = chatFirstStorageNotice ? (_jsx("p", { className: "text-sm text-destructive", role: "alert", children: chatFirstStorageNotice })) : null;
100
+ const connectAppsRow = connectAppsEnabled ? (_jsx(SettingsRow, { id: "connect-apps", label: t("settings.connectApps"), description: t("settings.connectAppsDescription"), control: _jsx(Button, { variant: "outline", asChild: true, children: _jsx(Link, { to: "/connect", children: t("settings.openConnectApps") }) }) })) : null;
101
+ const resourceSettingsButton = (_jsx(Button, { variant: "outline", asChild: true, children: _jsx(Link, { to: "/workspace", children: t("settings.openResourceSettings") }) }));
102
+ return (_jsx(SettingsTabsPage, { account: _jsx(AccountSettingsCard, {}), extraTabs: settingsTabs, generalSearchEntries: generalSearchEntries, general: _jsxs("div", { className: "mx-auto w-full max-w-2xl space-y-6", children: [_jsx("p", { className: "text-sm leading-6 text-muted-foreground", children: t("settings.description") }), _jsxs(SettingsGroup, { children: [_jsx(SettingsRow, { id: "language", label: t("settings.languageTitle"), description: t("settings.languageDescription"), control: _jsx("div", { className: "w-56", children: _jsx(LanguagePicker, { label: t("settings.languageLabel") }) }) }), _jsx(SettingsRow, { id: "workspace-resources", label: t("settings.workspaceTitle"), description: t("settings.workspaceDescription"), control: resourceSettingsButton }), connectAppsRow] }), _jsx(SettingsGroup, { id: "chat-first", children: _jsxs(SettingsRow, { label: t("settings.chatFirstTitle"), description: t("settings.chatFirstDescription"), control: chatFirstSwitch, children: [_jsx("p", { className: "text-sm leading-6 text-muted-foreground", children: t("settings.chatFirstSessionWatchDescription") }), chatFirstStorageAlert] }) })] }), generalGroups: _jsxs(SettingsGroup, { id: "workspace", title: t("settings.workspaceTitle"), children: [_jsx(SettingsRow, { id: "chat-first", label: t("settings.chatFirstTitle"), description: t("settings.chatFirstDescription"), control: chatFirstSwitch, children: chatFirstStorageAlert }), _jsx(SettingsRow, { id: "workspace-resources", label: t("settings.resourcesTitle"), description: t("settings.workspaceDescription"), control: resourceSettingsButton }), connectAppsRow] }), whatsNew: _jsx("div", { className: "mx-auto w-full max-w-2xl", children: _jsx(ChangelogSettingsCard, { markdown: changelog }) }), whatsNewMarkdown: changelog }));
103
+ }
104
+ //# sourceMappingURL=settings-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-page.js","sourceRoot":"","sources":["../../../src/routes/pages/settings-page.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n CHAT_FIRST_MODE_CHANGED_EVENT,\n readChatFirstModeState,\n writeChatFirstMode,\n} from \"@agent-native/core/client/agent-chat\";\nimport {\n useFeatureFlag,\n useFeatureFlagState,\n} from \"@agent-native/core/client/feature-flags\";\nimport { useT } from \"@agent-native/core/client/i18n\";\nimport { SETTINGS_REDESIGN_FLAG } from \"@agent-native/core/feature-flags/registry\";\nimport { ChangelogSettingsCard } from \"@agent-native/toolkit/app/changelog\";\nimport { OrgMembersPage, TeamPage } from \"@agent-native/toolkit/app/org\";\nimport {\n AccountSettingsCard,\n CORE_SETTINGS_PAGES,\n registerSettingsPages,\n SettingsGroup,\n SettingsRow,\n SettingsTabsPage,\n useAgentSettingsTabs,\n type SettingsSearchEntry,\n} from \"@agent-native/toolkit/app/settings\";\nimport { LanguagePicker } from \"@agent-native/toolkit/app/shared\";\nimport { IconShield } from \"@tabler/icons-react\";\nimport { useMemo, useState } from \"react\";\nimport { Link } from \"react-router\";\n\nimport { Button } from \"../../components/ui/button\";\nimport { Switch } from \"../../components/ui/switch\";\nimport { dispatchAccessDescriptor } from \"../../shared/app-roles.js\";\nimport { DISPATCH_CONNECT_APPS_FLAG } from \"../../shared/feature-flags.js\";\n\nconst coreMembersPage = CORE_SETTINGS_PAGES.find(\n (page) => page.id === \"members\",\n);\nif (!coreMembersPage) {\n throw new Error(\"Core Settings has no members page for Dispatch app roles\");\n}\n\nfunction DispatchMembersSettingsPage() {\n return <OrgMembersPage appRoles={dispatchAccessDescriptor} />;\n}\n\n// The redesigned Settings shows Members from core; Dispatch's replaces it so\n// the app-role column stays.\nregisterSettingsPages([\n { ...coreMembersPage, component: DispatchMembersSettingsPage },\n]);\n\nexport function meta() {\n return [{ title: \"Settings - Dispatch\" }];\n}\n\nexport interface DispatchSettingsPageProps {\n /** Raw CHANGELOG.md behind What's new. */\n changelog: string;\n}\n\n/** The template route supplies the app's own changelog. */\nexport function DispatchSettingsPage({ changelog }: DispatchSettingsPageProps) {\n const t = useT();\n const connectAppsEnabled = useFeatureFlag(DISPATCH_CONNECT_APPS_FLAG.key);\n // Core Preferences owns the interface language in the redesigned Settings,\n // whose Dispatch General page shows `generalGroups` instead of `general`.\n const redesign = useFeatureFlagState(SETTINGS_REDESIGN_FLAG.key).enabled;\n const agentSettingsTabs = useAgentSettingsTabs({\n usageAppId: \"dispatch\",\n usageViewAllHref: \"/admin/metrics\",\n organizationContent: (\n <div className=\"mx-auto w-full max-w-3xl\">\n <TeamPage\n showTitle={false}\n appRoles={dispatchAccessDescriptor}\n createOrgDescription=\"Set up a team to share dispatch destinations and approvals with your colleagues.\"\n />\n </div>\n ),\n });\n const settingsTabs = [\n ...agentSettingsTabs,\n {\n id: \"admin\",\n label: t(\"dispatch.nav.admin\", { defaultValue: \"Admin\" }),\n icon: IconShield,\n group: \"Admin\",\n href: \"/admin\",\n content: null,\n },\n ];\n const [chatFirstModeState] = useState(() => readChatFirstModeState());\n const [chatFirstMode, setChatFirstMode] = useState(\n () => chatFirstModeState.enabled,\n );\n const [chatFirstStorageNotice, setChatFirstStorageNotice] = useState<\n string | null\n >(\n chatFirstModeState.availability === \"unavailable\"\n ? t(\"settings.chatFirstStorageUnavailable\")\n : null,\n );\n\n function updateChatFirstMode(enabled: boolean) {\n const result = writeChatFirstMode(enabled);\n if (!result.ok) {\n setChatFirstStorageNotice(t(\"settings.chatFirstStorageBlocked\"));\n return;\n }\n setChatFirstStorageNotice(null);\n setChatFirstMode(enabled);\n window.dispatchEvent(\n new CustomEvent(CHAT_FIRST_MODE_CHANGED_EVENT, {\n detail: { enabled },\n }),\n );\n }\n\n const generalSearchEntries = useMemo<SettingsSearchEntry[]>(\n () => [\n ...(redesign\n ? []\n : [\n {\n id: \"dispatch-language\",\n label: t(\"settings.languageTitle\"),\n keywords: \"language locale translation i18n\",\n hash: \"language\",\n },\n ]),\n {\n id: \"dispatch-workspace\",\n label: redesign\n ? t(\"settings.resourcesTitle\")\n : t(\"settings.workspaceTitle\"),\n keywords: \"workspace resources integrations vault destinations\",\n hash: \"workspace-resources\",\n },\n {\n id: \"dispatch-chat-first\",\n label: t(\"settings.chatFirstTitle\"),\n keywords: \"chat first codex t3 apps pane navigation\",\n hash: \"chat-first\",\n },\n ],\n [redesign, t],\n );\n\n const chatFirstSwitch = (\n <Switch\n aria-label={t(\"settings.chatFirstAriaLabel\")}\n checked={chatFirstMode}\n onCheckedChange={updateChatFirstMode}\n />\n );\n const chatFirstStorageAlert = chatFirstStorageNotice ? (\n <p className=\"text-sm text-destructive\" role=\"alert\">\n {chatFirstStorageNotice}\n </p>\n ) : null;\n const connectAppsRow = connectAppsEnabled ? (\n <SettingsRow\n id=\"connect-apps\"\n label={t(\"settings.connectApps\")}\n description={t(\"settings.connectAppsDescription\")}\n control={\n <Button variant=\"outline\" asChild>\n <Link to=\"/connect\">{t(\"settings.openConnectApps\")}</Link>\n </Button>\n }\n />\n ) : null;\n const resourceSettingsButton = (\n <Button variant=\"outline\" asChild>\n <Link to=\"/workspace\">{t(\"settings.openResourceSettings\")}</Link>\n </Button>\n );\n\n return (\n <SettingsTabsPage\n account={<AccountSettingsCard />}\n extraTabs={settingsTabs}\n generalSearchEntries={generalSearchEntries}\n general={\n <div className=\"mx-auto w-full max-w-2xl space-y-6\">\n <p className=\"text-sm leading-6 text-muted-foreground\">\n {t(\"settings.description\")}\n </p>\n\n <SettingsGroup>\n <SettingsRow\n id=\"language\"\n label={t(\"settings.languageTitle\")}\n description={t(\"settings.languageDescription\")}\n control={\n <div className=\"w-56\">\n <LanguagePicker label={t(\"settings.languageLabel\")} />\n </div>\n }\n />\n <SettingsRow\n id=\"workspace-resources\"\n label={t(\"settings.workspaceTitle\")}\n description={t(\"settings.workspaceDescription\")}\n control={resourceSettingsButton}\n />\n {connectAppsRow}\n </SettingsGroup>\n\n <SettingsGroup id=\"chat-first\">\n <SettingsRow\n label={t(\"settings.chatFirstTitle\")}\n description={t(\"settings.chatFirstDescription\")}\n control={chatFirstSwitch}\n >\n <p className=\"text-sm leading-6 text-muted-foreground\">\n {t(\"settings.chatFirstSessionWatchDescription\")}\n </p>\n {chatFirstStorageAlert}\n </SettingsRow>\n </SettingsGroup>\n </div>\n }\n generalGroups={\n <SettingsGroup id=\"workspace\" title={t(\"settings.workspaceTitle\")}>\n <SettingsRow\n id=\"chat-first\"\n label={t(\"settings.chatFirstTitle\")}\n description={t(\"settings.chatFirstDescription\")}\n control={chatFirstSwitch}\n >\n {chatFirstStorageAlert}\n </SettingsRow>\n <SettingsRow\n id=\"workspace-resources\"\n label={t(\"settings.resourcesTitle\")}\n description={t(\"settings.workspaceDescription\")}\n control={resourceSettingsButton}\n />\n {connectAppsRow}\n </SettingsGroup>\n }\n whatsNew={\n <div className=\"mx-auto w-full max-w-2xl\">\n <ChangelogSettingsCard markdown={changelog} />\n </div>\n }\n whatsNewMarkdown={changelog}\n />\n );\n}\n"]}
@@ -1,14 +1,6 @@
1
- export declare function meta(): {
2
- title: string;
3
- }[];
4
- export interface DispatchSettingsPageProps {
5
- /** Raw CHANGELOG.md behind What's new. */
6
- changelog: string;
7
- }
8
- /**
9
- * Dispatch's Settings. The template route renders it with the app's own
10
- * changelog; `dispatchRoutes` consumers get the default export.
11
- */
12
- export declare function DispatchSettingsPage({ changelog }: DispatchSettingsPageProps): import("node_modules/@types/react").JSX.Element;
1
+ import { DispatchSettingsPage } from "./settings-page.js";
2
+ export { DispatchSettingsPage };
3
+ export type { DispatchSettingsPageProps } from "./settings-page.js";
4
+ export { meta } from "./settings-page.js";
13
5
  export default function SettingsRoute(): import("node_modules/@types/react").JSX.Element;
14
6
  //# sourceMappingURL=settings.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/settings.tsx"],"names":[],"mappings":"AAmDA,wBAAgB,IAAI;;IAEnB;AAED,MAAM,WAAW,yBAAyB;IACxC,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,SAAS,EAAE,EAAE,yBAAyB,mDA6L5E;AAED,MAAM,CAAC,OAAO,UAAU,aAAa,oDAEpC"}
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/settings.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,EAAE,oBAAoB,EAAE,CAAC;AAChC,YAAY,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAE1C,MAAM,CAAC,OAAO,UAAU,aAAa,oDAEpC"}
@@ -1,110 +1,8 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { CHAT_FIRST_MODE_CHANGED_EVENT, readChatFirstModeState, writeChatFirstMode, } from "@agent-native/core/client/agent-chat";
3
- import { useFeatureFlag, useFeatureFlagState, } from "@agent-native/core/client/feature-flags";
4
- import { useT } from "@agent-native/core/client/i18n";
5
- import { SETTINGS_REDESIGN_FLAG } from "@agent-native/core/feature-flags/registry";
6
- import { ChangelogSettingsCard } from "@agent-native/toolkit/app/changelog";
7
- import { OrgMembersPage, TeamPage } from "@agent-native/toolkit/app/org";
8
- import { AccountSettingsCard, CORE_SETTINGS_PAGES, registerSettingsPages, SettingsGroup, SettingsRow, SettingsTabsPage, useAgentSettingsTabs, } from "@agent-native/toolkit/app/settings";
9
- import { LanguagePicker } from "@agent-native/toolkit/app/shared";
10
- import { IconShield } from "@tabler/icons-react";
11
- import { useMemo, useState } from "react";
12
- import { Link } from "react-router";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
13
2
  import packageChangelog from "../../../CHANGELOG.md?raw";
14
- import { Button } from "../../components/ui/button.js";
15
- import { Switch } from "../../components/ui/switch.js";
16
- import { dispatchAccessDescriptor } from "../../shared/app-roles.js";
17
- import { DISPATCH_CONNECT_APPS_FLAG } from "../../shared/feature-flags.js";
18
- const coreMembersPage = CORE_SETTINGS_PAGES.find((page) => page.id === "members");
19
- if (!coreMembersPage) {
20
- throw new Error("Core Settings has no members page for Dispatch app roles");
21
- }
22
- function DispatchMembersSettingsPage() {
23
- return _jsx(OrgMembersPage, { appRoles: dispatchAccessDescriptor });
24
- }
25
- // The redesigned Settings shows Members from core; Dispatch's replaces it so
26
- // the app-role column stays.
27
- registerSettingsPages([
28
- { ...coreMembersPage, component: DispatchMembersSettingsPage },
29
- ]);
30
- export function meta() {
31
- return [{ title: "Settings - Dispatch" }];
32
- }
33
- /**
34
- * Dispatch's Settings. The template route renders it with the app's own
35
- * changelog; `dispatchRoutes` consumers get the default export.
36
- */
37
- export function DispatchSettingsPage({ changelog }) {
38
- const t = useT();
39
- const connectAppsEnabled = useFeatureFlag(DISPATCH_CONNECT_APPS_FLAG.key);
40
- // Core Preferences owns the interface language in the redesigned Settings,
41
- // whose Dispatch General page shows `generalGroups` instead of `general`.
42
- const redesign = useFeatureFlagState(SETTINGS_REDESIGN_FLAG.key).enabled;
43
- const agentSettingsTabs = useAgentSettingsTabs({
44
- usageAppId: "dispatch",
45
- usageViewAllHref: "/admin/metrics",
46
- organizationContent: (_jsx("div", { className: "mx-auto w-full max-w-3xl", children: _jsx(TeamPage, { showTitle: false, appRoles: dispatchAccessDescriptor, createOrgDescription: "Set up a team to share dispatch destinations and approvals with your colleagues." }) })),
47
- });
48
- const settingsTabs = [
49
- ...agentSettingsTabs,
50
- {
51
- id: "admin",
52
- label: t("dispatch.nav.admin", { defaultValue: "Admin" }),
53
- icon: IconShield,
54
- group: "Admin",
55
- href: "/admin",
56
- content: null,
57
- },
58
- ];
59
- const [chatFirstModeState] = useState(() => readChatFirstModeState());
60
- const [chatFirstMode, setChatFirstMode] = useState(() => chatFirstModeState.enabled);
61
- const [chatFirstStorageNotice, setChatFirstStorageNotice] = useState(chatFirstModeState.availability === "unavailable"
62
- ? t("settings.chatFirstStorageUnavailable")
63
- : null);
64
- function updateChatFirstMode(enabled) {
65
- const result = writeChatFirstMode(enabled);
66
- if (!result.ok) {
67
- setChatFirstStorageNotice(t("settings.chatFirstStorageBlocked"));
68
- return;
69
- }
70
- setChatFirstStorageNotice(null);
71
- setChatFirstMode(enabled);
72
- window.dispatchEvent(new CustomEvent(CHAT_FIRST_MODE_CHANGED_EVENT, {
73
- detail: { enabled },
74
- }));
75
- }
76
- const generalSearchEntries = useMemo(() => [
77
- ...(redesign
78
- ? []
79
- : [
80
- {
81
- id: "dispatch-language",
82
- label: t("settings.languageTitle"),
83
- keywords: "language locale translation i18n",
84
- hash: "language",
85
- },
86
- ]),
87
- {
88
- id: "dispatch-workspace",
89
- label: redesign
90
- ? t("settings.resourcesTitle")
91
- : t("settings.workspaceTitle"),
92
- keywords: "workspace resources integrations vault destinations",
93
- hash: "workspace-resources",
94
- },
95
- {
96
- id: "dispatch-chat-first",
97
- label: t("settings.chatFirstTitle"),
98
- keywords: "chat first codex t3 apps pane navigation",
99
- hash: "chat-first",
100
- },
101
- ], [redesign, t]);
102
- const chatFirstSwitch = (_jsx(Switch, { "aria-label": t("settings.chatFirstAriaLabel"), checked: chatFirstMode, onCheckedChange: updateChatFirstMode }));
103
- const chatFirstStorageAlert = chatFirstStorageNotice ? (_jsx("p", { className: "text-sm text-destructive", role: "alert", children: chatFirstStorageNotice })) : null;
104
- const connectAppsRow = connectAppsEnabled ? (_jsx(SettingsRow, { id: "connect-apps", label: t("settings.connectApps"), description: t("settings.connectAppsDescription"), control: _jsx(Button, { variant: "outline", asChild: true, children: _jsx(Link, { to: "/connect", children: t("settings.openConnectApps") }) }) })) : null;
105
- const resourceSettingsButton = (_jsx(Button, { variant: "outline", asChild: true, children: _jsx(Link, { to: "/workspace", children: t("settings.openResourceSettings") }) }));
106
- return (_jsx(SettingsTabsPage, { account: _jsx(AccountSettingsCard, {}), extraTabs: settingsTabs, generalSearchEntries: generalSearchEntries, general: _jsxs("div", { className: "mx-auto w-full max-w-2xl space-y-6", children: [_jsx("p", { className: "text-sm leading-6 text-muted-foreground", children: t("settings.description") }), _jsxs(SettingsGroup, { children: [_jsx(SettingsRow, { id: "language", label: t("settings.languageTitle"), description: t("settings.languageDescription"), control: _jsx("div", { className: "w-56", children: _jsx(LanguagePicker, { label: t("settings.languageLabel") }) }) }), _jsx(SettingsRow, { id: "workspace-resources", label: t("settings.workspaceTitle"), description: t("settings.workspaceDescription"), control: resourceSettingsButton }), connectAppsRow] }), _jsx(SettingsGroup, { id: "chat-first", children: _jsxs(SettingsRow, { label: t("settings.chatFirstTitle"), description: t("settings.chatFirstDescription"), control: chatFirstSwitch, children: [_jsx("p", { className: "text-sm leading-6 text-muted-foreground", children: t("settings.chatFirstSessionWatchDescription") }), chatFirstStorageAlert] }) })] }), generalGroups: _jsxs(SettingsGroup, { id: "workspace", title: t("settings.workspaceTitle"), children: [_jsx(SettingsRow, { id: "chat-first", label: t("settings.chatFirstTitle"), description: t("settings.chatFirstDescription"), control: chatFirstSwitch, children: chatFirstStorageAlert }), _jsx(SettingsRow, { id: "workspace-resources", label: t("settings.resourcesTitle"), description: t("settings.workspaceDescription"), control: resourceSettingsButton }), connectAppsRow] }), whatsNew: _jsx("div", { className: "mx-auto w-full max-w-2xl", children: _jsx(ChangelogSettingsCard, { markdown: changelog }) }), whatsNewMarkdown: changelog }));
107
- }
3
+ import { DispatchSettingsPage } from "./settings-page.js";
4
+ export { DispatchSettingsPage };
5
+ export { meta } from "./settings-page.js";
108
6
  export default function SettingsRoute() {
109
7
  return _jsx(DispatchSettingsPage, { changelog: packageChangelog });
110
8
  }
@@ -1 +1 @@
1
- {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../src/routes/pages/settings.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n CHAT_FIRST_MODE_CHANGED_EVENT,\n readChatFirstModeState,\n writeChatFirstMode,\n} from \"@agent-native/core/client/agent-chat\";\nimport {\n useFeatureFlag,\n useFeatureFlagState,\n} from \"@agent-native/core/client/feature-flags\";\nimport { useT } from \"@agent-native/core/client/i18n\";\nimport { SETTINGS_REDESIGN_FLAG } from \"@agent-native/core/feature-flags/registry\";\nimport { ChangelogSettingsCard } from \"@agent-native/toolkit/app/changelog\";\nimport { OrgMembersPage, TeamPage } from \"@agent-native/toolkit/app/org\";\nimport {\n AccountSettingsCard,\n CORE_SETTINGS_PAGES,\n registerSettingsPages,\n SettingsGroup,\n SettingsRow,\n SettingsTabsPage,\n useAgentSettingsTabs,\n type SettingsSearchEntry,\n} from \"@agent-native/toolkit/app/settings\";\nimport { LanguagePicker } from \"@agent-native/toolkit/app/shared\";\nimport { IconShield } from \"@tabler/icons-react\";\nimport { useMemo, useState } from \"react\";\nimport { Link } from \"react-router\";\n\nimport packageChangelog from \"../../../CHANGELOG.md?raw\";\nimport { Button } from \"../../components/ui/button\";\nimport { Switch } from \"../../components/ui/switch\";\nimport { dispatchAccessDescriptor } from \"../../shared/app-roles.js\";\nimport { DISPATCH_CONNECT_APPS_FLAG } from \"../../shared/feature-flags.js\";\n\nconst coreMembersPage = CORE_SETTINGS_PAGES.find(\n (page) => page.id === \"members\",\n);\nif (!coreMembersPage) {\n throw new Error(\"Core Settings has no members page for Dispatch app roles\");\n}\n\nfunction DispatchMembersSettingsPage() {\n return <OrgMembersPage appRoles={dispatchAccessDescriptor} />;\n}\n\n// The redesigned Settings shows Members from core; Dispatch's replaces it so\n// the app-role column stays.\nregisterSettingsPages([\n { ...coreMembersPage, component: DispatchMembersSettingsPage },\n]);\n\nexport function meta() {\n return [{ title: \"Settings - Dispatch\" }];\n}\n\nexport interface DispatchSettingsPageProps {\n /** Raw CHANGELOG.md behind What's new. */\n changelog: string;\n}\n\n/**\n * Dispatch's Settings. The template route renders it with the app's own\n * changelog; `dispatchRoutes` consumers get the default export.\n */\nexport function DispatchSettingsPage({ changelog }: DispatchSettingsPageProps) {\n const t = useT();\n const connectAppsEnabled = useFeatureFlag(DISPATCH_CONNECT_APPS_FLAG.key);\n // Core Preferences owns the interface language in the redesigned Settings,\n // whose Dispatch General page shows `generalGroups` instead of `general`.\n const redesign = useFeatureFlagState(SETTINGS_REDESIGN_FLAG.key).enabled;\n const agentSettingsTabs = useAgentSettingsTabs({\n usageAppId: \"dispatch\",\n usageViewAllHref: \"/admin/metrics\",\n organizationContent: (\n <div className=\"mx-auto w-full max-w-3xl\">\n <TeamPage\n showTitle={false}\n appRoles={dispatchAccessDescriptor}\n createOrgDescription=\"Set up a team to share dispatch destinations and approvals with your colleagues.\"\n />\n </div>\n ),\n });\n const settingsTabs = [\n ...agentSettingsTabs,\n {\n id: \"admin\",\n label: t(\"dispatch.nav.admin\", { defaultValue: \"Admin\" }),\n icon: IconShield,\n group: \"Admin\",\n href: \"/admin\",\n content: null,\n },\n ];\n const [chatFirstModeState] = useState(() => readChatFirstModeState());\n const [chatFirstMode, setChatFirstMode] = useState(\n () => chatFirstModeState.enabled,\n );\n const [chatFirstStorageNotice, setChatFirstStorageNotice] = useState<\n string | null\n >(\n chatFirstModeState.availability === \"unavailable\"\n ? t(\"settings.chatFirstStorageUnavailable\")\n : null,\n );\n\n function updateChatFirstMode(enabled: boolean) {\n const result = writeChatFirstMode(enabled);\n if (!result.ok) {\n setChatFirstStorageNotice(t(\"settings.chatFirstStorageBlocked\"));\n return;\n }\n setChatFirstStorageNotice(null);\n setChatFirstMode(enabled);\n window.dispatchEvent(\n new CustomEvent(CHAT_FIRST_MODE_CHANGED_EVENT, {\n detail: { enabled },\n }),\n );\n }\n\n const generalSearchEntries = useMemo<SettingsSearchEntry[]>(\n () => [\n ...(redesign\n ? []\n : [\n {\n id: \"dispatch-language\",\n label: t(\"settings.languageTitle\"),\n keywords: \"language locale translation i18n\",\n hash: \"language\",\n },\n ]),\n {\n id: \"dispatch-workspace\",\n label: redesign\n ? t(\"settings.resourcesTitle\")\n : t(\"settings.workspaceTitle\"),\n keywords: \"workspace resources integrations vault destinations\",\n hash: \"workspace-resources\",\n },\n {\n id: \"dispatch-chat-first\",\n label: t(\"settings.chatFirstTitle\"),\n keywords: \"chat first codex t3 apps pane navigation\",\n hash: \"chat-first\",\n },\n ],\n [redesign, t],\n );\n\n const chatFirstSwitch = (\n <Switch\n aria-label={t(\"settings.chatFirstAriaLabel\")}\n checked={chatFirstMode}\n onCheckedChange={updateChatFirstMode}\n />\n );\n const chatFirstStorageAlert = chatFirstStorageNotice ? (\n <p className=\"text-sm text-destructive\" role=\"alert\">\n {chatFirstStorageNotice}\n </p>\n ) : null;\n const connectAppsRow = connectAppsEnabled ? (\n <SettingsRow\n id=\"connect-apps\"\n label={t(\"settings.connectApps\")}\n description={t(\"settings.connectAppsDescription\")}\n control={\n <Button variant=\"outline\" asChild>\n <Link to=\"/connect\">{t(\"settings.openConnectApps\")}</Link>\n </Button>\n }\n />\n ) : null;\n const resourceSettingsButton = (\n <Button variant=\"outline\" asChild>\n <Link to=\"/workspace\">{t(\"settings.openResourceSettings\")}</Link>\n </Button>\n );\n\n return (\n <SettingsTabsPage\n account={<AccountSettingsCard />}\n extraTabs={settingsTabs}\n generalSearchEntries={generalSearchEntries}\n general={\n <div className=\"mx-auto w-full max-w-2xl space-y-6\">\n <p className=\"text-sm leading-6 text-muted-foreground\">\n {t(\"settings.description\")}\n </p>\n\n <SettingsGroup>\n <SettingsRow\n id=\"language\"\n label={t(\"settings.languageTitle\")}\n description={t(\"settings.languageDescription\")}\n control={\n <div className=\"w-56\">\n <LanguagePicker label={t(\"settings.languageLabel\")} />\n </div>\n }\n />\n <SettingsRow\n id=\"workspace-resources\"\n label={t(\"settings.workspaceTitle\")}\n description={t(\"settings.workspaceDescription\")}\n control={resourceSettingsButton}\n />\n {connectAppsRow}\n </SettingsGroup>\n\n <SettingsGroup id=\"chat-first\">\n <SettingsRow\n label={t(\"settings.chatFirstTitle\")}\n description={t(\"settings.chatFirstDescription\")}\n control={chatFirstSwitch}\n >\n <p className=\"text-sm leading-6 text-muted-foreground\">\n {t(\"settings.chatFirstSessionWatchDescription\")}\n </p>\n {chatFirstStorageAlert}\n </SettingsRow>\n </SettingsGroup>\n </div>\n }\n generalGroups={\n <SettingsGroup id=\"workspace\" title={t(\"settings.workspaceTitle\")}>\n <SettingsRow\n id=\"chat-first\"\n label={t(\"settings.chatFirstTitle\")}\n description={t(\"settings.chatFirstDescription\")}\n control={chatFirstSwitch}\n >\n {chatFirstStorageAlert}\n </SettingsRow>\n <SettingsRow\n id=\"workspace-resources\"\n label={t(\"settings.resourcesTitle\")}\n description={t(\"settings.workspaceDescription\")}\n control={resourceSettingsButton}\n />\n {connectAppsRow}\n </SettingsGroup>\n }\n whatsNew={\n <div className=\"mx-auto w-full max-w-2xl\">\n <ChangelogSettingsCard markdown={changelog} />\n </div>\n }\n whatsNewMarkdown={changelog}\n />\n );\n}\n\nexport default function SettingsRoute() {\n return <DispatchSettingsPage changelog={packageChangelog} />;\n}\n"]}
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../src/routes/pages/settings.tsx"],"names":[],"mappings":";AAAA,OAAO,gBAAgB,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,EAAE,oBAAoB,EAAE,CAAC;AAEhC,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAE1C,MAAM,CAAC,OAAO,UAAU,aAAa;IACnC,OAAO,KAAC,oBAAoB,IAAC,SAAS,EAAE,gBAAgB,GAAI,CAAC;AAC/D,CAAC","sourcesContent":["import packageChangelog from \"../../../CHANGELOG.md?raw\";\nimport { DispatchSettingsPage } from \"./settings-page.js\";\n\nexport { DispatchSettingsPage };\nexport type { DispatchSettingsPageProps } from \"./settings-page.js\";\nexport { meta } from \"./settings-page.js\";\n\nexport default function SettingsRoute() {\n return <DispatchSettingsPage changelog={packageChangelog} />;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/dispatch",
3
- "version": "0.40.2",
3
+ "version": "0.40.3",
4
4
  "description": "Dispatch — workspace control plane for agent-native apps. Vault, integrations, destinations, scheduled jobs, and cross-app delegation, shipped as a single drop-in package.",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -89,7 +89,7 @@
89
89
  "tailwind-merge": "^3.5.0",
90
90
  "vaul": "^1.1.2",
91
91
  "zod": "^4.3.6",
92
- "@agent-native/toolkit": "0.198.1"
92
+ "@agent-native/toolkit": "0.198.2"
93
93
  },
94
94
  "devDependencies": {
95
95
  "@react-router/dev": "^8.1.0",
@@ -103,7 +103,7 @@
103
103
  "typescript-7": "npm:typescript@^7.0.2",
104
104
  "vite": "8.1.0",
105
105
  "vitest": "^4.1.5",
106
- "@agent-native/core": "0.198.1"
106
+ "@agent-native/core": "0.198.2"
107
107
  },
108
108
  "peerDependencies": {
109
109
  "@agent-native/core": ">=0.8.0",
@@ -1,3 +1,4 @@
1
+ import { isSettingsPathname } from "@agent-native/toolkit/app/settings";
1
2
  // @vitest-environment happy-dom
2
3
  import React, { act } from "react";
3
4
  import { createRoot, type Root } from "react-dom/client";
@@ -12,7 +13,6 @@ import {
12
13
  dispatchNavLinkTarget,
13
14
  formatThreadAge,
14
15
  isElectronEmbeddedSearch,
15
- isSettingsShellPath,
16
16
  NavContent,
17
17
  renderChatFirstAppSurfaceTab,
18
18
  shouldAutoCollapseDispatchSidebar,
@@ -30,13 +30,27 @@ const clientState = vi.hoisted(() => ({
30
30
  .mockResolvedValue({ startUrl: "about:blank" }),
31
31
  }));
32
32
 
33
- vi.mock("@agent-native/core/client/agent-chat", () => ({
33
+ vi.mock("@agent-native/core/client/agent-chat", async (importOriginal) => ({
34
+ ...(await importOriginal<
35
+ typeof import("@agent-native/core/client/agent-chat")
36
+ >()),
34
37
  navigateWithAgentChatViewTransition: (
35
38
  navigate: (path: string) => void,
36
39
  path: string,
37
40
  ) => navigate(path),
38
41
  useAgentChatHomeHandoff: () => false,
39
42
  useAgentChatHomeHandoffLinks: vi.fn(),
43
+ useChatModels: () => ({
44
+ availableModels: [],
45
+ defaultModel: "auto",
46
+ selectedModel: "auto",
47
+ selectedEngine: "",
48
+ selectedEffort: "medium" as const,
49
+ isLoading: false,
50
+ onModelChange: vi.fn(),
51
+ onEffortChange: vi.fn(),
52
+ refreshEngines: vi.fn(),
53
+ }),
40
54
  useChatThreads: () => ({
41
55
  threads: clientState.threads,
42
56
  activeThreadId: "active-thread",
@@ -65,9 +79,11 @@ vi.mock("@agent-native/core/client/api-path", () => ({
65
79
  clientState.basePath && path.startsWith("/")
66
80
  ? `${clientState.basePath}${path}`
67
81
  : path,
82
+ frameworkRoutePrefix: () => "",
68
83
  }));
69
84
 
70
- vi.mock("@agent-native/core/client/hooks", () => ({
85
+ vi.mock("@agent-native/core/client/hooks", async (importOriginal) => ({
86
+ ...(await importOriginal<typeof import("@agent-native/core/client/hooks")>()),
71
87
  useActionQuery: (action: string) => ({
72
88
  data:
73
89
  action === "list-workspace-apps" ? clientState.workspaceApps : undefined,
@@ -87,6 +103,7 @@ vi.mock("next-themes", () => ({
87
103
  }));
88
104
 
89
105
  vi.mock("@agent-native/core/client/i18n", () => ({
106
+ useFormatters: () => ({ formatNumber: (value: number) => String(value) }),
90
107
  useT: () => (key: string, values?: Record<string, unknown>) => {
91
108
  const messages: Record<string, string> = {
92
109
  "dispatch.nav.chat": "Chat",
@@ -115,6 +132,10 @@ vi.mock("@agent-native/toolkit/app/shared", async (importOriginal) => ({
115
132
  openCommandMenu: vi.fn(),
116
133
  }));
117
134
 
135
+ vi.mock("../create-app-popover", () => ({
136
+ CreateAppPopover: () => null,
137
+ }));
138
+
118
139
  vi.mock("@agent-native/toolkit/app/feedback", () => ({
119
140
  FeedbackButton: () => <div>Feedback</div>,
120
141
  }));
@@ -204,14 +225,14 @@ describe("Dispatch workspace app sidebar", () => {
204
225
 
205
226
  describe("Dispatch Settings frame", () => {
206
227
  it("drops the Dispatch chrome on Settings", () => {
207
- expect(isSettingsShellPath("/settings")).toBe(true);
208
- expect(isSettingsShellPath("/settings/members")).toBe(true);
209
- expect(isSettingsShellPath("/settings/app")).toBe(true);
228
+ expect(isSettingsPathname("/settings")).toBe(true);
229
+ expect(isSettingsPathname("/settings/members")).toBe(true);
230
+ expect(isSettingsPathname("/settings/app")).toBe(true);
210
231
  });
211
232
 
212
233
  it("keeps the Dispatch chrome off Settings", () => {
213
- expect(isSettingsShellPath("/admin")).toBe(false);
214
- expect(isSettingsShellPath("/apps/mail/settings")).toBe(false);
234
+ expect(isSettingsPathname("/admin")).toBe(false);
235
+ expect(isSettingsPathname("/apps/mail/settings")).toBe(false);
215
236
  });
216
237
  });
217
238
 
@@ -748,8 +769,8 @@ describe("chat-first surface panel toggle stacking", () => {
748
769
  it("keeps the toggle above the mobile full-screen surface panel overlay", async () => {
749
770
  const { ChatFirstSurfacePanelToggle: RealChatFirstSurfacePanelToggle } =
750
771
  await vi.importActual<
751
- typeof import("@agent-native/core/client/agent-chat")
752
- >("@agent-native/core/client/agent-chat");
772
+ typeof import("@agent-native/toolkit/app/chat/chat-first")
773
+ >("@agent-native/toolkit/app/chat/chat-first");
753
774
  const { ChatFirstSurfacePanel } =
754
775
  await import("@agent-native/toolkit/app/chat/chat-first");
755
776
 
@@ -10,7 +10,7 @@ const railState = vi.hoisted(() => ({
10
10
  mutateAsync: vi.fn().mockResolvedValue({ startUrl: "about:blank" }),
11
11
  }));
12
12
 
13
- vi.mock("@agent-native/core/client/agent-chat", () => ({
13
+ vi.mock("@agent-native/toolkit/app/chat", () => ({
14
14
  AgentSidebar: (props: Record<string, unknown>) => {
15
15
  railState.sidebarProps.push(props);
16
16
  return (
@@ -12,7 +12,7 @@ const browserChat = vi.hoisted(() => ({
12
12
  surfaceProps: null as Record<string, unknown> | null,
13
13
  }));
14
14
 
15
- vi.mock("@agent-native/core/client/agent-chat", () => ({
15
+ vi.mock("@agent-native/toolkit/app/chat", () => ({
16
16
  AgentChatSurface: (props: Record<string, unknown>) => {
17
17
  browserChat.surfaceProps = props;
18
18
  return <div data-testid="browser-agent-chat" />;
@@ -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
+ }
@@ -1,257 +1,9 @@
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
1
  import packageChangelog from "../../../CHANGELOG.md?raw";
30
- import { Button } from "../../components/ui/button";
31
- import { Switch } from "../../components/ui/switch";
32
- import { dispatchAccessDescriptor } from "../../shared/app-roles.js";
33
- import { DISPATCH_CONNECT_APPS_FLAG } from "../../shared/feature-flags.js";
34
-
35
- const coreMembersPage = CORE_SETTINGS_PAGES.find(
36
- (page) => page.id === "members",
37
- );
38
- if (!coreMembersPage) {
39
- throw new Error("Core Settings has no members page for Dispatch app roles");
40
- }
41
-
42
- function DispatchMembersSettingsPage() {
43
- return <OrgMembersPage appRoles={dispatchAccessDescriptor} />;
44
- }
2
+ import { DispatchSettingsPage } from "./settings-page.js";
45
3
 
46
- // The redesigned Settings shows Members from core; Dispatch's replaces it so
47
- // the app-role column stays.
48
- registerSettingsPages([
49
- { ...coreMembersPage, component: DispatchMembersSettingsPage },
50
- ]);
51
-
52
- export function meta() {
53
- return [{ title: "Settings - Dispatch" }];
54
- }
55
-
56
- export interface DispatchSettingsPageProps {
57
- /** Raw CHANGELOG.md behind What's new. */
58
- changelog: string;
59
- }
60
-
61
- /**
62
- * Dispatch's Settings. The template route renders it with the app's own
63
- * changelog; `dispatchRoutes` consumers get the default export.
64
- */
65
- export function DispatchSettingsPage({ changelog }: DispatchSettingsPageProps) {
66
- const t = useT();
67
- const connectAppsEnabled = useFeatureFlag(DISPATCH_CONNECT_APPS_FLAG.key);
68
- // Core Preferences owns the interface language in the redesigned Settings,
69
- // whose Dispatch General page shows `generalGroups` instead of `general`.
70
- const redesign = useFeatureFlagState(SETTINGS_REDESIGN_FLAG.key).enabled;
71
- const agentSettingsTabs = useAgentSettingsTabs({
72
- usageAppId: "dispatch",
73
- usageViewAllHref: "/admin/metrics",
74
- organizationContent: (
75
- <div className="mx-auto w-full max-w-3xl">
76
- <TeamPage
77
- showTitle={false}
78
- appRoles={dispatchAccessDescriptor}
79
- createOrgDescription="Set up a team to share dispatch destinations and approvals with your colleagues."
80
- />
81
- </div>
82
- ),
83
- });
84
- const settingsTabs = [
85
- ...agentSettingsTabs,
86
- {
87
- id: "admin",
88
- label: t("dispatch.nav.admin", { defaultValue: "Admin" }),
89
- icon: IconShield,
90
- group: "Admin",
91
- href: "/admin",
92
- content: null,
93
- },
94
- ];
95
- const [chatFirstModeState] = useState(() => readChatFirstModeState());
96
- const [chatFirstMode, setChatFirstMode] = useState(
97
- () => chatFirstModeState.enabled,
98
- );
99
- const [chatFirstStorageNotice, setChatFirstStorageNotice] = useState<
100
- string | null
101
- >(
102
- chatFirstModeState.availability === "unavailable"
103
- ? t("settings.chatFirstStorageUnavailable")
104
- : null,
105
- );
106
-
107
- function updateChatFirstMode(enabled: boolean) {
108
- const result = writeChatFirstMode(enabled);
109
- if (!result.ok) {
110
- setChatFirstStorageNotice(t("settings.chatFirstStorageBlocked"));
111
- return;
112
- }
113
- setChatFirstStorageNotice(null);
114
- setChatFirstMode(enabled);
115
- window.dispatchEvent(
116
- new CustomEvent(CHAT_FIRST_MODE_CHANGED_EVENT, {
117
- detail: { enabled },
118
- }),
119
- );
120
- }
121
-
122
- const generalSearchEntries = useMemo<SettingsSearchEntry[]>(
123
- () => [
124
- ...(redesign
125
- ? []
126
- : [
127
- {
128
- id: "dispatch-language",
129
- label: t("settings.languageTitle"),
130
- keywords: "language locale translation i18n",
131
- hash: "language",
132
- },
133
- ]),
134
- {
135
- id: "dispatch-workspace",
136
- label: redesign
137
- ? t("settings.resourcesTitle")
138
- : t("settings.workspaceTitle"),
139
- keywords: "workspace resources integrations vault destinations",
140
- hash: "workspace-resources",
141
- },
142
- {
143
- id: "dispatch-chat-first",
144
- label: t("settings.chatFirstTitle"),
145
- keywords: "chat first codex t3 apps pane navigation",
146
- hash: "chat-first",
147
- },
148
- ],
149
- [redesign, t],
150
- );
151
-
152
- const chatFirstSwitch = (
153
- <Switch
154
- aria-label={t("settings.chatFirstAriaLabel")}
155
- checked={chatFirstMode}
156
- onCheckedChange={updateChatFirstMode}
157
- />
158
- );
159
- const chatFirstStorageAlert = chatFirstStorageNotice ? (
160
- <p className="text-sm text-destructive" role="alert">
161
- {chatFirstStorageNotice}
162
- </p>
163
- ) : null;
164
- const connectAppsRow = connectAppsEnabled ? (
165
- <SettingsRow
166
- id="connect-apps"
167
- label={t("settings.connectApps")}
168
- description={t("settings.connectAppsDescription")}
169
- control={
170
- <Button variant="outline" asChild>
171
- <Link to="/connect">{t("settings.openConnectApps")}</Link>
172
- </Button>
173
- }
174
- />
175
- ) : null;
176
- const resourceSettingsButton = (
177
- <Button variant="outline" asChild>
178
- <Link to="/workspace">{t("settings.openResourceSettings")}</Link>
179
- </Button>
180
- );
181
-
182
- return (
183
- <SettingsTabsPage
184
- account={<AccountSettingsCard />}
185
- extraTabs={settingsTabs}
186
- generalSearchEntries={generalSearchEntries}
187
- general={
188
- <div className="mx-auto w-full max-w-2xl space-y-6">
189
- <p className="text-sm leading-6 text-muted-foreground">
190
- {t("settings.description")}
191
- </p>
192
-
193
- <SettingsGroup>
194
- <SettingsRow
195
- id="language"
196
- label={t("settings.languageTitle")}
197
- description={t("settings.languageDescription")}
198
- control={
199
- <div className="w-56">
200
- <LanguagePicker label={t("settings.languageLabel")} />
201
- </div>
202
- }
203
- />
204
- <SettingsRow
205
- id="workspace-resources"
206
- label={t("settings.workspaceTitle")}
207
- description={t("settings.workspaceDescription")}
208
- control={resourceSettingsButton}
209
- />
210
- {connectAppsRow}
211
- </SettingsGroup>
212
-
213
- <SettingsGroup id="chat-first">
214
- <SettingsRow
215
- label={t("settings.chatFirstTitle")}
216
- description={t("settings.chatFirstDescription")}
217
- control={chatFirstSwitch}
218
- >
219
- <p className="text-sm leading-6 text-muted-foreground">
220
- {t("settings.chatFirstSessionWatchDescription")}
221
- </p>
222
- {chatFirstStorageAlert}
223
- </SettingsRow>
224
- </SettingsGroup>
225
- </div>
226
- }
227
- generalGroups={
228
- <SettingsGroup id="workspace" title={t("settings.workspaceTitle")}>
229
- <SettingsRow
230
- id="chat-first"
231
- label={t("settings.chatFirstTitle")}
232
- description={t("settings.chatFirstDescription")}
233
- control={chatFirstSwitch}
234
- >
235
- {chatFirstStorageAlert}
236
- </SettingsRow>
237
- <SettingsRow
238
- id="workspace-resources"
239
- label={t("settings.resourcesTitle")}
240
- description={t("settings.workspaceDescription")}
241
- control={resourceSettingsButton}
242
- />
243
- {connectAppsRow}
244
- </SettingsGroup>
245
- }
246
- whatsNew={
247
- <div className="mx-auto w-full max-w-2xl">
248
- <ChangelogSettingsCard markdown={changelog} />
249
- </div>
250
- }
251
- whatsNewMarkdown={changelog}
252
- />
253
- );
254
- }
4
+ export { DispatchSettingsPage };
5
+ export type { DispatchSettingsPageProps } from "./settings-page.js";
6
+ export { meta } from "./settings-page.js";
255
7
 
256
8
  export default function SettingsRoute() {
257
9
  return <DispatchSettingsPage changelog={packageChangelog} />;