@shipfox/client-integrations 8.0.0 → 9.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.
@@ -1,2 +1,2 @@
1
1
  $ shipfox-swc
2
- Successfully compiled: 51 files with swc (100.18ms)
2
+ Successfully compiled: 51 files with swc (94.26ms)
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # @shipfox/client-integrations
2
2
 
3
+ ## 9.0.0
4
+
5
+ ### Patch Changes
6
+
7
+ - 8e1820a: Improves source and repository picker cards for easier scanning.
8
+ - Updated dependencies [56e2c58]
9
+ - Updated dependencies [87170f8]
10
+ - @shipfox/client-shell@9.0.0
11
+ - @shipfox/client-auth@9.0.0
12
+
3
13
  ## 8.0.0
4
14
 
5
15
  ### Patch Changes
@@ -20,10 +20,9 @@ export function ConnectionPicker({ connections, selectedConnectionId, onSelect }
20
20
  "aria-labelledby": labelId,
21
21
  value: selectedConnectionId ?? '',
22
22
  onValueChange: onSelect,
23
- className: "grid grid-cols-2 gap-8 min-[1200px]:grid-cols-3 max-[760px]:grid-cols-1",
23
+ className: "grid grid-cols-2 gap-8 max-[760px]:grid-cols-1",
24
24
  children: connections.map((connection)=>/*#__PURE__*/ _jsx(RadioGroupItem, {
25
25
  value: connection.id,
26
- className: "p-12",
27
26
  children: /*#__PURE__*/ _jsx(ConnectionOption, {
28
27
  connection: connection
29
28
  })
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/connection-picker.tsx"],"sourcesContent":["import {IntegrationIcon} from '@shipfox/integration-icons';\nimport {useIsTextTruncated} from '@shipfox/react-ui/hooks';\nimport {Label} from '@shipfox/react-ui/label';\nimport {RadioGroup, RadioGroupItem} from '@shipfox/react-ui/radio-group';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {useId} from 'react';\nimport type {IntegrationConnection} from '#core/models.js';\n\nexport function ConnectionPicker({\n connections,\n selectedConnectionId,\n onSelect,\n}: {\n connections: IntegrationConnection[];\n selectedConnectionId: string | undefined;\n onSelect: (connectionId: string) => void;\n}) {\n const labelId = useId();\n\n return (\n <div className=\"flex flex-col gap-10\">\n <Label id={labelId} className=\"sr-only\">\n Source integration\n </Label>\n <RadioGroup\n aria-labelledby={labelId}\n value={selectedConnectionId ?? ''}\n onValueChange={onSelect}\n className=\"grid grid-cols-2 gap-8 min-[1200px]:grid-cols-3 max-[760px]:grid-cols-1\"\n >\n {connections.map((connection) => (\n <RadioGroupItem key={connection.id} value={connection.id} className=\"p-12\">\n <ConnectionOption connection={connection} />\n </RadioGroupItem>\n ))}\n </RadioGroup>\n </div>\n );\n}\n\nfunction ConnectionOption({connection}: {connection: IntegrationConnection}) {\n const {ref: nameRef, isTruncated} = useIsTextTruncated<HTMLSpanElement>(connection.displayName);\n\n return (\n <span className=\"flex min-w-0 items-center gap-10\">\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"shrink-0\">\n <IntegrationIcon\n source={connection.provider}\n aria-hidden\n className=\"size-20 text-foreground-neutral-base\"\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>{integrationName(connection.provider)}</TooltipContent>\n </Tooltip>\n\n <Tooltip>\n <TooltipTrigger asChild>\n <span ref={nameRef} className=\"min-w-0 truncate\">\n <Text as=\"span\" size=\"sm\" bold>\n {connection.displayName}\n </Text>\n </span>\n </TooltipTrigger>\n {isTruncated ? <TooltipContent>{connection.displayName}</TooltipContent> : null}\n </Tooltip>\n </span>\n );\n}\n\nfunction integrationName(provider: string): string {\n switch (provider) {\n case 'github':\n return 'GitHub';\n case 'gitea':\n return 'Gitea';\n case 'sentry':\n return 'Sentry';\n case 'webhook':\n return 'Webhook';\n case 'debug':\n return 'Debug';\n default:\n return provider;\n }\n}\n"],"names":["IntegrationIcon","useIsTextTruncated","Label","RadioGroup","RadioGroupItem","Tooltip","TooltipContent","TooltipTrigger","Text","useId","ConnectionPicker","connections","selectedConnectionId","onSelect","labelId","div","className","id","aria-labelledby","value","onValueChange","map","connection","ConnectionOption","ref","nameRef","isTruncated","displayName","span","asChild","source","provider","aria-hidden","integrationName","as","size","bold"],"mappings":";AAAA,SAAQA,eAAe,QAAO,6BAA6B;AAC3D,SAAQC,kBAAkB,QAAO,0BAA0B;AAC3D,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,UAAU,EAAEC,cAAc,QAAO,gCAAgC;AACzE,SAAQC,OAAO,EAAEC,cAAc,EAAEC,cAAc,QAAO,4BAA4B;AAClF,SAAQC,IAAI,QAAO,+BAA+B;AAClD,SAAQC,KAAK,QAAO,QAAQ;AAG5B,OAAO,SAASC,iBAAiB,EAC/BC,WAAW,EACXC,oBAAoB,EACpBC,QAAQ,EAKT;IACC,MAAMC,UAAUL;IAEhB,qBACE,MAACM;QAAIC,WAAU;;0BACb,KAACd;gBAAMe,IAAIH;gBAASE,WAAU;0BAAU;;0BAGxC,KAACb;gBACCe,mBAAiBJ;gBACjBK,OAAOP,wBAAwB;gBAC/BQ,eAAeP;gBACfG,WAAU;0BAETL,YAAYU,GAAG,CAAC,CAACC,2BAChB,KAAClB;wBAAmCe,OAAOG,WAAWL,EAAE;wBAAED,WAAU;kCAClE,cAAA,KAACO;4BAAiBD,YAAYA;;uBADXA,WAAWL,EAAE;;;;AAO5C;AAEA,SAASM,iBAAiB,EAACD,UAAU,EAAsC;IACzE,MAAM,EAACE,KAAKC,OAAO,EAAEC,WAAW,EAAC,GAAGzB,mBAAoCqB,WAAWK,WAAW;IAE9F,qBACE,MAACC;QAAKZ,WAAU;;0BACd,MAACX;;kCACC,KAACE;wBAAesB,OAAO;kCACrB,cAAA,KAACD;4BAAKZ,WAAU;sCACd,cAAA,KAAChB;gCACC8B,QAAQR,WAAWS,QAAQ;gCAC3BC,aAAW;gCACXhB,WAAU;;;;kCAIhB,KAACV;kCAAgB2B,gBAAgBX,WAAWS,QAAQ;;;;0BAGtD,MAAC1B;;kCACC,KAACE;wBAAesB,OAAO;kCACrB,cAAA,KAACD;4BAAKJ,KAAKC;4BAAST,WAAU;sCAC5B,cAAA,KAACR;gCAAK0B,IAAG;gCAAOC,MAAK;gCAAKC,IAAI;0CAC3Bd,WAAWK,WAAW;;;;oBAI5BD,4BAAc,KAACpB;kCAAgBgB,WAAWK,WAAW;yBAAqB;;;;;AAInF;AAEA,SAASM,gBAAgBF,QAAgB;IACvC,OAAQA;QACN,KAAK;YACH,OAAO;QACT,KAAK;YACH,OAAO;QACT,KAAK;YACH,OAAO;QACT,KAAK;YACH,OAAO;QACT,KAAK;YACH,OAAO;QACT;YACE,OAAOA;IACX;AACF"}
1
+ {"version":3,"sources":["../../src/components/connection-picker.tsx"],"sourcesContent":["import {IntegrationIcon} from '@shipfox/integration-icons';\nimport {useIsTextTruncated} from '@shipfox/react-ui/hooks';\nimport {Label} from '@shipfox/react-ui/label';\nimport {RadioGroup, RadioGroupItem} from '@shipfox/react-ui/radio-group';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {useId} from 'react';\nimport type {IntegrationConnection} from '#core/models.js';\n\nexport function ConnectionPicker({\n connections,\n selectedConnectionId,\n onSelect,\n}: {\n connections: IntegrationConnection[];\n selectedConnectionId: string | undefined;\n onSelect: (connectionId: string) => void;\n}) {\n const labelId = useId();\n\n return (\n <div className=\"flex flex-col gap-10\">\n <Label id={labelId} className=\"sr-only\">\n Source integration\n </Label>\n <RadioGroup\n aria-labelledby={labelId}\n value={selectedConnectionId ?? ''}\n onValueChange={onSelect}\n className=\"grid grid-cols-2 gap-8 max-[760px]:grid-cols-1\"\n >\n {connections.map((connection) => (\n <RadioGroupItem key={connection.id} value={connection.id}>\n <ConnectionOption connection={connection} />\n </RadioGroupItem>\n ))}\n </RadioGroup>\n </div>\n );\n}\n\nfunction ConnectionOption({connection}: {connection: IntegrationConnection}) {\n const {ref: nameRef, isTruncated} = useIsTextTruncated<HTMLSpanElement>(connection.displayName);\n\n return (\n <span className=\"flex min-w-0 items-center gap-10\">\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"shrink-0\">\n <IntegrationIcon\n source={connection.provider}\n aria-hidden\n className=\"size-20 text-foreground-neutral-base\"\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>{integrationName(connection.provider)}</TooltipContent>\n </Tooltip>\n\n <Tooltip>\n <TooltipTrigger asChild>\n <span ref={nameRef} className=\"min-w-0 truncate\">\n <Text as=\"span\" size=\"sm\" bold>\n {connection.displayName}\n </Text>\n </span>\n </TooltipTrigger>\n {isTruncated ? <TooltipContent>{connection.displayName}</TooltipContent> : null}\n </Tooltip>\n </span>\n );\n}\n\nfunction integrationName(provider: string): string {\n switch (provider) {\n case 'github':\n return 'GitHub';\n case 'gitea':\n return 'Gitea';\n case 'sentry':\n return 'Sentry';\n case 'webhook':\n return 'Webhook';\n case 'debug':\n return 'Debug';\n default:\n return provider;\n }\n}\n"],"names":["IntegrationIcon","useIsTextTruncated","Label","RadioGroup","RadioGroupItem","Tooltip","TooltipContent","TooltipTrigger","Text","useId","ConnectionPicker","connections","selectedConnectionId","onSelect","labelId","div","className","id","aria-labelledby","value","onValueChange","map","connection","ConnectionOption","ref","nameRef","isTruncated","displayName","span","asChild","source","provider","aria-hidden","integrationName","as","size","bold"],"mappings":";AAAA,SAAQA,eAAe,QAAO,6BAA6B;AAC3D,SAAQC,kBAAkB,QAAO,0BAA0B;AAC3D,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,UAAU,EAAEC,cAAc,QAAO,gCAAgC;AACzE,SAAQC,OAAO,EAAEC,cAAc,EAAEC,cAAc,QAAO,4BAA4B;AAClF,SAAQC,IAAI,QAAO,+BAA+B;AAClD,SAAQC,KAAK,QAAO,QAAQ;AAG5B,OAAO,SAASC,iBAAiB,EAC/BC,WAAW,EACXC,oBAAoB,EACpBC,QAAQ,EAKT;IACC,MAAMC,UAAUL;IAEhB,qBACE,MAACM;QAAIC,WAAU;;0BACb,KAACd;gBAAMe,IAAIH;gBAASE,WAAU;0BAAU;;0BAGxC,KAACb;gBACCe,mBAAiBJ;gBACjBK,OAAOP,wBAAwB;gBAC/BQ,eAAeP;gBACfG,WAAU;0BAETL,YAAYU,GAAG,CAAC,CAACC,2BAChB,KAAClB;wBAAmCe,OAAOG,WAAWL,EAAE;kCACtD,cAAA,KAACM;4BAAiBD,YAAYA;;uBADXA,WAAWL,EAAE;;;;AAO5C;AAEA,SAASM,iBAAiB,EAACD,UAAU,EAAsC;IACzE,MAAM,EAACE,KAAKC,OAAO,EAAEC,WAAW,EAAC,GAAGzB,mBAAoCqB,WAAWK,WAAW;IAE9F,qBACE,MAACC;QAAKZ,WAAU;;0BACd,MAACX;;kCACC,KAACE;wBAAesB,OAAO;kCACrB,cAAA,KAACD;4BAAKZ,WAAU;sCACd,cAAA,KAAChB;gCACC8B,QAAQR,WAAWS,QAAQ;gCAC3BC,aAAW;gCACXhB,WAAU;;;;kCAIhB,KAACV;kCAAgB2B,gBAAgBX,WAAWS,QAAQ;;;;0BAGtD,MAAC1B;;kCACC,KAACE;wBAAesB,OAAO;kCACrB,cAAA,KAACD;4BAAKJ,KAAKC;4BAAST,WAAU;sCAC5B,cAAA,KAACR;gCAAK0B,IAAG;gCAAOC,MAAK;gCAAKC,IAAI;0CAC3Bd,WAAWK,WAAW;;;;oBAI5BD,4BAAc,KAACpB;kCAAgBgB,WAAWK,WAAW;yBAAqB;;;;;AAInF;AAEA,SAASM,gBAAgBF,QAAgB;IACvC,OAAQA;QACN,KAAK;YACH,OAAO;QACT,KAAK;YACH,OAAO;QACT,KAAK;YACH,OAAO;QACT,KAAK;YACH,OAAO;QACT,KAAK;YACH,OAAO;QACT;YACE,OAAOA;IACX;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"repository-picker.d.ts","sourceRoot":"","sources":["../../src/components/repository-picker.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAC;AAEhD,wBAAgB,gBAAgB,CAAC,EAC/B,YAAY,EACZ,oBAAoB,EACpB,QAAQ,EACR,SAAS,EACT,kBAAkB,EAClB,WAAW,EACX,UAAU,EACV,YAAuC,EACvC,WAAW,EACX,cAAc,EACd,cAAc,GACf,EAAE;IACD,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,SAAS,EAAE,OAAO,CAAC;IACnB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,+BAoEA"}
1
+ {"version":3,"file":"repository-picker.d.ts","sourceRoot":"","sources":["../../src/components/repository-picker.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAC;AAKhD,wBAAgB,gBAAgB,CAAC,EAC/B,YAAY,EACZ,oBAAoB,EACpB,QAAQ,EACR,SAAS,EACT,kBAAkB,EAClB,WAAW,EACX,UAAU,EACV,YAAuC,EACvC,WAAW,EACX,cAAc,EACd,cAAc,GACf,EAAE;IACD,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,SAAS,EAAE,OAAO,CAAC;IACnB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,+BAuDA"}
@@ -1,11 +1,20 @@
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
+ import { useIsTextTruncated } from '@shipfox/react-ui/hooks';
3
4
  import { Input } from '@shipfox/react-ui/input';
4
5
  import { Label } from '@shipfox/react-ui/label';
5
6
  import { RadioGroup, RadioGroupItem } from '@shipfox/react-ui/radio-group';
6
7
  import { Skeleton } from '@shipfox/react-ui/skeleton';
8
+ import { Tooltip, TooltipContent, TooltipTrigger } from '@shipfox/react-ui/tooltip';
7
9
  import { Text } from '@shipfox/react-ui/typography';
8
10
  import { useId } from 'react';
11
+ const REPOSITORY_GRID_CLASS_NAME = 'grid grid-cols-2 gap-8 max-[760px]:grid-cols-1';
12
+ const REPOSITORY_SKELETON_WIDTHS = [
13
+ 'w-64',
14
+ 'w-96',
15
+ 'w-80',
16
+ 'w-112'
17
+ ];
9
18
  export function RepositoryPicker({ repositories, selectedRepositoryId, onSelect, isLoading, isFetchingNextPage, hasNextPage, onLoadMore, emptyMessage = 'No repositories found.', searchValue, onSearchChange, searchDisabled }) {
10
19
  const labelId = useId();
11
20
  const showSearch = onSearchChange !== undefined;
@@ -25,9 +34,7 @@ export function RepositoryPicker({ repositories, selectedRepositoryId, onSelect,
25
34
  onChange: (event)=>onSearchChange?.(event.target.value),
26
35
  disabled: searchDisabled
27
36
  }) : null,
28
- isLoading ? /*#__PURE__*/ _jsx(Skeleton, {
29
- className: "h-58 w-full"
30
- }) : null,
37
+ isLoading ? /*#__PURE__*/ _jsx(RepositoryLoadingState, {}) : null,
31
38
  !isLoading && repositories.length === 0 ? /*#__PURE__*/ _jsx("div", {
32
39
  className: "rounded-8 border border-border-neutral-base bg-background-subtle-base p-14",
33
40
  children: /*#__PURE__*/ _jsx(Text, {
@@ -39,28 +46,9 @@ export function RepositoryPicker({ repositories, selectedRepositoryId, onSelect,
39
46
  "aria-labelledby": labelId,
40
47
  value: selectedRepositoryId ?? '',
41
48
  onValueChange: onSelect,
42
- className: "grid grid-cols-2 gap-8 min-[1200px]:grid-cols-3 max-[760px]:grid-cols-1",
43
- children: repositories.map((repository)=>/*#__PURE__*/ _jsx(RadioGroupItem, {
44
- value: repository.externalRepositoryId,
45
- className: "p-12",
46
- children: /*#__PURE__*/ _jsxs("span", {
47
- className: "flex min-w-0 items-center justify-between gap-10",
48
- children: [
49
- /*#__PURE__*/ _jsx(Text, {
50
- as: "span",
51
- size: "sm",
52
- bold: true,
53
- className: "truncate",
54
- children: repository.fullName
55
- }),
56
- /*#__PURE__*/ _jsx(Text, {
57
- as: "span",
58
- size: "xs",
59
- className: "shrink-0 text-foreground-neutral-muted",
60
- children: repository.defaultBranch
61
- })
62
- ]
63
- })
49
+ className: REPOSITORY_GRID_CLASS_NAME,
50
+ children: repositories.map((repository)=>/*#__PURE__*/ _jsx(RepositoryCard, {
51
+ repository: repository
64
52
  }, repository.externalRepositoryId))
65
53
  }) : null,
66
54
  hasNextPage && onLoadMore ? /*#__PURE__*/ _jsx(Button, {
@@ -74,5 +62,53 @@ export function RepositoryPicker({ repositories, selectedRepositoryId, onSelect,
74
62
  ]
75
63
  });
76
64
  }
65
+ function RepositoryCard({ repository }) {
66
+ const { ref: nameRef, isTruncated } = useIsTextTruncated(repository.name);
67
+ return /*#__PURE__*/ _jsxs(Tooltip, {
68
+ children: [
69
+ /*#__PURE__*/ _jsx(TooltipTrigger, {
70
+ asChild: true,
71
+ children: /*#__PURE__*/ _jsx(RadioGroupItem, {
72
+ value: repository.externalRepositoryId,
73
+ className: "min-w-0",
74
+ children: /*#__PURE__*/ _jsx("span", {
75
+ ref: nameRef,
76
+ className: "block min-w-0 truncate",
77
+ children: /*#__PURE__*/ _jsx(Text, {
78
+ as: "span",
79
+ size: "sm",
80
+ bold: true,
81
+ children: repository.name
82
+ })
83
+ })
84
+ })
85
+ }),
86
+ isTruncated ? /*#__PURE__*/ _jsx(TooltipContent, {
87
+ children: repository.name
88
+ }) : null
89
+ ]
90
+ });
91
+ }
92
+ function RepositoryLoadingState() {
93
+ return /*#__PURE__*/ _jsxs(_Fragment, {
94
+ children: [
95
+ /*#__PURE__*/ _jsx("div", {
96
+ role: "status",
97
+ className: "sr-only",
98
+ children: "Loading repositories."
99
+ }),
100
+ /*#__PURE__*/ _jsx("div", {
101
+ "aria-hidden": "true",
102
+ className: REPOSITORY_GRID_CLASS_NAME,
103
+ children: REPOSITORY_SKELETON_WIDTHS.map((width)=>/*#__PURE__*/ _jsx("div", {
104
+ className: "h-50 min-w-0 rounded-8 border border-border-neutral-base bg-background-neutral-base p-14",
105
+ children: /*#__PURE__*/ _jsx(Skeleton, {
106
+ className: `h-20 ${width}`
107
+ })
108
+ }, width))
109
+ })
110
+ ]
111
+ });
112
+ }
77
113
 
78
114
  //# sourceMappingURL=repository-picker.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/repository-picker.tsx"],"sourcesContent":["import {Button} from '@shipfox/react-ui/button';\nimport {Input} from '@shipfox/react-ui/input';\nimport {Label} from '@shipfox/react-ui/label';\nimport {RadioGroup, RadioGroupItem} from '@shipfox/react-ui/radio-group';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {useId} from 'react';\nimport type {Repository} from '#core/models.js';\n\nexport function RepositoryPicker({\n repositories,\n selectedRepositoryId,\n onSelect,\n isLoading,\n isFetchingNextPage,\n hasNextPage,\n onLoadMore,\n emptyMessage = 'No repositories found.',\n searchValue,\n onSearchChange,\n searchDisabled,\n}: {\n repositories: Repository[];\n selectedRepositoryId: string | undefined;\n onSelect: (repositoryId: string) => void;\n isLoading: boolean;\n isFetchingNextPage?: boolean;\n hasNextPage?: boolean;\n onLoadMore?: () => void;\n emptyMessage?: string;\n searchValue?: string;\n onSearchChange?: (value: string) => void;\n searchDisabled?: boolean;\n}) {\n const labelId = useId();\n const showSearch = onSearchChange !== undefined;\n\n return (\n <div className=\"flex flex-col gap-10\">\n <Label id={labelId} className=\"sr-only\">\n Repository\n </Label>\n\n {showSearch ? (\n <Input\n type=\"search\"\n placeholder=\"Search repositories…\"\n aria-label=\"Search repositories\"\n value={searchValue ?? ''}\n onChange={(event) => onSearchChange?.(event.target.value)}\n disabled={searchDisabled}\n />\n ) : null}\n\n {isLoading ? <Skeleton className=\"h-58 w-full\" /> : null}\n\n {!isLoading && repositories.length === 0 ? (\n <div className=\"rounded-8 border border-border-neutral-base bg-background-subtle-base p-14\">\n <Text size=\"sm\">{emptyMessage}</Text>\n </div>\n ) : null}\n\n {repositories.length > 0 ? (\n <RadioGroup\n aria-labelledby={labelId}\n value={selectedRepositoryId ?? ''}\n onValueChange={onSelect}\n className=\"grid grid-cols-2 gap-8 min-[1200px]:grid-cols-3 max-[760px]:grid-cols-1\"\n >\n {repositories.map((repository) => (\n <RadioGroupItem\n key={repository.externalRepositoryId}\n value={repository.externalRepositoryId}\n className=\"p-12\"\n >\n <span className=\"flex min-w-0 items-center justify-between gap-10\">\n <Text as=\"span\" size=\"sm\" bold className=\"truncate\">\n {repository.fullName}\n </Text>\n <Text as=\"span\" size=\"xs\" className=\"shrink-0 text-foreground-neutral-muted\">\n {repository.defaultBranch}\n </Text>\n </span>\n </RadioGroupItem>\n ))}\n </RadioGroup>\n ) : null}\n\n {hasNextPage && onLoadMore ? (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n isLoading={isFetchingNextPage ?? false}\n onClick={onLoadMore}\n >\n Load more\n </Button>\n ) : null}\n </div>\n );\n}\n"],"names":["Button","Input","Label","RadioGroup","RadioGroupItem","Skeleton","Text","useId","RepositoryPicker","repositories","selectedRepositoryId","onSelect","isLoading","isFetchingNextPage","hasNextPage","onLoadMore","emptyMessage","searchValue","onSearchChange","searchDisabled","labelId","showSearch","undefined","div","className","id","type","placeholder","aria-label","value","onChange","event","target","disabled","length","size","aria-labelledby","onValueChange","map","repository","externalRepositoryId","span","as","bold","fullName","defaultBranch","variant","onClick"],"mappings":";AAAA,SAAQA,MAAM,QAAO,2BAA2B;AAChD,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,UAAU,EAAEC,cAAc,QAAO,gCAAgC;AACzE,SAAQC,QAAQ,QAAO,6BAA6B;AACpD,SAAQC,IAAI,QAAO,+BAA+B;AAClD,SAAQC,KAAK,QAAO,QAAQ;AAG5B,OAAO,SAASC,iBAAiB,EAC/BC,YAAY,EACZC,oBAAoB,EACpBC,QAAQ,EACRC,SAAS,EACTC,kBAAkB,EAClBC,WAAW,EACXC,UAAU,EACVC,eAAe,wBAAwB,EACvCC,WAAW,EACXC,cAAc,EACdC,cAAc,EAaf;IACC,MAAMC,UAAUb;IAChB,MAAMc,aAAaH,mBAAmBI;IAEtC,qBACE,MAACC;QAAIC,WAAU;;0BACb,KAACtB;gBAAMuB,IAAIL;gBAASI,WAAU;0BAAU;;YAIvCH,2BACC,KAACpB;gBACCyB,MAAK;gBACLC,aAAY;gBACZC,cAAW;gBACXC,OAAOZ,eAAe;gBACtBa,UAAU,CAACC,QAAUb,iBAAiBa,MAAMC,MAAM,CAACH,KAAK;gBACxDI,UAAUd;iBAEV;YAEHP,0BAAY,KAACP;gBAASmB,WAAU;iBAAmB;YAEnD,CAACZ,aAAaH,aAAayB,MAAM,KAAK,kBACrC,KAACX;gBAAIC,WAAU;0BACb,cAAA,KAAClB;oBAAK6B,MAAK;8BAAMnB;;iBAEjB;YAEHP,aAAayB,MAAM,GAAG,kBACrB,KAAC/B;gBACCiC,mBAAiBhB;gBACjBS,OAAOnB,wBAAwB;gBAC/B2B,eAAe1B;gBACfa,WAAU;0BAETf,aAAa6B,GAAG,CAAC,CAACC,2BACjB,KAACnC;wBAECyB,OAAOU,WAAWC,oBAAoB;wBACtChB,WAAU;kCAEV,cAAA,MAACiB;4BAAKjB,WAAU;;8CACd,KAAClB;oCAAKoC,IAAG;oCAAOP,MAAK;oCAAKQ,IAAI;oCAACnB,WAAU;8CACtCe,WAAWK,QAAQ;;8CAEtB,KAACtC;oCAAKoC,IAAG;oCAAOP,MAAK;oCAAKX,WAAU;8CACjCe,WAAWM,aAAa;;;;uBATxBN,WAAWC,oBAAoB;iBAexC;YAEH1B,eAAeC,2BACd,KAACf;gBACC0B,MAAK;gBACLoB,SAAQ;gBACRX,MAAK;gBACLvB,WAAWC,sBAAsB;gBACjCkC,SAAShC;0BACV;iBAGC;;;AAGV"}
1
+ {"version":3,"sources":["../../src/components/repository-picker.tsx"],"sourcesContent":["import {Button} from '@shipfox/react-ui/button';\nimport {useIsTextTruncated} from '@shipfox/react-ui/hooks';\nimport {Input} from '@shipfox/react-ui/input';\nimport {Label} from '@shipfox/react-ui/label';\nimport {RadioGroup, RadioGroupItem} from '@shipfox/react-ui/radio-group';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {useId} from 'react';\nimport type {Repository} from '#core/models.js';\n\nconst REPOSITORY_GRID_CLASS_NAME = 'grid grid-cols-2 gap-8 max-[760px]:grid-cols-1';\nconst REPOSITORY_SKELETON_WIDTHS = ['w-64', 'w-96', 'w-80', 'w-112'] as const;\n\nexport function RepositoryPicker({\n repositories,\n selectedRepositoryId,\n onSelect,\n isLoading,\n isFetchingNextPage,\n hasNextPage,\n onLoadMore,\n emptyMessage = 'No repositories found.',\n searchValue,\n onSearchChange,\n searchDisabled,\n}: {\n repositories: Repository[];\n selectedRepositoryId: string | undefined;\n onSelect: (repositoryId: string) => void;\n isLoading: boolean;\n isFetchingNextPage?: boolean;\n hasNextPage?: boolean;\n onLoadMore?: () => void;\n emptyMessage?: string;\n searchValue?: string;\n onSearchChange?: (value: string) => void;\n searchDisabled?: boolean;\n}) {\n const labelId = useId();\n const showSearch = onSearchChange !== undefined;\n\n return (\n <div className=\"flex flex-col gap-10\">\n <Label id={labelId} className=\"sr-only\">\n Repository\n </Label>\n\n {showSearch ? (\n <Input\n type=\"search\"\n placeholder=\"Search repositories…\"\n aria-label=\"Search repositories\"\n value={searchValue ?? ''}\n onChange={(event) => onSearchChange?.(event.target.value)}\n disabled={searchDisabled}\n />\n ) : null}\n\n {isLoading ? <RepositoryLoadingState /> : null}\n\n {!isLoading && repositories.length === 0 ? (\n <div className=\"rounded-8 border border-border-neutral-base bg-background-subtle-base p-14\">\n <Text size=\"sm\">{emptyMessage}</Text>\n </div>\n ) : null}\n\n {repositories.length > 0 ? (\n <RadioGroup\n aria-labelledby={labelId}\n value={selectedRepositoryId ?? ''}\n onValueChange={onSelect}\n className={REPOSITORY_GRID_CLASS_NAME}\n >\n {repositories.map((repository) => (\n <RepositoryCard key={repository.externalRepositoryId} repository={repository} />\n ))}\n </RadioGroup>\n ) : null}\n\n {hasNextPage && onLoadMore ? (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n isLoading={isFetchingNextPage ?? false}\n onClick={onLoadMore}\n >\n Load more\n </Button>\n ) : null}\n </div>\n );\n}\n\nfunction RepositoryCard({repository}: {repository: Repository}) {\n const {ref: nameRef, isTruncated} = useIsTextTruncated<HTMLSpanElement>(repository.name);\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <RadioGroupItem value={repository.externalRepositoryId} className=\"min-w-0\">\n <span ref={nameRef} className=\"block min-w-0 truncate\">\n <Text as=\"span\" size=\"sm\" bold>\n {repository.name}\n </Text>\n </span>\n </RadioGroupItem>\n </TooltipTrigger>\n {isTruncated ? <TooltipContent>{repository.name}</TooltipContent> : null}\n </Tooltip>\n );\n}\n\nfunction RepositoryLoadingState() {\n return (\n <>\n <div role=\"status\" className=\"sr-only\">\n Loading repositories.\n </div>\n <div aria-hidden=\"true\" className={REPOSITORY_GRID_CLASS_NAME}>\n {REPOSITORY_SKELETON_WIDTHS.map((width) => (\n <div\n key={width}\n className=\"h-50 min-w-0 rounded-8 border border-border-neutral-base bg-background-neutral-base p-14\"\n >\n <Skeleton className={`h-20 ${width}`} />\n </div>\n ))}\n </div>\n </>\n );\n}\n"],"names":["Button","useIsTextTruncated","Input","Label","RadioGroup","RadioGroupItem","Skeleton","Tooltip","TooltipContent","TooltipTrigger","Text","useId","REPOSITORY_GRID_CLASS_NAME","REPOSITORY_SKELETON_WIDTHS","RepositoryPicker","repositories","selectedRepositoryId","onSelect","isLoading","isFetchingNextPage","hasNextPage","onLoadMore","emptyMessage","searchValue","onSearchChange","searchDisabled","labelId","showSearch","undefined","div","className","id","type","placeholder","aria-label","value","onChange","event","target","disabled","RepositoryLoadingState","length","size","aria-labelledby","onValueChange","map","repository","RepositoryCard","externalRepositoryId","variant","onClick","ref","nameRef","isTruncated","name","asChild","span","as","bold","role","aria-hidden","width"],"mappings":";AAAA,SAAQA,MAAM,QAAO,2BAA2B;AAChD,SAAQC,kBAAkB,QAAO,0BAA0B;AAC3D,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,UAAU,EAAEC,cAAc,QAAO,gCAAgC;AACzE,SAAQC,QAAQ,QAAO,6BAA6B;AACpD,SAAQC,OAAO,EAAEC,cAAc,EAAEC,cAAc,QAAO,4BAA4B;AAClF,SAAQC,IAAI,QAAO,+BAA+B;AAClD,SAAQC,KAAK,QAAO,QAAQ;AAG5B,MAAMC,6BAA6B;AACnC,MAAMC,6BAA6B;IAAC;IAAQ;IAAQ;IAAQ;CAAQ;AAEpE,OAAO,SAASC,iBAAiB,EAC/BC,YAAY,EACZC,oBAAoB,EACpBC,QAAQ,EACRC,SAAS,EACTC,kBAAkB,EAClBC,WAAW,EACXC,UAAU,EACVC,eAAe,wBAAwB,EACvCC,WAAW,EACXC,cAAc,EACdC,cAAc,EAaf;IACC,MAAMC,UAAUf;IAChB,MAAMgB,aAAaH,mBAAmBI;IAEtC,qBACE,MAACC;QAAIC,WAAU;;0BACb,KAAC3B;gBAAM4B,IAAIL;gBAASI,WAAU;0BAAU;;YAIvCH,2BACC,KAACzB;gBACC8B,MAAK;gBACLC,aAAY;gBACZC,cAAW;gBACXC,OAAOZ,eAAe;gBACtBa,UAAU,CAACC,QAAUb,iBAAiBa,MAAMC,MAAM,CAACH,KAAK;gBACxDI,UAAUd;iBAEV;YAEHP,0BAAY,KAACsB,8BAA4B;YAEzC,CAACtB,aAAaH,aAAa0B,MAAM,KAAK,kBACrC,KAACZ;gBAAIC,WAAU;0BACb,cAAA,KAACpB;oBAAKgC,MAAK;8BAAMpB;;iBAEjB;YAEHP,aAAa0B,MAAM,GAAG,kBACrB,KAACrC;gBACCuC,mBAAiBjB;gBACjBS,OAAOnB,wBAAwB;gBAC/B4B,eAAe3B;gBACfa,WAAWlB;0BAEVG,aAAa8B,GAAG,CAAC,CAACC,2BACjB,KAACC;wBAAqDD,YAAYA;uBAA7CA,WAAWE,oBAAoB;iBAGtD;YAEH5B,eAAeC,2BACd,KAACrB;gBACCgC,MAAK;gBACLiB,SAAQ;gBACRP,MAAK;gBACLxB,WAAWC,sBAAsB;gBACjC+B,SAAS7B;0BACV;iBAGC;;;AAGV;AAEA,SAAS0B,eAAe,EAACD,UAAU,EAA2B;IAC5D,MAAM,EAACK,KAAKC,OAAO,EAAEC,WAAW,EAAC,GAAGpD,mBAAoC6C,WAAWQ,IAAI;IAEvF,qBACE,MAAC/C;;0BACC,KAACE;gBAAe8C,OAAO;0BACrB,cAAA,KAAClD;oBAAe8B,OAAOW,WAAWE,oBAAoB;oBAAElB,WAAU;8BAChE,cAAA,KAAC0B;wBAAKL,KAAKC;wBAAStB,WAAU;kCAC5B,cAAA,KAACpB;4BAAK+C,IAAG;4BAAOf,MAAK;4BAAKgB,IAAI;sCAC3BZ,WAAWQ,IAAI;;;;;YAKvBD,4BAAc,KAAC7C;0BAAgBsC,WAAWQ,IAAI;iBAAqB;;;AAG1E;AAEA,SAASd;IACP,qBACE;;0BACE,KAACX;gBAAI8B,MAAK;gBAAS7B,WAAU;0BAAU;;0BAGvC,KAACD;gBAAI+B,eAAY;gBAAO9B,WAAWlB;0BAChCC,2BAA2BgC,GAAG,CAAC,CAACgB,sBAC/B,KAAChC;wBAECC,WAAU;kCAEV,cAAA,KAACxB;4BAASwB,WAAW,CAAC,KAAK,EAAE+B,OAAO;;uBAH/BA;;;;AASjB"}