@shipfox/client-agent 21.0.0 → 22.0.1

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 (39) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +24 -0
  3. package/dist/components/add-custom-provider-card.d.ts.map +1 -1
  4. package/dist/components/add-custom-provider-card.js +11 -31
  5. package/dist/components/add-custom-provider-card.js.map +1 -1
  6. package/dist/components/available-provider-card.d.ts.map +1 -1
  7. package/dist/components/available-provider-card.js +11 -31
  8. package/dist/components/available-provider-card.js.map +1 -1
  9. package/dist/components/available-providers-grid.d.ts +0 -1
  10. package/dist/components/available-providers-grid.d.ts.map +1 -1
  11. package/dist/components/available-providers-grid.js +33 -27
  12. package/dist/components/available-providers-grid.js.map +1 -1
  13. package/dist/components/harnesses-section.d.ts.map +1 -1
  14. package/dist/components/harnesses-section.js +152 -146
  15. package/dist/components/harnesses-section.js.map +1 -1
  16. package/dist/components/model-provider-grid-skeleton.d.ts +4 -0
  17. package/dist/components/model-provider-grid-skeleton.d.ts.map +1 -0
  18. package/dist/components/model-provider-grid-skeleton.js +34 -0
  19. package/dist/components/model-provider-grid-skeleton.js.map +1 -0
  20. package/dist/components/model-providers-section.d.ts.map +1 -1
  21. package/dist/components/model-providers-section.js +268 -281
  22. package/dist/components/model-providers-section.js.map +1 -1
  23. package/dist/pages/model-provider-onboarding-page.d.ts.map +1 -1
  24. package/dist/pages/model-provider-onboarding-page.js +32 -64
  25. package/dist/pages/model-provider-onboarding-page.js.map +1 -1
  26. package/dist/routes/agents-settings.js +15 -5
  27. package/dist/routes/agents-settings.js.map +1 -1
  28. package/dist/tsconfig.test.tsbuildinfo +1 -1
  29. package/package.json +4 -4
  30. package/src/components/add-custom-provider-card.tsx +9 -23
  31. package/src/components/available-provider-card.tsx +9 -23
  32. package/src/components/available-providers-grid.tsx +36 -29
  33. package/src/components/harnesses-section.tsx +116 -109
  34. package/src/components/model-provider-grid-skeleton.tsx +21 -0
  35. package/src/components/model-providers-section.test.tsx +2 -2
  36. package/src/components/model-providers-section.tsx +208 -200
  37. package/src/pages/model-provider-onboarding-page.tsx +26 -54
  38. package/src/routes/agents-settings.tsx +7 -3
  39. package/tsconfig.build.tsbuildinfo +1 -1
@@ -4,17 +4,16 @@ import { IconButton } from '@shipfox/react-ui/button';
4
4
  import { Callout } from '@shipfox/react-ui/callout';
5
5
  import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@shipfox/react-ui/dropdown-menu';
6
6
  import { Icon } from '@shipfox/react-ui/icon';
7
+ import { Panel, PanelBody, PanelRow } from '@shipfox/react-ui/panel';
7
8
  import { Skeleton } from '@shipfox/react-ui/skeleton';
8
9
  import { toast } from '@shipfox/react-ui/toast';
9
10
  import { Tooltip, TooltipContent, TooltipTrigger } from '@shipfox/react-ui/tooltip';
10
11
  import { Header, Text } from '@shipfox/react-ui/typography';
11
- import { cn } from '@shipfox/react-ui/utils';
12
12
  import { useRef, useState } from 'react';
13
13
  import { DEFAULT_HARNESS, listHarnesses } from '#core/harness-policy.js';
14
14
  import { useModelProviderConfigsQuery, useSetDefaultHarnessMutation } from '#hooks/api/model-providers.js';
15
15
  import { modelProviderConfigErrorToFormError } from './form-errors.js';
16
16
  import { isHarnessAvailable } from './harness-availability.js';
