|
1 | 1 | <script lang="ts">
|
2 |
| - import { |
3 |
| - ApplicationOrderField, |
4 |
| - OrderDirection, |
5 |
| - type ApplicationOrderField$options, |
6 |
| - type OrderDirection$options |
7 |
| - } from '$houdini'; |
| 2 | + import { page } from '$app/state'; |
| 3 | + import { ApplicationOrderField } from '$houdini'; |
8 | 4 | import AggregatedCostForApplications from '$lib/components/AggregatedCostForApplications.svelte';
|
9 | 5 | import AppListItem from '$lib/components/list/AppListItem.svelte';
|
10 | 6 | import List from '$lib/components/list/List.svelte';
|
| 7 | + import OrderByMenu from '$lib/components/OrderByMenu.svelte'; |
11 | 8 | import GraphErrors from '$lib/GraphErrors.svelte';
|
12 | 9 | import Pagination from '$lib/Pagination.svelte';
|
13 | 10 | import { changeParams } from '$lib/utils/searchparams.svelte';
|
14 | 11 | import { BodyLong, Button, Search } from '@nais/ds-svelte-community';
|
15 |
| - import { |
16 |
| - ActionMenu, |
17 |
| - ActionMenuCheckboxItem, |
18 |
| - ActionMenuDivider, |
19 |
| - ActionMenuRadioGroup, |
20 |
| - ActionMenuRadioItem |
21 |
| - } from '@nais/ds-svelte-community/experimental.js'; |
22 |
| - import { ChevronDownIcon, SortDownIcon, SortUpIcon } from '@nais/ds-svelte-community/icons'; |
| 12 | + import { ActionMenu, ActionMenuCheckboxItem } from '@nais/ds-svelte-community/experimental.js'; |
| 13 | + import { ChevronDownIcon } from '@nais/ds-svelte-community/icons'; |
23 | 14 | import type { PageData } from './$houdini';
|
24 | 15 |
|
25 | 16 | interface Props {
|
26 | 17 | data: PageData;
|
27 | 18 | }
|
28 | 19 |
|
29 | 20 | let { data }: Props = $props();
|
30 |
| - let { Applications, initialEnvironments } = $derived(data); |
| 21 | + let { Applications } = $derived(data); |
31 | 22 |
|
32 | 23 | let filter = $state($Applications.variables?.filter?.name ?? '');
|
33 | 24 |
|
34 |
| - let filteredEnvs = $derived( |
35 |
| - initialEnvironments === 'none' |
36 |
| - ? [] |
37 |
| - : (initialEnvironments?.split(',') ?? |
38 |
| - $Applications.data?.team.environments.map((env) => env.name) ?? |
39 |
| - []) |
40 |
| - ); |
| 25 | + let after: string = $derived($Applications.variables?.after ?? ''); |
| 26 | + let before: string = $derived($Applications.variables?.before ?? ''); |
41 | 27 |
|
42 |
| - let orderField: keyof typeof ApplicationOrderField = $derived( |
43 |
| - $Applications.variables?.orderBy?.field ?? ApplicationOrderField.NAME |
44 |
| - ); |
| 28 | + const allEnvs = $Applications.data?.team.environments.map((env) => env.name) ?? []; |
45 | 29 |
|
46 |
| - let orderDirection: keyof typeof OrderDirection = $derived( |
47 |
| - $Applications.variables?.orderBy?.direction ?? OrderDirection.ASC |
| 30 | + let filteredEnvs = $state( |
| 31 | + page.url.searchParams.get('environments') === 'none' |
| 32 | + ? [] |
| 33 | + : (page.url.searchParams.get('environments')?.split(',') ?? allEnvs) |
48 | 34 | );
|
49 | 35 |
|
50 |
| - const handleCheckboxChange = (checkboxId: string, checked: boolean) => { |
51 |
| - changeQuery({ |
52 |
| - environments: |
53 |
| - checkboxId === '*' |
54 |
| - ? checked |
55 |
| - ? ($Applications.data?.team.environments.map((env) => env.name) ?? []) |
56 |
| - : [] |
57 |
| - : checked |
58 |
| - ? [...filteredEnvs, checkboxId] |
59 |
| - : filteredEnvs.filter((env) => env !== checkboxId) |
60 |
| - }); |
61 |
| - }; |
| 36 | + $effect(() => { |
| 37 | + const environments = |
| 38 | + filteredEnvs.length === 0 |
| 39 | + ? 'none' |
| 40 | + : filteredEnvs.length === allEnvs.length |
| 41 | + ? '' |
| 42 | + : filteredEnvs.join(','); |
62 | 43 |
|
63 |
| - const handleSortDirection = (key: string) => { |
64 |
| - changeQuery({ direction: key as OrderDirection$options }); |
65 |
| - }; |
66 |
| -
|
67 |
| - const handleSortField = (key: string) => { |
68 |
| - changeQuery({ |
69 |
| - field: key as keyof typeof ApplicationOrderField |
70 |
| - }); |
71 |
| - }; |
| 44 | + if (environments !== (page.url.searchParams.get('environments') ?? '')) { |
| 45 | + changeQuery({ environments }); |
| 46 | + } |
| 47 | + }); |
72 | 48 |
|
73 | 49 | const changeQuery = (
|
74 | 50 | params: {
|
75 |
| - field?: ApplicationOrderField$options; |
76 |
| - direction?: OrderDirection$options; |
77 | 51 | after?: string;
|
78 | 52 | before?: string;
|
79 | 53 | newFilter?: string;
|
80 |
| - environments?: string[]; |
| 54 | + environments?: string; |
81 | 55 | } = {}
|
82 | 56 | ) => {
|
83 | 57 | changeParams({
|
84 |
| - direction: params.direction || orderDirection, |
85 |
| - field: params.field || orderField, |
86 |
| - before: params.before ?? '', |
87 |
| - after: params.after ?? '', |
| 58 | + before: params.before ?? before, |
| 59 | + after: params.after ?? after, |
88 | 60 | filter: params.newFilter ?? filter,
|
89 |
| - environments: |
90 |
| - params.environments?.length === 0 |
91 |
| - ? 'none' |
92 |
| - : (params.environments?.join(',') ?? filteredEnvs.join(',')) |
| 61 | + environments: params.environments ?? '' |
93 | 62 | });
|
94 | 63 | };
|
95 | 64 | </script>
|
|
166 | 135 | : filteredEnvs.length > 0
|
167 | 136 | ? 'indeterminate'
|
168 | 137 | : false}
|
169 |
| - onchange={(checked) => handleCheckboxChange('*', checked)} |
| 138 | + onchange={(checked) => (filteredEnvs = checked ? allEnvs : [])} |
170 | 139 | >
|
171 | 140 | All environments
|
172 | 141 | </ActionMenuCheckboxItem>
|
173 |
| - {#each $Applications.data?.team.environments ?? [] as env (env.id)} |
| 142 | + {#each $Applications.data?.team.environments ?? [] as { name, id } (id)} |
174 | 143 | <ActionMenuCheckboxItem
|
175 |
| - checked={filteredEnvs.includes(env.name)} |
176 |
| - onchange={(checked) => handleCheckboxChange(env.name, checked)} |
| 144 | + checked={filteredEnvs.includes(name)} |
| 145 | + onchange={(checked) => |
| 146 | + (filteredEnvs = checked |
| 147 | + ? [...filteredEnvs, name] |
| 148 | + : filteredEnvs.filter((env) => env !== name))} |
177 | 149 | >
|
178 |
| - {env.name} |
| 150 | + {name} |
179 | 151 | </ActionMenuCheckboxItem>
|
180 | 152 | {/each}
|
181 | 153 | </ActionMenu>
|
182 |
| - <ActionMenu> |
183 |
| - {#snippet trigger(props)} |
184 |
| - <div style="min-width: 164px"> |
185 |
| - <Button variant="tertiary-neutral" size="small" iconPosition="left" {...props}> |
186 |
| - {#snippet icon()} |
187 |
| - {#if orderDirection === OrderDirection.ASC} |
188 |
| - <SortUpIcon size="1rem" /> |
189 |
| - {:else} |
190 |
| - <SortDownIcon size="1rem" /> |
191 |
| - {/if} |
192 |
| - {/snippet} |
193 |
| - <span style="display: flex; align-items: center; gap: 8px;"> |
194 |
| - {orderField === ApplicationOrderField.NAME |
195 |
| - ? 'Name' |
196 |
| - : orderField === ApplicationOrderField.STATUS |
197 |
| - ? 'Status' |
198 |
| - : orderField === ApplicationOrderField.ENVIRONMENT |
199 |
| - ? 'Environment' |
200 |
| - : 'Deployed'} |
201 |
| - <ChevronDownIcon aria-hidden="true" height="20px" width="20px" /> |
202 |
| - </span> |
203 |
| - </Button> |
204 |
| - </div> |
205 |
| - {/snippet} |
206 |
| - {#key orderField} |
207 |
| - <ActionMenuRadioGroup value={orderField} label="Order by"> |
208 |
| - <ActionMenuRadioItem |
209 |
| - value={ApplicationOrderField.NAME} |
210 |
| - onselect={(value) => handleSortField(value as string)}>Name</ActionMenuRadioItem |
211 |
| - > |
212 |
| - <ActionMenuRadioItem |
213 |
| - value={ApplicationOrderField.STATUS} |
214 |
| - onselect={(value) => handleSortField(value as string)}>Status</ActionMenuRadioItem |
215 |
| - > |
216 |
| - <ActionMenuRadioItem |
217 |
| - value={ApplicationOrderField.ENVIRONMENT} |
218 |
| - onselect={(value) => handleSortField(value as string)} |
219 |
| - >Environment</ActionMenuRadioItem |
220 |
| - > |
221 |
| - <ActionMenuRadioItem |
222 |
| - value={ApplicationOrderField.DEPLOYMENT_TIME} |
223 |
| - onselect={(value) => handleSortField(value as string)} |
224 |
| - >Deployed</ActionMenuRadioItem |
225 |
| - > |
226 |
| - </ActionMenuRadioGroup> |
227 |
| - {/key} |
228 |
| - <ActionMenuDivider /> |
229 |
| - {#key orderDirection} |
230 |
| - <ActionMenuRadioGroup value={orderDirection} label="Sort direction"> |
231 |
| - {#if orderField === ApplicationOrderField.DEPLOYMENT_TIME} |
232 |
| - <ActionMenuRadioItem |
233 |
| - value={OrderDirection.ASC} |
234 |
| - onselect={(value) => handleSortDirection(value as string)} |
235 |
| - > |
236 |
| - <div class="icon"> |
237 |
| - <SortUpIcon size="1rem" />Oldest |
238 |
| - </div> |
239 |
| - </ActionMenuRadioItem> |
240 |
| - <ActionMenuRadioItem |
241 |
| - value={OrderDirection.DESC} |
242 |
| - onselect={(value) => handleSortDirection(value as string)} |
243 |
| - > |
244 |
| - <div class="icon"> |
245 |
| - <SortDownIcon size="1rem" />Newest |
246 |
| - </div> |
247 |
| - </ActionMenuRadioItem> |
248 |
| - {:else} |
249 |
| - <ActionMenuRadioItem |
250 |
| - value={OrderDirection.ASC} |
251 |
| - onselect={(value) => handleSortDirection(value as string)} |
252 |
| - > |
253 |
| - <div class="icon"> |
254 |
| - <SortUpIcon size="1rem" />Ascending |
255 |
| - </div> |
256 |
| - </ActionMenuRadioItem> |
257 |
| - <ActionMenuRadioItem |
258 |
| - value={OrderDirection.DESC} |
259 |
| - onselect={(value) => handleSortDirection(value as string)} |
260 |
| - > |
261 |
| - <div class="icon"> |
262 |
| - <SortDownIcon size="1rem" />Descending |
263 |
| - </div> |
264 |
| - </ActionMenuRadioItem> |
265 |
| - {/if} |
266 |
| - </ActionMenuRadioGroup> |
267 |
| - {/key} |
268 |
| - </ActionMenu> |
| 154 | + <OrderByMenu |
| 155 | + orderField={ApplicationOrderField} |
| 156 | + defaultOrderField={ApplicationOrderField.STATUS} |
| 157 | + /> |
269 | 158 | {/snippet}
|
270 | 159 | {#each apps.nodes as app (app.id)}
|
271 | 160 | <AppListItem {app} />
|
|
0 commit comments