@shipfox/client-projects 4.0.0 → 6.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +78 -0
- package/dist/chrome.d.ts.map +1 -1
- package/dist/chrome.js +7 -10
- package/dist/chrome.js.map +1 -1
- package/dist/components/model-provider-reminder-banner.d.ts.map +1 -1
- package/dist/components/model-provider-reminder-banner.js +1 -1
- package/dist/components/model-provider-reminder-banner.js.map +1 -1
- package/dist/components/source-strip.d.ts +2 -2
- package/dist/components/source-strip.d.ts.map +1 -1
- package/dist/components/source-strip.js +2 -2
- package/dist/components/source-strip.js.map +1 -1
- package/dist/core/definition.d.ts +32 -0
- package/dist/core/definition.d.ts.map +1 -0
- package/dist/core/definition.js +3 -0
- package/dist/core/definition.js.map +1 -0
- package/dist/core/project.d.ts +26 -0
- package/dist/core/project.d.ts.map +1 -0
- package/dist/core/project.js +12 -0
- package/dist/core/project.js.map +1 -0
- package/dist/feature.d.ts +8 -10
- package/dist/feature.d.ts.map +1 -1
- package/dist/feature.js +11 -22
- package/dist/feature.js.map +1 -1
- package/dist/hooks/api/definitions.d.ts +12 -88
- package/dist/hooks/api/definitions.d.ts.map +1 -1
- package/dist/hooks/api/definitions.js +18 -10
- package/dist/hooks/api/definitions.js.map +1 -1
- package/dist/hooks/api/mappers.d.ts +17 -0
- package/dist/hooks/api/mappers.d.ts.map +1 -0
- package/dist/hooks/api/mappers.js +56 -0
- package/dist/hooks/api/mappers.js.map +1 -0
- package/dist/hooks/api/projects.d.ts +19 -81
- package/dist/hooks/api/projects.d.ts.map +1 -1
- package/dist/hooks/api/projects.js +72 -18
- package/dist/hooks/api/projects.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/pages/create-project-page.d.ts.map +1 -1
- package/dist/pages/create-project-page.js +12 -37
- package/dist/pages/create-project-page.js.map +1 -1
- package/dist/pages/create-project-page.stories.d.ts.map +1 -1
- package/dist/pages/create-project-page.stories.js +4 -5
- package/dist/pages/create-project-page.stories.js.map +1 -1
- package/dist/pages/home-router.d.ts +4 -1
- package/dist/pages/home-router.d.ts.map +1 -1
- package/dist/pages/home-router.js +4 -2
- package/dist/pages/home-router.js.map +1 -1
- package/dist/pages/projects-hub-page.d.ts +3 -1
- package/dist/pages/projects-hub-page.d.ts.map +1 -1
- package/dist/pages/projects-hub-page.js +26 -30
- package/dist/pages/projects-hub-page.js.map +1 -1
- package/dist/routes/home.d.ts +3 -2
- package/dist/routes/home.d.ts.map +1 -1
- package/dist/routes/home.js +7 -2
- package/dist/routes/home.js.map +1 -1
- package/dist/routes/inputs.d.ts +6 -0
- package/dist/routes/inputs.d.ts.map +1 -0
- package/dist/routes/inputs.js +14 -0
- package/dist/routes/inputs.js.map +1 -0
- package/dist/routes/search.d.ts +5 -0
- package/dist/routes/search.d.ts.map +1 -0
- package/dist/routes/search.js +8 -0
- package/dist/routes/search.js.map +1 -0
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +14 -17
- package/src/chrome.tsx +11 -6
- package/src/components/model-provider-reminder-banner.tsx +1 -3
- package/src/components/project-switcher.test.tsx +2 -1
- package/src/components/source-strip.tsx +5 -5
- package/src/core/definition.ts +31 -0
- package/src/core/project.ts +47 -0
- package/src/feature.ts +13 -23
- package/src/hooks/api/definitions.ts +54 -19
- package/src/hooks/api/mappers.ts +67 -0
- package/src/hooks/api/projects.test.ts +11 -4
- package/src/hooks/api/projects.ts +125 -28
- package/src/index.ts +10 -6
- package/src/pages/create-project-page.stories.tsx +7 -5
- package/src/pages/create-project-page.test.tsx +3 -1
- package/src/pages/create-project-page.tsx +16 -51
- package/src/pages/home-router.tsx +3 -2
- package/src/pages/projects-hub-page.test.tsx +13 -8
- package/src/pages/projects-hub-page.tsx +24 -34
- package/src/routes/home.tsx +6 -2
- package/src/routes/inputs.test.ts +14 -0
- package/src/routes/inputs.ts +15 -0
- package/src/routes/search.ts +8 -0
- package/test/pages.tsx +2 -17
- package/tsconfig.build.tsbuildinfo +1 -1
- package/dist/components/workspace-setup-guard.d.ts +0 -9
- package/dist/components/workspace-setup-guard.d.ts.map +0 -1
- package/dist/components/workspace-setup-guard.js +0 -160
- package/dist/components/workspace-setup-guard.js.map +0 -1
- package/dist/pages/project-workflows-page.d.ts +0 -4
- package/dist/pages/project-workflows-page.d.ts.map +0 -1
- package/dist/pages/project-workflows-page.js +0 -481
- package/dist/pages/project-workflows-page.js.map +0 -1
- package/dist/routes/workflows.d.ts +0 -5
- package/dist/routes/workflows.d.ts.map +0 -1
- package/dist/routes/workflows.js +0 -16
- package/dist/routes/workflows.js.map +0 -1
- package/src/components/workspace-setup-guard.test.tsx +0 -534
- package/src/components/workspace-setup-guard.tsx +0 -185
- package/src/pages/project-workflows-page.test.tsx +0 -258
- package/src/pages/project-workflows-page.tsx +0 -445
- package/src/routes/workflows.tsx +0 -10
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shipfox/client-projects",
|
|
3
3
|
"license": "MIT",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "6.0.1",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/ShipfoxHQ/shipfox.git",
|
|
@@ -10,10 +10,6 @@
|
|
|
10
10
|
"type": "module",
|
|
11
11
|
"main": "dist/index.js",
|
|
12
12
|
"types": "dist/index.d.ts",
|
|
13
|
-
"imports": {
|
|
14
|
-
"#*": "./dist/*",
|
|
15
|
-
"#test/*": "./test/*"
|
|
16
|
-
},
|
|
17
13
|
"exports": {
|
|
18
14
|
".": {
|
|
19
15
|
"types": "./dist/index.d.ts",
|
|
@@ -31,18 +27,16 @@
|
|
|
31
27
|
"dependencies": {
|
|
32
28
|
"@swc/helpers": "^0.5.17",
|
|
33
29
|
"@tanstack/react-form": "^1.32.0",
|
|
34
|
-
"@shipfox/api-definitions-dto": "
|
|
35
|
-
"@shipfox/api-projects-dto": "
|
|
36
|
-
"@shipfox/api
|
|
37
|
-
"@shipfox/
|
|
38
|
-
"@shipfox/
|
|
39
|
-
"@shipfox/client-
|
|
40
|
-
"@shipfox/client-
|
|
41
|
-
"@shipfox/client-shell": "
|
|
42
|
-
"@shipfox/client-
|
|
43
|
-
"@shipfox/
|
|
44
|
-
"@shipfox/client-ui": "4.0.0",
|
|
45
|
-
"@shipfox/react-ui": "0.3.5"
|
|
30
|
+
"@shipfox/api-definitions-dto": "9.0.1",
|
|
31
|
+
"@shipfox/api-projects-dto": "9.0.1",
|
|
32
|
+
"@shipfox/client-api": "6.0.1",
|
|
33
|
+
"@shipfox/client-agent": "6.0.1",
|
|
34
|
+
"@shipfox/api-integration-core-dto": "9.0.1",
|
|
35
|
+
"@shipfox/client-auth": "6.0.1",
|
|
36
|
+
"@shipfox/client-integrations": "6.0.1",
|
|
37
|
+
"@shipfox/client-shell": "6.0.1",
|
|
38
|
+
"@shipfox/client-ui": "6.0.1",
|
|
39
|
+
"@shipfox/react-ui": "0.3.6"
|
|
46
40
|
},
|
|
47
41
|
"peerDependencies": {
|
|
48
42
|
"@tanstack/react-query": "^5.101.0",
|
|
@@ -51,6 +45,9 @@
|
|
|
51
45
|
"react": "^19.0.0",
|
|
52
46
|
"react-dom": "^19.0.0"
|
|
53
47
|
},
|
|
48
|
+
"imports": {
|
|
49
|
+
"#*": "./dist/*"
|
|
50
|
+
},
|
|
54
51
|
"scripts": {
|
|
55
52
|
"build": "shipfox-swc",
|
|
56
53
|
"check": "shipfox-biome-check",
|
package/src/chrome.tsx
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
parseWorkspaceProjectParams,
|
|
3
|
+
useActiveWorkspace,
|
|
4
|
+
useRouteParams,
|
|
5
|
+
} from '@shipfox/client-shell/runtime';
|
|
6
|
+
import {Outlet, useNavigate} from '@tanstack/react-router';
|
|
3
7
|
import {useEffect} from 'react';
|
|
4
8
|
import {ProjectCrumb} from '#components/project-crumb.js';
|
|
5
9
|
import {useProjectQuery} from '#hooks/api/projects.js';
|
|
10
|
+
import {projectRouteParams} from './routes/inputs.js';
|
|
6
11
|
|
|
7
12
|
export function ProjectBreadcrumb() {
|
|
8
13
|
const workspace = useActiveWorkspace();
|
|
9
|
-
const {pid} =
|
|
14
|
+
const {pid} = useRouteParams(parseWorkspaceProjectParams);
|
|
10
15
|
const project = useProjectQuery(pid).data;
|
|
11
16
|
return (
|
|
12
17
|
<ProjectCrumb workspaceId={workspace.id} projectId={project?.id} projectName={project?.name} />
|
|
@@ -14,13 +19,13 @@ export function ProjectBreadcrumb() {
|
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
export function ProjectLayoutGuard() {
|
|
17
|
-
const {wid, pid} =
|
|
22
|
+
const {wid, pid} = useRouteParams(projectRouteParams);
|
|
18
23
|
const navigate = useNavigate();
|
|
19
24
|
const project = useProjectQuery(pid).data;
|
|
20
25
|
useEffect(() => {
|
|
21
|
-
if (project && project.
|
|
26
|
+
if (project && project.workspaceId !== wid)
|
|
22
27
|
void navigate({to: '/workspaces/$wid', params: {wid}, replace: true});
|
|
23
28
|
}, [navigate, project, wid]);
|
|
24
|
-
if (project && project.
|
|
29
|
+
if (project && project.workspaceId !== wid) return null;
|
|
25
30
|
return <Outlet />;
|
|
26
31
|
}
|
|
@@ -17,9 +17,7 @@ export function ModelProviderReminderBanner({workspaceId}: {workspaceId: string}
|
|
|
17
17
|
const [dismissed, setDismissed] = useState(() => isReminderDismissed(workspaceId));
|
|
18
18
|
const configs = configsQuery.data?.configs;
|
|
19
19
|
const unconfigured =
|
|
20
|
-
Array.isArray(configs) &&
|
|
21
|
-
configs.length === 0 &&
|
|
22
|
-
configsQuery.data?.default_provider_id === null;
|
|
20
|
+
Array.isArray(configs) && configs.length === 0 && configsQuery.data?.defaultProviderId === null;
|
|
23
21
|
|
|
24
22
|
if (!unconfigured || dismissed) return null;
|
|
25
23
|
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
RouterProvider,
|
|
9
9
|
} from '@tanstack/react-router';
|
|
10
10
|
import {fireEvent, render, screen} from '@testing-library/react';
|
|
11
|
+
import {toProject} from '#hooks/api/mappers.js';
|
|
11
12
|
import {projectsQueryKeys} from '#hooks/api/projects.js';
|
|
12
13
|
import {PROJECT_TEST_WID} from '#test/pages.js';
|
|
13
14
|
import {ProjectSwitcher} from './project-switcher.js';
|
|
@@ -50,7 +51,7 @@ function renderProjectSwitcher({
|
|
|
50
51
|
defaultOptions: {queries: {retry: false, staleTime: Number.POSITIVE_INFINITY}},
|
|
51
52
|
});
|
|
52
53
|
queryClient.setQueryData(projectsQueryKeys.list(PROJECT_TEST_WID), {
|
|
53
|
-
pages: [{projects,
|
|
54
|
+
pages: [{projects: projects.map(toProject), nextCursor: null}],
|
|
54
55
|
pageParams: [undefined],
|
|
55
56
|
});
|
|
56
57
|
const rootRoute = createRootRoute({component: Outlet});
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type {DefinitionSyncSummaryDto} from '@shipfox/api-definitions-dto';
|
|
2
1
|
import {useActiveWorkspace} from '@shipfox/client-auth';
|
|
3
2
|
import {useSourceConnectionsQuery} from '@shipfox/client-integrations';
|
|
4
3
|
import {StatusBadge} from '@shipfox/react-ui/badge';
|
|
@@ -6,6 +5,7 @@ import {Icon, type IconName} from '@shipfox/react-ui/icon';
|
|
|
6
5
|
import {Skeleton} from '@shipfox/react-ui/skeleton';
|
|
7
6
|
import {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';
|
|
8
7
|
import {Code, Text} from '@shipfox/react-ui/typography';
|
|
8
|
+
import type {DefinitionSyncSummary} from '#core/definition.js';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* We cannot cheaply resolve `external_repository_id` → `owner/repo`
|
|
@@ -21,12 +21,12 @@ export function SourceStrip({
|
|
|
21
21
|
}: {
|
|
22
22
|
connectionId: string;
|
|
23
23
|
externalRepositoryId: string;
|
|
24
|
-
sync:
|
|
24
|
+
sync: DefinitionSyncSummary | null | undefined;
|
|
25
25
|
isPending: boolean;
|
|
26
26
|
}) {
|
|
27
27
|
const workspace = useActiveWorkspace();
|
|
28
28
|
const connectionsQuery = useSourceConnectionsQuery(workspace.id);
|
|
29
|
-
const connection = connectionsQuery.data?.
|
|
29
|
+
const connection = connectionsQuery.data?.find((c) => c.id === connectionId);
|
|
30
30
|
|
|
31
31
|
return (
|
|
32
32
|
<section
|
|
@@ -40,7 +40,7 @@ export function SourceStrip({
|
|
|
40
40
|
<Skeleton className="h-16 w-160" />
|
|
41
41
|
) : (
|
|
42
42
|
<Text size="sm" bold className="truncate">
|
|
43
|
-
{connection?.
|
|
43
|
+
{connection?.displayName ?? 'Connected source'}
|
|
44
44
|
</Text>
|
|
45
45
|
)}
|
|
46
46
|
<Tooltip>
|
|
@@ -69,7 +69,7 @@ function SyncBadge({
|
|
|
69
69
|
sync,
|
|
70
70
|
isPending,
|
|
71
71
|
}: {
|
|
72
|
-
sync:
|
|
72
|
+
sync: DefinitionSyncSummary | null | undefined;
|
|
73
73
|
isPending: boolean;
|
|
74
74
|
}) {
|
|
75
75
|
if (isPending) return <StatusBadge variant="neutral">Loading</StatusBadge>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface Definition {
|
|
2
|
+
id: string;
|
|
3
|
+
projectId: string;
|
|
4
|
+
configPath: string | null;
|
|
5
|
+
source: 'manual' | 'vcs';
|
|
6
|
+
sha: string | null;
|
|
7
|
+
ref: string | null;
|
|
8
|
+
name: string;
|
|
9
|
+
workflowDocument: unknown;
|
|
10
|
+
workflowModel: unknown;
|
|
11
|
+
manualTrigger: {name: string} | null;
|
|
12
|
+
fetchedAt: string;
|
|
13
|
+
createdAt: string;
|
|
14
|
+
updatedAt: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface DefinitionSyncSummary {
|
|
18
|
+
ref: string | null;
|
|
19
|
+
status: 'pending' | 'syncing' | 'succeeded' | 'failed';
|
|
20
|
+
lastSyncAt: string;
|
|
21
|
+
startedAt: string | null;
|
|
22
|
+
finishedAt: string | null;
|
|
23
|
+
lastErrorCode: string | null;
|
|
24
|
+
lastErrorMessage: string | null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface DefinitionList {
|
|
28
|
+
definitions: Definition[];
|
|
29
|
+
sync: DefinitionSyncSummary | null;
|
|
30
|
+
nextCursor: string | null;
|
|
31
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export interface ProjectSource {
|
|
2
|
+
connectionId: string;
|
|
3
|
+
externalRepositoryId: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface Project {
|
|
7
|
+
id: string;
|
|
8
|
+
workspaceId: string;
|
|
9
|
+
name: string;
|
|
10
|
+
source: ProjectSource;
|
|
11
|
+
createdAt: string;
|
|
12
|
+
updatedAt: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ProjectList {
|
|
16
|
+
projects: Project[];
|
|
17
|
+
nextCursor: string | null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface CreateProjectCommand {
|
|
21
|
+
workspaceId: string;
|
|
22
|
+
name: string;
|
|
23
|
+
source: ProjectSource;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const REPOSITORY_NAME_SPLIT_RE = /[/-]/;
|
|
27
|
+
|
|
28
|
+
export function projectNameFromRepository(repositoryId: string): string {
|
|
29
|
+
return repositoryId
|
|
30
|
+
.trim()
|
|
31
|
+
.split(REPOSITORY_NAME_SPLIT_RE)
|
|
32
|
+
.filter(Boolean)
|
|
33
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
34
|
+
.join(' ');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function selectProjectSource<T extends {externalRepositoryId: string}>(
|
|
38
|
+
repositories: T[],
|
|
39
|
+
selectedRepositoryId: string | undefined,
|
|
40
|
+
): T | undefined {
|
|
41
|
+
if (selectedRepositoryId) {
|
|
42
|
+
return repositories.find(
|
|
43
|
+
(repository) => repository.externalRepositoryId === selectedRepositoryId,
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
return repositories[0];
|
|
47
|
+
}
|
package/src/feature.ts
CHANGED
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
import {defineClientFeature} from '@shipfox/client-shell';
|
|
1
|
+
import {defineClientFeature, type NavTabEntry} from '@shipfox/client-shell';
|
|
2
|
+
|
|
3
|
+
export const projectsNavigation = [
|
|
4
|
+
{
|
|
5
|
+
id: 'nav.projects',
|
|
6
|
+
scope: 'workspace',
|
|
7
|
+
label: 'Projects',
|
|
8
|
+
to: '/workspaces/$wid',
|
|
9
|
+
exact: true,
|
|
10
|
+
order: 100,
|
|
11
|
+
},
|
|
12
|
+
] as const satisfies readonly NavTabEntry[];
|
|
2
13
|
|
|
3
14
|
export const projectsFeature = defineClientFeature({
|
|
4
15
|
id: 'shipfox.projects',
|
|
@@ -18,27 +29,6 @@ export const projectsFeature = defineClientFeature({
|
|
|
18
29
|
parent: 'projectLayout',
|
|
19
30
|
impl: '@shipfox/client-projects/routes/project-index',
|
|
20
31
|
},
|
|
21
|
-
{
|
|
22
|
-
path: '/workspaces/$wid/projects/$pid/workflows',
|
|
23
|
-
parent: 'projectLayout',
|
|
24
|
-
impl: '@shipfox/client-projects/routes/workflows',
|
|
25
|
-
},
|
|
26
|
-
],
|
|
27
|
-
navigation: [
|
|
28
|
-
{
|
|
29
|
-
id: 'nav.projects',
|
|
30
|
-
scope: 'workspace',
|
|
31
|
-
label: 'Projects',
|
|
32
|
-
to: '/workspaces/$wid',
|
|
33
|
-
exact: true,
|
|
34
|
-
order: 100,
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
id: 'nav.workflows',
|
|
38
|
-
scope: 'project',
|
|
39
|
-
label: 'Workflows',
|
|
40
|
-
to: '/workspaces/$wid/projects/$pid/workflows',
|
|
41
|
-
order: 200,
|
|
42
|
-
},
|
|
43
32
|
],
|
|
33
|
+
navigation: projectsNavigation,
|
|
44
34
|
});
|
|
@@ -1,12 +1,38 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import {definitionListResponseSchema} from '@shipfox/api-definitions-dto';
|
|
2
|
+
import {checkedApiRequest} from '@shipfox/client-api';
|
|
3
|
+
import {
|
|
4
|
+
type InfiniteData,
|
|
5
|
+
keepPreviousData,
|
|
6
|
+
queryOptions,
|
|
7
|
+
type UseInfiniteQueryOptions,
|
|
8
|
+
type UseQueryOptions,
|
|
9
|
+
useInfiniteQuery,
|
|
10
|
+
useQuery,
|
|
11
|
+
} from '@tanstack/react-query';
|
|
12
|
+
import type {DefinitionList} from '#core/definition.js';
|
|
13
|
+
import {toDefinitionList} from './mappers.js';
|
|
4
14
|
|
|
5
15
|
export const definitionsQueryKeys = {
|
|
6
16
|
all: ['definitions'] as const,
|
|
7
17
|
list: (projectId: string) => [...definitionsQueryKeys.all, 'list', projectId] as const,
|
|
8
18
|
};
|
|
9
19
|
|
|
20
|
+
type DefinitionListQueryKey =
|
|
21
|
+
| ReturnType<typeof definitionsQueryKeys.list>
|
|
22
|
+
| readonly ['definitions', 'list'];
|
|
23
|
+
type DefinitionListInfiniteQueryOptions = UseInfiniteQueryOptions<
|
|
24
|
+
DefinitionList,
|
|
25
|
+
Error,
|
|
26
|
+
InfiniteData<DefinitionList, string | undefined>,
|
|
27
|
+
DefinitionListQueryKey,
|
|
28
|
+
string | undefined
|
|
29
|
+
>;
|
|
30
|
+
type DefinitionListQueryOptions = UseQueryOptions<
|
|
31
|
+
DefinitionList,
|
|
32
|
+
Error,
|
|
33
|
+
DefinitionList,
|
|
34
|
+
DefinitionListQueryKey
|
|
35
|
+
>;
|
|
10
36
|
export async function listDefinitions({
|
|
11
37
|
projectId,
|
|
12
38
|
limit = 50,
|
|
@@ -16,35 +42,44 @@ export async function listDefinitions({
|
|
|
16
42
|
projectId: string;
|
|
17
43
|
limit?: number;
|
|
18
44
|
cursor?: string | undefined;
|
|
19
|
-
signal?: AbortSignal;
|
|
20
|
-
}) {
|
|
45
|
+
signal?: AbortSignal | undefined;
|
|
46
|
+
}): Promise<DefinitionList> {
|
|
21
47
|
const params = new URLSearchParams({project_id: projectId, limit: String(limit)});
|
|
22
48
|
if (cursor) params.set('cursor', cursor);
|
|
23
|
-
return
|
|
24
|
-
|
|
25
|
-
|
|
49
|
+
return toDefinitionList(
|
|
50
|
+
await checkedApiRequest(definitionListResponseSchema, `/definitions?${params.toString()}`, {
|
|
51
|
+
signal,
|
|
52
|
+
}),
|
|
53
|
+
);
|
|
26
54
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
55
|
+
export function definitionsInfiniteQueryOptions(
|
|
56
|
+
projectId: string | undefined,
|
|
57
|
+
limit = 50,
|
|
58
|
+
): DefinitionListInfiniteQueryOptions {
|
|
59
|
+
return {
|
|
30
60
|
queryKey: projectId
|
|
31
61
|
? definitionsQueryKeys.list(projectId)
|
|
32
|
-
: [...definitionsQueryKeys.all, 'list'],
|
|
62
|
+
: ([...definitionsQueryKeys.all, 'list'] as const),
|
|
33
63
|
enabled: Boolean(projectId),
|
|
34
64
|
initialPageParam: undefined as string | undefined,
|
|
35
|
-
queryFn: ({pageParam, signal}) =>
|
|
65
|
+
queryFn: ({pageParam, signal}: {pageParam: string | undefined; signal: AbortSignal}) =>
|
|
36
66
|
listDefinitions({projectId: projectId ?? '', limit, cursor: pageParam, signal}),
|
|
37
|
-
getNextPageParam: (lastPage) => lastPage.
|
|
67
|
+
getNextPageParam: (lastPage: DefinitionList) => lastPage.nextCursor ?? undefined,
|
|
38
68
|
placeholderData: keepPreviousData,
|
|
39
|
-
}
|
|
69
|
+
};
|
|
40
70
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return useQuery({
|
|
71
|
+
export function definitionsQueryOptions(projectId: string | undefined): DefinitionListQueryOptions {
|
|
72
|
+
return queryOptions({
|
|
44
73
|
queryKey: projectId
|
|
45
74
|
? definitionsQueryKeys.list(projectId)
|
|
46
|
-
: [...definitionsQueryKeys.all, 'list'],
|
|
75
|
+
: ([...definitionsQueryKeys.all, 'list'] as const),
|
|
47
76
|
enabled: Boolean(projectId),
|
|
48
77
|
queryFn: ({signal}) => listDefinitions({projectId: projectId ?? '', signal}),
|
|
49
78
|
});
|
|
50
79
|
}
|
|
80
|
+
export function useDefinitionsInfiniteQuery(projectId: string | undefined, limit = 50) {
|
|
81
|
+
return useInfiniteQuery(definitionsInfiniteQueryOptions(projectId, limit));
|
|
82
|
+
}
|
|
83
|
+
export function useDefinitionsQuery(projectId: string | undefined) {
|
|
84
|
+
return useQuery(definitionsQueryOptions(projectId));
|
|
85
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type {DefinitionDto, DefinitionSyncSummaryDto} from '@shipfox/api-definitions-dto';
|
|
2
|
+
import type {ProjectResponseDto} from '@shipfox/api-projects-dto';
|
|
3
|
+
import type {Definition, DefinitionList, DefinitionSyncSummary} from '#core/definition.js';
|
|
4
|
+
import type {Project, ProjectList} from '#core/project.js';
|
|
5
|
+
|
|
6
|
+
export function toProject(dto: ProjectResponseDto): Project {
|
|
7
|
+
return {
|
|
8
|
+
id: dto.id,
|
|
9
|
+
workspaceId: dto.workspace_id,
|
|
10
|
+
name: dto.name,
|
|
11
|
+
source: {
|
|
12
|
+
connectionId: dto.source.connection_id,
|
|
13
|
+
externalRepositoryId: dto.source.external_repository_id,
|
|
14
|
+
},
|
|
15
|
+
createdAt: dto.created_at,
|
|
16
|
+
updatedAt: dto.updated_at,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function toProjectList(dto: {
|
|
21
|
+
projects: ProjectResponseDto[];
|
|
22
|
+
next_cursor: string | null;
|
|
23
|
+
}): ProjectList {
|
|
24
|
+
return {projects: dto.projects.map(toProject), nextCursor: dto.next_cursor};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function toDefinition(dto: DefinitionDto): Definition {
|
|
28
|
+
return {
|
|
29
|
+
id: dto.id,
|
|
30
|
+
projectId: dto.project_id,
|
|
31
|
+
configPath: dto.config_path,
|
|
32
|
+
source: dto.source,
|
|
33
|
+
sha: dto.sha,
|
|
34
|
+
ref: dto.ref,
|
|
35
|
+
name: dto.name,
|
|
36
|
+
workflowDocument: dto.workflow_document,
|
|
37
|
+
workflowModel: dto.workflow_model,
|
|
38
|
+
manualTrigger: dto.manual_trigger,
|
|
39
|
+
fetchedAt: dto.fetched_at,
|
|
40
|
+
createdAt: dto.created_at,
|
|
41
|
+
updatedAt: dto.updated_at,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function toDefinitionSyncSummary(dto: DefinitionSyncSummaryDto): DefinitionSyncSummary {
|
|
46
|
+
return {
|
|
47
|
+
ref: dto.ref,
|
|
48
|
+
status: dto.status,
|
|
49
|
+
lastSyncAt: dto.last_sync_at,
|
|
50
|
+
startedAt: dto.started_at,
|
|
51
|
+
finishedAt: dto.finished_at,
|
|
52
|
+
lastErrorCode: dto.last_error_code,
|
|
53
|
+
lastErrorMessage: dto.last_error_message,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function toDefinitionList(dto: {
|
|
58
|
+
definitions: DefinitionDto[];
|
|
59
|
+
sync: DefinitionSyncSummaryDto | null;
|
|
60
|
+
next_cursor: string | null;
|
|
61
|
+
}): DefinitionList {
|
|
62
|
+
return {
|
|
63
|
+
definitions: dto.definitions.map(toDefinition),
|
|
64
|
+
sync: dto.sync && toDefinitionSyncSummary(dto.sync),
|
|
65
|
+
nextCursor: dto.next_cursor,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
@@ -59,11 +59,11 @@ describe('createProject', () => {
|
|
|
59
59
|
});
|
|
60
60
|
configureApiClient({fetchImpl});
|
|
61
61
|
const body = {
|
|
62
|
-
|
|
62
|
+
workspaceId: '11111111-1111-4111-8111-111111111111',
|
|
63
63
|
name: 'Platform',
|
|
64
64
|
source: {
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
connectionId: '33333333-3333-4333-8333-333333333333',
|
|
66
|
+
externalRepositoryId: 'platform',
|
|
67
67
|
},
|
|
68
68
|
};
|
|
69
69
|
|
|
@@ -73,6 +73,13 @@ describe('createProject', () => {
|
|
|
73
73
|
expect(result.name).toBe('Platform');
|
|
74
74
|
expect(request.url).toBe('https://api.example.test/projects');
|
|
75
75
|
expect(request.method).toBe('POST');
|
|
76
|
-
expect(requestBody).toEqual(
|
|
76
|
+
expect(requestBody).toEqual({
|
|
77
|
+
workspace_id: body.workspaceId,
|
|
78
|
+
name: body.name,
|
|
79
|
+
source: {
|
|
80
|
+
connection_id: body.source.connectionId,
|
|
81
|
+
external_repository_id: body.source.externalRepositoryId,
|
|
82
|
+
},
|
|
83
|
+
});
|
|
77
84
|
});
|
|
78
85
|
});
|