Skip to content

Commit bd87007

Browse files
committed
refactor team error messages
1 parent 9c80139 commit bd87007

File tree

6 files changed

+305
-88
lines changed

6 files changed

+305
-88
lines changed

src/lib/components/ErrorMessage.stories.svelte

+151
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script module>
22
import { defineMeta } from '@storybook/addon-svelte-csf';
33
import ErrorMessage from './ErrorMessage.svelte';
4+
import TeamErrorMessage from './TeamErrorMessage.svelte';
45
56
const { Story } = defineMeta({
67
component: ErrorMessage,
@@ -21,6 +22,24 @@
2122
/>
2223
</Story>
2324

25+
<Story name="Team - Invalid Manifest">
26+
<TeamErrorMessage
27+
teamSlug="team-service-management"
28+
error={{
29+
__typename: 'WorkloadStatusInvalidNaisYaml',
30+
level: 'ERROR'
31+
}}
32+
workloads={[
33+
{
34+
__typename: 'App',
35+
name: 'ip-lookup-prod',
36+
teamEnvironment: { environment: { name: 'prod-fss' } },
37+
team: { slug: 'team-service-management' }
38+
}
39+
]}
40+
/>
41+
</Story>
42+
2443
<Story name="Synchronization Error">
2544
<ErrorMessage
2645
docURL={(p) => p}
@@ -34,6 +53,30 @@
3453
/>
3554
</Story>
3655

56+
<Story name="Team - Synchronization Error">
57+
<TeamErrorMessage
58+
teamSlug="team-service-management"
59+
error={{
60+
__typename: 'WorkloadStatusSynchronizationFailing',
61+
level: 'ERROR'
62+
}}
63+
workloads={[
64+
{
65+
__typename: 'App',
66+
name: 'ip-lookup-preprod',
67+
teamEnvironment: { environment: { name: 'dev-fss' } },
68+
team: { slug: 'team-service-management' }
69+
},
70+
{
71+
__typename: 'App',
72+
name: 'tsm-dustin-integration-preprod',
73+
teamEnvironment: { environment: { name: 'dev-fss' } },
74+
team: { slug: 'team-service-management' }
75+
}
76+
]}
77+
/>
78+
</Story>
79+
3780
<Story name="Deprecated Image Registry">
3881
<ErrorMessage
3982
docURL={(p) => p}
@@ -46,6 +89,66 @@
4689
/>
4790
</Story>
4891

92+
<Story name="Team - Deprecated Image Registry">
93+
<TeamErrorMessage
94+
teamSlug="team-service-management"
95+
error={{
96+
__typename: 'WorkloadStatusDeprecatedRegistry',
97+
level: 'WARNING'
98+
}}
99+
workloads={[
100+
{
101+
__typename: 'App',
102+
name: 'ip-lookup-preprod',
103+
teamEnvironment: { environment: { name: 'dev-fss' } },
104+
team: { slug: 'team-service-management' }
105+
},
106+
{
107+
__typename: 'App',
108+
name: 'tsm-dustin-integration-preprod',
109+
teamEnvironment: { environment: { name: 'prod-fss' } },
110+
team: { slug: 'team-service-management' }
111+
},
112+
{
113+
__typename: 'App',
114+
name: 'tsm-dustin-integration-preprod',
115+
teamEnvironment: { environment: { name: 'prod-fss' } },
116+
team: { slug: 'team-service-management' }
117+
},
118+
{
119+
__typename: 'App',
120+
name: 'tsm-dustin-integration',
121+
teamEnvironment: { environment: { name: 'dev-fss' } },
122+
team: { slug: 'team-service-management' }
123+
},
124+
{
125+
__typename: 'App',
126+
name: 'dustin-integration-preprod',
127+
teamEnvironment: { environment: { name: 'prod-gcp' } },
128+
team: { slug: 'team-service-management' }
129+
},
130+
{
131+
__typename: 'App',
132+
name: 'tsm-dustin-preprod',
133+
teamEnvironment: { environment: { name: 'dev-gcp' } },
134+
team: { slug: 'team-service-management' }
135+
},
136+
{
137+
__typename: 'App',
138+
name: 'tsm-integration-preprod',
139+
teamEnvironment: { environment: { name: 'dev-fss' } },
140+
team: { slug: 'team-service-management' }
141+
},
142+
{
143+
__typename: 'App',
144+
name: 'tsm-dust',
145+
teamEnvironment: { environment: { name: 'dev-fss' } },
146+
team: { slug: 'team-service-management' }
147+
}
148+
]}
149+
/>
150+
</Story>
151+
49152
<Story name="No Running Instances">
50153
<ErrorMessage
51154
docURL={(p) => p}
@@ -67,6 +170,30 @@
67170
/>
68171
</Story>
69172

173+
<Story name="Team - No Running Instances">
174+
<TeamErrorMessage
175+
teamSlug="team-service-management"
176+
error={{
177+
__typename: 'WorkloadStatusNoRunningInstances',
178+
level: 'ERROR'
179+
}}
180+
workloads={[
181+
{
182+
__typename: 'App',
183+
name: 'ip-lookup-preprod',
184+
teamEnvironment: { environment: { name: 'dev-fss' } },
185+
team: { slug: 'team-service-management' }
186+
},
187+
{
188+
__typename: 'App',
189+
name: 'tsm-dustin-integration-preprod',
190+
teamEnvironment: { environment: { name: 'dev-fss' } },
191+
team: { slug: 'team-service-management' }
192+
}
193+
]}
194+
/>
195+
</Story>
196+
70197
<Story name="Failed Run">
71198
<ErrorMessage
72199
docURL={(p) => p}
@@ -79,3 +206,27 @@
79206
}}
80207
/>
81208
</Story>
209+
210+
<Story name="Team - Failed Run">
211+
<TeamErrorMessage
212+
teamSlug="team-service-management"
213+
error={{
214+
__typename: 'WorkloadStatusFailedRun',
215+
level: 'ERROR'
216+
}}
217+
workloads={[
218+
{
219+
__typename: 'Job',
220+
name: 'ip-lookup-preprod',
221+
teamEnvironment: { environment: { name: 'dev-fss' } },
222+
team: { slug: 'team-service-management' }
223+
},
224+
{
225+
__typename: 'Job',
226+
name: 'tsm-dustin-integration-preprod',
227+
teamEnvironment: { environment: { name: 'dev-fss' } },
228+
team: { slug: 'team-service-management' }
229+
}
230+
]}
231+
/>
232+
</Story>
+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
<script lang="ts">
2+
import { WorkloadStatusErrorLevel, type ValueOf } from '$houdini';
3+
import { Alert, BodyLong, Heading } from '@nais/ds-svelte-community';
4+
import WorkloadLink from './WorkloadLink.svelte';
5+
6+
const {
7+
teamSlug,
8+
error,
9+
workloads
10+
}: {
11+
teamSlug: string;
12+
error: {
13+
level: ValueOf<typeof WorkloadStatusErrorLevel>;
14+
__typename:
15+
| 'WorkloadStatusInvalidNaisYaml'
16+
| 'WorkloadStatusSynchronizationFailing'
17+
| 'WorkloadStatusDeprecatedRegistry'
18+
| 'WorkloadStatusNoRunningInstances'
19+
| 'WorkloadStatusFailedRun';
20+
};
21+
workloads: {
22+
__typename: string | null;
23+
name: string;
24+
teamEnvironment: { environment: { name: string } };
25+
team: { slug: string };
26+
}[];
27+
} = $props();
28+
29+
const levelVariant = (level?: ValueOf<typeof WorkloadStatusErrorLevel>) => {
30+
switch (level) {
31+
case 'ERROR':
32+
return 'error';
33+
case 'WARNING':
34+
return 'warning';
35+
case 'TODO':
36+
default:
37+
return 'info';
38+
}
39+
};
40+
41+
const heading = {
42+
WorkloadStatusInvalidNaisYaml: 'Rollout Failed - Invalid Manifest',
43+
WorkloadStatusSynchronizationFailing: 'Rollout Failed - Synchronization Error',
44+
WorkloadStatusDeprecatedRegistry: 'Deprecated Image Registry',
45+
WorkloadStatusNoRunningInstances: 'No Running Instances',
46+
WorkloadStatusFailedRun: 'Job Failed'
47+
};
48+
const summary = {
49+
WorkloadStatusInvalidNaisYaml: 'Workloads with invalid manifests',
50+
WorkloadStatusSynchronizationFailing: 'Workloads with synchronization errors',
51+
WorkloadStatusDeprecatedRegistry: 'Workloads with deprecated image registries',
52+
WorkloadStatusNoRunningInstances: 'Applications with no running instances',
53+
WorkloadStatusFailedRun: 'Failed jobs'
54+
};
55+
</script>
56+
57+
<Alert variant={levelVariant(error.level)}>
58+
<div class="content">
59+
<Heading level="2" size="small">{heading[error.__typename]}</Heading>
60+
{#if error.__typename === 'WorkloadStatusInvalidNaisYaml'}
61+
<BodyLong>
62+
The rollout of the following workload{workloads.length === 1 ? '' : 's'} failed because of {workloads.length ===
63+
1
64+
? 'an'
65+
: ''} invalid manifest{workloads.length === 1 ? '' : 's'}.
66+
</BodyLong>
67+
{:else if error.__typename === 'WorkloadStatusSynchronizationFailing'}
68+
<BodyLong>
69+
The rollout of the following workload{workloads.length === 1 ? '' : 's'} failed because of synchronization
70+
errors.
71+
</BodyLong>
72+
{:else if error.__typename === 'WorkloadStatusDeprecatedRegistry'}
73+
<BodyLong>
74+
Starting April 1st, applications and jobs on Nais must use images from Google Artifact
75+
Registry (GAR). The easiest way to ensure that images are stored in GAR is to use Nais'
76+
GitHub Actions in the workflow. <a
77+
href="https://nais.io/log/#2025-02-24-image-policy"
78+
target="_blank"
79+
rel="noopener noreferrer">Read more in Nais announcement</a
80+
>.
81+
</BodyLong>
82+
<BodyLong>
83+
{teamSlug} currently has <strong>{workloads.length}</strong> workload{workloads.length === 1
84+
? ''
85+
: 's'} using {workloads.length === 1
86+
? 'a deprecated image registry'
87+
: 'deprecated image registries'}.
88+
</BodyLong>
89+
{:else if error.__typename === 'WorkloadStatusNoRunningInstances'}
90+
<BodyLong>
91+
The following application{workloads.length === 1 ? ' has' : 's have'} no running instances.
92+
</BodyLong>
93+
{:else if error.__typename === 'WorkloadStatusFailedRun'}
94+
<BodyLong>
95+
The following job{workloads.length === 1 ? ' has' : 's have'} failed.
96+
</BodyLong>
97+
{/if}
98+
<div>
99+
{#if workloads.length < 5}
100+
{#each workloads as workload (workload)}
101+
<WorkloadLink {workload} />
102+
{/each}
103+
{:else}
104+
<details>
105+
<summary>{summary[error.__typename]}</summary>
106+
{#each workloads as workload (workload)}
107+
<WorkloadLink {workload} />
108+
{/each}
109+
</details>
110+
{/if}
111+
</div>
112+
</div></Alert
113+
>
114+
115+
<style>
116+
.content {
117+
display: grid;
118+
gap: var(--a-spacing-3);
119+
}
120+
</style>

src/routes/team/[team]/+page.gql

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ query TeamOverview($team: Slug!) @cache(policy: NetworkOnly) {
1616

1717
status {
1818
errors {
19+
level
1920
... on WorkloadStatusDeprecatedRegistry {
2021
name
2122
registry

0 commit comments

Comments
 (0)