@agent-native/toolkit 0.198.3 → 0.198.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/dist/app/agentkit/react/components.d.ts +8 -3
  2. package/dist/app/agentkit/react/components.d.ts.map +1 -1
  3. package/dist/app/agentkit/react/components.js +24 -10
  4. package/dist/app/agentkit/react/components.js.map +1 -1
  5. package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
  6. package/dist/app/chat/AgentKitAssistantChat.js +65 -33
  7. package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
  8. package/dist/app/chat/AgentSidebar.d.ts.map +1 -1
  9. package/dist/app/chat/AgentSidebar.js +2 -0
  10. package/dist/app/chat/AgentSidebar.js.map +1 -1
  11. package/dist/app/chat/FileStorageSetupPopover.js +2 -2
  12. package/dist/app/chat/FileStorageSetupPopover.js.map +1 -1
  13. package/dist/app/chat/MultiTabAssistantChat.js +1 -1
  14. package/dist/app/chat/agentkit-chat/connections.d.ts +1 -4
  15. package/dist/app/chat/agentkit-chat/connections.d.ts.map +1 -1
  16. package/dist/app/chat/agentkit-chat/connections.js +1 -26
  17. package/dist/app/chat/agentkit-chat/connections.js.map +1 -1
  18. package/dist/app/chat/agentkit-chat/history.d.ts +4 -1
  19. package/dist/app/chat/agentkit-chat/history.d.ts.map +1 -1
  20. package/dist/app/chat/agentkit-chat/history.js +17 -5
  21. package/dist/app/chat/agentkit-chat/history.js.map +1 -1
  22. package/dist/app/chat/chat/history-types.d.ts +1 -1
  23. package/dist/app/chat/chat/history-types.d.ts.map +1 -1
  24. package/dist/app/chat/chat-first/copy.d.ts +1 -2
  25. package/dist/app/chat/chat-first/copy.d.ts.map +1 -1
  26. package/dist/app/chat/chat-first/copy.js +1 -121
  27. package/dist/app/chat/chat-first/copy.js.map +1 -1
  28. package/dist/app/chat/chat-first-copy.d.ts +3 -0
  29. package/dist/app/chat/chat-first-copy.d.ts.map +1 -0
  30. package/dist/app/chat/chat-first-copy.js +122 -0
  31. package/dist/app/chat/chat-first-copy.js.map +1 -0
  32. package/dist/app/feature-flags/FeatureFlagsPanel.d.ts.map +1 -1
  33. package/dist/app/feature-flags/FeatureFlagsPanel.js +1 -0
  34. package/dist/app/feature-flags/FeatureFlagsPanel.js.map +1 -1
  35. package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
  36. package/dist/app/i18n/catalogs/ar-SA.js +2 -1
  37. package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
  38. package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
  39. package/dist/app/i18n/catalogs/de-DE.js +2 -1
  40. package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
  41. package/dist/app/i18n/catalogs/en-US.d.ts +2 -1
  42. package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
  43. package/dist/app/i18n/catalogs/en-US.js +2 -1
  44. package/dist/app/i18n/catalogs/en-US.js.map +1 -1
  45. package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
  46. package/dist/app/i18n/catalogs/es-ES.js +2 -1
  47. package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
  48. package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
  49. package/dist/app/i18n/catalogs/fr-FR.js +2 -1
  50. package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
  51. package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
  52. package/dist/app/i18n/catalogs/hi-IN.js +2 -1
  53. package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
  54. package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
  55. package/dist/app/i18n/catalogs/ja-JP.js +2 -1
  56. package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
  57. package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
  58. package/dist/app/i18n/catalogs/ko-KR.js +2 -1
  59. package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
  60. package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
  61. package/dist/app/i18n/catalogs/pt-BR.js +2 -1
  62. package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
  63. package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
  64. package/dist/app/i18n/catalogs/zh-CN.js +2 -1
  65. package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
  66. package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
  67. package/dist/app/i18n/catalogs/zh-TW.js +2 -1
  68. package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
  69. package/dist/app/labs/LabsSettings.d.ts.map +1 -1
  70. package/dist/app/labs/LabsSettings.js +7 -3
  71. package/dist/app/labs/LabsSettings.js.map +1 -1
  72. package/dist/app/org/OrgGeneralSection.d.ts.map +1 -1
  73. package/dist/app/org/OrgGeneralSection.js +21 -18
  74. package/dist/app/org/OrgGeneralSection.js.map +1 -1
  75. package/dist/app/org/OrgSwitcher.d.ts.map +1 -1
  76. package/dist/app/org/OrgSwitcher.js +3 -2
  77. package/dist/app/org/OrgSwitcher.js.map +1 -1
  78. package/dist/app/org/workspace-app-links.d.ts +1 -0
  79. package/dist/app/org/workspace-app-links.d.ts.map +1 -1
  80. package/dist/app/org/workspace-app-links.js +3 -0
  81. package/dist/app/org/workspace-app-links.js.map +1 -1
  82. package/dist/app/resources/McpAgentKitConnectionRequest.d.ts +7 -2
  83. package/dist/app/resources/McpAgentKitConnectionRequest.d.ts.map +1 -1
  84. package/dist/app/resources/McpAgentKitConnectionRequest.js +132 -13
  85. package/dist/app/resources/McpAgentKitConnectionRequest.js.map +1 -1
  86. package/dist/composer/PromptComposer.d.ts +3 -0
  87. package/dist/composer/PromptComposer.d.ts.map +1 -1
  88. package/dist/composer/PromptComposer.js +2 -2
  89. package/dist/composer/PromptComposer.js.map +1 -1
  90. package/dist/composer/TiptapComposer.d.ts +4 -1
  91. package/dist/composer/TiptapComposer.d.ts.map +1 -1
  92. package/dist/composer/TiptapComposer.js +8 -4
  93. package/dist/composer/TiptapComposer.js.map +1 -1
  94. package/dist/icons/ResourceIconPicker.d.ts +6 -1
  95. package/dist/icons/ResourceIconPicker.d.ts.map +1 -1
  96. package/dist/icons/ResourceIconPicker.js +45 -6
  97. package/dist/icons/ResourceIconPicker.js.map +1 -1
  98. package/package.json +6 -4
  99. package/src/app/agentkit/react/components.interaction.spec.tsx +93 -0
  100. package/src/app/agentkit/react/components.spec.tsx +4 -5
  101. package/src/app/agentkit/react/components.tsx +51 -8
  102. package/src/app/agentkit/react/composer-context.spec.tsx +7 -0
  103. package/src/app/agentkit/react/lifecycle.spec.tsx +42 -0
  104. package/src/app/chat/AgentKitAssistantChat.spec.tsx +151 -11
  105. package/src/app/chat/AgentKitAssistantChat.tsx +110 -28
  106. package/src/app/chat/AgentPanel.header.spec.ts +59 -22
  107. package/src/app/chat/AgentSidebar.tsx +2 -0
  108. package/src/app/chat/FileStorageSetupPopover.tsx +2 -2
  109. package/src/app/chat/MultiTabAssistantChat.messageCount.spec.tsx +3 -1
  110. package/src/app/chat/MultiTabAssistantChat.spec.tsx +8 -4
  111. package/src/app/chat/MultiTabAssistantChat.tsx +1 -1
  112. package/src/app/chat/agentkit-chat/action-widget.spec.tsx +5 -17
  113. package/src/app/chat/agentkit-chat/connections.spec.tsx +137 -0
  114. package/src/app/chat/agentkit-chat/connections.ts +2 -37
  115. package/src/app/chat/agentkit-chat/history.tsx +23 -8
  116. package/src/app/chat/chat/history-types.ts +1 -1
  117. package/src/app/chat/chat/tool-call-display.spec.tsx +2 -2
  118. package/src/app/chat/chat/widgets/record-change-widget.spec.tsx +20 -29
  119. package/src/app/chat/chat-first/copy.ts +1 -133
  120. package/src/app/chat/chat-first-copy.ts +133 -0
  121. package/src/app/chat/composer/use-agentkit-capabilities.hardening.spec.tsx +3 -2
  122. package/src/app/feature-flags/FeatureFlagsPanel.tsx +1 -0
  123. package/src/app/i18n/catalogs/ar-SA.ts +2 -1
  124. package/src/app/i18n/catalogs/de-DE.ts +3 -1
  125. package/src/app/i18n/catalogs/en-US.ts +2 -1
  126. package/src/app/i18n/catalogs/es-ES.ts +2 -1
  127. package/src/app/i18n/catalogs/fr-FR.ts +3 -1
  128. package/src/app/i18n/catalogs/hi-IN.ts +2 -1
  129. package/src/app/i18n/catalogs/ja-JP.ts +2 -1
  130. package/src/app/i18n/catalogs/ko-KR.ts +2 -1
  131. package/src/app/i18n/catalogs/pt-BR.ts +3 -1
  132. package/src/app/i18n/catalogs/zh-CN.ts +2 -1
  133. package/src/app/i18n/catalogs/zh-TW.ts +2 -1
  134. package/src/app/integrations/IntegrationDetailPage.spec.tsx +1 -1
  135. package/src/app/labs/LabsSettings.tsx +46 -10
  136. package/src/app/observability/ThumbsFeedback.spec.tsx +15 -0
  137. package/src/app/onboarding/FirstRunOnboarding.spec.tsx +4 -0
  138. package/src/app/org/OrgGeneralSection.tsx +32 -22
  139. package/src/app/org/OrgSwitcher.tsx +3 -2
  140. package/src/app/org/workspace-app-links.spec.ts +4 -0
  141. package/src/app/org/workspace-app-links.ts +8 -1
  142. package/src/app/resources/McpAgentKitConnectionRequest.spec.tsx +371 -2
  143. package/src/app/resources/McpAgentKitConnectionRequest.tsx +171 -11
  144. package/src/app/settings/SettingsTabsPage.spec.tsx +4 -2
  145. package/src/app/settings/shell/SettingsShell.spec.tsx +14 -8
  146. package/src/app/settings/shell/pages/app-group-pages.spec.tsx +35 -5
  147. package/src/app/settings/shell/pages/resource-pages.spec.tsx +3 -0
  148. package/src/app/settings/usage/UsagePage.spec.tsx +3 -3
  149. package/src/app/shared/lazy-chunk-error-boundary.spec.tsx +2 -0
  150. package/src/app-shell/sidebar-overflow.spec.tsx +4 -1
  151. package/src/composer/PromptComposer.tsx +7 -0
  152. package/src/composer/TiptapComposer.spec.ts +26 -4
  153. package/src/composer/TiptapComposer.tsx +12 -3
  154. package/src/design-tweaks/visual-style-controls.spec.tsx +38 -0
  155. package/src/editor/useCollabReconcile.concurrent.spec.ts +2 -1
  156. package/src/icons/ResourceIconPicker.spec.tsx +270 -0
  157. package/src/icons/ResourceIconPicker.tsx +72 -4
