@shipfox/client-projects 5.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 +57 -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 -0
- package/dist/feature.d.ts.map +1 -1
- package/dist/feature.js +11 -10
- 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 +18 -84
- package/dist/hooks/api/projects.d.ts.map +1 -1
- package/dist/hooks/api/projects.js +72 -29
- package/dist/hooks/api/projects.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- 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.js +3 -1
- 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 -15
- 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 -11
- 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 +114 -39
- package/src/index.ts +9 -0
- package/src/pages/create-project-page.stories.tsx +6 -1
- 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/tsconfig.build.tsbuildinfo +1 -1
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,16 +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-
|
|
36
|
-
"@shipfox/api
|
|
37
|
-
"@shipfox/client-agent": "
|
|
38
|
-
"@shipfox/
|
|
39
|
-
"@shipfox/client-auth": "
|
|
40
|
-
"@shipfox/client-integrations": "
|
|
41
|
-
"@shipfox/client-shell": "
|
|
42
|
-
"@shipfox/client-ui": "
|
|
43
|
-
"@shipfox/react-ui": "0.3.
|
|
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"
|
|
44
40
|
},
|
|
45
41
|
"peerDependencies": {
|
|
46
42
|
"@tanstack/react-query": "^5.101.0",
|
|
@@ -49,6 +45,9 @@
|
|
|
49
45
|
"react": "^19.0.0",
|
|
50
46
|
"react-dom": "^19.0.0"
|
|
51
47
|
},
|
|
48
|
+
"imports": {
|
|
49
|
+
"#*": "./dist/*"
|
|
50
|
+
},
|
|
52
51
|
"scripts": {
|
|
53
52
|
"build": "shipfox-swc",
|
|
54
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',
|
|
@@ -19,14 +30,5 @@ export const projectsFeature = defineClientFeature({
|
|
|
19
30
|
impl: '@shipfox/client-projects/routes/project-index',
|
|
20
31
|
},
|
|
21
32
|
],
|
|
22
|
-
navigation:
|
|
23
|
-
{
|
|
24
|
-
id: 'nav.projects',
|
|
25
|
-
scope: 'workspace',
|
|
26
|
-
label: 'Projects',
|
|
27
|
-
to: '/workspaces/$wid',
|
|
28
|
-
exact: true,
|
|
29
|
-
order: 100,
|
|
30
|
-
},
|
|
31
|
-
],
|
|
33
|
+
navigation: projectsNavigation,
|
|
32
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
|
});
|