@shipfox/client-projects 12.0.1 → 13.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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +59 -0
- package/dist/chrome.d.ts +5 -1
- package/dist/chrome.d.ts.map +1 -1
- package/dist/chrome.js +18 -26
- 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 +4 -2
- package/dist/components/model-provider-reminder-banner.js.map +1 -1
- package/dist/components/project-crumb.d.ts +3 -1
- package/dist/components/project-crumb.d.ts.map +1 -1
- package/dist/components/project-crumb.js +7 -5
- package/dist/components/project-crumb.js.map +1 -1
- package/dist/components/project-switcher.d.ts +2 -1
- package/dist/components/project-switcher.d.ts.map +1 -1
- package/dist/components/project-switcher.js +10 -8
- package/dist/components/project-switcher.js.map +1 -1
- package/dist/core/definition.d.ts +6 -0
- package/dist/core/definition.d.ts.map +1 -1
- package/dist/core/definition.js.map +1 -1
- package/dist/core/project.d.ts +7 -0
- package/dist/core/project.d.ts.map +1 -1
- package/dist/core/project.js.map +1 -1
- package/dist/feature.d.ts +29 -5
- package/dist/feature.d.ts.map +1 -1
- package/dist/feature.js +26 -5
- package/dist/feature.js.map +1 -1
- package/dist/hooks/api/mappers.d.ts.map +1 -1
- package/dist/hooks/api/mappers.js +9 -1
- package/dist/hooks/api/mappers.js.map +1 -1
- package/dist/hooks/api/projects.d.ts +21 -2
- package/dist/hooks/api/projects.d.ts.map +1 -1
- package/dist/hooks/api/projects.js +175 -2
- package/dist/hooks/api/projects.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- 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 +97 -21
- package/dist/pages/create-project-page.js.map +1 -1
- package/dist/pages/create-project-page.stories.js +5 -3
- package/dist/pages/create-project-page.stories.js.map +1 -1
- package/dist/pages/project-settings-form-errors.d.ts +11 -0
- package/dist/pages/project-settings-form-errors.d.ts.map +1 -0
- package/dist/pages/project-settings-form-errors.js +16 -0
- package/dist/pages/project-settings-form-errors.js.map +1 -0
- package/dist/pages/project-settings-page.d.ts +2 -0
- package/dist/pages/project-settings-page.d.ts.map +1 -0
- package/dist/pages/project-settings-page.js +225 -0
- package/dist/pages/project-settings-page.js.map +1 -0
- package/dist/pages/project-settings-page.stories.d.ts +23 -0
- package/dist/pages/project-settings-page.stories.d.ts.map +1 -0
- package/dist/pages/project-settings-page.stories.js +206 -0
- package/dist/pages/project-settings-page.stories.js.map +1 -0
- package/dist/pages/projects-hub-page.js +11 -11
- package/dist/pages/projects-hub-page.js.map +1 -1
- package/dist/project-error.d.ts +1 -0
- package/dist/project-error.d.ts.map +1 -1
- package/dist/project-error.js +7 -0
- package/dist/project-error.js.map +1 -1
- package/dist/routes/inputs.d.ts +2 -2
- package/dist/routes/inputs.d.ts.map +1 -1
- package/dist/routes/inputs.js +5 -5
- package/dist/routes/inputs.js.map +1 -1
- package/dist/routes/project-index.d.ts +2 -2
- package/dist/routes/project-index.d.ts.map +1 -1
- package/dist/routes/project-index.js +3 -3
- package/dist/routes/project-index.js.map +1 -1
- package/dist/routes/project-settings-index.d.ts +10 -0
- package/dist/routes/project-settings-index.d.ts.map +1 -0
- package/dist/routes/project-settings-index.js +12 -0
- package/dist/routes/project-settings-index.js.map +1 -0
- package/dist/routes/project-settings.d.ts +6 -0
- package/dist/routes/project-settings.d.ts.map +1 -0
- package/dist/routes/project-settings.js +7 -0
- package/dist/routes/project-settings.js.map +1 -0
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +11 -10
- package/src/chrome.tsx +27 -19
- package/src/components/model-provider-reminder-banner.tsx +3 -1
- package/src/components/project-crumb.tsx +18 -5
- package/src/components/project-switcher.test.tsx +7 -4
- package/src/components/project-switcher.tsx +16 -5
- package/src/core/definition.ts +7 -0
- package/src/core/project.ts +8 -0
- package/src/feature.ts +26 -4
- package/src/hooks/api/mappers.test.ts +19 -0
- package/src/hooks/api/mappers.ts +6 -0
- package/src/hooks/api/projects.test.ts +247 -1
- package/src/hooks/api/projects.ts +227 -2
- package/src/index.ts +9 -1
- package/src/pages/create-project-page.stories.tsx +5 -4
- package/src/pages/create-project-page.test.tsx +191 -12
- package/src/pages/create-project-page.tsx +102 -15
- package/src/pages/home-router.test.tsx +2 -2
- package/src/pages/project-settings-form-errors.ts +17 -0
- package/src/pages/project-settings-page.stories.tsx +216 -0
- package/src/pages/project-settings-page.test.tsx +74 -0
- package/src/pages/project-settings-page.tsx +220 -0
- package/src/pages/projects-hub-page.test.tsx +17 -11
- package/src/pages/projects-hub-page.tsx +9 -9
- package/src/project-error.test.ts +1 -0
- package/src/project-error.ts +8 -0
- package/src/routes/inputs.test.ts +8 -6
- package/src/routes/inputs.ts +7 -6
- package/src/routes/project-index.tsx +3 -3
- package/src/routes/project-settings-index.tsx +11 -0
- package/src/routes/project-settings.tsx +4 -0
- package/test/pages.tsx +26 -22
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -2,11 +2,13 @@ import {
|
|
|
2
2
|
createProjectBodySchema,
|
|
3
3
|
listProjectsResponseSchema,
|
|
4
4
|
projectResponseSchema,
|
|
5
|
+
updateProjectBodySchema,
|
|
5
6
|
} from '@shipfox/api-projects-dto';
|
|
6
7
|
import {checkedApiRequest} from '@shipfox/client-api';
|
|
7
8
|
import {
|
|
8
9
|
type InfiniteData,
|
|
9
10
|
keepPreviousData,
|
|
11
|
+
type QueryClient,
|
|
10
12
|
queryOptions,
|
|
11
13
|
type UseInfiniteQueryOptions,
|
|
12
14
|
type UseQueryOptions,
|
|
@@ -15,13 +17,23 @@ import {
|
|
|
15
17
|
useQuery,
|
|
16
18
|
useQueryClient,
|
|
17
19
|
} from '@tanstack/react-query';
|
|
18
|
-
import
|
|
20
|
+
import {useCallback} from 'react';
|
|
21
|
+
import type {
|
|
22
|
+
CreateProjectCommand,
|
|
23
|
+
Project,
|
|
24
|
+
ProjectList,
|
|
25
|
+
UpdateProjectCommand,
|
|
26
|
+
} from '#core/project.js';
|
|
19
27
|
import {toProject, toProjectList} from './mappers.js';
|
|
20
28
|
|
|
29
|
+
const PROJECT_LIST_STALE_TIME = 30_000;
|
|
30
|
+
|
|
21
31
|
export const projectsQueryKeys = {
|
|
22
32
|
all: ['projects'] as const,
|
|
23
33
|
list: (workspaceId: string, search = '') =>
|
|
24
34
|
[...projectsQueryKeys.all, 'list', workspaceId, search] as const,
|
|
35
|
+
slug: (workspaceId: string, projectSlug: string) =>
|
|
36
|
+
[...projectsQueryKeys.all, 'slug', workspaceId, projectSlug] as const,
|
|
25
37
|
exists: (workspaceId: string) => [...projectsQueryKeys.all, 'exists', workspaceId] as const,
|
|
26
38
|
detail: (projectId: string) => [...projectsQueryKeys.all, 'detail', projectId] as const,
|
|
27
39
|
};
|
|
@@ -32,6 +44,9 @@ type ProjectListQueryKey =
|
|
|
32
44
|
type ProjectExistenceQueryKey =
|
|
33
45
|
| ReturnType<typeof projectsQueryKeys.exists>
|
|
34
46
|
| readonly ['projects', 'exists'];
|
|
47
|
+
type ProjectSlugQueryKey =
|
|
48
|
+
| ReturnType<typeof projectsQueryKeys.slug>
|
|
49
|
+
| readonly ['projects', 'slug'];
|
|
35
50
|
type ProjectDetailQueryKey =
|
|
36
51
|
| ReturnType<typeof projectsQueryKeys.detail>
|
|
37
52
|
| readonly ['projects', 'detail'];
|
|
@@ -49,6 +64,12 @@ type ProjectExistenceQueryOptions = UseQueryOptions<
|
|
|
49
64
|
ProjectList,
|
|
50
65
|
ProjectExistenceQueryKey
|
|
51
66
|
>;
|
|
67
|
+
type ProjectSlugQueryOptions = UseQueryOptions<
|
|
68
|
+
Project | null,
|
|
69
|
+
Error,
|
|
70
|
+
Project | null,
|
|
71
|
+
ProjectSlugQueryKey
|
|
72
|
+
>;
|
|
52
73
|
type ProjectDetailQueryOptions = UseQueryOptions<Project, Error, Project, ProjectDetailQueryKey>;
|
|
53
74
|
|
|
54
75
|
export async function listProjects({
|
|
@@ -72,6 +93,112 @@ export async function listProjects({
|
|
|
72
93
|
);
|
|
73
94
|
}
|
|
74
95
|
|
|
96
|
+
export async function resolveProjectSlug({
|
|
97
|
+
queryClient,
|
|
98
|
+
workspaceId,
|
|
99
|
+
projectSlug,
|
|
100
|
+
}: {
|
|
101
|
+
queryClient: QueryClient;
|
|
102
|
+
workspaceId: string;
|
|
103
|
+
projectSlug: string;
|
|
104
|
+
}): Promise<string | undefined> {
|
|
105
|
+
const queryKey = projectsQueryKeys.list(workspaceId);
|
|
106
|
+
let data = queryClient.getQueryData<InfiniteData<ProjectList, string | undefined>>(queryKey);
|
|
107
|
+
|
|
108
|
+
if (!data) {
|
|
109
|
+
await queryClient.fetchInfiniteQuery(projectsInfiniteQueryOptions(workspaceId));
|
|
110
|
+
data = queryClient.getQueryData<InfiniteData<ProjectList, string | undefined>>(queryKey);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (data) {
|
|
114
|
+
const project = data.pages
|
|
115
|
+
.flatMap((page) => page.projects)
|
|
116
|
+
.find((candidate) => candidate.slug === projectSlug);
|
|
117
|
+
const dataUpdatedAt = queryClient.getQueryState(queryKey)?.dataUpdatedAt ?? 0;
|
|
118
|
+
if (project && Date.now() - dataUpdatedAt < PROJECT_LIST_STALE_TIME) {
|
|
119
|
+
cacheResolvedProject(queryClient, workspaceId, projectSlug, project);
|
|
120
|
+
return project.id;
|
|
121
|
+
}
|
|
122
|
+
const cursor = data.pages.at(-1)?.nextCursor;
|
|
123
|
+
if (project || !cursor) {
|
|
124
|
+
return await refetchAndResolveProjectSlug(queryClient, queryKey, workspaceId, projectSlug);
|
|
125
|
+
}
|
|
126
|
+
return await resolveProjectSlugBySearch(queryClient, workspaceId, projectSlug);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async function refetchAndResolveProjectSlug(
|
|
133
|
+
queryClient: QueryClient,
|
|
134
|
+
queryKey: ReturnType<typeof projectsQueryKeys.list>,
|
|
135
|
+
workspaceId: string,
|
|
136
|
+
projectSlug: string,
|
|
137
|
+
): Promise<string | undefined> {
|
|
138
|
+
await queryClient.refetchQueries({queryKey, type: 'all'});
|
|
139
|
+
const data = queryClient.getQueryData<InfiniteData<ProjectList, string | undefined>>(queryKey);
|
|
140
|
+
|
|
141
|
+
if (!data) return undefined;
|
|
142
|
+
const project = data.pages
|
|
143
|
+
.flatMap((page) => page.projects)
|
|
144
|
+
.find((candidate) => candidate.slug === projectSlug);
|
|
145
|
+
if (project) {
|
|
146
|
+
cacheResolvedProject(queryClient, workspaceId, projectSlug, project);
|
|
147
|
+
return project.id;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (!data.pages.at(-1)?.nextCursor) return undefined;
|
|
151
|
+
return await resolveProjectSlugBySearch(queryClient, workspaceId, projectSlug);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function cacheResolvedProject(
|
|
155
|
+
queryClient: QueryClient,
|
|
156
|
+
workspaceId: string,
|
|
157
|
+
projectSlug: string,
|
|
158
|
+
project: Project,
|
|
159
|
+
): void {
|
|
160
|
+
queryClient.setQueryData(projectsQueryKeys.slug(workspaceId, projectSlug), project);
|
|
161
|
+
queryClient.setQueryData(projectsQueryKeys.detail(project.id), project);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async function resolveProjectSlugBySearch(
|
|
165
|
+
queryClient: QueryClient,
|
|
166
|
+
workspaceId: string,
|
|
167
|
+
projectSlug: string,
|
|
168
|
+
signal?: AbortSignal,
|
|
169
|
+
): Promise<string | undefined> {
|
|
170
|
+
const project = await findProjectBySlug({workspaceId, projectSlug, signal});
|
|
171
|
+
if (project) {
|
|
172
|
+
cacheResolvedProject(queryClient, workspaceId, projectSlug, project);
|
|
173
|
+
return project.id;
|
|
174
|
+
}
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async function findProjectBySlug({
|
|
179
|
+
workspaceId,
|
|
180
|
+
projectSlug,
|
|
181
|
+
signal,
|
|
182
|
+
}: {
|
|
183
|
+
workspaceId: string;
|
|
184
|
+
projectSlug: string;
|
|
185
|
+
signal?: AbortSignal | undefined;
|
|
186
|
+
}): Promise<Project | undefined> {
|
|
187
|
+
let result = await listProjects({workspaceId, search: projectSlug, limit: 100, signal});
|
|
188
|
+
while (true) {
|
|
189
|
+
const project = result.projects.find((candidate) => candidate.slug === projectSlug);
|
|
190
|
+
if (project) return project;
|
|
191
|
+
if (!result.nextCursor) return undefined;
|
|
192
|
+
result = await listProjects({
|
|
193
|
+
workspaceId,
|
|
194
|
+
search: projectSlug,
|
|
195
|
+
limit: 100,
|
|
196
|
+
cursor: result.nextCursor,
|
|
197
|
+
signal,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
75
202
|
export async function getProject(projectId: string): Promise<Project> {
|
|
76
203
|
return toProject(await checkedApiRequest(projectResponseSchema, `/projects/${projectId}`));
|
|
77
204
|
}
|
|
@@ -80,6 +207,7 @@ export async function createProject(command: CreateProjectCommand): Promise<Proj
|
|
|
80
207
|
const body = createProjectBodySchema.parse({
|
|
81
208
|
workspace_id: command.workspaceId,
|
|
82
209
|
name: command.name,
|
|
210
|
+
slug: command.slug,
|
|
83
211
|
source: {
|
|
84
212
|
connection_id: command.source.connectionId,
|
|
85
213
|
external_repository_id: command.source.externalRepositoryId,
|
|
@@ -90,6 +218,54 @@ export async function createProject(command: CreateProjectCommand): Promise<Proj
|
|
|
90
218
|
);
|
|
91
219
|
}
|
|
92
220
|
|
|
221
|
+
export async function updateProject(command: UpdateProjectCommand): Promise<Project> {
|
|
222
|
+
const body = updateProjectBodySchema.parse({name: command.name, slug: command.slug});
|
|
223
|
+
return toProject(
|
|
224
|
+
await checkedApiRequest(projectResponseSchema, `/projects/${command.projectId}`, {
|
|
225
|
+
method: 'PATCH',
|
|
226
|
+
body,
|
|
227
|
+
}),
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export function isProjectSlugAvailable({
|
|
232
|
+
queryClient,
|
|
233
|
+
workspaceId,
|
|
234
|
+
projectSlug,
|
|
235
|
+
currentProjectId,
|
|
236
|
+
}: {
|
|
237
|
+
queryClient: QueryClient;
|
|
238
|
+
workspaceId: string;
|
|
239
|
+
projectSlug: string;
|
|
240
|
+
currentProjectId?: string | undefined;
|
|
241
|
+
}): boolean {
|
|
242
|
+
const cachedLists = queryClient.getQueriesData<InfiniteData<ProjectList, string | undefined>>({
|
|
243
|
+
queryKey: [...projectsQueryKeys.all, 'list', workspaceId],
|
|
244
|
+
});
|
|
245
|
+
const conflict = cachedLists
|
|
246
|
+
.flatMap(([, data]) => data?.pages.flatMap((page) => page.projects) ?? [])
|
|
247
|
+
.some((project) => project.slug === projectSlug && project.id !== currentProjectId);
|
|
248
|
+
return !conflict;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export function useProjectSlugAvailability(
|
|
252
|
+
workspaceId: string | undefined,
|
|
253
|
+
currentProjectId?: string,
|
|
254
|
+
): (projectSlug: string) => Promise<boolean> {
|
|
255
|
+
const queryClient = useQueryClient();
|
|
256
|
+
return useCallback(
|
|
257
|
+
async (projectSlug: string) => {
|
|
258
|
+
if (!workspaceId) return false;
|
|
259
|
+
if (!isProjectSlugAvailable({queryClient, workspaceId, projectSlug, currentProjectId})) {
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
const project = await findProjectBySlug({workspaceId, projectSlug});
|
|
263
|
+
return project === undefined || project.id === currentProjectId;
|
|
264
|
+
},
|
|
265
|
+
[currentProjectId, queryClient, workspaceId],
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
93
269
|
export function projectsInfiniteQueryOptions(
|
|
94
270
|
workspaceId: string | undefined,
|
|
95
271
|
search?: string,
|
|
@@ -112,6 +288,7 @@ export function projectsInfiniteQueryOptions(
|
|
|
112
288
|
}),
|
|
113
289
|
getNextPageParam: (lastPage: ProjectList) => lastPage.nextCursor ?? undefined,
|
|
114
290
|
placeholderData: keepPreviousData,
|
|
291
|
+
staleTime: PROJECT_LIST_STALE_TIME,
|
|
115
292
|
};
|
|
116
293
|
}
|
|
117
294
|
|
|
@@ -138,6 +315,33 @@ export function projectQueryOptions(projectId: string | undefined): ProjectDetai
|
|
|
138
315
|
});
|
|
139
316
|
}
|
|
140
317
|
|
|
318
|
+
export function projectSlugQueryOptions(
|
|
319
|
+
workspaceId: string | undefined,
|
|
320
|
+
projectSlug: string | undefined,
|
|
321
|
+
): ProjectSlugQueryOptions {
|
|
322
|
+
return queryOptions({
|
|
323
|
+
queryKey:
|
|
324
|
+
workspaceId && projectSlug
|
|
325
|
+
? projectsQueryKeys.slug(workspaceId, projectSlug)
|
|
326
|
+
: ([...projectsQueryKeys.all, 'slug'] as const),
|
|
327
|
+
enabled: Boolean(workspaceId && projectSlug),
|
|
328
|
+
queryFn: async ({signal, client}) => {
|
|
329
|
+
const resolvedWorkspaceId = workspaceId ?? '';
|
|
330
|
+
const resolvedProjectSlug = projectSlug ?? '';
|
|
331
|
+
const project = await findProjectBySlug({
|
|
332
|
+
workspaceId: resolvedWorkspaceId,
|
|
333
|
+
projectSlug: resolvedProjectSlug,
|
|
334
|
+
signal,
|
|
335
|
+
});
|
|
336
|
+
if (project) {
|
|
337
|
+
cacheResolvedProject(client, resolvedWorkspaceId, resolvedProjectSlug, project);
|
|
338
|
+
}
|
|
339
|
+
return project ?? null;
|
|
340
|
+
},
|
|
341
|
+
staleTime: 30_000,
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
|
|
141
345
|
export function useProjectsInfiniteQuery(
|
|
142
346
|
workspaceId: string | undefined,
|
|
143
347
|
search?: string,
|
|
@@ -148,7 +352,12 @@ export function useProjectsInfiniteQuery(
|
|
|
148
352
|
export function useProjectQuery(projectId: string | undefined) {
|
|
149
353
|
return useQuery(projectQueryOptions(projectId));
|
|
150
354
|
}
|
|
151
|
-
|
|
355
|
+
export function useProjectSlugQuery(
|
|
356
|
+
workspaceId: string | undefined,
|
|
357
|
+
projectSlug: string | undefined,
|
|
358
|
+
) {
|
|
359
|
+
return useQuery(projectSlugQueryOptions(workspaceId, projectSlug));
|
|
360
|
+
}
|
|
152
361
|
export function useCreateProjectMutation() {
|
|
153
362
|
const queryClient = useQueryClient();
|
|
154
363
|
return useMutation({
|
|
@@ -170,3 +379,19 @@ export function useCreateProjectMutation() {
|
|
|
170
379
|
},
|
|
171
380
|
});
|
|
172
381
|
}
|
|
382
|
+
|
|
383
|
+
export function useUpdateProjectMutation() {
|
|
384
|
+
const queryClient = useQueryClient();
|
|
385
|
+
|
|
386
|
+
return useMutation({
|
|
387
|
+
mutationFn: updateProject,
|
|
388
|
+
onSuccess: async (project) => {
|
|
389
|
+
queryClient.setQueryData(projectsQueryKeys.detail(project.id), project);
|
|
390
|
+
queryClient.setQueryData(projectsQueryKeys.slug(project.workspaceId, project.slug), project);
|
|
391
|
+
await queryClient.invalidateQueries({
|
|
392
|
+
queryKey: [...projectsQueryKeys.all, 'slug', project.workspaceId],
|
|
393
|
+
});
|
|
394
|
+
await queryClient.invalidateQueries({queryKey: projectsQueryKeys.list(project.workspaceId)});
|
|
395
|
+
},
|
|
396
|
+
});
|
|
397
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -6,8 +6,15 @@ export {
|
|
|
6
6
|
type ProjectSource,
|
|
7
7
|
projectNameFromRepository,
|
|
8
8
|
selectProjectSource,
|
|
9
|
+
type UpdateProjectCommand,
|
|
9
10
|
} from '#core/project.js';
|
|
10
|
-
export {
|
|
11
|
+
export {
|
|
12
|
+
ProjectBreadcrumb,
|
|
13
|
+
resolveProjectSlug,
|
|
14
|
+
useActiveProject,
|
|
15
|
+
useMaybeActiveProject,
|
|
16
|
+
useMaybeActiveProjectQuery,
|
|
17
|
+
} from './chrome.js';
|
|
11
18
|
export {ProjectCrumb, type ProjectCrumbProps} from './components/project-crumb.js';
|
|
12
19
|
export {ProjectSwitcher, type ProjectSwitcherProps} from './components/project-switcher.js';
|
|
13
20
|
export {SourceStrip} from './components/source-strip.js';
|
|
@@ -15,5 +22,6 @@ export * from './hooks/api/definitions.js';
|
|
|
15
22
|
export * from './hooks/api/projects.js';
|
|
16
23
|
export * from './pages/create-project-page.js';
|
|
17
24
|
export * from './pages/home-router.js';
|
|
25
|
+
export {ProjectSettingsPage} from './pages/project-settings-page.js';
|
|
18
26
|
export * from './pages/projects-hub-page.js';
|
|
19
27
|
export * from './project-error.js';
|
|
@@ -17,7 +17,7 @@ import {useMemo} from 'react';
|
|
|
17
17
|
import {CreateProjectPage} from './create-project-page.js';
|
|
18
18
|
|
|
19
19
|
const WORKSPACE_ID = '11111111-1111-4111-8111-111111111111';
|
|
20
|
-
const WORKSPACE_PATH =
|
|
20
|
+
const WORKSPACE_PATH = '/w/acme/projects/new';
|
|
21
21
|
const GITHUB_CONNECTION_ID = '33333333-3333-4333-8333-333333333333';
|
|
22
22
|
const GITEA_CONNECTION_ID = '44444444-4444-4444-8444-444444444444';
|
|
23
23
|
|
|
@@ -41,7 +41,7 @@ const authState: AuthState = {
|
|
|
41
41
|
name: 'Platform Engineer',
|
|
42
42
|
emailVerifiedAt: '2026-01-01T00:00:00.000Z',
|
|
43
43
|
},
|
|
44
|
-
workspaces: [{id: WORKSPACE_ID, name: 'Acme', membershipId: 'membership-1'}],
|
|
44
|
+
workspaces: [{id: WORKSPACE_ID, name: 'Acme', slug: 'acme', membershipId: 'membership-1'}],
|
|
45
45
|
};
|
|
46
46
|
|
|
47
47
|
function CreateProjectPageStory({scenario}: CreateProjectPageStoryProps) {
|
|
@@ -107,7 +107,7 @@ function createStoryRouter() {
|
|
|
107
107
|
const rootRoute = createRootRoute({component: Outlet});
|
|
108
108
|
const workspaceRoute = createRoute({
|
|
109
109
|
getParentRoute: () => rootRoute,
|
|
110
|
-
path: '/
|
|
110
|
+
path: '/w/$workspaceSlug',
|
|
111
111
|
component: Outlet,
|
|
112
112
|
});
|
|
113
113
|
const createProjectRoute = createRoute({
|
|
@@ -127,7 +127,7 @@ function createStoryRouter() {
|
|
|
127
127
|
});
|
|
128
128
|
const projectRoute = createRoute({
|
|
129
129
|
getParentRoute: () => workspaceRoute,
|
|
130
|
-
path: '
|
|
130
|
+
path: 'p/$projectSlug',
|
|
131
131
|
component: () => <div />,
|
|
132
132
|
});
|
|
133
133
|
|
|
@@ -176,6 +176,7 @@ function fetchForScenario(scenario: Scenario): typeof fetch {
|
|
|
176
176
|
id: '99999999-9999-4999-8999-999999999999',
|
|
177
177
|
workspace_id: WORKSPACE_ID,
|
|
178
178
|
name: 'Platform',
|
|
179
|
+
slug: 'platform',
|
|
179
180
|
source: {
|
|
180
181
|
connection_id: GITHUB_CONNECTION_ID,
|
|
181
182
|
external_repository_id: 'platform',
|