Skip to content

Commit 638b592

Browse files
committed
feat: refactor applications list and use OrderByMenu component
1 parent 2a38a92 commit 638b592

File tree

4 files changed

+56
-185
lines changed

4 files changed

+56
-185
lines changed

src/lib/components/OrderByMenu.svelte

+6-3
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,17 @@
1414
| ValueOf<T>
1515
| undefined) ?? defaultValue;
1616
17-
export const urlToOrderDirection = (url: URL) =>
17+
export const urlToOrderDirection = (
18+
url: URL,
19+
defaultDirection: OrderDirection$options = OrderDirection.ASC
20+
) =>
1821
Object.values(OrderDirection).find((dir) => url.searchParams.get('sort')?.endsWith(dir)) ??
19-
OrderDirection.ASC;
22+
defaultDirection;
2023
</script>
2124

2225
<script lang="ts" generics="T extends OrderField">
2326
import { page } from '$app/state';
24-
import { OrderDirection } from '$houdini';
27+
import { OrderDirection, type OrderDirection$options } from '$houdini';
2528
import { changeParams } from '$lib/utils/searchparams.svelte';
2629
import { Button } from '@nais/ds-svelte-community';
2730
import {

src/routes/team/[team]/applications/+page.svelte

+40-151
Original file line numberDiff line numberDiff line change
@@ -1,95 +1,64 @@
11
<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';
84
import AggregatedCostForApplications from '$lib/components/AggregatedCostForApplications.svelte';
95
import AppListItem from '$lib/components/list/AppListItem.svelte';
106
import List from '$lib/components/list/List.svelte';
7+
import OrderByMenu from '$lib/components/OrderByMenu.svelte';
118
import GraphErrors from '$lib/GraphErrors.svelte';
129
import Pagination from '$lib/Pagination.svelte';
1310
import { changeParams } from '$lib/utils/searchparams.svelte';
1411
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';
2314
import type { PageData } from './$houdini';
2415
2516
interface Props {
2617
data: PageData;
2718
}
2819
2920
let { data }: Props = $props();
30-
let { Applications, initialEnvironments } = $derived(data);
21+
let { Applications } = $derived(data);
3122
3223
let filter = $state($Applications.variables?.filter?.name ?? '');
3324
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 ?? '');
4127
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) ?? [];
4529
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)
4834
);
4935
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(',');
6243
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+
});
7248
7349
const changeQuery = (
7450
params: {
75-
field?: ApplicationOrderField$options;
76-
direction?: OrderDirection$options;
7751
after?: string;
7852
before?: string;
7953
newFilter?: string;
80-
environments?: string[];
54+
environments?: string;
8155
} = {}
8256
) => {
8357
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,
8860
filter: params.newFilter ?? filter,
89-
environments:
90-
params.environments?.length === 0
91-
? 'none'
92-
: (params.environments?.join(',') ?? filteredEnvs.join(','))
61+
environments: params.environments ?? ''
9362
});
9463
};
9564
</script>
@@ -166,106 +135,26 @@
166135
: filteredEnvs.length > 0
167136
? 'indeterminate'
168137
: false}
169-
onchange={(checked) => handleCheckboxChange('*', checked)}
138+
onchange={(checked) => (filteredEnvs = checked ? allEnvs : [])}
170139
>
171140
All environments
172141
</ActionMenuCheckboxItem>
173-
{#each $Applications.data?.team.environments ?? [] as env (env.id)}
142+
{#each $Applications.data?.team.environments ?? [] as { name, id } (id)}
174143
<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))}
177149
>
178-
{env.name}
150+
{name}
179151
</ActionMenuCheckboxItem>
180152
{/each}
181153
</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+
/>
269158
{/snippet}
270159
{#each apps.nodes as app (app.id)}
271160
<AppListItem {app} />
+9-13
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
1-
import {
2-
ApplicationOrderField,
3-
type ApplicationOrder,
4-
type ApplicationOrderField$options,
5-
type OrderDirection$options,
6-
type TeamApplicationsFilter
7-
} from '$houdini';
1+
import { ApplicationOrderField, OrderDirection, type TeamApplicationsFilter } from '$houdini';
2+
import { urlToOrderDirection, urlToOrderField } from '$lib/components/OrderByMenu.svelte';
83
import type { AfterLoadEvent, ApplicationsVariables } from './$houdini';
94

105
const rows = 25;
@@ -15,24 +10,25 @@ export const _ApplicationsVariables: ApplicationsVariables = ({ url }) => {
1510
url.searchParams.get('environments') === 'none'
1611
? undefined
1712
: url.searchParams.get('environments')?.split(',') || [];
18-
const field: string = (url.searchParams.get('field') ||
19-
ApplicationOrderField.NAME) as ApplicationOrderField$options;
20-
const direction = (url.searchParams.get('direction') || 'ASC') as OrderDirection$options;
2113

2214
const after = url.searchParams.get('after') || '';
2315
const before = url.searchParams.get('before') || '';
2416

2517
return {
2618
filter: { name: filter, environments } as TeamApplicationsFilter,
27-
orderBy: { field: field, direction: direction } as ApplicationOrder,
19+
orderBy: {
20+
field: urlToOrderField(ApplicationOrderField, ApplicationOrderField.STATUS, url),
21+
direction: urlToOrderDirection(url, OrderDirection.DESC)
22+
},
2823
...(before ? { before, last: rows } : { after, first: rows })
2924
};
3025
};
3126

3227
export function _houdini_afterLoad({ data, event: { url } }: AfterLoadEvent) {
3328
return {
3429
data,
35-
rows,
36-
initialEnvironments: url.searchParams.get('environments') ?? null
30+
rows
31+
/*,
32+
initialEnvironments: url.searchParams.get('environments') ?? null*/
3733
};
3834
}

src/routes/team/[team]/jobs/+page.svelte

+1-18
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
<script lang="ts">
22
import { page } from '$app/state';
3-
import {
4-
JobOrderField,
5-
OrderDirection,
6-
type JobOrderField$options,
7-
type OrderDirection$options
8-
} from '$houdini';
3+
import { JobOrderField } from '$houdini';
94
import AggregatedCostForJobs from '$lib/components/AggregatedCostForJobs.svelte';
105
import JobListItem from '$lib/components/list/JobListItem.svelte';
116
import List from '$lib/components/list/List.svelte';
@@ -30,14 +25,6 @@
3025
let after: string = $derived($Jobs.variables?.after ?? '');
3126
let before: string = $derived($Jobs.variables?.before ?? '');
3227
33-
let orderField: keyof typeof JobOrderField = $derived(
34-
$Jobs.variables?.orderBy?.field ?? JobOrderField.NAME
35-
);
36-
37-
let orderDirection: keyof typeof OrderDirection = $derived(
38-
$Jobs.variables?.orderBy?.direction ?? OrderDirection.ASC
39-
);
40-
4128
const allEnvs = $Jobs.data?.team.environments.map((env) => env.name) ?? [];
4229
4330
let filteredEnvs = $state(
@@ -61,17 +48,13 @@
6148
6249
const changeQuery = (
6350
params: {
64-
field?: JobOrderField$options;
65-
direction?: OrderDirection$options;
6651
after?: string;
6752
before?: string;
6853
newFilter?: string;
6954
environments?: string;
7055
} = {}
7156
) => {
7257
changeParams({
73-
direction: params.direction || orderDirection,
74-
field: params.field || orderField,
7558
before: params.before ?? before,
7659
after: params.after ?? after,
7760
filter: params.newFilter ?? filter,

0 commit comments

Comments
 (0)