Skip to content

Commit d93a68d

Browse files
committed
routing refactors
1 parent ab7816c commit d93a68d

22 files changed

Lines changed: 763 additions & 244 deletions

e2e/dogfooding.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ test('DOG FOODING TIME - Create a service that uses the StackCraft GitHub reposi
3131

3232
await expect(page.getByTestId('page-header-title')).toContainText(displayName)
3333

34-
// Create the service with the StackCraft GitHub repository
34+
// Navigate to services list via the dashboard card
35+
await page.locator('shade-dashboard a', { hasText: 'Services' }).click()
36+
await expect(page.locator('shade-services-list')).toBeVisible()
3537
await page.locator('button', { hasText: 'Create Service' }).first().click()
3638
await expect(page.locator('shade-create-service-wizard')).toBeVisible()
3739

e2e/smoke.spec.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ test.describe.serial('App Flow', () => {
3434

3535
await expect(page.getByTestId('page-header-title')).toContainText(displayName)
3636

37-
// Create an example "Hello World" service
37+
// Navigate to services list via the dashboard card
38+
await page.locator('shade-dashboard a', { hasText: 'Services' }).click()
39+
await expect(page.locator('shade-services-list')).toBeVisible()
3840
await page.locator('button', { hasText: 'Create Service' }).first().click()
3941
await expect(page.locator('shade-create-service-wizard')).toBeVisible()
4042

@@ -43,20 +45,27 @@ test.describe.serial('App Flow', () => {
4345
await page.locator('input[name="runCommand"]').fill('echo hello')
4446
await page.locator('button', { hasText: 'Create' }).click()
4547

46-
await expect(page.locator('shade-dashboard')).toBeVisible()
47-
await expect(page.getByTestId('page-header-title')).toContainText(displayName)
48+
await expect(page.locator('shade-services-list')).toBeVisible()
4849

49-
// Create a repository - FuryStack (https://github.com/furystack/furystack)
50+
// Navigate back to dashboard then to repositories list via dashboard card
51+
await page.locator('shade-sidebar-stack-link a', { hasText: 'Overview' }).first().click()
52+
await expect(page.locator('shade-dashboard')).toBeVisible()
53+
await page.locator('shade-dashboard a', { hasText: 'Repositories' }).click()
54+
await expect(page.locator('shade-repositories-list')).toBeVisible()
5055
await page.locator('button', { hasText: 'Add Repository' }).first().click()
5156
await expect(page.locator('shade-create-repository')).toBeVisible()
5257

5358
await page.locator('input[name="displayName"]').fill('FuryStack')
5459
await page.locator('input[name="url"]').fill('https://github.com/furystack/furystack')
5560
await page.locator('button', { hasText: 'Add' }).click()
5661

57-
await expect(page.locator('shade-dashboard')).toBeVisible()
58-
await expect(page.getByTestId('page-header-title')).toContainText(displayName)
62+
await expect(page.locator('shade-repositories-list')).toBeVisible()
5963

64+
// Navigate back to dashboard then to services list via dashboard card
65+
await page.locator('shade-sidebar-stack-link a', { hasText: 'Overview' }).first().click()
66+
await expect(page.locator('shade-dashboard')).toBeVisible()
67+
await page.locator('shade-dashboard a', { hasText: 'Services' }).click()
68+
await expect(page.locator('shade-services-list')).toBeVisible()
6069
await page.locator('button', { hasText: 'Create Service' }).first().click()
6170
await expect(page.locator('shade-create-service-wizard')).toBeVisible()
6271

@@ -65,6 +74,6 @@ test.describe.serial('App Flow', () => {
6574
await page.locator('input[name="runCommand"]').fill('echo hello')
6675
await page.locator('button', { hasText: 'Create' }).click()
6776

68-
await expect(page.locator('shade-dashboard')).toBeVisible()
77+
await expect(page.locator('shade-services-list')).toBeVisible()
6978
})
7079
})

frontend/src/components/app-routes.tsx

Lines changed: 65 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@ import type { MatchResult } from 'path-to-regexp'
33
import { Dashboard } from '../pages/dashboard/index.js'
44
import { ExportStack } from '../pages/import-export/export-stack.js'
55
import { ImportStack } from '../pages/import-export/import-stack.js'
6+
import { PrerequisitesList } from '../pages/prerequisites/prerequisites-list.js'
67
import { CreateRepository } from '../pages/repositories/create-repository.js'
78
import { EditRepository } from '../pages/repositories/edit-repository.js'
9+
import { RepositoriesList } from '../pages/repositories/repositories-list.js'
810
import { CreateService } from '../pages/services/create-service.js'
911
import { ServiceDetail } from '../pages/services/service-detail.js'
1012
import { ServiceLogs } from '../pages/services/service-logs.js'
13+
import { ServicesList } from '../pages/services/services-list.js'
1114
import { UserSettings } from '../pages/settings/user-settings.js'
1215
import { CreateStack } from '../pages/stacks/create-stack.js'
1316
import { EditStack } from '../pages/stacks/edit-stack.js'
@@ -18,55 +21,88 @@ export const appRoutes = {
1821
'/': {
1922
component: () => <Dashboard />,
2023
},
21-
'/services/create/:stackName': {
24+
'/settings': {
25+
component: () => <UserSettings />,
26+
},
27+
'/stacks/create': {
28+
component: () => <CreateStack />,
29+
},
30+
'/stacks/import': {
31+
component: () => <ImportStack />,
32+
},
33+
'/stacks/:stackName': {
2234
component: ({ match }: { match: MatchResult<{ stackName: string }> }) => (
23-
<CreateService stackName={match.params.stackName} />
35+
<Dashboard stackName={match.params.stackName} />
2436
),
2537
},
26-
'/services/wizard/:stackName': {
38+
'/stacks/:stackName/edit': {
2739
component: ({ match }: { match: MatchResult<{ stackName: string }> }) => (
28-
<CreateServiceWizard stackName={match.params.stackName} />
40+
<EditStack stackName={match.params.stackName} />
2941
),
3042
},
31-
'/services/:id/logs/:processUid': {
32-
component: ({ match }: { match: MatchResult<{ id: string; processUid: string }> }) => (
33-
<ServiceLogs serviceId={match.params.id} processUid={match.params.processUid} />
43+
'/stacks/:stackName/export': {
44+
component: ({ match }: { match: MatchResult<{ stackName: string }> }) => (
45+
<ExportStack stackName={match.params.stackName} />
3446
),
3547
},
36-
'/services/:id/logs': {
37-
component: ({ match }: { match: MatchResult<{ id: string }> }) => <ServiceLogs serviceId={match.params.id} />,
48+
'/stacks/:stackName/setup': {
49+
component: ({ match }: { match: MatchResult<{ stackName: string }> }) => (
50+
<StackSetup stackName={match.params.stackName} />
51+
),
3852
},
39-
'/services/:id': {
40-
component: ({ match }: { match: MatchResult<{ id: string }> }) => <ServiceDetail serviceId={match.params.id} />,
53+
'/stacks/:stackName/services': {
54+
component: ({ match }: { match: MatchResult<{ stackName: string }> }) => (
55+
<ServicesList stackName={match.params.stackName} />
56+
),
4157
},
42-
'/repositories/create/:stackName': {
58+
'/stacks/:stackName/services/create': {
4359
component: ({ match }: { match: MatchResult<{ stackName: string }> }) => (
44-
<CreateRepository stackName={match.params.stackName} />
60+
<CreateService stackName={match.params.stackName} />
4561
),
4662
},
47-
'/repositories/:id': {
48-
component: ({ match }: { match: MatchResult<{ id: string }> }) => <EditRepository repositoryId={match.params.id} />,
63+
'/stacks/:stackName/services/wizard': {
64+
component: ({ match }: { match: MatchResult<{ stackName: string }> }) => (
65+
<CreateServiceWizard stackName={match.params.stackName} />
66+
),
4967
},
50-
'/settings': {
51-
component: () => <UserSettings />,
68+
'/stacks/:stackName/services/:serviceId/logs/:processUid': {
69+
component: ({ match }: { match: MatchResult<{ stackName: string; serviceId: string; processUid: string }> }) => (
70+
<ServiceLogs
71+
stackName={match.params.stackName}
72+
serviceId={match.params.serviceId}
73+
processUid={match.params.processUid}
74+
/>
75+
),
5276
},
53-
'/stacks/create': {
54-
component: () => <CreateStack />,
77+
'/stacks/:stackName/services/:serviceId/logs': {
78+
component: ({ match }: { match: MatchResult<{ stackName: string; serviceId: string }> }) => (
79+
<ServiceLogs stackName={match.params.stackName} serviceId={match.params.serviceId} />
80+
),
5581
},
56-
'/stacks/import': {
57-
component: () => <ImportStack />,
82+
'/stacks/:stackName/services/:serviceId': {
83+
component: ({ match }: { match: MatchResult<{ stackName: string; serviceId: string }> }) => (
84+
<ServiceDetail stackName={match.params.stackName} serviceId={match.params.serviceId} />
85+
),
5886
},
59-
'/stacks/:name/setup': {
60-
component: ({ match }: { match: MatchResult<{ name: string }> }) => <StackSetup stackName={match.params.name} />,
87+
'/stacks/:stackName/repositories': {
88+
component: ({ match }: { match: MatchResult<{ stackName: string }> }) => (
89+
<RepositoriesList stackName={match.params.stackName} />
90+
),
6191
},
62-
'/stacks/:name/edit': {
63-
component: ({ match }: { match: MatchResult<{ name: string }> }) => <EditStack stackName={match.params.name} />,
92+
'/stacks/:stackName/repositories/create': {
93+
component: ({ match }: { match: MatchResult<{ stackName: string }> }) => (
94+
<CreateRepository stackName={match.params.stackName} />
95+
),
6496
},
65-
'/stacks/:name': {
66-
component: ({ match }: { match: MatchResult<{ name: string }> }) => <Dashboard stackName={match.params.name} />,
97+
'/stacks/:stackName/repositories/:repositoryId': {
98+
component: ({ match }: { match: MatchResult<{ stackName: string; repositoryId: string }> }) => (
99+
<EditRepository stackName={match.params.stackName} repositoryId={match.params.repositoryId} />
100+
),
67101
},
68-
'/stacks/:name/export': {
69-
component: ({ match }: { match: MatchResult<{ name: string }> }) => <ExportStack stackName={match.params.name} />,
102+
'/stacks/:stackName/prerequisites': {
103+
component: ({ match }: { match: MatchResult<{ stackName: string }> }) => (
104+
<PrerequisitesList stackName={match.params.stackName} />
105+
),
70106
},
71107
} as const satisfies Record<string, NestedRoute<any>>
72108

frontend/src/components/body.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Dashboard } from '../pages/dashboard/index.js'
44
import { Init, Offline } from '../pages/index.js'
55
import { SessionService } from '../services/session.js'
66
import { appRoutes } from './app-routes.js'
7+
import { Breadcrumbs } from './breadcrumbs.js'
78

89
export const Body = Shade<{ style?: Partial<CSSStyleDeclaration>; injector?: Injector }>({
910
customElementName: 'shade-app-body',
@@ -15,7 +16,14 @@ export const Body = Shade<{ style?: Partial<CSSStyleDeclaration>; injector?: Inj
1516
{(() => {
1617
switch (sessionState) {
1718
case 'authenticated':
18-
return <NestedRouter routes={appRoutes} notFound={<Dashboard />} />
19+
return (
20+
<div>
21+
<div style={{ padding: '0 24px' }}>
22+
<Breadcrumbs />
23+
</div>
24+
<NestedRouter routes={appRoutes} notFound={<Dashboard />} />
25+
</div>
26+
)
1927
case 'offline':
2028
return <Offline />
2129
default:

0 commit comments

Comments
 (0)