17
- const SURFACE_CLASS = 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';
18
17
  export function WorkspaceHarnessesSection({ workspaceId }) {
19
18
  const configsQuery = useModelProviderConfigsQuery(workspaceId);
20
19
  const setDefaultHarness = useSetDefaultHarnessMutation();
@@ -69,149 +68,149 @@ export function WorkspaceHarnessesSection({ workspaceId }) {
69
68
  className: "flex flex-col gap-group",
70
69
  "aria-label": "Harnesses",
71
70
  children: [
72
- /*#__PURE__*/ _jsxs("div", {
71
+ /*#__PURE__*/ _jsx("div", {
73
72
  className: "flex flex-col gap-tight",
74
- children: [
75
- /*#__PURE__*/ _jsx(Header, {
76
- variant: "h3",
77
- children: "Harnesses"
78
- }),
79
- /*#__PURE__*/ _jsx(Text, {
80
- size: "sm",
81
- className: "text-foreground-neutral-muted",
82
- children: "Harnesses available to run agent steps in this workspace."
83
- })
84
- ]
73
+ children: /*#__PURE__*/ _jsx(Header, {
74
+ variant: "h3",
75
+ children: "Harnesses"
76
+ })
85
77
  }),
86
78
  configsQuery.isPending ? /*#__PURE__*/ _jsx(HarnessRowsSkeleton, {}) : null,
87
- configsQuery.isError && configsQuery.data === undefined ? /*#__PURE__*/ _jsx("div", {
88
- className: cn(SURFACE_CLASS, 'px-row'),
79
+ configsQuery.isError && configsQuery.data === undefined ? /*#__PURE__*/ _jsx(Panel, {
89
80
  children: /*#__PURE__*/ _jsx(QueryLoadError, {
90
81
  query: configsQuery,
91
- subject: "harnesses"
82
+ subject: "harnesses",
83
+ variant: "panel"
92
84
  })
93
85
  }) : null,
94
- configsQuery.data !== undefined ? /*#__PURE__*/ _jsx("ul", {
95
- className: cn('divide-y divide-border-neutral-base', SURFACE_CLASS),
96
- children: listHarnesses().map((harness)=>/*#__PURE__*/ _jsx(HarnessRow, {
97
- harness: harness,
98
- isDefault: harness.id === defaultHarnessId,
99
- isAvailable: isHarnessAvailable(harness, configs),
100
- isSettingDefault: pendingDefaultHarness?.workspaceId === workspaceId,
101
- defaultError: defaultError?.workspaceId === workspaceId && defaultError.harnessId === harness.id ? defaultError.message : undefined,
102
- onSetDefault: handleSetDefault
103
- }, harness.id))
86
+ configsQuery.data !== undefined ? /*#__PURE__*/ _jsx(Panel, {
87
+ children: /*#__PURE__*/ _jsx(PanelBody, {
88
+ asChild: true,
89
+ children: /*#__PURE__*/ _jsx("ul", {
90
+ children: listHarnesses().map((harness)=>/*#__PURE__*/ _jsx(HarnessRow, {
91
+ harness: harness,
92
+ isDefault: harness.id === defaultHarnessId,
93
+ isAvailable: isHarnessAvailable(harness, configs),
94
+ isSettingDefault: pendingDefaultHarness?.workspaceId === workspaceId,
95
+ defaultError: defaultError?.workspaceId === workspaceId && defaultError.harnessId === harness.id ? defaultError.message : undefined,
96
+ onSetDefault: handleSetDefault
97
+ }, harness.id))
98
+ })
99
+ })
104
100
  }) : null
105
101
  ]
106
102
  });
107
103
  }
108
104
  function HarnessRow({ harness, isDefault, isAvailable, isSettingDefault, defaultError, onSetDefault }) {
109
105
  const unavailableCopy = harnessUnavailableCopy(isDefault);
110
- return /*#__PURE__*/ _jsxs("li", {
111
- className: "flex flex-col gap-inline px-row py-row transition-colors hover:bg-background-components-hover",
112
- children: [
113
- /*#__PURE__*/ _jsxs("div", {
114
- className: "flex items-center justify-between gap-cluster",
115
- children: [
116
- /*#__PURE__*/ _jsxs("div", {
117
- className: "flex min-w-0 items-center gap-inline",
118
- children: [
119
- isDefault ? /*#__PURE__*/ _jsxs(_Fragment, {
120
- children: [
121
- /*#__PURE__*/ _jsxs(Tooltip, {
122
- children: [
123
- /*#__PURE__*/ _jsx(TooltipTrigger, {
124
- asChild: true,
125
- children: /*#__PURE__*/ _jsx("span", {
126
- className: "inline-flex size-16 shrink-0 items-center justify-center",
127
- children: /*#__PURE__*/ _jsx(Icon, {
128
- name: "starLine",
129
- className: "size-16 text-foreground-neutral-muted",
130
- "aria-hidden": true
106
+ return /*#__PURE__*/ _jsx(PanelRow, {
107
+ asChild: true,
108
+ className: "flex-col items-stretch gap-inline",
109
+ children: /*#__PURE__*/ _jsxs("li", {
110
+ children: [
111
+ /*#__PURE__*/ _jsxs("div", {
112
+ className: "flex items-center justify-between gap-cluster",
113
+ children: [
114
+ /*#__PURE__*/ _jsxs("div", {
115
+ className: "flex min-w-0 items-center gap-inline",
116
+ children: [
117
+ isDefault ? /*#__PURE__*/ _jsxs(_Fragment, {
118
+ children: [
119
+ /*#__PURE__*/ _jsxs(Tooltip, {
120
+ children: [
121
+ /*#__PURE__*/ _jsx(TooltipTrigger, {
122
+ asChild: true,
123
+ children: /*#__PURE__*/ _jsx("span", {
124
+ className: "inline-flex size-16 shrink-0 items-center justify-center",
125
+ children: /*#__PURE__*/ _jsx(Icon, {
126
+ name: "starLine",
127
+ className: "size-16 text-foreground-neutral-muted",
128
+ "aria-hidden": true
129
+ })
131
130
  })
131
+ }),
132
+ /*#__PURE__*/ _jsx(TooltipContent, {
133
+ children: "Default harness"
132
134
  })
133
- }),
134
- /*#__PURE__*/ _jsx(TooltipContent, {
135
- children: "Default harness"
136
- })
137
- ]
138
- }),
139
- /*#__PURE__*/ _jsx("span", {
140
- className: "sr-only",
141
- children: "Default harness"
142
- })
143
- ]
144
- }) : null,
145
- /*#__PURE__*/ _jsx(Text, {
146
- size: "md",
147
- bold: true,
148
- className: "truncate",
149
- children: harness.label
150
- }),
151
- !isAvailable ? /*#__PURE__*/ _jsxs(_Fragment, {
152
- children: [
153
- /*#__PURE__*/ _jsxs(Tooltip, {
154
- children: [
155
- /*#__PURE__*/ _jsx(TooltipTrigger, {
156
- asChild: true,
157
- children: /*#__PURE__*/ _jsx("span", {
158
- className: "inline-flex size-16 shrink-0 items-center justify-center",
159
- children: /*#__PURE__*/ _jsx(Icon, {
160
- name: "errorWarningLine",
161
- className: "size-16 text-foreground-warning-base",
162
- "aria-hidden": true
135
+ ]
136
+ }),
137
+ /*#__PURE__*/ _jsx("span", {
138
+ className: "sr-only",
139
+ children: "Default harness"
140
+ })
141
+ ]
142
+ }) : null,
143
+ /*#__PURE__*/ _jsx(Text, {
144
+ size: "md",
145
+ bold: true,
146
+ className: "truncate",
147
+ children: harness.label
148
+ }),
149
+ !isAvailable ? /*#__PURE__*/ _jsxs(_Fragment, {
150
+ children: [
151
+ /*#__PURE__*/ _jsxs(Tooltip, {
152
+ children: [
153
+ /*#__PURE__*/ _jsx(TooltipTrigger, {
154
+ asChild: true,
155
+ children: /*#__PURE__*/ _jsx("span", {
156
+ className: "inline-flex size-16 shrink-0 items-center justify-center",
157
+ children: /*#__PURE__*/ _jsx(Icon, {
158
+ name: "errorWarningLine",
159
+ className: "size-16 text-foreground-warning-base",
160
+ "aria-hidden": true
161
+ })
163
162
  })
163
+ }),
164
+ /*#__PURE__*/ _jsx(TooltipContent, {
165
+ children: unavailableCopy
164
166
  })
165
- }),
166
- /*#__PURE__*/ _jsx(TooltipContent, {
167
- children: unavailableCopy
168
- })
169
- ]
170
- }),
171
- /*#__PURE__*/ _jsx("span", {
172
- className: "sr-only",
173
- children: unavailableCopy
167
+ ]
168
+ }),
169
+ /*#__PURE__*/ _jsx("span", {
170
+ className: "sr-only",
171
+ children: unavailableCopy
172
+ })
173
+ ]
174
+ }) : null
175
+ ]
176
+ }),
177
+ !isDefault ? /*#__PURE__*/ _jsxs(DropdownMenu, {
178
+ children: [
179
+ /*#__PURE__*/ _jsx(DropdownMenuTrigger, {
180
+ asChild: true,
181
+ children: /*#__PURE__*/ _jsx(IconButton, {
182
+ size: "sm",
183
+ variant: "transparent",
184
+ icon: "more2Line",
185
+ disabled: isSettingDefault,
186
+ "aria-label": `Open ${harness.label} harness actions`
187
+ })
188
+ }),
189
+ /*#__PURE__*/ _jsx(DropdownMenuContent, {
190
+ align: "end",
191
+ children: /*#__PURE__*/ _jsx(DropdownMenuItem, {
192
+ icon: "starLine",
193
+ disabled: isSettingDefault || !isAvailable,
194
+ onSelect: ()=>{
195
+ onSetDefault(harness);
196
+ },
197
+ children: "Set as default"
174
198
  })
175
- ]
176
- }) : null
177
- ]
178
- }),
179
- !isDefault ? /*#__PURE__*/ _jsxs(DropdownMenu, {
180
- children: [
181
- /*#__PURE__*/ _jsx(DropdownMenuTrigger, {
182
- asChild: true,
183
- children: /*#__PURE__*/ _jsx(IconButton, {
184
- size: "sm",
185
- variant: "transparent",
186
- icon: "more2Line",
187
- disabled: isSettingDefault,
188
- "aria-label": `Open ${harness.label} harness actions`
189
- })
190
- }),
191
- /*#__PURE__*/ _jsx(DropdownMenuContent, {
192
- align: "end",
193
- children: /*#__PURE__*/ _jsx(DropdownMenuItem, {
194
- icon: "starLine",
195
- disabled: isSettingDefault || !isAvailable,
196
- onSelect: ()=>{
197
- onSetDefault(harness);
198
- },
199
- children: "Set as default"
200
199
  })
201
- })
202
- ]
203
- }) : null
204
- ]
205
- }),
206
- defaultError ? /*#__PURE__*/ _jsx(Callout, {
207
- role: "alert",
208
- type: "error",
209
- children: /*#__PURE__*/ _jsx(Text, {
210
- size: "sm",
211
- children: defaultError
212
- })
213
- }) : null
214
- ]
200
+ ]
201
+ }) : null
202
+ ]
203
+ }),
204
+ defaultError ? /*#__PURE__*/ _jsx(Callout, {
205
+ role: "alert",
206
+ type: "error",
207
+ children: /*#__PURE__*/ _jsx(Text, {
208
+ size: "sm",
209
+ children: defaultError
210
+ })
211
+ }) : null
212
+ ]
213
+ })
215
214
  });
216
215
  }
217
216
  function harnessUnavailableCopy(isDefault) {
@@ -220,27 +219,34 @@ function harnessUnavailableCopy(isDefault) {
220
219
  return `${base} The stored default harness cannot currently run in this workspace.`;
221
220
  }
222
221
  function HarnessRowsSkeleton() {
223
- return /*#__PURE__*/ _jsx("ul", {
224
- role: "status",
225
- "aria-label": "Loading harnesses",
226
- className: cn('divide-y divide-border-neutral-base', SURFACE_CLASS),
227
- children: [
228
- 0,
229
- 1
230
- ].map((row)=>/*#__PURE__*/ _jsxs("li", {
231
- className: "flex items-center gap-cluster px-row py-row",
222
+ return /*#__PURE__*/ _jsx(Panel, {
223
+ children: /*#__PURE__*/ _jsx(PanelBody, {
224
+ asChild: true,
225
+ children: /*#__PURE__*/ _jsx("ul", {
226
+ role: "status",
227
+ "aria-label": "Loading harnesses",
232
228
  children: [
233
- /*#__PURE__*/ _jsx(Skeleton, {
234
- className: "size-16 shrink-0"
235
- }),
236
- /*#__PURE__*/ _jsx(Skeleton, {
237
- className: "h-16 w-120"
238
- }),
239
- /*#__PURE__*/ _jsx(Skeleton, {
240
- className: "ml-auto size-28 shrink-0"
241
- })
242
- ]
243
- }, row))
229
+ 0,
230
+ 1
231
+ ].map((row)=>/*#__PURE__*/ _jsx(PanelRow, {
232
+ asChild: true,
233
+ className: "justify-start gap-cluster hover:bg-background-neutral-base",
234
+ children: /*#__PURE__*/ _jsxs("li", {
235
+ children: [
236
+ /*#__PURE__*/ _jsx(Skeleton, {
237
+ className: "size-16 shrink-0"
238
+ }),
239
+ /*#__PURE__*/ _jsx(Skeleton, {
240
+ className: "h-16 w-120"
241
+ }),
242
+ /*#__PURE__*/ _jsx(Skeleton, {
243
+ className: "ml-auto size-28 shrink-0"
244
+ })
245
+ ]
246
+ })
247
+ }, row))
248
+ })
249
+ })
244
250
  });
245
251
  }
246
252
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/harnesses-section.tsx"],"sourcesContent":["import {QueryLoadError} from '@shipfox/client-ui';\nimport {IconButton} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@shipfox/react-ui/dropdown-menu';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {useRef, useState} from 'react';\nimport {DEFAULT_HARNESS, listHarnesses} from '#core/harness-policy.js';\nimport type {HarnessDescriptor, HarnessId} from '#core/models.js';\nimport {\n useModelProviderConfigsQuery,\n useSetDefaultHarnessMutation,\n} from '#hooks/api/model-providers.js';\nimport {modelProviderConfigErrorToFormError} from './form-errors.js';\nimport {isHarnessAvailable} from './harness-availability.js';\n\nconst SURFACE_CLASS =\n 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';\n\nexport function WorkspaceHarnessesSection({workspaceId}: {workspaceId: string}) {\n const configsQuery = useModelProviderConfigsQuery(workspaceId);\n const setDefaultHarness = useSetDefaultHarnessMutation();\n const activeWorkspaceIdRef = useRef(workspaceId);\n const defaultRequestSeqRef = useRef(0);\n const activeDefaultRequestRef = useRef<{workspaceId: string; id: number} | null>(null);\n const [pendingDefaultHarness, setPendingDefaultHarness] = useState<{\n workspaceId: string;\n harnessId: HarnessId;\n } | null>(null);\n const [defaultError, setDefaultError] = useState<\n {workspaceId: string; harnessId: HarnessId; message: string} | undefined\n >();\n const configs = configsQuery.data?.configs ?? [];\n const defaultHarnessId = configsQuery.data?.defaultHarnessId ?? DEFAULT_HARNESS;\n activeWorkspaceIdRef.current = workspaceId;\n\n function isActiveDefaultRequest(request: {workspaceId: string; id: number}) {\n const activeRequest = activeDefaultRequestRef.current;\n return (\n activeWorkspaceIdRef.current === request.workspaceId &&\n activeRequest?.workspaceId === request.workspaceId &&\n activeRequest.id === request.id\n );\n }\n\n async function handleSetDefault(harness: HarnessDescriptor) {\n if (activeDefaultRequestRef.current?.workspaceId === workspaceId) return;\n\n const request = {workspaceId, id: defaultRequestSeqRef.current + 1};\n defaultRequestSeqRef.current = request.id;\n activeDefaultRequestRef.current = request;\n setPendingDefaultHarness({workspaceId, harnessId: harness.id});\n setDefaultError(undefined);\n try {\n await setDefaultHarness.mutateAsync({\n workspaceId,\n harnessId: harness.id,\n });\n if (!isActiveDefaultRequest(request)) return;\n toast.success(`${harness.label} is now the default harness`);\n } catch (error) {\n if (!isActiveDefaultRequest(request)) return;\n const mapped = modelProviderConfigErrorToFormError(error);\n setDefaultError({\n workspaceId,\n harnessId: harness.id,\n message: mapped.message || 'Could not save default harness. Try again.',\n });\n } finally {\n if (isActiveDefaultRequest(request)) {\n activeDefaultRequestRef.current = null;\n setPendingDefaultHarness(null);\n }\n }\n }\n\n return (\n <section className=\"flex flex-col gap-group\" aria-label=\"Harnesses\">\n <div className=\"flex flex-col gap-tight\">\n <Header variant=\"h3\">Harnesses</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Harnesses available to run agent steps in this workspace.\n </Text>\n </div>\n\n {configsQuery.isPending ? <HarnessRowsSkeleton /> : null}\n\n {configsQuery.isError && configsQuery.data === undefined ? (\n <div className={cn(SURFACE_CLASS, 'px-row')}>\n <QueryLoadError query={configsQuery} subject=\"harnesses\" />\n </div>\n ) : null}\n\n {configsQuery.data !== undefined ? (\n <ul className={cn('divide-y divide-border-neutral-base', SURFACE_CLASS)}>\n {listHarnesses().map((harness) => (\n <HarnessRow\n key={harness.id}\n harness={harness}\n isDefault={harness.id === defaultHarnessId}\n isAvailable={isHarnessAvailable(harness, configs)}\n isSettingDefault={pendingDefaultHarness?.workspaceId === workspaceId}\n defaultError={\n defaultError?.workspaceId === workspaceId && defaultError.harnessId === harness.id\n ? defaultError.message\n : undefined\n }\n onSetDefault={handleSetDefault}\n />\n ))}\n </ul>\n ) : null}\n </section>\n );\n}\n\nfunction HarnessRow({\n harness,\n isDefault,\n isAvailable,\n isSettingDefault,\n defaultError,\n onSetDefault,\n}: {\n harness: HarnessDescriptor;\n isDefault: boolean;\n isAvailable: boolean;\n isSettingDefault: boolean;\n defaultError: string | undefined;\n onSetDefault: (harness: HarnessDescriptor) => void;\n}) {\n const unavailableCopy = harnessUnavailableCopy(isDefault);\n\n return (\n <li className=\"flex flex-col gap-inline px-row py-row transition-colors hover:bg-background-components-hover\">\n <div className=\"flex items-center justify-between gap-cluster\">\n <div className=\"flex min-w-0 items-center gap-inline\">\n {isDefault ? (\n <>\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"inline-flex size-16 shrink-0 items-center justify-center\">\n <Icon\n name=\"starLine\"\n className=\"size-16 text-foreground-neutral-muted\"\n aria-hidden\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>Default harness</TooltipContent>\n </Tooltip>\n <span className=\"sr-only\">Default harness</span>\n </>\n ) : null}\n <Text size=\"md\" bold className=\"truncate\">\n {harness.label}\n </Text>\n {!isAvailable ? (\n <>\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"inline-flex size-16 shrink-0 items-center justify-center\">\n <Icon\n name=\"errorWarningLine\"\n className=\"size-16 text-foreground-warning-base\"\n aria-hidden\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>{unavailableCopy}</TooltipContent>\n </Tooltip>\n <span className=\"sr-only\">{unavailableCopy}</span>\n </>\n ) : null}\n </div>\n {!isDefault ? (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <IconButton\n size=\"sm\"\n variant=\"transparent\"\n icon=\"more2Line\"\n disabled={isSettingDefault}\n aria-label={`Open ${harness.label} harness actions`}\n />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem\n icon=\"starLine\"\n disabled={isSettingDefault || !isAvailable}\n onSelect={() => {\n onSetDefault(harness);\n }}\n >\n Set as default\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n ) : null}\n </div>\n {defaultError ? (\n <Callout role=\"alert\" type=\"error\">\n <Text size=\"sm\">{defaultError}</Text>\n </Callout>\n ) : null}\n </li>\n );\n}\n\nfunction harnessUnavailableCopy(isDefault: boolean): string {\n const base = 'Configure a compatible model provider to use this harness.';\n if (!isDefault) return base;\n return `${base} The stored default harness cannot currently run in this workspace.`;\n}\n\nfunction HarnessRowsSkeleton() {\n return (\n <ul\n role=\"status\"\n aria-label=\"Loading harnesses\"\n className={cn('divide-y divide-border-neutral-base', SURFACE_CLASS)}\n >\n {[0, 1].map((row) => (\n <li key={row} className=\"flex items-center gap-cluster px-row py-row\">\n <Skeleton className=\"size-16 shrink-0\" />\n <Skeleton className=\"h-16 w-120\" />\n <Skeleton className=\"ml-auto size-28 shrink-0\" />\n </li>\n ))}\n </ul>\n );\n}\n"],"names":["QueryLoadError","IconButton","Callout","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","Icon","Skeleton","toast","Tooltip","TooltipContent","TooltipTrigger","Header","Text","cn","useRef","useState","DEFAULT_HARNESS","listHarnesses","useModelProviderConfigsQuery","useSetDefaultHarnessMutation","modelProviderConfigErrorToFormError","isHarnessAvailable","SURFACE_CLASS","WorkspaceHarnessesSection","workspaceId","configsQuery","setDefaultHarness","activeWorkspaceIdRef","defaultRequestSeqRef","activeDefaultRequestRef","pendingDefaultHarness","setPendingDefaultHarness","defaultError","setDefaultError","configs","data","defaultHarnessId","current","isActiveDefaultRequest","request","activeRequest","id","handleSetDefault","harness","harnessId","undefined","mutateAsync","success","label","error","mapped","message","section","className","aria-label","div","variant","size","isPending","HarnessRowsSkeleton","isError","query","subject","ul","map","HarnessRow","isDefault","isAvailable","isSettingDefault","onSetDefault","unavailableCopy","harnessUnavailableCopy","li","asChild","span","name","aria-hidden","bold","icon","disabled","align","onSelect","role","type","base","row"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/components/harnesses-section.tsx"],"sourcesContent":["import {QueryLoadError} from '@shipfox/client-ui';\nimport {IconButton} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@shipfox/react-ui/dropdown-menu';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {Panel, PanelBody, PanelRow} from '@shipfox/react-ui/panel';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {useRef, useState} from 'react';\nimport {DEFAULT_HARNESS, listHarnesses} from '#core/harness-policy.js';\nimport type {HarnessDescriptor, HarnessId} from '#core/models.js';\nimport {\n useModelProviderConfigsQuery,\n useSetDefaultHarnessMutation,\n} from '#hooks/api/model-providers.js';\nimport {modelProviderConfigErrorToFormError} from './form-errors.js';\nimport {isHarnessAvailable} from './harness-availability.js';\n\nexport function WorkspaceHarnessesSection({workspaceId}: {workspaceId: string}) {\n const configsQuery = useModelProviderConfigsQuery(workspaceId);\n const setDefaultHarness = useSetDefaultHarnessMutation();\n const activeWorkspaceIdRef = useRef(workspaceId);\n const defaultRequestSeqRef = useRef(0);\n const activeDefaultRequestRef = useRef<{workspaceId: string; id: number} | null>(null);\n const [pendingDefaultHarness, setPendingDefaultHarness] = useState<{\n workspaceId: string;\n harnessId: HarnessId;\n } | null>(null);\n const [defaultError, setDefaultError] = useState<\n {workspaceId: string; harnessId: HarnessId; message: string} | undefined\n >();\n const configs = configsQuery.data?.configs ?? [];\n const defaultHarnessId = configsQuery.data?.defaultHarnessId ?? DEFAULT_HARNESS;\n activeWorkspaceIdRef.current = workspaceId;\n\n function isActiveDefaultRequest(request: {workspaceId: string; id: number}) {\n const activeRequest = activeDefaultRequestRef.current;\n return (\n activeWorkspaceIdRef.current === request.workspaceId &&\n activeRequest?.workspaceId === request.workspaceId &&\n activeRequest.id === request.id\n );\n }\n\n async function handleSetDefault(harness: HarnessDescriptor) {\n if (activeDefaultRequestRef.current?.workspaceId === workspaceId) return;\n\n const request = {workspaceId, id: defaultRequestSeqRef.current + 1};\n defaultRequestSeqRef.current = request.id;\n activeDefaultRequestRef.current = request;\n setPendingDefaultHarness({workspaceId, harnessId: harness.id});\n setDefaultError(undefined);\n try {\n await setDefaultHarness.mutateAsync({\n workspaceId,\n harnessId: harness.id,\n });\n if (!isActiveDefaultRequest(request)) return;\n toast.success(`${harness.label} is now the default harness`);\n } catch (error) {\n if (!isActiveDefaultRequest(request)) return;\n const mapped = modelProviderConfigErrorToFormError(error);\n setDefaultError({\n workspaceId,\n harnessId: harness.id,\n message: mapped.message || 'Could not save default harness. Try again.',\n });\n } finally {\n if (isActiveDefaultRequest(request)) {\n activeDefaultRequestRef.current = null;\n setPendingDefaultHarness(null);\n }\n }\n }\n\n return (\n <section className=\"flex flex-col gap-group\" aria-label=\"Harnesses\">\n <div className=\"flex flex-col gap-tight\">\n <Header variant=\"h3\">Harnesses</Header>\n </div>\n\n {configsQuery.isPending ? <HarnessRowsSkeleton /> : null}\n\n {configsQuery.isError && configsQuery.data === undefined ? (\n <Panel>\n <QueryLoadError query={configsQuery} subject=\"harnesses\" variant=\"panel\" />\n </Panel>\n ) : null}\n\n {configsQuery.data !== undefined ? (\n <Panel>\n <PanelBody asChild>\n <ul>\n {listHarnesses().map((harness) => (\n <HarnessRow\n key={harness.id}\n harness={harness}\n isDefault={harness.id === defaultHarnessId}\n isAvailable={isHarnessAvailable(harness, configs)}\n isSettingDefault={pendingDefaultHarness?.workspaceId === workspaceId}\n defaultError={\n defaultError?.workspaceId === workspaceId &&\n defaultError.harnessId === harness.id\n ? defaultError.message\n : undefined\n }\n onSetDefault={handleSetDefault}\n />\n ))}\n </ul>\n </PanelBody>\n </Panel>\n ) : null}\n </section>\n );\n}\n\nfunction HarnessRow({\n harness,\n isDefault,\n isAvailable,\n isSettingDefault,\n defaultError,\n onSetDefault,\n}: {\n harness: HarnessDescriptor;\n isDefault: boolean;\n isAvailable: boolean;\n isSettingDefault: boolean;\n defaultError: string | undefined;\n onSetDefault: (harness: HarnessDescriptor) => void;\n}) {\n const unavailableCopy = harnessUnavailableCopy(isDefault);\n\n return (\n <PanelRow asChild className=\"flex-col items-stretch gap-inline\">\n <li>\n <div className=\"flex items-center justify-between gap-cluster\">\n <div className=\"flex min-w-0 items-center gap-inline\">\n {isDefault ? (\n <>\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"inline-flex size-16 shrink-0 items-center justify-center\">\n <Icon\n name=\"starLine\"\n className=\"size-16 text-foreground-neutral-muted\"\n aria-hidden\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>Default harness</TooltipContent>\n </Tooltip>\n <span className=\"sr-only\">Default harness</span>\n </>\n ) : null}\n <Text size=\"md\" bold className=\"truncate\">\n {harness.label}\n </Text>\n {!isAvailable ? (\n <>\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"inline-flex size-16 shrink-0 items-center justify-center\">\n <Icon\n name=\"errorWarningLine\"\n className=\"size-16 text-foreground-warning-base\"\n aria-hidden\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>{unavailableCopy}</TooltipContent>\n </Tooltip>\n <span className=\"sr-only\">{unavailableCopy}</span>\n </>\n ) : null}\n </div>\n {!isDefault ? (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <IconButton\n size=\"sm\"\n variant=\"transparent\"\n icon=\"more2Line\"\n disabled={isSettingDefault}\n aria-label={`Open ${harness.label} harness actions`}\n />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem\n icon=\"starLine\"\n disabled={isSettingDefault || !isAvailable}\n onSelect={() => {\n onSetDefault(harness);\n }}\n >\n Set as default\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n ) : null}\n </div>\n {defaultError ? (\n <Callout role=\"alert\" type=\"error\">\n <Text size=\"sm\">{defaultError}</Text>\n </Callout>\n ) : null}\n </li>\n </PanelRow>\n );\n}\n\nfunction harnessUnavailableCopy(isDefault: boolean): string {\n const base = 'Configure a compatible model provider to use this harness.';\n if (!isDefault) return base;\n return `${base} The stored default harness cannot currently run in this workspace.`;\n}\n\nfunction HarnessRowsSkeleton() {\n return (\n <Panel>\n <PanelBody asChild>\n <ul role=\"status\" aria-label=\"Loading harnesses\">\n {[0, 1].map((row) => (\n <PanelRow\n asChild\n className=\"justify-start gap-cluster hover:bg-background-neutral-base\"\n key={row}\n >\n <li>\n <Skeleton className=\"size-16 shrink-0\" />\n <Skeleton className=\"h-16 w-120\" />\n <Skeleton className=\"ml-auto size-28 shrink-0\" />\n </li>\n </PanelRow>\n ))}\n </ul>\n </PanelBody>\n </Panel>\n );\n}\n"],"names":["QueryLoadError","IconButton","Callout","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","Icon","Panel","PanelBody","PanelRow","Skeleton","toast","Tooltip","TooltipContent","TooltipTrigger","Header","Text","useRef","useState","DEFAULT_HARNESS","listHarnesses","useModelProviderConfigsQuery","useSetDefaultHarnessMutation","modelProviderConfigErrorToFormError","isHarnessAvailable","WorkspaceHarnessesSection","workspaceId","configsQuery","setDefaultHarness","activeWorkspaceIdRef","defaultRequestSeqRef","activeDefaultRequestRef","pendingDefaultHarness","setPendingDefaultHarness","defaultError","setDefaultError","configs","data","defaultHarnessId","current","isActiveDefaultRequest","request","activeRequest","id","handleSetDefault","harness","harnessId","undefined","mutateAsync","success","label","error","mapped","message","section","className","aria-label","div","variant","isPending","HarnessRowsSkeleton","isError","query","subject","asChild","ul","map","HarnessRow","isDefault","isAvailable","isSettingDefault","onSetDefault","unavailableCopy","harnessUnavailableCopy","li","span","name","aria-hidden","size","bold","icon","disabled","align","onSelect","role","type","base","row"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function ModelProviderGridSkeleton({ label }: {
2
+ label: string;
3
+ }): import("react").JSX.Element;
4
+ //# sourceMappingURL=model-provider-grid-skeleton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-provider-grid-skeleton.d.ts","sourceRoot":"","sources":["../../src/components/model-provider-grid-skeleton.tsx"],"names":[],"mappings":"AAGA,wBAAgB,yBAAyB,CAAC,EAAC,KAAK,EAAC,EAAE;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,+BAiBjE"}
@@ -0,0 +1,34 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Panel, PanelBody, PanelCell, PanelGrid } from '@shipfox/react-ui/panel';
3
+ import { Skeleton } from '@shipfox/react-ui/skeleton';
4
+ export function ModelProviderGridSkeleton({ label }) {
5
+ return /*#__PURE__*/ _jsx(Panel, {
6
+ children: /*#__PURE__*/ _jsx(PanelBody, {
7
+ children: /*#__PURE__*/ _jsx(PanelGrid, {
8
+ role: "status",
9
+ "aria-busy": "true",
10
+ "aria-label": label,
11
+ children: [
12
+ 0,
13
+ 1,
14
+ 2,
15
+ 3
16
+ ].map((tile)=>/*#__PURE__*/ _jsx(PanelCell, {
17
+ children: /*#__PURE__*/ _jsxs("div", {
18
+ className: "flex items-center justify-between gap-cluster px-row py-row",
19
+ children: [
20
+ /*#__PURE__*/ _jsx(Skeleton, {
21
+ className: "h-16 w-100"
22
+ }),
23
+ /*#__PURE__*/ _jsx(Skeleton, {
24
+ className: "h-16 w-64 shrink-0"
25
+ })
26
+ ]
27
+ })
28
+ }, tile))
29
+ })
30
+ })
31
+ });
32
+ }
33
+
34
+ //# sourceMappingURL=model-provider-grid-skeleton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/model-provider-grid-skeleton.tsx"],"sourcesContent":["import {Panel, PanelBody, PanelCell, PanelGrid} from '@shipfox/react-ui/panel';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\n\nexport function ModelProviderGridSkeleton({label}: {label: string}) {\n return (\n <Panel>\n <PanelBody>\n <PanelGrid role=\"status\" aria-busy=\"true\" aria-label={label}>\n {[0, 1, 2, 3].map((tile) => (\n <PanelCell key={tile}>\n <div className=\"flex items-center justify-between gap-cluster px-row py-row\">\n <Skeleton className=\"h-16 w-100\" />\n <Skeleton className=\"h-16 w-64 shrink-0\" />\n </div>\n </PanelCell>\n ))}\n </PanelGrid>\n </PanelBody>\n </Panel>\n );\n}\n"],"names":["Panel","PanelBody","PanelCell","PanelGrid","Skeleton","ModelProviderGridSkeleton","label","role","aria-busy","aria-label","map","tile","div","className"],"mappings":";AAAA,SAAQA,KAAK,EAAEC,SAAS,EAAEC,SAAS,EAAEC,SAAS,QAAO,0BAA0B;AAC/E,SAAQC,QAAQ,QAAO,6BAA6B;AAEpD,OAAO,SAASC,0BAA0B,EAACC,KAAK,EAAkB;IAChE,qBACE,KAACN;kBACC,cAAA,KAACC;sBACC,cAAA,KAACE;gBAAUI,MAAK;gBAASC,aAAU;gBAAOC,cAAYH;0BACnD;oBAAC;oBAAG;oBAAG;oBAAG;iBAAE,CAACI,GAAG,CAAC,CAACC,qBACjB,KAACT;kCACC,cAAA,MAACU;4BAAIC,WAAU;;8CACb,KAACT;oCAASS,WAAU;;8CACpB,KAACT;oCAASS,WAAU;;;;uBAHRF;;;;AAW5B"}
@@ -1 +1 @@
1
- {"version":3,"file":"model-providers-section.d.ts","sourceRoot":"","sources":["../../src/components/model-providers-section.tsx"],"names":[],"mappings":"AAuEA,wBAAgB,8BAA8B,CAAC,EAAC,WAAW,EAAC,EAAE;IAAC,WAAW,EAAE,MAAM,CAAA;CAAC,+BA2TlF"}
1
+ {"version":3,"file":"model-providers-section.d.ts","sourceRoot":"","sources":["../../src/components/model-providers-section.tsx"],"names":[],"mappings":"AAqEA,wBAAgB,8BAA8B,CAAC,EAAC,WAAW,EAAC,EAAE;IAAC,WAAW,EAAE,MAAM,CAAA;CAAC,+BAuUlF"}