@shipfox/client-projects 17.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 (58) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +42 -0
  3. package/dist/components/source-strip.d.ts.map +1 -1
  4. package/dist/components/source-strip.js +49 -45
  5. package/dist/components/source-strip.js.map +1 -1
  6. package/dist/pages/create-project-page.d.ts.map +1 -1
  7. package/dist/pages/create-project-page.js +161 -175
  8. package/dist/pages/create-project-page.js.map +1 -1
  9. package/dist/pages/create-project-page.stories.js +1 -1
  10. package/dist/pages/create-project-page.stories.js.map +1 -1
  11. package/dist/pages/project-settings-page.d.ts.map +1 -1
  12. package/dist/pages/project-settings-page.js +82 -84
  13. package/dist/pages/project-settings-page.js.map +1 -1
  14. package/dist/pages/project-settings-page.stories.js +1 -1
  15. package/dist/pages/project-settings-page.stories.js.map +1 -1
  16. package/dist/pages/projects-hub-page.d.ts.map +1 -1
  17. package/dist/pages/projects-hub-page.js +160 -159
  18. package/dist/pages/projects-hub-page.js.map +1 -1
  19. package/dist/pages/projects-hub-page.stories.d.ts +22 -0
  20. package/dist/pages/projects-hub-page.stories.d.ts.map +1 -0
  21. package/dist/pages/projects-hub-page.stories.js +214 -0
  22. package/dist/pages/projects-hub-page.stories.js.map +1 -0
  23. package/dist/routes/create-project.d.ts +3 -0
  24. package/dist/routes/create-project.js +3 -0
  25. package/dist/routes/create-project.js.map +1 -1
  26. package/dist/routes/home.d.ts +3 -0
  27. package/dist/routes/home.js +3 -0
  28. package/dist/routes/home.js.map +1 -1
  29. package/dist/routes/project-index.d.ts +3 -0
  30. package/dist/routes/project-index.d.ts.map +1 -1
  31. package/dist/routes/project-index.js +3 -0
  32. package/dist/routes/project-index.js.map +1 -1
  33. package/dist/routes/project-settings-index.d.ts +3 -0
  34. package/dist/routes/project-settings-index.d.ts.map +1 -1
  35. package/dist/routes/project-settings-index.js +3 -0
  36. package/dist/routes/project-settings-index.js.map +1 -1
  37. package/dist/routes/project-settings.d.ts +3 -0
  38. package/dist/routes/project-settings.js +3 -0
  39. package/dist/routes/project-settings.js.map +1 -1
  40. package/dist/tsconfig.test.tsbuildinfo +1 -1
  41. package/package.json +7 -7
  42. package/src/components/source-strip.tsx +29 -26
  43. package/src/pages/create-project-page.stories.tsx +1 -1
  44. package/src/pages/create-project-page.test.tsx +85 -1
  45. package/src/pages/create-project-page.tsx +165 -153
  46. package/src/pages/home-router.test.tsx +2 -1
  47. package/src/pages/project-settings-page.stories.tsx +1 -1
  48. package/src/pages/project-settings-page.test.tsx +10 -1
  49. package/src/pages/project-settings-page.tsx +88 -76
  50. package/src/pages/projects-hub-page.stories.tsx +203 -0
  51. package/src/pages/projects-hub-page.test.tsx +90 -10
  52. package/src/pages/projects-hub-page.tsx +136 -125
  53. package/src/routes/create-project.tsx +4 -1
  54. package/src/routes/home.tsx +1 -0
  55. package/src/routes/project-index.tsx +1 -0
  56. package/src/routes/project-settings-index.tsx +1 -0
  57. package/src/routes/project-settings.tsx +4 -1
  58. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1,2 +1,2 @@
1
1
  $ shipfox-swc
2
- Successfully compiled: 27 files with swc (631.23ms)
2
+ Successfully compiled: 28 files with swc (277.09ms)
package/CHANGELOG.md CHANGED
@@ -1,5 +1,47 @@
1
1
  # @shipfox/client-projects
2
2
 
3
+ ## 22.0.0
4
+
5
+ ### Patch Changes
6
+
7
+ - 7693eb3: Render empty and load-error states inside bordered panel bodies and keep loading placeholders aligned with their data regions.
8
+ - 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.
9
+ - 00c1cb8: Rework the projects index into one Panel with header controls, two-column hairline cells, and preserved loading, empty, error, integration connection, and pagination states.
10
+ - 56f4526: Project settings and project creation now use shared panels, with source integrations presented as button-style radio choices.
11
+ - Updated dependencies [50b3867]
12
+ - Updated dependencies [00c1cb8]
13
+ - Updated dependencies [7693eb3]
14
+ - Updated dependencies [00c1cb8]
15
+ - Updated dependencies [00c1cb8]
16
+ - Updated dependencies [56f4526]
17
+ - @shipfox/client-agent@22.0.0
18
+ - @shipfox/client-auth@22.0.0
19
+ - @shipfox/client-integrations@22.0.0
20
+ - @shipfox/client-shell@22.0.0
21
+ - @shipfox/react-ui@2.1.0
22
+ - @shipfox/client-ui@22.0.0
23
+
24
+ ## 21.0.0
25
+
26
+ ### Patch Changes
27
+
28
+ - Updated dependencies [0f4abe4]
29
+ - Updated dependencies [71d0c44]
30
+ - Updated dependencies [9c21429]
31
+ - Updated dependencies [30beb8f]
32
+ - Updated dependencies [16733a7]
33
+ - Updated dependencies [163c40a]
34
+ - Updated dependencies [c4376a1]
35
+ - Updated dependencies [6703982]
36
+ - Updated dependencies [f1d127e]
37
+ - Updated dependencies [0e860d7]
38
+ - @shipfox/react-ui@2.0.0
39
+ - @shipfox/client-shell@21.0.0
40
+ - @shipfox/client-agent@21.0.0
41
+ - @shipfox/client-auth@21.0.0
42
+ - @shipfox/client-integrations@21.0.0
43
+ - @shipfox/client-ui@21.0.0
44
+
3
45
  ## 17.0.0