@@ -745,7 +745,7 @@ const messages: ToolkitAgentChatTranslation = {
745
745
  "mcpIntegrations.catalog.gong.useCase":
746
746
  "銷售通話、逐字稿、交易洞察、客戶摘要",
747
747
  "mcpIntegrations.catalog.gong.setupNote":
748
- "Gong 需要技術管理員建立 MCP 整合,並選擇個人或共用授權。連線前必須先設定產生的用戶端 ID 和密鑰。",
748
+ "Gong 技術管理員需要建立 MCP 整合並選擇個人或共用授權。使用手動註冊時,請將產生的用戶端 ID 和密鑰儲存為工作區密鑰 `GONG_MCP_CLIENT_ID` 和 `GONG_MCP_CLIENT_SECRET`;自動註冊不需要用戶端憑證。",
749
749
  "mcpIntegrations.catalog.semgrep.description": "掃描程式碼中的安全性問題。",
750
750
  "mcpIntegrations.catalog.semgrep.useCase": "安全性掃描、漏洞偵測、程式碼分析",
751
751
  "mcpIntegrations.catalog.linear.description": "讀取及撰寫 Linear 議題。",
@@ -937,6 +937,7 @@ const messages: ToolkitAgentChatTranslation = {
937
937
  "message.restoreQuestion": "要還原到這裡嗎?",
938
938
  "message.revertQuestion": "要還原到這裡嗎?之後所做的變更將會遺失。",
939
939
  "message.restoreRequestFailed": "還原要求失敗。",
940
+ "message.historyUnavailable": "無法載入變更歷史。",
940
941
  "message.threadNotFound":
941
942
  "此聊天串已無法使用。請開始新的聊天;如果這是意外情況,也可以重試。",
942
943
  "message.restoring": "正在還原...",
@@ -36,7 +36,7 @@ vi.mock("../settings/api-keys/api-keys-client.js", () => keys);
36
36
  vi.mock("@agent-native/core/client/org/hooks", () => ({
37
37
  useOrg: () => ({ data: { orgName: "Acme" } }),
38
38
  }));
39
- vi.mock("./useIntegrationStatus.js", () => ({
39
+ vi.mock("@agent-native/core/client/integrations/useIntegrationStatus", () => ({
40
40
  useIntegrationStatus: () => ({ statuses: [], loading: false, refetch() {} }),
41
41
  }));
42
42
  vi.mock("sonner", () => ({ toast: { success: vi.fn(), error: vi.fn() } }));
@@ -1,5 +1,8 @@
1
1
  import { useT } from "@agent-native/core/client/i18n";
2
- import type { LabValues } from "@agent-native/core/client/labs/use-lab";
2
+ import type {
3
+ LabStates,
4
+ LabValues,
5
+ } from "@agent-native/core/client/labs/use-lab";
3
6
  import {
4
7
  useActionMutation,
5
8
  useActionQuery,
@@ -21,6 +24,7 @@ interface LabsSettingsState {
21
24
  /** The labs to list: every one passed until the server answers, then the ones it registered. */
22
25
  labs: readonly LabDefinition[];
23
26
  enabled: (lab: LabDefinition) => boolean;
27
+ mixed: (lab: LabDefinition) => boolean;
24
28
  toggle: (lab: LabDefinition, enabled: boolean) => void;
25
29
  /** Switches wait for the server's answer; they can't save before it. */
26
30
  disabled: boolean;
@@ -30,7 +34,7 @@ interface LabsSettingsState {
30
34
  failedLab: LabDefinition | null;
31
35
  }
32
36
 
33
- function hasOwn(values: LabValues, key: string): boolean {
37
+ function hasOwn(values: LabStates, key: string): boolean {
34
38
  return Object.prototype.hasOwnProperty.call(values, key);
35
39
  }
36
40
 
@@ -43,7 +47,7 @@ function hasOwn(values: LabValues, key: string): boolean {
43
47
  function useLabsSettingsState(
44
48
  labs: readonly LabDefinition[],
45
49
  ): LabsSettingsState {
46
- const valuesQuery = useActionQuery<LabValues>("get-labs" as never);
50
+ const valuesQuery = useActionQuery<LabStates>("get-lab-states" as never);
47
51
  const setLab = useActionMutation<
48
52
  { key: string; enabled: boolean; values: LabValues },
49
53
  { key: string; enabled: boolean }
@@ -80,7 +84,11 @@ function useLabsSettingsState(
80
84
  labs: visible,
81
85
  enabled: (lab) =>
82
86
  overrides[lab.key] ??
83
- (values ? values[lab.key] === true : lab.defaultEnabled === true),
87
+ (values
88
+ ? values[lab.key]?.enabled === true
89
+ : lab.defaultEnabled === true),
90
+ mixed: (lab) =>
91
+ overrides[lab.key] === undefined && values?.[lab.key]?.mixed === true,
84
92
  toggle,
85
93
  disabled: !values || setLab.isPending,
86
94
  loadFailed: !values && valuesQuery.isError,
@@ -111,6 +119,7 @@ function LabRows({ state }: { state: LabsSettingsState }) {
111
119
  {state.labs.map((lab) => {
112
120
  const label = lab.displayName ?? lab.key;
113
121
  const failed = state.failedLab?.key === lab.key;
122
+ const mixed = state.mixed(lab);
114
123
  return (
115
124
  <SettingsRow
116
125
  key={lab.key}
@@ -123,17 +132,44 @@ function LabRows({ state }: { state: LabsSettingsState }) {
123
132
  lab: label,
124
133
  })}
125
134
  </span>
135
+ ) : mixed ? (
136
+ (lab.inheritedMixedDescription ?? lab.description)
126
137
  ) : (
127
138
  lab.description
128
139
  )
129
140
  }
130
141
  control={
131
- <Switch
132
- checked={state.enabled(lab)}
133
- onChange={(next) => state.toggle(lab, next)}
134
- disabled={state.disabled}
135
- aria-label={label}
136
- />
142
+ mixed ? (
143
+ <div className="flex gap-2">
144
+ <Button
145
+ type="button"
146
+ variant="outline"
147
+ size="sm"
148
+ disabled={state.disabled}
149
+ onClick={() => state.toggle(lab, true)}
150
+ aria-label={`${label}: ${t("agentChat.settingsShell.channels.state.on")}`}
151
+ >
152
+ {t("agentChat.settingsShell.channels.state.on")}
153
+ </Button>
154
+ <Button
155
+ type="button"
156
+ variant="outline"
157
+ size="sm"
158
+ disabled={state.disabled}
159
+ onClick={() => state.toggle(lab, false)}
160
+ aria-label={`${label}: ${t("agentChat.settingsShell.channels.state.off")}`}
161
+ >
162
+ {t("agentChat.settingsShell.channels.state.off")}
163
+ </Button>
164
+ </div>
165
+ ) : (
166
+ <Switch
167
+ checked={state.enabled(lab)}
168
+ onChange={(next) => state.toggle(lab, next)}
169
+ disabled={state.disabled}
170
+ aria-label={label}
171
+ />
172
+ )
137
173
  }
138
174
  />
139
175
  );
@@ -52,11 +52,14 @@ afterEach(() => {
52
52
  vi.unstubAllEnvs();
53
53
  });
54
54
 
55
+ const catalog = createToolkitI18nCatalog({ messages: {} });
56
+
55
57
  describe("ThumbsFeedback localization", () => {
56
58
  it("renders localized accessible labels and explanation copy", async () => {
57
59
  act(() => {
58
60
  root.render(
59
61
  <AgentNativeI18nProvider
62
+ catalog={catalog}
60
63
  initialLocale="de-DE"
61
64
  initialPreference="de-DE"
62
65
  persistPreference={false}
@@ -87,6 +90,7 @@ describe("ThumbsFeedback localization", () => {
87
90
  act(() => {
88
91
  root.render(
89
92
  <AgentNativeI18nProvider
93
+ catalog={catalog}
90
94
  initialLocale="en-US"
91
95
  initialPreference="en-US"
92
96
  persistPreference={false}
@@ -181,6 +185,7 @@ describe("ThumbsFeedback localization", () => {
181
185
  act(() => {
182
186
  root.render(
183
187
  <AgentNativeI18nProvider
188
+ catalog={catalog}
184
189
  initialLocale="en-US"
185
190
  initialPreference="en-US"
186
191
  persistPreference={false}
@@ -295,6 +300,7 @@ describe("ThumbsFeedback localization", () => {
295
300
  act(() => {
296
301
  root.render(
297
302
  <AgentNativeI18nProvider
303
+ catalog={catalog}
298
304
  initialLocale="en-US"
299
305
  initialPreference="en-US"
300
306
  persistPreference={false}
@@ -421,6 +427,7 @@ describe("ThumbsFeedback localization", () => {
421
427
  act(() => {
422
428
  root.render(
423
429
  <AgentNativeI18nProvider
430
+ catalog={catalog}
424
431
  initialLocale="en-US"
425
432
  initialPreference="en-US"
426
433
  persistPreference={false}
@@ -511,6 +518,7 @@ describe("ThumbsFeedback localization", () => {
511
518
  act(() => {
512
519
  root.render(
513
520
  <AgentNativeI18nProvider
521
+ catalog={catalog}
514
522
  initialLocale="en-US"
515
523
  initialPreference="en-US"
516
524
  persistPreference={false}
@@ -558,6 +566,7 @@ describe("ThumbsFeedback localization", () => {
558
566
  act(() => {
559
567
  root.render(
560
568
  <AgentNativeI18nProvider
569
+ catalog={catalog}
561
570
  initialLocale="en-US"
562
571
  initialPreference="en-US"
563
572
  persistPreference={false}
@@ -596,6 +605,7 @@ describe("ThumbsFeedback localization", () => {
596
605
  act(() => {
597
606
  root.render(
598
607
  <AgentNativeI18nProvider
608
+ catalog={catalog}
599
609
  initialLocale="en-US"
600
610
  initialPreference="en-US"
601
611
  persistPreference={false}
@@ -639,6 +649,7 @@ describe("ThumbsFeedback localization", () => {
639
649
  act(() => {
640
650
  root.render(
641
651
  <AgentNativeI18nProvider
652
+ catalog={catalog}
642
653
  initialLocale="en-US"
643
654
  initialPreference="en-US"
644
655
  persistPreference={false}
@@ -674,6 +685,7 @@ describe("ThumbsFeedback localization", () => {
674
685
  act(() => {
675
686
  root.render(
676
687
  <AgentNativeI18nProvider
688
+ catalog={catalog}
677
689
  initialLocale="en-US"
678
690
  initialPreference="en-US"
679
691
  persistPreference={false}
@@ -709,6 +721,7 @@ describe("ThumbsFeedback localization", () => {
709
721
  act(() => {
710
722
  root.render(
711
723
  <AgentNativeI18nProvider
724
+ catalog={catalog}
712
725
  initialLocale="en-US"
713
726
  initialPreference="en-US"
714
727
  persistPreference={false}
@@ -746,6 +759,7 @@ describe("ThumbsFeedback localization", () => {
746
759
  act(() => {
747
760
  root.render(
748
761
  <AgentNativeI18nProvider
762
+ catalog={catalog}
749
763
  initialLocale="en-US"
750
764
  initialPreference="en-US"
751
765
  persistPreference={false}
@@ -797,6 +811,7 @@ describe("ThumbsFeedback localization", () => {
797
811
  act(() => {
798
812
  root.render(
799
813
  <AgentNativeI18nProvider
814
+ catalog={catalog}
800
815
  initialLocale="en-US"
801
816
  initialPreference="en-US"
802
817
  persistPreference={false}
@@ -45,6 +45,10 @@ vi.mock("react-router", async (importOriginal) => {
45
45
  };
46
46
  });
47
47
 
48
+ vi.mock("@agent-native/core/client/feature-flags/use-feature-flag", () => ({
49
+ useFeatureFlagState: () => ({ status: "ready", enabled: true }),
50
+ }));
51
+
48
52
  vi.mock("@agent-native/core/client/onboarding/use-onboarding", () => ({
49
53
  trackOnboardingEvent: mocks.trackOnboardingEvent,
50
54
  useOnboarding: mocks.useOnboarding,
@@ -1,3 +1,4 @@
1
+ import { useActionQuery } from "@agent-native/core/client/hooks";
1
2
  import { useIconPickerLabels, useT } from "@agent-native/core/client/i18n";
2
3
  import {
3
4
  useOrg,
@@ -8,8 +9,11 @@ import {
8
9
  useSwitchOrg,
9
10
  useSetOrgWorkspaceUrl,
10
11
  } from "@agent-native/core/client/org";
11
- import { uploadEditorImage } from "@agent-native/core/client/uploads";
12
- import { useFileUploadStatus } from "@agent-native/core/client/uploads/use-file-upload-status";
12
+ import {
13
+ uploadWorkspacePrivateIcon,
14
+ workspacePrivateIconLibraryUrl,
15
+ workspacePrivateIconUrl,
16
+ } from "@agent-native/core/client/uploads";
13
17
  import type { IconValue } from "@agent-native/core/icons";
14
18
  import { docsUrl } from "@agent-native/core/shared/docs-url";
15
19
  import { ResourceIcon, ResourceIconPicker } from "@agent-native/toolkit/icons";
@@ -368,31 +372,37 @@ export function OrgIconControl({
368
372
  }) {
369
373
  const t = useT();
370
374
  const iconPickerLabels = useIconPickerLabels();
371
- const fileUploadStatus = useFileUploadStatus(canEdit);
372
- const fileStorageConfigured =
373
- fileUploadStatus.data?.configured === true && !fileUploadStatus.isError;
375
+ const { data: org } = useOrg();
376
+ const uploadedIcons = useActionQuery<{
377
+ assets: Array<{ id: string; alt?: string }>;
378
+ }>("list-workspace-icons", {}, { enabled: canEdit && !!org?.orgId });
374
379
  return canEdit ? (
375
380
  <ResourceIconPicker
376
381
  value={icon}
382
+ uploadedImages={(uploadedIcons.data?.assets ?? []).map((asset) => ({
383
+ version: 1,
384
+ kind: "image",
385
+ authority: "private-icon",
386
+ assetId: asset.id,
387
+ ...(asset.alt ? { alt: asset.alt } : {}),
388
+ }))}
389
+ uploadedImagesError={Boolean(uploadedIcons.error)}
390
+ onUploadedImagesRetry={() => {
391
+ void uploadedIcons.refetch();
392
+ }}
377
393
  onValueChange={async (next) => {
378
394
  await setVisualIdentity.mutateAsync(next);
379
395
  }}
380
- onUpload={
381
- fileStorageConfigured
382
- ? async (file) => {
383
- const uploaded = await uploadEditorImage(file);
384
- return {
385
- version: 1,
386
- kind: "image",
387
- authority: "url",
388
- assetId: uploaded.src,
389
- alt: uploaded.alt || file.name,
390
- };
391
- }
392
- : undefined
393
- }
396
+ onUpload={async (file) => {
397
+ const uploaded = await uploadWorkspacePrivateIcon(file);
398
+ void uploadedIcons.refetch();
399
+ return uploaded;
400
+ }}
401
+ formatUploadError={() => iconPickerLabels.uploadFailed}
394
402
  resolveImageUrl={(image) =>
395
- image.authority === "url" ? image.assetId : undefined
403
+ image.assetId === (icon?.kind === "image" ? icon.assetId : null)
404
+ ? workspacePrivateIconUrl(org?.orgId ?? "", image)
405
+ : workspacePrivateIconLibraryUrl(org?.orgId ?? "", image)
396
406
  }
397
407
  disabled={setVisualIdentity.isPending}
398
408
  labels={{
@@ -439,7 +449,7 @@ export function OrgIconControl({
439
449
  value={icon}
440
450
  size={16}
441
451
  resolveImageUrl={(image) =>
442
- image.authority === "url" ? image.assetId : undefined
452
+ workspacePrivateIconUrl(org?.orgId ?? "", image)
443
453
  }
444
454
  fallback={<IconUsersGroup className="size-4 text-muted-foreground" />}
445
455
  />
@@ -450,7 +460,7 @@ export function OrgIconControl({
450
460
  value={icon}
451
461
  size={16}
452
462
  resolveImageUrl={(image) =>
453
- image.authority === "url" ? image.assetId : undefined
463
+ workspacePrivateIconUrl(org?.orgId ?? "", image)
454
464
  }
455
465
  fallback={<IconUsersGroup className="size-4 text-muted-foreground" />}
456
466
  />
@@ -11,6 +11,7 @@ import {
11
11
  useJoinByDomain,
12
12
  } from "@agent-native/core/client/org";
13
13
  import { signOut } from "@agent-native/core/client/sign-out";
14
+ import { workspacePrivateIconUrl } from "@agent-native/core/client/uploads";
14
15
  import { setBrowserDemoModeEnabled } from "@agent-native/core/demo/browser-state";
15
16
  import { buildSettingsRoute } from "@agent-native/core/navigation";
16
17
  import { shouldOfferWorkspace } from "@agent-native/core/org/workspace-url";
@@ -503,7 +504,7 @@ export function OrgSwitcher({
503
504
  value={org.icon}
504
505
  size={12}
505
506
  resolveImageUrl={(image) =>
506
- image.authority === "url" ? image.assetId : undefined
507
+ workspacePrivateIconUrl(org.orgId ?? "", image)
507
508
  }
508
509
  fallback={<IconBriefcase className="size-3 shrink-0" />}
509
510
  />
@@ -585,7 +586,7 @@ export function OrgSwitcher({
585
586
  value={o.icon}
586
587
  size={14}
587
588
  resolveImageUrl={(image) =>
588
- image.authority === "url" ? image.assetId : undefined
589
+ workspacePrivateIconUrl(o.orgId, image)
589
590
  }
590
591
  fallback={<IconBriefcase className={ITEM_ICON_CLASS} />}
591
592
  />
@@ -3,6 +3,7 @@ import { describe, expect, it } from "vitest";
3
3
  import {
4
4
  defaultOrgAppLinks,
5
5
  dispatchAppsHref,
6
+ dispatchIntegrationsHref,
6
7
  isWorkspaceAppEnvironment,
7
8
  parseWorkspaceAppLinks,
8
9
  visibleOrgAppLinks,
@@ -66,6 +67,9 @@ describe("org switcher app links", () => {
66
67
  expect(dispatchAppsHref(apps ?? [])).toBe(
67
68
  "http://127.0.0.1:8080/dispatch/apps",
68
69
  );
70
+ expect(dispatchIntegrationsHref(apps ?? [])).toBe(
71
+ "http://127.0.0.1:8080/dispatch/integrations",
72
+ );
69
73
  });
70
74
 
71
75
  it("uses a published custom home path for workspace app links", () => {
@@ -266,7 +266,7 @@ export function isWorkspaceAppEnvironment(
266
266
 
267
267
  function dispatchPageHref(
268
268
  apps: OrgSwitcherAppLink[],
269
- page: "overview" | "apps" | "vault" | "workspace",
269
+ page: "overview" | "apps" | "vault" | "workspace" | "integrations",
270
270
  env: RuntimeEnv,
271
271
  ): string {
272
272
  const dispatch = apps.find((app) => app.isDispatch);
@@ -303,6 +303,13 @@ export function dispatchResourcesHref(
303
303
  return dispatchPageHref(apps, "workspace", env);
304
304
  }
305
305
 
306
+ export function dispatchIntegrationsHref(
307
+ apps: OrgSwitcherAppLink[],
308
+ env: RuntimeEnv = runtimeEnv(),
309
+ ): string {
310
+ return dispatchPageHref(apps, "integrations", env);
311
+ }
312
+
306
313
  export function visibleOrgAppLinks(
307
314
  apps: OrgSwitcherAppLink[],
308
315
  max = ORG_SWITCHER_MAX_APP_LINKS,