@shipfox/client-agent 21.0.0 → 22.0.0

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 (35) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +16 -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 +147 -134
  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 +253 -245
  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/tsconfig.test.tsbuildinfo +1 -1
  27. package/package.json +4 -4
  28. package/src/components/add-custom-provider-card.tsx +9 -23
  29. package/src/components/available-provider-card.tsx +9 -23
  30. package/src/components/available-providers-grid.tsx +36 -29
  31. package/src/components/harnesses-section.tsx +116 -106
  32. package/src/components/model-provider-grid-skeleton.tsx +21 -0
  33. package/src/components/model-providers-section.tsx +208 -191
  34. package/src/pages/model-provider-onboarding-page.tsx +26 -54
  35. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1,2 +1,2 @@
1
1
  $ shipfox-swc
2
- Successfully compiled: 37 files with swc (358.51ms)
2
+ Successfully compiled: 38 files with swc (560.28ms)
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @shipfox/client-agent
2
2
 
3
+ ## 22.0.0
4
+
5
+ ### Patch Changes
6
+
7
+ - 50b3867: Consolidate authentication, onboarding, integration-install, and callback surfaces onto the shared focused frame.
8
+ - 7693eb3: Render empty and load-error states inside bordered panel bodies and keep loading placeholders aligned with their data regions.
9
+ - 00c1cb8: Panels across these surfaces share one hover, focus, and elevation treatment. Grids of openable things, including the integration gallery, the available providers grid, and the harness picker, render as cells inside a single panel divided by hairlines instead of separate bordered tiles.
10
+ - Updated dependencies [50b3867]
11
+ - Updated dependencies [00c1cb8]
12
+ - Updated dependencies [7693eb3]
13
+ - Updated dependencies [00c1cb8]
14
+ - Updated dependencies [56f4526]
15
+ - @shipfox/client-shell@22.0.0
16
+ - @shipfox/react-ui@2.1.0
17
+ - @shipfox/client-ui@22.0.0
18
+
3
19
  ## 21.0.0
4
20
 
5
21
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"add-custom-provider-card.d.ts","sourceRoot":"","sources":["../../src/components/add-custom-provider-card.tsx"],"names":[],"mappings":"AAOA,wBAAgB,qBAAqB,CAAC,EAAC,WAAW,EAAC,EAAE;IAAC,WAAW,EAAE,MAAM,IAAI,CAAA;CAAC,+BAwB7E"}
1
+ {"version":3,"file":"add-custom-provider-card.d.ts","sourceRoot":"","sources":["../../src/components/add-custom-provider-card.tsx"],"names":[],"mappings":"AAGA,wBAAgB,qBAAqB,CAAC,EAAC,WAAW,EAAC,EAAE;IAAC,WAAW,EAAE,MAAM,IAAI,CAAA;CAAC,+BAc7E"}
@@ -1,38 +1,18 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Icon } from '@shipfox/react-ui/icon';
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { PanelCell, PanelCellAction } from '@shipfox/react-ui/panel';
3
3
  import { Text } from '@shipfox/react-ui/typography';