4
46
 
5
47
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"source-strip.d.ts","sourceRoot":"","sources":["../../src/components/source-strip.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,qBAAqB,CAAC;AAE/D;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,EAC1B,YAAY,EACZ,oBAAoB,EACpB,IAAI,EACJ,SAAS,GACV,EAAE;IACD,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,IAAI,EAAE,qBAAqB,GAAG,IAAI,GAAG,SAAS,CAAC;IAC/C,SAAS,EAAE,OAAO,CAAC;CACpB,+BAmCA"}
1
+ {"version":3,"file":"source-strip.d.ts","sourceRoot":"","sources":["../../src/components/source-strip.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,qBAAqB,CAAC;AAE/D;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,EAC1B,YAAY,EACZ,oBAAoB,EACpB,IAAI,EACJ,SAAS,GACV,EAAE;IACD,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,IAAI,EAAE,qBAAqB,GAAG,IAAI,GAAG,SAAS,CAAC;IAC/C,SAAS,EAAE,OAAO,CAAC;CACpB,+BAqCA"}
@@ -3,6 +3,7 @@ import { useActiveWorkspace } from '@shipfox/client-auth';
3
3
  import { useSourceConnectionsQuery } from '@shipfox/client-integrations';
4
4
  import { StatusBadge } from '@shipfox/react-ui/badge';
5
5
  import { Icon } from '@shipfox/react-ui/icon';
6
+ import { Panel } from '@shipfox/react-ui/panel';
6
7
  import { Skeleton } from '@shipfox/react-ui/skeleton';
7
8
  import { Tooltip, TooltipContent, TooltipTrigger } from '@shipfox/react-ui/tooltip';
8
9
  import { Code, Text } from '@shipfox/react-ui/typography';
@@ -15,55 +16,58 @@ import { Code, Text } from '@shipfox/react-ui/typography';
15
16
  const workspace = useActiveWorkspace();
16
17
  const connectionsQuery = useSourceConnectionsQuery(workspace.id);
17
18
  const connection = connectionsQuery.data?.find((c)=>c.id === connectionId);
18
- return /*#__PURE__*/ _jsxs("section", {
19
- className: "flex flex-col gap-inline rounded-8 border border-border-neutral-base bg-background-neutral-base px-row py-row sm:flex-row sm:items-center sm:justify-between",
20
- "aria-label": "Project source",
21
- children: [
22
- /*#__PURE__*/ _jsxs("div", {
23
- className: "flex min-w-0 items-center gap-inline",
24
- children: [
25
- /*#__PURE__*/ _jsx(Icon, {
26
- name: providerIconName(connection?.provider),
27
- className: "size-20 shrink-0"
28
- }),
29
- /*#__PURE__*/ _jsxs("div", {
30
- className: "flex min-w-0 flex-col gap-tight sm:flex-row sm:items-center sm:gap-inline",
31
- children: [
32
- connectionsQuery.isPending ? /*#__PURE__*/ _jsx(Skeleton, {
33
- className: "h-16 w-160"
34
- }) : /*#__PURE__*/ _jsx(Text, {
35
- size: "sm",
36
- bold: true,
37
- className: "truncate",
38
- children: connection?.displayName ?? 'Connected source'
39
- }),
40
- /*#__PURE__*/ _jsxs(Tooltip, {
41
- children: [
42
- /*#__PURE__*/ _jsx(TooltipTrigger, {
43
- asChild: true,
44
- children: /*#__PURE__*/ _jsx(Code, {
45
- variant: "label",
46
- className: "truncate text-foreground-neutral-muted",
19
+ return /*#__PURE__*/ _jsx(Panel, {
20
+ asChild: true,
21
+ className: "gap-inline px-row py-row sm:flex-row sm:items-center sm:justify-between",
22
+ children: /*#__PURE__*/ _jsxs("section", {
23
+ "aria-label": "Project source",
24
+ children: [
25
+ /*#__PURE__*/ _jsxs("div", {
26
+ className: "flex min-w-0 items-center gap-inline",
27
+ children: [
28
+ /*#__PURE__*/ _jsx(Icon, {
29
+ name: providerIconName(connection?.provider),
30
+ className: "size-20 shrink-0"
31
+ }),
32
+ /*#__PURE__*/ _jsxs("div", {
33
+ className: "flex min-w-0 flex-col gap-tight sm:flex-row sm:items-center sm:gap-inline",
34
+ children: [
35
+ connectionsQuery.isPending ? /*#__PURE__*/ _jsx(Skeleton, {
36
+ className: "h-16 w-160"
37
+ }) : /*#__PURE__*/ _jsx(Text, {
38
+ size: "sm",
39
+ bold: true,
40
+ className: "truncate",
41
+ children: connection?.displayName ?? 'Connected source'
42
+ }),
43
+ /*#__PURE__*/ _jsxs(Tooltip, {
44
+ children: [
45
+ /*#__PURE__*/ _jsx(TooltipTrigger, {
46
+ asChild: true,
47
+ children: /*#__PURE__*/ _jsx(Code, {
48
+ variant: "label",
49
+ className: "truncate text-foreground-neutral-muted",
50
+ children: externalRepositoryId
51
+ })
52
+ }),
53
+ /*#__PURE__*/ _jsx(TooltipContent, {
47
54
  children: externalRepositoryId
48
55
  })
49
- }),
50
- /*#__PURE__*/ _jsx(TooltipContent, {
51
- children: externalRepositoryId
52
- })
53
- ]
54
- })
55
- ]
56
+ ]
57
+ })
58
+ ]
59
+ })
60
+ ]
61
+ }),
62
+ /*#__PURE__*/ _jsx("div", {
63
+ className: "shrink-0",
64
+ children: /*#__PURE__*/ _jsx(SyncBadge, {
65
+ sync: sync,
66
+ isPending: isPending
56
67
  })
57
- ]
58
- }),
59
- /*#__PURE__*/ _jsx("div", {
60
- className: "shrink-0",
61
- children: /*#__PURE__*/ _jsx(SyncBadge, {
62
- sync: sync,
63
- isPending: isPending
64
68
  })
65
- })
66
- ]
69
+ ]
70
+ })
67
71
  });
68
72
  }
69
73
  function providerIconName(provider) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/source-strip.tsx"],"sourcesContent":["import {useActiveWorkspace} from '@shipfox/client-auth';\nimport {useSourceConnectionsQuery} from '@shipfox/client-integrations';\nimport {StatusBadge} from '@shipfox/react-ui/badge';\nimport {Icon, type IconName} from '@shipfox/react-ui/icon';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Code, Text} from '@shipfox/react-ui/typography';\nimport type {DefinitionSyncSummary} from '#core/definition.js';\n\n/**\n * We cannot cheaply resolve `external_repository_id` → `owner/repo`\n * (no by-id endpoint; `listRepositories` is paginated by connection).\n * The strip surfaces the raw id as a `<Code>` chip with a tooltip carrying the\n * full string.\n */\nexport function SourceStrip({\n connectionId,\n externalRepositoryId,\n sync,\n isPending,\n}: {\n connectionId: string;\n externalRepositoryId: string;\n sync: DefinitionSyncSummary | null | undefined;\n isPending: boolean;\n}) {\n const workspace = useActiveWorkspace();\n const connectionsQuery = useSourceConnectionsQuery(workspace.id);\n const connection = connectionsQuery.data?.find((c) => c.id === connectionId);\n\n return (\n <section\n className=\"flex flex-col gap-inline rounded-8 border border-border-neutral-base bg-background-neutral-base px-row py-row sm:flex-row sm:items-center sm:justify-between\"\n aria-label=\"Project source\"\n >\n <div className=\"flex min-w-0 items-center gap-inline\">\n <Icon name={providerIconName(connection?.provider)} className=\"size-20 shrink-0\" />\n <div className=\"flex min-w-0 flex-col gap-tight sm:flex-row sm:items-center sm:gap-inline\">\n {connectionsQuery.isPending ? (\n <Skeleton className=\"h-16 w-160\" />\n ) : (\n <Text size=\"sm\" bold className=\"truncate\">\n {connection?.displayName ?? 'Connected source'}\n </Text>\n )}\n <Tooltip>\n <TooltipTrigger asChild>\n <Code variant=\"label\" className=\"truncate text-foreground-neutral-muted\">\n {externalRepositoryId}\n </Code>\n </TooltipTrigger>\n <TooltipContent>{externalRepositoryId}</TooltipContent>\n </Tooltip>\n </div>\n </div>\n <div className=\"shrink-0\">\n <SyncBadge sync={sync} isPending={isPending} />\n </div>\n </section>\n );\n}\n\nfunction providerIconName(provider: string | undefined): IconName {\n if (provider === 'github') return 'github' as IconName;\n return 'componentLine' as IconName;\n}\n\nfunction SyncBadge({\n sync,\n isPending,\n}: {\n sync: DefinitionSyncSummary | null | undefined;\n isPending: boolean;\n}) {\n if (isPending) return <StatusBadge variant=\"neutral\">Loading</StatusBadge>;\n if (sync === undefined) return <StatusBadge variant=\"neutral\">Unavailable</StatusBadge>;\n if (sync === null) return <StatusBadge variant=\"neutral\">No sync</StatusBadge>;\n\n const variantByStatus = {\n pending: 'neutral',\n syncing: 'info',\n succeeded: 'success',\n failed: 'error',\n } as const;\n\n return (\n <StatusBadge variant={variantByStatus[sync.status as keyof typeof variantByStatus]}>\n {sync.status}\n </StatusBadge>\n );\n}\n"],"names":["useActiveWorkspace","useSourceConnectionsQuery","StatusBadge","Icon","Skeleton","Tooltip","TooltipContent","TooltipTrigger","Code","Text","SourceStrip","connectionId","externalRepositoryId","sync","isPending","workspace","connectionsQuery","id","connection","data","find","c","section","className","aria-label","div","name","providerIconName","provider","size","bold","displayName","asChild","variant","SyncBadge","undefined","variantByStatus","pending","syncing","succeeded","failed","status"],"mappings":";AAAA,SAAQA,kBAAkB,QAAO,uBAAuB;AACxD,SAAQC,yBAAyB,QAAO,+BAA+B;AACvE,SAAQC,WAAW,QAAO,0BAA0B;AACpD,SAAQC,IAAI,QAAsB,yBAAyB;AAC3D,SAAQC,QAAQ,QAAO,6BAA6B;AACpD,SAAQC,OAAO,EAAEC,cAAc,EAAEC,cAAc,QAAO,4BAA4B;AAClF,SAAQC,IAAI,EAAEC,IAAI,QAAO,+BAA+B;AAGxD;;;;;CAKC,GACD,OAAO,SAASC,YAAY,EAC1BC,YAAY,EACZC,oBAAoB,EACpBC,IAAI,EACJC,SAAS,EAMV;IACC,MAAMC,YAAYf;IAClB,MAAMgB,mBAAmBf,0BAA0Bc,UAAUE,EAAE;IAC/D,MAAMC,aAAaF,iBAAiBG,IAAI,EAAEC,KAAK,CAACC,IAAMA,EAAEJ,EAAE,KAAKN;IAE/D,qBACE,MAACW;QACCC,WAAU;QACVC,cAAW;;0BAEX,MAACC;gBAAIF,WAAU;;kCACb,KAACpB;wBAAKuB,MAAMC,iBAAiBT,YAAYU;wBAAWL,WAAU;;kCAC9D,MAACE;wBAAIF,WAAU;;4BACZP,iBAAiBF,SAAS,iBACzB,KAACV;gCAASmB,WAAU;+CAEpB,KAACd;gCAAKoB,MAAK;gCAAKC,IAAI;gCAACP,WAAU;0CAC5BL,YAAYa,eAAe;;0CAGhC,MAAC1B;;kDACC,KAACE;wCAAeyB,OAAO;kDACrB,cAAA,KAACxB;4CAAKyB,SAAQ;4CAAQV,WAAU;sDAC7BX;;;kDAGL,KAACN;kDAAgBM;;;;;;;;0BAIvB,KAACa;gBAAIF,WAAU;0BACb,cAAA,KAACW;oBAAUrB,MAAMA;oBAAMC,WAAWA;;;;;AAI1C;AAEA,SAASa,iBAAiBC,QAA4B;IACpD,IAAIA,aAAa,UAAU,OAAO;IAClC,OAAO;AACT;AAEA,SAASM,UAAU,EACjBrB,IAAI,EACJC,SAAS,EAIV;IACC,IAAIA,WAAW,qBAAO,KAACZ;QAAY+B,SAAQ;kBAAU;;IACrD,IAAIpB,SAASsB,WAAW,qBAAO,KAACjC;QAAY+B,SAAQ;kBAAU;;IAC9D,IAAIpB,SAAS,MAAM,qBAAO,KAACX;QAAY+B,SAAQ;kBAAU;;IAEzD,MAAMG,kBAAkB;QACtBC,SAAS;QACTC,SAAS;QACTC,WAAW;QACXC,QAAQ;IACV;IAEA,qBACE,KAACtC;QAAY+B,SAASG,eAAe,CAACvB,KAAK4B,MAAM,CAAiC;kBAC/E5B,KAAK4B,MAAM;;AAGlB"}
1
+ {"version":3,"sources":["../../src/components/source-strip.tsx"],"sourcesContent":["import {useActiveWorkspace} from '@shipfox/client-auth';\nimport {useSourceConnectionsQuery} from '@shipfox/client-integrations';\nimport {StatusBadge} from '@shipfox/react-ui/badge';\nimport {Icon, type IconName} from '@shipfox/react-ui/icon';\nimport {Panel} from '@shipfox/react-ui/panel';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Code, Text} from '@shipfox/react-ui/typography';\nimport type {DefinitionSyncSummary} from '#core/definition.js';\n\n/**\n * We cannot cheaply resolve `external_repository_id` → `owner/repo`\n * (no by-id endpoint; `listRepositories` is paginated by connection).\n * The strip surfaces the raw id as a `<Code>` chip with a tooltip carrying the\n * full string.\n */\nexport function SourceStrip({\n connectionId,\n externalRepositoryId,\n sync,\n isPending,\n}: {\n connectionId: string;\n externalRepositoryId: string;\n sync: DefinitionSyncSummary | null | undefined;\n isPending: boolean;\n}) {\n const workspace = useActiveWorkspace();\n const connectionsQuery = useSourceConnectionsQuery(workspace.id);\n const connection = connectionsQuery.data?.find((c) => c.id === connectionId);\n\n return (\n <Panel\n asChild\n className=\"gap-inline px-row py-row sm:flex-row sm:items-center sm:justify-between\"\n >\n <section aria-label=\"Project source\">\n <div className=\"flex min-w-0 items-center gap-inline\">\n <Icon name={providerIconName(connection?.provider)} className=\"size-20 shrink-0\" />\n <div className=\"flex min-w-0 flex-col gap-tight sm:flex-row sm:items-center sm:gap-inline\">\n {connectionsQuery.isPending ? (\n <Skeleton className=\"h-16 w-160\" />\n ) : (\n <Text size=\"sm\" bold className=\"truncate\">\n {connection?.displayName ?? 'Connected source'}\n </Text>\n )}\n <Tooltip>\n <TooltipTrigger asChild>\n <Code variant=\"label\" className=\"truncate text-foreground-neutral-muted\">\n {externalRepositoryId}\n </Code>\n </TooltipTrigger>\n <TooltipContent>{externalRepositoryId}</TooltipContent>\n </Tooltip>\n </div>\n </div>\n <div className=\"shrink-0\">\n <SyncBadge sync={sync} isPending={isPending} />\n </div>\n </section>\n </Panel>\n );\n}\n\nfunction providerIconName(provider: string | undefined): IconName {\n if (provider === 'github') return 'github' as IconName;\n return 'componentLine' as IconName;\n}\n\nfunction SyncBadge({\n sync,\n isPending,\n}: {\n sync: DefinitionSyncSummary | null | undefined;\n isPending: boolean;\n}) {\n if (isPending) return <StatusBadge variant=\"neutral\">Loading</StatusBadge>;\n if (sync === undefined) return <StatusBadge variant=\"neutral\">Unavailable</StatusBadge>;\n if (sync === null) return <StatusBadge variant=\"neutral\">No sync</StatusBadge>;\n\n const variantByStatus = {\n pending: 'neutral',\n syncing: 'info',\n succeeded: 'success',\n failed: 'error',\n } as const;\n\n return (\n <StatusBadge variant={variantByStatus[sync.status as keyof typeof variantByStatus]}>\n {sync.status}\n </StatusBadge>\n );\n}\n"],"names":["useActiveWorkspace","useSourceConnectionsQuery","StatusBadge","Icon","Panel","Skeleton","Tooltip","TooltipContent","TooltipTrigger","Code","Text","SourceStrip","connectionId","externalRepositoryId","sync","isPending","workspace","connectionsQuery","id","connection","data","find","c","asChild","className","section","aria-label","div","name","providerIconName","provider","size","bold","displayName","variant","SyncBadge","undefined","variantByStatus","pending","syncing","succeeded","failed","status"],"mappings":";AAAA,SAAQA,kBAAkB,QAAO,uBAAuB;AACxD,SAAQC,yBAAyB,QAAO,+BAA+B;AACvE,SAAQC,WAAW,QAAO,0BAA0B;AACpD,SAAQC,IAAI,QAAsB,yBAAyB;AAC3D,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,QAAQ,QAAO,6BAA6B;AACpD,SAAQC,OAAO,EAAEC,cAAc,EAAEC,cAAc,QAAO,4BAA4B;AAClF,SAAQC,IAAI,EAAEC,IAAI,QAAO,+BAA+B;AAGxD;;;;;CAKC,GACD,OAAO,SAASC,YAAY,EAC1BC,YAAY,EACZC,oBAAoB,EACpBC,IAAI,EACJC,SAAS,EAMV;IACC,MAAMC,YAAYhB;IAClB,MAAMiB,mBAAmBhB,0BAA0Be,UAAUE,EAAE;IAC/D,MAAMC,aAAaF,iBAAiBG,IAAI,EAAEC,KAAK,CAACC,IAAMA,EAAEJ,EAAE,KAAKN;IAE/D,qBACE,KAACR;QACCmB,OAAO;QACPC,WAAU;kBAEV,cAAA,MAACC;YAAQC,cAAW;;8BAClB,MAACC;oBAAIH,WAAU;;sCACb,KAACrB;4BAAKyB,MAAMC,iBAAiBV,YAAYW;4BAAWN,WAAU;;sCAC9D,MAACG;4BAAIH,WAAU;;gCACZP,iBAAiBF,SAAS,iBACzB,KAACV;oCAASmB,WAAU;mDAEpB,KAACd;oCAAKqB,MAAK;oCAAKC,IAAI;oCAACR,WAAU;8CAC5BL,YAAYc,eAAe;;8CAGhC,MAAC3B;;sDACC,KAACE;4CAAee,OAAO;sDACrB,cAAA,KAACd;gDAAKyB,SAAQ;gDAAQV,WAAU;0DAC7BX;;;sDAGL,KAACN;sDAAgBM;;;;;;;;8BAIvB,KAACc;oBAAIH,WAAU;8BACb,cAAA,KAACW;wBAAUrB,MAAMA;wBAAMC,WAAWA;;;;;;AAK5C;AAEA,SAASc,iBAAiBC,QAA4B;IACpD,IAAIA,aAAa,UAAU,OAAO;IAClC,OAAO;AACT;AAEA,SAASK,UAAU,EACjBrB,IAAI,EACJC,SAAS,EAIV;IACC,IAAIA,WAAW,qBAAO,KAACb;QAAYgC,SAAQ;kBAAU;;IACrD,IAAIpB,SAASsB,WAAW,qBAAO,KAAClC;QAAYgC,SAAQ;kBAAU;;IAC9D,IAAIpB,SAAS,MAAM,qBAAO,KAACZ;QAAYgC,SAAQ;kBAAU;;IAEzD,MAAMG,kBAAkB;QACtBC,SAAS;QACTC,SAAS;QACTC,WAAW;QACXC,QAAQ;IACV;IAEA,qBACE,KAACvC;QAAYgC,SAASG,eAAe,CAACvB,KAAK4B,MAAM,CAAiC;kBAC/E5B,KAAK4B,MAAM;;AAGlB"}
@@ -1 +1 @@
1
- {"version":3,"file":"create-project-page.d.ts","sourceRoot":"","sources":["../../src/pages/create-project-page.tsx"],"names":[],"mappings":"AAkCA,wBAAgB,iBAAiB,gCA+WhC"}
1
+ {"version":3,"file":"create-project-page.d.ts","sourceRoot":"","sources":["../../src/pages/create-project-page.tsx"],"names":[],"mappings":"AAoCA,wBAAgB,iBAAiB,gCAyXhC"}
@@ -7,7 +7,9 @@ import { displayNameFieldError, SlugField } from '@shipfox/client-ui';
7
7
  import { Button } from '@shipfox/react-ui/button';
8
8
  import { Callout } from '@shipfox/react-ui/callout';
9
9
  import { FormField, FormFieldInput, fieldError } from '@shipfox/react-ui/form-field';
10
+ import { Input } from '@shipfox/react-ui/input';
10
11
  import { FullPageLoader } from '@shipfox/react-ui/loader';
12
+ import { Panel, PanelActions, PanelBody, PanelHeader, PanelTitle } from '@shipfox/react-ui/panel';
11
13
  import { toast } from '@shipfox/react-ui/toast';
12
14
  import { Header, Text } from '@shipfox/react-ui/typography';
13
15
  import { useForm } from '@tanstack/react-form';
@@ -185,20 +187,10 @@ export function CreateProjectPage() {
185
187
  return /*#__PURE__*/ _jsxs("div", {
186
188
  className: "flex w-full flex-col gap-section",
187
189
  children: [
188
- /*#__PURE__*/ _jsxs("header", {
189
- className: "flex flex-col gap-inline",
190
- children: [
191
- /*#__PURE__*/ _jsx(Header, {
192
- id: "create-project-title",
193
- variant: "h1",
194
- children: "Create project"
195
- }),
196
- /*#__PURE__*/ _jsx(Text, {
197
- size: "sm",
198
- className: "text-foreground-neutral-muted",
199
- children: "A Shipfox project starts from a Git repository. Choose the repository Shipfox should track, then give the project a name."
200
- })
201
- ]
190
+ /*#__PURE__*/ _jsx(Header, {
191
+ id: "create-project-title",
192
+ variant: "h1",
193
+ children: "Create project"
202
194
  }),
203
195
  /*#__PURE__*/ _jsx(ModelProviderReminderBanner, {
204
196
  workspaceId: workspace.id
@@ -237,184 +229,178 @@ export function CreateProjectPage() {
237
229
  /*#__PURE__*/ _jsxs("div", {
238
230
  className: "flex min-w-0 flex-col gap-region",
239
231
  children: [
240
- /*#__PURE__*/ _jsxs("section", {
241
- className: "flex flex-col gap-group",
232
+ connections.length > 0 ? /*#__PURE__*/ _jsx("section", {
242
233
  "aria-label": "Source integration",
243
- children: [
244
- /*#__PURE__*/ _jsxs("div", {
245
- className: "flex items-start justify-between gap-group",
246
- children: [
247
- /*#__PURE__*/ _jsxs("div", {
248
- className: "flex flex-col gap-tight",
249
- children: [
250
- /*#__PURE__*/ _jsx(Header, {
251
- variant: "h3",
252
- children: "Source integration"
253
- }),
254
- /*#__PURE__*/ _jsx(Text, {
234
+ children: /*#__PURE__*/ _jsxs(Panel, {
235
+ children: [
236
+ /*#__PURE__*/ _jsxs(PanelHeader, {
237
+ children: [
238
+ /*#__PURE__*/ _jsx(PanelTitle, {
239
+ children: "Source integration"
240
+ }),
241
+ connections.length === 1 ? /*#__PURE__*/ _jsx(PanelActions, {
242
+ children: /*#__PURE__*/ _jsx(Button, {
243
+ asChild: true,
244
+ variant: "transparent",
255
245
  size: "sm",
256
- className: "text-foreground-neutral-muted",
257
- children: "Choose the integration that can access the repository."
246
+ className: "shrink-0",
247
+ children: /*#__PURE__*/ _jsx(Link, {
248
+ to: "/w/$workspaceSlug/integrations",
249
+ params: {
250
+ workspaceSlug: workspace.slug
251
+ },
252
+ children: "Add another integration"
253
+ })
258
254
  })
259
- ]
260
- }),
261
- connections.length === 1 ? /*#__PURE__*/ _jsx(Button, {
262
- asChild: true,
263
- variant: "transparent",
264
- size: "sm",
265
- className: "shrink-0",
266
- children: /*#__PURE__*/ _jsx(Link, {
267
- to: "/w/$workspaceSlug/integrations",
268
- params: {
269
- workspaceSlug: workspace.slug
270
- },
271
- children: "Add another integration"
272
- })
273
- }) : null
274
- ]
275
- }),
276
- connections.length > 0 ? /*#__PURE__*/ _jsx(ConnectionPicker, {
277
- connections: connections,
278
- selectedConnectionId: effectiveSelectedConnectionId,
279
- onSelect: selectConnection
280
- }) : null
281
- ]
282
- }),
283
- showRepoPicker ? /*#__PURE__*/ _jsxs("section", {
284
- className: "flex flex-col gap-group",
255
+ }) : null
256
+ ]
257
+ }),
258
+ /*#__PURE__*/ _jsx(PanelBody, {
259
+ children: /*#__PURE__*/ _jsx(ConnectionPicker, {
260
+ connections: connections,
261
+ selectedConnectionId: effectiveSelectedConnectionId,
262
+ onSelect: selectConnection
263
+ })
264
+ })
265
+ ]
266
+ })
267
+ }) : null,
268
+ showRepoPicker ? /*#__PURE__*/ _jsx("section", {
285
269
  "aria-label": "Repository",
286
- children: [
287
- /*#__PURE__*/ _jsxs("div", {
288
- className: "flex flex-col gap-tight",
289
- children: [
290
- /*#__PURE__*/ _jsx(Header, {
291
- variant: "h3",
292
- children: "Repository"
293
- }),
294
- /*#__PURE__*/ _jsx(Text, {
295
- size: "sm",
296
- className: "text-foreground-neutral-muted",
297
- children: "Select the repository this project tracks."
270
+ children: /*#__PURE__*/ _jsxs(Panel, {
271
+ children: [
272
+ /*#__PURE__*/ _jsxs(PanelHeader, {
273
+ className: "flex-wrap",
274
+ children: [
275
+ /*#__PURE__*/ _jsx(PanelTitle, {
276
+ children: "Repository"
277
+ }),
278
+ /*#__PURE__*/ _jsx(PanelActions, {
279
+ className: "min-w-0 max-[640px]:ml-0 max-[640px]:basis-full",
280
+ children: /*#__PURE__*/ _jsx(Input, {
281
+ type: "search",
282
+ placeholder: "Search repositories…",
283
+ "aria-label": "Search repositories",
284
+ value: repoFilter,
285
+ onChange: (event)=>setRepoFilter(event.target.value),
286
+ className: "w-full max-w-[320px]"
287
+ })
288
+ })
289
+ ]
290
+ }),
291
+ /*#__PURE__*/ _jsx(PanelBody, {
292
+ children: /*#__PURE__*/ _jsx(RepositoryPicker, {
293
+ repositories: repositories,
294
+ selectedRepositoryId: selectedRepositoryId,
295
+ onSelect: setSelectedRepositoryId,
296
+ isLoading: repositoriesQuery.isPending,
297
+ isFetchingNextPage: repositoriesQuery.isFetchingNextPage,
298
+ hasNextPage: repositoriesQuery.hasNextPage,
299
+ onLoadMore: ()=>repositoriesQuery.fetchNextPage(),
300
+ emptyMessage: filteredEmptyMessage
298
301
  })
299
- ]
300
- }),
301
- /*#__PURE__*/ _jsx(RepositoryPicker, {
302
- repositories: repositories,
303
- selectedRepositoryId: selectedRepositoryId,
304
- onSelect: setSelectedRepositoryId,
305
- isLoading: repositoriesQuery.isPending,
306
- isFetchingNextPage: repositoriesQuery.isFetchingNextPage,
307
- hasNextPage: repositoriesQuery.hasNextPage,
308
- onLoadMore: ()=>repositoriesQuery.fetchNextPage(),
309
- emptyMessage: filteredEmptyMessage,
310
- searchValue: repoFilter,
311
- onSearchChange: setRepoFilter
312
- })
313
- ]
302
+ })
303
+ ]
304
+ })
314
305
  }) : null
315
306
  ]
316
307
  }),
317
308
  /*#__PURE__*/ _jsx("aside", {
318
309
  className: "lg:sticky lg:top-32",
319
- children: /*#__PURE__*/ _jsxs("div", {
320
- className: "flex flex-col gap-group rounded-8 border border-border-neutral-base bg-background-neutral-base p-panel",
310
+ children: /*#__PURE__*/ _jsxs(Panel, {
321
311
  children: [
322
- /*#__PURE__*/ _jsxs("div", {
323
- className: "flex flex-col gap-tight",
324
- children: [
325
- /*#__PURE__*/ _jsx(Header, {
326
- variant: "h3",
327
- children: "Project details"
328
- }),
329
- /*#__PURE__*/ _jsx(Text, {
330
- size: "sm",
331
- className: "text-foreground-neutral-muted",
332
- children: "Confirm the source and create the project."
333
- })
334
- ]
335
- }),
336
- formError ? /*#__PURE__*/ _jsx(Callout, {
337
- role: "alert",
338
- type: "error",
339
- children: /*#__PURE__*/ _jsx("div", {
340
- ref: errorRef,
341
- tabIndex: -1,
342
- children: formError
312
+ /*#__PURE__*/ _jsx(PanelHeader, {
313
+ children: /*#__PURE__*/ _jsx(PanelTitle, {
314
+ children: "Project details"
343
315
  })
344
- }) : null,
345
- /*#__PURE__*/ _jsx(ProjectSummary, {
346
- connection: selectedConnection,
347
- repositoryName: selectedRepository?.fullName
348
316
  }),
349
- /*#__PURE__*/ _jsx(form.Field, {
350
- name: "name",
351
- validators: {
352
- onBlur: ({ value })=>displayNameFieldError(value, 'Project name', createProjectBodySchema.shape.name),
353
- onSubmit: ({ value })=>displayNameFieldError(value, 'Project name', createProjectBodySchema.shape.name)
354
- },
355
- children: (field)=>/*#__PURE__*/ _jsx(FormField, {
356
- label: "Project name",
357
- id: "project-name",
358
- error: fieldError(field),
359
- children: /*#__PURE__*/ _jsx(FormFieldInput, {
360
- name: "name",
361
- type: "text",
362
- value: field.state.value,
363
- onChange: (event)=>{
364
- const nextName = event.target.value;
365
- setNameTouched(true);
366
- field.handleChange(nextName);
367
- if (!slugManuallyEdited) {
368
- setSlugCheckEnabled(true);
369
- setSlugConflict(false);
370
- form.setFieldValue('slug', slugifyName(nextName, {
371
- fallback: 'project'
372
- }));
373
- }
374
- },
375
- onBlur: field.handleBlur,
376
- placeholder: "Platform"
317
+ /*#__PURE__*/ _jsxs(PanelBody, {
318
+ className: "gap-group p-panel",
319
+ children: [
320
+ formError ? /*#__PURE__*/ _jsx(Callout, {
321
+ role: "alert",
322
+ type: "error",
323
+ children: /*#__PURE__*/ _jsx("div", {
324
+ ref: errorRef,
325
+ tabIndex: -1,
326
+ children: formError
377
327
  })
378
- })
379
- }),
380
- /*#__PURE__*/ _jsx(form.Field, {
381
- name: "slug",
382
- validators: {
383
- onBlur: createProjectBodySchema.shape.slug,
384
- onSubmit: createProjectBodySchema.shape.slug
385
- },
386
- children: (field)=>/*#__PURE__*/ _jsx(SlugField, {
387
- id: "project-slug",
388
- label: "Project slug",
328
+ }) : null,
329
+ /*#__PURE__*/ _jsx(ProjectSummary, {
330
+ connection: selectedConnection,
331
+ repositoryName: selectedRepository?.fullName
332
+ }),
333
+ /*#__PURE__*/ _jsx(form.Field, {
334
+ name: "name",
335
+ validators: {
336
+ onBlur: ({ value })=>displayNameFieldError(value, 'Project name', createProjectBodySchema.shape.name),
337
+ onSubmit: ({ value })=>displayNameFieldError(value, 'Project name', createProjectBodySchema.shape.name)
338
+ },
339
+ children: (field)=>/*#__PURE__*/ _jsx(FormField, {
340
+ label: "Project name",
341
+ id: "project-name",
342
+ error: fieldError(field),
343
+ children: /*#__PURE__*/ _jsx(FormFieldInput, {
344
+ name: "name",
345
+ type: "text",
346
+ value: field.state.value,
347
+ onChange: (event)=>{
348
+ const nextName = event.target.value;
349
+ setNameTouched(true);
350
+ field.handleChange(nextName);
351
+ if (!slugManuallyEdited) {
352
+ setSlugCheckEnabled(true);
353
+ setSlugConflict(false);
354
+ form.setFieldValue('slug', slugifyName(nextName, {
355
+ fallback: 'project'
356
+ }));
357
+ }
358
+ },
359
+ onBlur: field.handleBlur,
360
+ placeholder: "Platform"
361
+ })
362
+ })
363
+ }),
364
+ /*#__PURE__*/ _jsx(form.Field, {
389
365
  name: "slug",
390
- value: field.state.value,
391
- onChange: (value)=>{
392
- setSlugManuallyEdited(true);
393
- setSlugCheckEnabled(true);
394
- setSlugConflict(false);
395
- field.handleChange(value);
366
+ validators: {
367
+ onBlur: createProjectBodySchema.shape.slug,
368
+ onSubmit: createProjectBodySchema.shape.slug
396
369
  },
397
- onBlur: field.handleBlur,
398
- error: slugConflict ? 'This project slug is already in use.' : fieldError(field),
399
- description: /*#__PURE__*/ _jsx("span", {
400
- className: "font-code",
401
- children: `/w/${workspace.slug}/p/${field.state.value}`
402
- }),
403
- placeholder: "platform",
404
- className: "font-code",
405
- checkEnabled: slugCheckEnabled,
406
- debounceMs: 0,
407
- isValid: isSlugValid,
408
- checkAvailability: checkProjectSlugAvailability
370
+ children: (field)=>/*#__PURE__*/ _jsx(SlugField, {
371
+ id: "project-slug",
372
+ label: "Project slug",
373
+ name: "slug",
374
+ value: field.state.value,
375
+ onChange: (value)=>{
376
+ setSlugManuallyEdited(true);
377
+ setSlugCheckEnabled(true);
378
+ setSlugConflict(false);
379
+ field.handleChange(value);
380
+ },
381
+ onBlur: field.handleBlur,
382
+ error: slugConflict ? 'This project slug is already in use.' : fieldError(field),
383
+ description: /*#__PURE__*/ _jsx("span", {
384
+ className: "font-code",
385
+ children: `/w/${workspace.slug}/p/${field.state.value}`
386
+ }),
387
+ placeholder: "platform",
388
+ className: "font-code",
389
+ checkEnabled: slugCheckEnabled,
390
+ debounceMs: 0,
391
+ isValid: isSlugValid,
392
+ checkAvailability: checkProjectSlugAvailability
393
+ })
394
+ }),
395
+ /*#__PURE__*/ _jsx(Button, {
396
+ type: "submit",
397
+ iconRight: "chevronRight",
398
+ isLoading: createProject.isPending,
399
+ disabled: !selectedConnection || !selectedRepository,
400
+ className: "w-full",
401
+ children: "Create project"
409
402
  })
410
- }),
411
- /*#__PURE__*/ _jsx(Button, {
412
- type: "submit",
413
- iconRight: "chevronRight",
414
- isLoading: createProject.isPending,
415
- disabled: !selectedConnection || !selectedRepository,
416
- className: "w-full",
417
- children: "Create project"
403
+ ]
418
404
  })
419
405
  ]
420
406
  })