4
- import { cn } from '@shipfox/react-ui/utils';
5
- const SURFACE_CLASS = 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';
6
4
  export function AddCustomProviderCard({ onConfigure }) {
7
- return /*#__PURE__*/ _jsx("li", {
8
- children: /*#__PURE__*/ _jsx("button", {
9
- type: "button",
10
- className: cn('group block h-full w-full cursor-pointer p-panel-compact text-left outline-none transition-colors hover:bg-background-components-hover focus-visible:shadow-button-neutral-focus', SURFACE_CLASS),
5
+ return /*#__PURE__*/ _jsx(PanelCell, {
6
+ children: /*#__PURE__*/ _jsx(PanelCellAction, {
7
+ action: "Configure",
11
8
  "aria-label": "Configure custom provider",
12
9
  onClick: onConfigure,
13
- children: /*#__PURE__*/ _jsxs("div", {
14
- className: "flex min-w-0 items-center justify-between gap-cluster",
15
- children: [
16
- /*#__PURE__*/ _jsx(Text, {
17
- size: "md",
18
- bold: true,
19
- className: "min-w-0 truncate",
20
- children: "Custom"
21
- }),
22
- /*#__PURE__*/ _jsxs("div", {
23
- className: "flex shrink-0 items-center gap-tight text-foreground-neutral-muted transition-colors group-hover:text-foreground-highlight-interactive",
24
- children: [
25
- /*#__PURE__*/ _jsx(Text, {
26
- size: "sm",
27
- children: "Configure"
28
- }),
29
- /*#__PURE__*/ _jsx(Icon, {
30
- name: "chevronRight",
31
- className: "size-16"
32
- })
33
- ]
34
- })
35
- ]
10
+ children: /*#__PURE__*/ _jsx(Text, {
11
+ as: "span",
12
+ size: "md",
13
+ bold: true,
14
+ className: "min-w-0 truncate",
15
+ children: "Custom"
36
16
  })
37
17
  })
38
18
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/add-custom-provider-card.tsx"],"sourcesContent":["import {Icon} from '@shipfox/react-ui/icon';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\n\nconst SURFACE_CLASS =\n 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';\n\nexport function AddCustomProviderCard({onConfigure}: {onConfigure: () => void}) {\n return (\n <li>\n <button\n type=\"button\"\n className={cn(\n 'group block h-full w-full cursor-pointer p-panel-compact text-left outline-none transition-colors hover:bg-background-components-hover focus-visible:shadow-button-neutral-focus',\n SURFACE_CLASS,\n )}\n aria-label=\"Configure custom provider\"\n onClick={onConfigure}\n >\n <div className=\"flex min-w-0 items-center justify-between gap-cluster\">\n <Text size=\"md\" bold className=\"min-w-0 truncate\">\n Custom\n </Text>\n <div className=\"flex shrink-0 items-center gap-tight text-foreground-neutral-muted transition-colors group-hover:text-foreground-highlight-interactive\">\n <Text size=\"sm\">Configure</Text>\n <Icon name=\"chevronRight\" className=\"size-16\" />\n </div>\n </div>\n </button>\n </li>\n );\n}\n"],"names":["Icon","Text","cn","SURFACE_CLASS","AddCustomProviderCard","onConfigure","li","button","type","className","aria-label","onClick","div","size","bold","name"],"mappings":";AAAA,SAAQA,IAAI,QAAO,yBAAyB;AAC5C,SAAQC,IAAI,QAAO,+BAA+B;AAClD,SAAQC,EAAE,QAAO,0BAA0B;AAE3C,MAAMC,gBACJ;AAEF,OAAO,SAASC,sBAAsB,EAACC,WAAW,EAA4B;IAC5E,qBACE,KAACC;kBACC,cAAA,KAACC;YACCC,MAAK;YACLC,WAAWP,GACT,oLACAC;YAEFO,cAAW;YACXC,SAASN;sBAET,cAAA,MAACO;gBAAIH,WAAU;;kCACb,KAACR;wBAAKY,MAAK;wBAAKC,IAAI;wBAACL,WAAU;kCAAmB;;kCAGlD,MAACG;wBAAIH,WAAU;;0CACb,KAACR;gCAAKY,MAAK;0CAAK;;0CAChB,KAACb;gCAAKe,MAAK;gCAAeN,WAAU;;;;;;;;AAMhD"}
1
+ {"version":3,"sources":["../../src/components/add-custom-provider-card.tsx"],"sourcesContent":["import {PanelCell, PanelCellAction} from '@shipfox/react-ui/panel';\nimport {Text} from '@shipfox/react-ui/typography';\n\nexport function AddCustomProviderCard({onConfigure}: {onConfigure: () => void}) {\n return (\n <PanelCell>\n <PanelCellAction\n action=\"Configure\"\n aria-label=\"Configure custom provider\"\n onClick={onConfigure}\n >\n <Text as=\"span\" size=\"md\" bold className=\"min-w-0 truncate\">\n Custom\n </Text>\n </PanelCellAction>\n </PanelCell>\n );\n}\n"],"names":["PanelCell","PanelCellAction","Text","AddCustomProviderCard","onConfigure","action","aria-label","onClick","as","size","bold","className"],"mappings":";AAAA,SAAQA,SAAS,EAAEC,eAAe,QAAO,0BAA0B;AACnE,SAAQC,IAAI,QAAO,+BAA+B;AAElD,OAAO,SAASC,sBAAsB,EAACC,WAAW,EAA4B;IAC5E,qBACE,KAACJ;kBACC,cAAA,KAACC;YACCI,QAAO;YACPC,cAAW;YACXC,SAASH;sBAET,cAAA,KAACF;gBAAKM,IAAG;gBAAOC,MAAK;gBAAKC,IAAI;gBAACC,WAAU;0BAAmB;;;;AAMpE"}
@@ -1 +1 @@
1
- {"version":3,"file":"available-provider-card.d.ts","sourceRoot":"","sources":["../../src/components/available-provider-card.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,iBAAiB,CAAC;AAKvD,wBAAgB,qBAAqB,CAAC,EACpC,KAAK,EACL,WAAW,GACZ,EAAE;IACD,KAAK,EAAE,iBAAiB,CAAC;IACzB,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB,+BAwBA"}
1
+ {"version":3,"file":"available-provider-card.d.ts","sourceRoot":"","sources":["../../src/components/available-provider-card.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,iBAAiB,CAAC;AAEvD,wBAAgB,qBAAqB,CAAC,EACpC,KAAK,EACL,WAAW,GACZ,EAAE;IACD,KAAK,EAAE,iBAAiB,CAAC;IACzB,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB,+BAcA"}
@@ -1,38 +1,18 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Icon } from '@shipfox/react-ui/icon';
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { PanelCell, PanelCellAction } from '@shipfox/react-ui/panel';
3
3
  import { Text } from '@shipfox/react-ui/typography';
4
- import { cn } from '@shipfox/react-ui/utils';
5
- const SURFACE_CLASS = 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';
6
4
  export function AvailableProviderCard({ entry, onConfigure }) {
7
- return /*#__PURE__*/ _jsx("li", {
8
- children: /*#__PURE__*/ _jsx("button", {
9
- type: "button",
10
- className: cn('group block w-full cursor-pointer p-panel-compact text-left outline-none transition-colors hover:bg-background-components-hover focus-visible:shadow-button-neutral-focus', SURFACE_CLASS),
5
+ return /*#__PURE__*/ _jsx(PanelCell, {
6
+ children: /*#__PURE__*/ _jsx(PanelCellAction, {
7
+ action: "Configure",
11
8
  "aria-label": `Configure ${entry.label}`,
12
9
  onClick: onConfigure,
13
- children: /*#__PURE__*/ _jsxs("div", {
14
- className: "flex min-w-0 items-center justify-between gap-cluster",
15
- children: [
16
- /*#__PURE__*/ _jsx(Text, {
17
- size: "md",
18
- bold: true,
19
- className: "min-w-0 truncate",
20
- children: entry.label
21
- }),
22
- /*#__PURE__*/ _jsxs("div", {
23
- className: "flex shrink-0 items-center gap-tight text-foreground-neutral-muted transition-colors group-hover:text-foreground-highlight-interactive",
24
- children: [
25
- /*#__PURE__*/ _jsx(Text, {
26
- size: "sm",
27
- children: "Configure"
28
- }),
29
- /*#__PURE__*/ _jsx(Icon, {
30
- name: "chevronRight",
31
- className: "size-16"
32
- })
33
- ]
34
- })
35
- ]
10
+ children: /*#__PURE__*/ _jsx(Text, {
11
+ as: "span",
12
+ size: "md",
13
+ bold: true,
14
+ className: "min-w-0 truncate",
15
+ children: entry.label
36
16
  })
37
17
  })
38
18
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/available-provider-card.tsx"],"sourcesContent":["import {Icon} from '@shipfox/react-ui/icon';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport type {SupportedProvider} from '#core/models.js';\n\nconst SURFACE_CLASS =\n 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';\n\nexport function AvailableProviderCard({\n entry,\n onConfigure,\n}: {\n entry: SupportedProvider;\n onConfigure: () => void;\n}) {\n return (\n <li>\n <button\n type=\"button\"\n className={cn(\n 'group block w-full cursor-pointer p-panel-compact text-left outline-none transition-colors hover:bg-background-components-hover focus-visible:shadow-button-neutral-focus',\n SURFACE_CLASS,\n )}\n aria-label={`Configure ${entry.label}`}\n onClick={onConfigure}\n >\n <div className=\"flex min-w-0 items-center justify-between gap-cluster\">\n <Text size=\"md\" bold className=\"min-w-0 truncate\">\n {entry.label}\n </Text>\n <div className=\"flex shrink-0 items-center gap-tight text-foreground-neutral-muted transition-colors group-hover:text-foreground-highlight-interactive\">\n <Text size=\"sm\">Configure</Text>\n <Icon name=\"chevronRight\" className=\"size-16\" />\n </div>\n </div>\n </button>\n </li>\n );\n}\n"],"names":["Icon","Text","cn","SURFACE_CLASS","AvailableProviderCard","entry","onConfigure","li","button","type","className","aria-label","label","onClick","div","size","bold","name"],"mappings":";AAAA,SAAQA,IAAI,QAAO,yBAAyB;AAC5C,SAAQC,IAAI,QAAO,+BAA+B;AAClD,SAAQC,EAAE,QAAO,0BAA0B;AAG3C,MAAMC,gBACJ;AAEF,OAAO,SAASC,sBAAsB,EACpCC,KAAK,EACLC,WAAW,EAIZ;IACC,qBACE,KAACC;kBACC,cAAA,KAACC;YACCC,MAAK;YACLC,WAAWR,GACT,6KACAC;YAEFQ,cAAY,CAAC,UAAU,EAAEN,MAAMO,KAAK,EAAE;YACtCC,SAASP;sBAET,cAAA,MAACQ;gBAAIJ,WAAU;;kCACb,KAACT;wBAAKc,MAAK;wBAAKC,IAAI;wBAACN,WAAU;kCAC5BL,MAAMO,KAAK;;kCAEd,MAACE;wBAAIJ,WAAU;;0CACb,KAACT;gCAAKc,MAAK;0CAAK;;0CAChB,KAACf;gCAAKiB,MAAK;gCAAeP,WAAU;;;;;;;;AAMhD"}
1
+ {"version":3,"sources":["../../src/components/available-provider-card.tsx"],"sourcesContent":["import {PanelCell, PanelCellAction} from '@shipfox/react-ui/panel';\nimport {Text} from '@shipfox/react-ui/typography';\nimport type {SupportedProvider} from '#core/models.js';\n\nexport function AvailableProviderCard({\n entry,\n onConfigure,\n}: {\n entry: SupportedProvider;\n onConfigure: () => void;\n}) {\n return (\n <PanelCell>\n <PanelCellAction\n action=\"Configure\"\n aria-label={`Configure ${entry.label}`}\n onClick={onConfigure}\n >\n <Text as=\"span\" size=\"md\" bold className=\"min-w-0 truncate\">\n {entry.label}\n </Text>\n </PanelCellAction>\n </PanelCell>\n );\n}\n"],"names":["PanelCell","PanelCellAction","Text","AvailableProviderCard","entry","onConfigure","action","aria-label","label","onClick","as","size","bold","className"],"mappings":";AAAA,SAAQA,SAAS,EAAEC,eAAe,QAAO,0BAA0B;AACnE,SAAQC,IAAI,QAAO,+BAA+B;AAGlD,OAAO,SAASC,sBAAsB,EACpCC,KAAK,EACLC,WAAW,EAIZ;IACC,qBACE,KAACL;kBACC,cAAA,KAACC;YACCK,QAAO;YACPC,cAAY,CAAC,UAAU,EAAEH,MAAMI,KAAK,EAAE;YACtCC,SAASJ;sBAET,cAAA,KAACH;gBAAKQ,IAAG;gBAAOC,MAAK;gBAAKC,IAAI;gBAACC,WAAU;0BACtCT,MAAMI,KAAK;;;;AAKtB"}
@@ -1,6 +1,5 @@
1
1
  import type { ReactNode } from 'react';
2
2
  import type { SupportedProvider } from '#core/models.js';
3
- export declare const PROVIDER_GRID_CLASS = "grid grid-cols-2 gap-cluster max-[760px]:grid-cols-1";
4
3
  export declare function AvailableProvidersGrid<TEntry extends SupportedProvider>({ entries, onSelect, trailingCard, trailingCardMatchesSearch, }: {
5
4
  entries: TEntry[];
6
5
  onSelect: (entry: TEntry) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"available-providers-grid.d.ts","sourceRoot":"","sources":["../../src/components/available-providers-grid.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAErC,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,iBAAiB,CAAC;AAIvD,eAAO,MAAM,mBAAmB,yDAAyD,CAAC;AAK1F,wBAAgB,sBAAsB,CAAC,MAAM,SAAS,iBAAiB,EAAE,EACvE,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,yBAAsC,GACvC,EAAE;IACD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,YAAY,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IACrC,yBAAyB,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,SAAS,CAAC;CACtE,+BAuDA"}
1
+ {"version":3,"file":"available-providers-grid.d.ts","sourceRoot":"","sources":["../../src/components/available-providers-grid.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAErC,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,iBAAiB,CAAC;AAOvD,wBAAgB,sBAAsB,CAAC,MAAM,SAAS,iBAAiB,EAAE,EACvE,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,yBAAsC,GACvC,EAAE;IACD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,YAAY,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IACrC,yBAAyB,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,SAAS,CAAC;CACtE,+BA+DA"}
@@ -1,12 +1,12 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { Button } from '@shipfox/react-ui/button';
3
3
  import { EmptyState } from '@shipfox/react-ui/empty-state';
4
4
  import { Icon } from '@shipfox/react-ui/icon';
5
5
  import { Input } from '@shipfox/react-ui/input';
6
+ import { Panel, PanelBody, PanelGrid, PanelHeader } from '@shipfox/react-ui/panel';
6
7
  import { useMemo, useRef, useState } from 'react';
7
8
  import { providerMatchesSearch } from '#core/provider-policy.js';
8
9
  import { AvailableProviderCard } from './available-provider-card.js';
9
- export const PROVIDER_GRID_CLASS = 'grid grid-cols-2 gap-cluster max-[760px]:grid-cols-1';
10
10
  const SEARCH_VISIBILITY_THRESHOLD = 8;
11
11
  const MAX_ECHOED_QUERY_LENGTH = 40;
12
12
  export function AvailableProvidersGrid({ entries, onSelect, trailingCard, trailingCardMatchesSearch = ()=>true }) {
@@ -26,34 +26,40 @@ export function AvailableProvidersGrid({ entries, onSelect, trailingCard, traili
26
26
  setSearch('');
27
27
  inputRef.current?.focus();
28
28
  }
29
- return /*#__PURE__*/ _jsxs("div", {
30
- className: "flex flex-col gap-cluster",
29
+ return /*#__PURE__*/ _jsxs(_Fragment, {
31
30
  children: [
32
- showSearch ? /*#__PURE__*/ _jsx(Input, {
33
- ref: inputRef,
34
- type: "search",
35
- "aria-label": "Search providers",
36
- placeholder: "Search providers...",
37
- value: search,
38
- iconLeft: /*#__PURE__*/ _jsx(Icon, {
39
- name: "searchLine",
40
- className: "size-16 text-foreground-neutral-muted"
41
- }),
42
- onChange: (event)=>setSearch(event.target.value)
43
- }) : null,
44
- visibleCount > 0 ? /*#__PURE__*/ _jsxs("ul", {
45
- className: PROVIDER_GRID_CLASS,
46
- "aria-label": providerListLabel,
31
+ /*#__PURE__*/ _jsxs(Panel, {
47
32
  children: [
48
- filteredEntries.map((entry)=>/*#__PURE__*/ _jsx(AvailableProviderCard, {
49
- entry: entry,
50
- onConfigure: ()=>onSelect(entry)
51
- }, entry.id)),
52
- trailingCardVisible ? trailingCard : null
33
+ showSearch ? /*#__PURE__*/ _jsx(PanelHeader, {
34
+ children: /*#__PURE__*/ _jsx(Input, {
35
+ ref: inputRef,
36
+ type: "search",
37
+ "aria-label": "Search providers",
38
+ placeholder: "Search providers...",
39
+ value: search,
40
+ iconLeft: /*#__PURE__*/ _jsx(Icon, {
41
+ name: "searchLine",
42
+ className: "size-16 text-foreground-neutral-muted"
43
+ }),
44
+ onChange: (event)=>setSearch(event.target.value)
45
+ })
46
+ }) : null,
47
+ /*#__PURE__*/ _jsx(PanelBody, {
48
+ children: visibleCount > 0 ? /*#__PURE__*/ _jsxs(PanelGrid, {
49
+ "aria-label": providerListLabel,
50
+ children: [
51
+ filteredEntries.map((entry)=>/*#__PURE__*/ _jsx(AvailableProviderCard, {
52
+ entry: entry,
53
+ onConfigure: ()=>onSelect(entry)
54
+ }, entry.id)),
55
+ trailingCardVisible ? trailingCard : null
56
+ ]
57
+ }) : /*#__PURE__*/ _jsx(NoProviderSearchResults, {
58
+ search: trimmedSearch,
59
+ onClear: clearSearch
60
+ })
61
+ })
53
62
  ]
54
- }) : /*#__PURE__*/ _jsx(NoProviderSearchResults, {
55
- search: trimmedSearch,
56
- onClear: clearSearch
57
63
  }),
58
64
  /*#__PURE__*/ _jsx("p", {
59
65
  role: "status",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/available-providers-grid.tsx"],"sourcesContent":["import {Button} from '@shipfox/react-ui/button';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {Input} from '@shipfox/react-ui/input';\nimport type {ReactNode} from 'react';\nimport {useMemo, useRef, useState} from 'react';\nimport type {SupportedProvider} from '#core/models.js';\nimport {providerMatchesSearch} from '#core/provider-policy.js';\nimport {AvailableProviderCard} from './available-provider-card.js';\n\nexport const PROVIDER_GRID_CLASS = 'grid grid-cols-2 gap-cluster max-[760px]:grid-cols-1';\n\nconst SEARCH_VISIBILITY_THRESHOLD = 8;\nconst MAX_ECHOED_QUERY_LENGTH = 40;\n\nexport function AvailableProvidersGrid<TEntry extends SupportedProvider>({\n entries,\n onSelect,\n trailingCard,\n trailingCardMatchesSearch = () => true,\n}: {\n entries: TEntry[];\n onSelect: (entry: TEntry) => void;\n trailingCard?: ReactNode | undefined;\n trailingCardMatchesSearch?: ((query: string) => boolean) | undefined;\n}) {\n const [search, setSearch] = useState('');\n const inputRef = useRef<HTMLInputElement | null>(null);\n const trimmedSearch = search.trim();\n const filteredEntries = useMemo(\n () => entries.filter((entry) => providerMatchesSearch(entry, search)),\n [entries, search],\n );\n const trailingCardVisible = trailingCard !== undefined && trailingCardMatchesSearch(search);\n const visibleCount = filteredEntries.length + (trailingCardVisible ? 1 : 0);\n const showSearch = entries.length > SEARCH_VISIBILITY_THRESHOLD || trimmedSearch !== '';\n const providerListLabel =\n trimmedSearch !== '' ? 'Available providers matching search' : 'Available providers';\n const resultCountText =\n trimmedSearch === '' ? '' : providerResultCountText(filteredEntries.length, trimmedSearch);\n\n function clearSearch() {\n setSearch('');\n inputRef.current?.focus();\n }\n\n return (\n <div className=\"flex flex-col gap-cluster\">\n {showSearch ? (\n <Input\n ref={inputRef}\n type=\"search\"\n aria-label=\"Search providers\"\n placeholder=\"Search providers...\"\n value={search}\n iconLeft={<Icon name=\"searchLine\" className=\"size-16 text-foreground-neutral-muted\" />}\n onChange={(event) => setSearch(event.target.value)}\n />\n ) : null}\n\n {visibleCount > 0 ? (\n <ul className={PROVIDER_GRID_CLASS} aria-label={providerListLabel}>\n {filteredEntries.map((entry) => (\n <AvailableProviderCard\n key={entry.id}\n entry={entry}\n onConfigure={() => onSelect(entry)}\n />\n ))}\n {trailingCardVisible ? trailingCard : null}\n </ul>\n ) : (\n <NoProviderSearchResults search={trimmedSearch} onClear={clearSearch} />\n )}\n\n <p role=\"status\" aria-live=\"polite\" className=\"sr-only\">\n {resultCountText}\n </p>\n </div>\n );\n}\n\nfunction NoProviderSearchResults({search, onClear}: {search: string; onClear: () => void}) {\n return (\n <EmptyState\n icon=\"searchLine\"\n title={`No providers match \"${truncateQuery(search)}\"`}\n description=\"Try a different search, or clear it to see all providers.\"\n action={\n <Button size=\"sm\" variant=\"secondary\" onClick={onClear}>\n Clear search\n </Button>\n }\n />\n );\n}\n\nfunction truncateQuery(query: string): string {\n if (query.length <= MAX_ECHOED_QUERY_LENGTH) return query;\n return `${query.slice(0, MAX_ECHOED_QUERY_LENGTH - 3)}...`;\n}\n\nfunction providerResultCountText(count: number, query: string): string {\n if (count === 1) return `1 provider matches \"${query}\"`;\n return `${count} providers match \"${query}\"`;\n}\n"],"names":["Button","EmptyState","Icon","Input","useMemo","useRef","useState","providerMatchesSearch","AvailableProviderCard","PROVIDER_GRID_CLASS","SEARCH_VISIBILITY_THRESHOLD","MAX_ECHOED_QUERY_LENGTH","AvailableProvidersGrid","entries","onSelect","trailingCard","trailingCardMatchesSearch","search","setSearch","inputRef","trimmedSearch","trim","filteredEntries","filter","entry","trailingCardVisible","undefined","visibleCount","length","showSearch","providerListLabel","resultCountText","providerResultCountText","clearSearch","current","focus","div","className","ref","type","aria-label","placeholder","value","iconLeft","name","onChange","event","target","ul","map","onConfigure","id","NoProviderSearchResults","onClear","p","role","aria-live","icon","title","truncateQuery","description","action","size","variant","onClick","query","slice","count"],"mappings":";AAAA,SAAQA,MAAM,QAAO,2BAA2B;AAChD,SAAQC,UAAU,QAAO,gCAAgC;AACzD,SAAQC,IAAI,QAAO,yBAAyB;AAC5C,SAAQC,KAAK,QAAO,0BAA0B;AAE9C,SAAQC,OAAO,EAAEC,MAAM,EAAEC,QAAQ,QAAO,QAAQ;AAEhD,SAAQC,qBAAqB,QAAO,2BAA2B;AAC/D,SAAQC,qBAAqB,QAAO,+BAA+B;AAEnE,OAAO,MAAMC,sBAAsB,uDAAuD;AAE1F,MAAMC,8BAA8B;AACpC,MAAMC,0BAA0B;AAEhC,OAAO,SAASC,uBAAyD,EACvEC,OAAO,EACPC,QAAQ,EACRC,YAAY,EACZC,4BAA4B,IAAM,IAAI,EAMvC;IACC,MAAM,CAACC,QAAQC,UAAU,GAAGZ,SAAS;IACrC,MAAMa,WAAWd,OAAgC;IACjD,MAAMe,gBAAgBH,OAAOI,IAAI;IACjC,MAAMC,kBAAkBlB,QACtB,IAAMS,QAAQU,MAAM,CAAC,CAACC,QAAUjB,sBAAsBiB,OAAOP,UAC7D;QAACJ;QAASI;KAAO;IAEnB,MAAMQ,sBAAsBV,iBAAiBW,aAAaV,0BAA0BC;IACpF,MAAMU,eAAeL,gBAAgBM,MAAM,GAAIH,CAAAA,sBAAsB,IAAI,CAAA;IACzE,MAAMI,aAAahB,QAAQe,MAAM,GAAGlB,+BAA+BU,kBAAkB;IACrF,MAAMU,oBACJV,kBAAkB,KAAK,wCAAwC;IACjE,MAAMW,kBACJX,kBAAkB,KAAK,KAAKY,wBAAwBV,gBAAgBM,MAAM,EAAER;IAE9E,SAASa;QACPf,UAAU;QACVC,SAASe,OAAO,EAAEC;IACpB;IAEA,qBACE,MAACC;QAAIC,WAAU;;YACZR,2BACC,KAAC1B;gBACCmC,KAAKnB;gBACLoB,MAAK;gBACLC,cAAW;gBACXC,aAAY;gBACZC,OAAOzB;gBACP0B,wBAAU,KAACzC;oBAAK0C,MAAK;oBAAaP,WAAU;;gBAC5CQ,UAAU,CAACC,QAAU5B,UAAU4B,MAAMC,MAAM,CAACL,KAAK;iBAEjD;YAEHf,eAAe,kBACd,MAACqB;gBAAGX,WAAW5B;gBAAqB+B,cAAYV;;oBAC7CR,gBAAgB2B,GAAG,CAAC,CAACzB,sBACpB,KAAChB;4BAECgB,OAAOA;4BACP0B,aAAa,IAAMpC,SAASU;2BAFvBA,MAAM2B,EAAE;oBAKhB1B,sBAAsBV,eAAe;;+BAGxC,KAACqC;gBAAwBnC,QAAQG;gBAAeiC,SAASpB;;0BAG3D,KAACqB;gBAAEC,MAAK;gBAASC,aAAU;gBAASnB,WAAU;0BAC3CN;;;;AAIT;AAEA,SAASqB,wBAAwB,EAACnC,MAAM,EAAEoC,OAAO,EAAwC;IACvF,qBACE,KAACpD;QACCwD,MAAK;QACLC,OAAO,CAAC,oBAAoB,EAAEC,cAAc1C,QAAQ,CAAC,CAAC;QACtD2C,aAAY;QACZC,sBACE,KAAC7D;YAAO8D,MAAK;YAAKC,SAAQ;YAAYC,SAASX;sBAAS;;;AAMhE;AAEA,SAASM,cAAcM,KAAa;IAClC,IAAIA,MAAMrC,MAAM,IAAIjB,yBAAyB,OAAOsD;IACpD,OAAO,GAAGA,MAAMC,KAAK,CAAC,GAAGvD,0BAA0B,GAAG,GAAG,CAAC;AAC5D;AAEA,SAASqB,wBAAwBmC,KAAa,EAAEF,KAAa;IAC3D,IAAIE,UAAU,GAAG,OAAO,CAAC,oBAAoB,EAAEF,MAAM,CAAC,CAAC;IACvD,OAAO,GAAGE,MAAM,kBAAkB,EAAEF,MAAM,CAAC,CAAC;AAC9C"}
1
+ {"version":3,"sources":["../../src/components/available-providers-grid.tsx"],"sourcesContent":["import {Button} from '@shipfox/react-ui/button';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {Input} from '@shipfox/react-ui/input';\nimport {Panel, PanelBody, PanelGrid, PanelHeader} from '@shipfox/react-ui/panel';\nimport type {ReactNode} from 'react';\nimport {useMemo, useRef, useState} from 'react';\nimport type {SupportedProvider} from '#core/models.js';\nimport {providerMatchesSearch} from '#core/provider-policy.js';\nimport {AvailableProviderCard} from './available-provider-card.js';\n\nconst SEARCH_VISIBILITY_THRESHOLD = 8;\nconst MAX_ECHOED_QUERY_LENGTH = 40;\n\nexport function AvailableProvidersGrid<TEntry extends SupportedProvider>({\n entries,\n onSelect,\n trailingCard,\n trailingCardMatchesSearch = () => true,\n}: {\n entries: TEntry[];\n onSelect: (entry: TEntry) => void;\n trailingCard?: ReactNode | undefined;\n trailingCardMatchesSearch?: ((query: string) => boolean) | undefined;\n}) {\n const [search, setSearch] = useState('');\n const inputRef = useRef<HTMLInputElement | null>(null);\n const trimmedSearch = search.trim();\n const filteredEntries = useMemo(\n () => entries.filter((entry) => providerMatchesSearch(entry, search)),\n [entries, search],\n );\n const trailingCardVisible = trailingCard !== undefined && trailingCardMatchesSearch(search);\n const visibleCount = filteredEntries.length + (trailingCardVisible ? 1 : 0);\n const showSearch = entries.length > SEARCH_VISIBILITY_THRESHOLD || trimmedSearch !== '';\n const providerListLabel =\n trimmedSearch !== '' ? 'Available providers matching search' : 'Available providers';\n const resultCountText =\n trimmedSearch === '' ? '' : providerResultCountText(filteredEntries.length, trimmedSearch);\n\n function clearSearch() {\n setSearch('');\n inputRef.current?.focus();\n }\n\n return (\n <>\n <Panel>\n {showSearch ? (\n <PanelHeader>\n <Input\n ref={inputRef}\n type=\"search\"\n aria-label=\"Search providers\"\n placeholder=\"Search providers...\"\n value={search}\n iconLeft={\n <Icon name=\"searchLine\" className=\"size-16 text-foreground-neutral-muted\" />\n }\n onChange={(event) => setSearch(event.target.value)}\n />\n </PanelHeader>\n ) : null}\n\n <PanelBody>\n {visibleCount > 0 ? (\n <PanelGrid aria-label={providerListLabel}>\n {filteredEntries.map((entry) => (\n <AvailableProviderCard\n key={entry.id}\n entry={entry}\n onConfigure={() => onSelect(entry)}\n />\n ))}\n {trailingCardVisible ? trailingCard : null}\n </PanelGrid>\n ) : (\n <NoProviderSearchResults search={trimmedSearch} onClear={clearSearch} />\n )}\n </PanelBody>\n </Panel>\n\n <p role=\"status\" aria-live=\"polite\" className=\"sr-only\">\n {resultCountText}\n </p>\n </>\n );\n}\n\nfunction NoProviderSearchResults({search, onClear}: {search: string; onClear: () => void}) {\n return (\n <EmptyState\n icon=\"searchLine\"\n title={`No providers match \"${truncateQuery(search)}\"`}\n description=\"Try a different search, or clear it to see all providers.\"\n action={\n <Button size=\"sm\" variant=\"secondary\" onClick={onClear}>\n Clear search\n </Button>\n }\n />\n );\n}\n\nfunction truncateQuery(query: string): string {\n if (query.length <= MAX_ECHOED_QUERY_LENGTH) return query;\n return `${query.slice(0, MAX_ECHOED_QUERY_LENGTH - 3)}...`;\n}\n\nfunction providerResultCountText(count: number, query: string): string {\n if (count === 1) return `1 provider matches \"${query}\"`;\n return `${count} providers match \"${query}\"`;\n}\n"],"names":["Button","EmptyState","Icon","Input","Panel","PanelBody","PanelGrid","PanelHeader","useMemo","useRef","useState","providerMatchesSearch","AvailableProviderCard","SEARCH_VISIBILITY_THRESHOLD","MAX_ECHOED_QUERY_LENGTH","AvailableProvidersGrid","entries","onSelect","trailingCard","trailingCardMatchesSearch","search","setSearch","inputRef","trimmedSearch","trim","filteredEntries","filter","entry","trailingCardVisible","undefined","visibleCount","length","showSearch","providerListLabel","resultCountText","providerResultCountText","clearSearch","current","focus","ref","type","aria-label","placeholder","value","iconLeft","name","className","onChange","event","target","map","onConfigure","id","NoProviderSearchResults","onClear","p","role","aria-live","icon","title","truncateQuery","description","action","size","variant","onClick","query","slice","count"],"mappings":";AAAA,SAAQA,MAAM,QAAO,2BAA2B;AAChD,SAAQC,UAAU,QAAO,gCAAgC;AACzD,SAAQC,IAAI,QAAO,yBAAyB;AAC5C,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,KAAK,EAAEC,SAAS,EAAEC,SAAS,EAAEC,WAAW,QAAO,0BAA0B;AAEjF,SAAQC,OAAO,EAAEC,MAAM,EAAEC,QAAQ,QAAO,QAAQ;AAEhD,SAAQC,qBAAqB,QAAO,2BAA2B;AAC/D,SAAQC,qBAAqB,QAAO,+BAA+B;AAEnE,MAAMC,8BAA8B;AACpC,MAAMC,0BAA0B;AAEhC,OAAO,SAASC,uBAAyD,EACvEC,OAAO,EACPC,QAAQ,EACRC,YAAY,EACZC,4BAA4B,IAAM,IAAI,EAMvC;IACC,MAAM,CAACC,QAAQC,UAAU,GAAGX,SAAS;IACrC,MAAMY,WAAWb,OAAgC;IACjD,MAAMc,gBAAgBH,OAAOI,IAAI;IACjC,MAAMC,kBAAkBjB,QACtB,IAAMQ,QAAQU,MAAM,CAAC,CAACC,QAAUhB,sBAAsBgB,OAAOP,UAC7D;QAACJ;QAASI;KAAO;IAEnB,MAAMQ,sBAAsBV,iBAAiBW,aAAaV,0BAA0BC;IACpF,MAAMU,eAAeL,gBAAgBM,MAAM,GAAIH,CAAAA,sBAAsB,IAAI,CAAA;IACzE,MAAMI,aAAahB,QAAQe,MAAM,GAAGlB,+BAA+BU,kBAAkB;IACrF,MAAMU,oBACJV,kBAAkB,KAAK,wCAAwC;IACjE,MAAMW,kBACJX,kBAAkB,KAAK,KAAKY,wBAAwBV,gBAAgBM,MAAM,EAAER;IAE9E,SAASa;QACPf,UAAU;QACVC,SAASe,OAAO,EAAEC;IACpB;IAEA,qBACE;;0BACE,MAAClC;;oBACE4B,2BACC,KAACzB;kCACC,cAAA,KAACJ;4BACCoC,KAAKjB;4BACLkB,MAAK;4BACLC,cAAW;4BACXC,aAAY;4BACZC,OAAOvB;4BACPwB,wBACE,KAAC1C;gCAAK2C,MAAK;gCAAaC,WAAU;;4BAEpCC,UAAU,CAACC,QAAU3B,UAAU2B,MAAMC,MAAM,CAACN,KAAK;;yBAGnD;kCAEJ,KAACtC;kCACEyB,eAAe,kBACd,MAACxB;4BAAUmC,cAAYR;;gCACpBR,gBAAgByB,GAAG,CAAC,CAACvB,sBACpB,KAACf;wCAECe,OAAOA;wCACPwB,aAAa,IAAMlC,SAASU;uCAFvBA,MAAMyB,EAAE;gCAKhBxB,sBAAsBV,eAAe;;2CAGxC,KAACmC;4BAAwBjC,QAAQG;4BAAe+B,SAASlB;;;;;0BAK/D,KAACmB;gBAAEC,MAAK;gBAASC,aAAU;gBAASX,WAAU;0BAC3CZ;;;;AAIT;AAEA,SAASmB,wBAAwB,EAACjC,MAAM,EAAEkC,OAAO,EAAwC;IACvF,qBACE,KAACrD;QACCyD,MAAK;QACLC,OAAO,CAAC,oBAAoB,EAAEC,cAAcxC,QAAQ,CAAC,CAAC;QACtDyC,aAAY;QACZC,sBACE,KAAC9D;YAAO+D,MAAK;YAAKC,SAAQ;YAAYC,SAASX;sBAAS;;;AAMhE;AAEA,SAASM,cAAcM,KAAa;IAClC,IAAIA,MAAMnC,MAAM,IAAIjB,yBAAyB,OAAOoD;IACpD,OAAO,GAAGA,MAAMC,KAAK,CAAC,GAAGrD,0BAA0B,GAAG,GAAG,CAAC;AAC5D;AAEA,SAASqB,wBAAwBiC,KAAa,EAAEF,KAAa;IAC3D,IAAIE,UAAU,GAAG,OAAO,CAAC,oBAAoB,EAAEF,MAAM,CAAC,CAAC;IACvD,OAAO,GAAGE,MAAM,kBAAkB,EAAEF,MAAM,CAAC,CAAC;AAC9C"}
@@ -1 +1 @@
1
- {"version":3,"file":"harnesses-section.d.ts","sourceRoot":"","sources":["../../src/components/harnesses-section.tsx"],"names":[],"mappings":"AA4BA,wBAAgB,yBAAyB,CAAC,EAAC,WAAW,EAAC,EAAE;IAAC,WAAW,EAAE,MAAM,CAAA;CAAC,+BA+F7E"}
1
+ {"version":3,"file":"harnesses-section.d.ts","sourceRoot":"","sources":["../../src/components/harnesses-section.tsx"],"names":[],"mappings":"AAyBA,wBAAgB,yBAAyB,CAAC,EAAC,WAAW,EAAC,EAAE;IAAC,WAAW,EAAE,MAAM,CAAA;CAAC,+BAoG7E"}