Implement Fluid Emerald app redesign
linter / quality (pull_request) Successful in 1m18s
tests / ci (8.4) (pull_request) Successful in 1m54s

This commit is contained in:
2026-07-18 16:45:54 +02:00
parent 59817ad30f
commit a46695c2eb
62 changed files with 2165 additions and 1434 deletions
@@ -89,7 +89,8 @@ const breadcrumbs: BreadcrumbItem[] = [
let filterStateCounter = 0;
const nextFilterStateId = (): string => `notification-filter-${filterStateCounter++}`;
const nextFilterStateId = (): string =>
`notification-filter-${filterStateCounter++}`;
const parseInFilterValues = (value: string): string[] =>
value
@@ -100,7 +101,8 @@ const parseInFilterValues = (value: string): string[] =>
const supportsFilterValue = (operator: string): boolean =>
!['exists', 'not_exists'].includes(operator);
const supportsArrayFilterValue = (operator: string): boolean => operator === 'in';
const supportsArrayFilterValue = (operator: string): boolean =>
operator === 'in';
const createFilter = (): NotificationFilterFormState => ({
attribute: defaultFilterAttribute,
@@ -159,8 +161,9 @@ const resetCreateFilters = (): void => {
createFilterState.filters = [];
};
const editFilters = (notificationActionId: number): NotificationFilterFormState[] =>
editFilterState[notificationActionId] ?? [];
const editFilters = (
notificationActionId: number,
): NotificationFilterFormState[] => editFilterState[notificationActionId] ?? [];
const addEditFilter = (notificationActionId: number): void => {
editFilterState[notificationActionId] = [
@@ -169,10 +172,13 @@ const addEditFilter = (notificationActionId: number): void => {
];
};
const removeEditFilter = (notificationActionId: number, index: number): void => {
editFilterState[notificationActionId] = editFilters(notificationActionId).filter(
(_, candidateIndex) => candidateIndex !== index,
);
const removeEditFilter = (
notificationActionId: number,
index: number,
): void => {
editFilterState[notificationActionId] = editFilters(
notificationActionId,
).filter((_, candidateIndex) => candidateIndex !== index);
};
const createSerializedFilters = computed<string>(() =>
@@ -246,10 +252,10 @@ const notificationActionTimestamp = (
</script>
<template>
<AppLayout :breadcrumbs="breadcrumbs">
<AppLayout :breadcrumbs="breadcrumbs" :project="project">
<Head :title="`${project.name} notification settings`" />
<div class="flex flex-1 flex-col gap-6 p-4">
<div class="app-page">
<div
class="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between"
>
@@ -298,10 +304,7 @@ const notificationActionTimestamp = (
</div>
</div>
<div
v-if="status"
class="rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-900 dark:border-emerald-900/70 dark:bg-emerald-950/40 dark:text-emerald-100"
>
<div v-if="status" class="status-success">
{{ status }}
</div>
@@ -311,7 +314,8 @@ const notificationActionTimestamp = (
Template inheritance: {{ templateState.templateName }}
</CardTitle>
<CardDescription>
Notification rules can remain inherited from the template or diverge here as project-level overrides.
Notification rules can remain inherited from the
template or diverge here as project-level overrides.
</CardDescription>
</CardHeader>
<CardContent class="flex flex-wrap gap-2">
@@ -543,7 +547,10 @@ const notificationActionTimestamp = (
/>
<div
v-if="createFilterState.filters.length === 0"
v-if="
createFilterState.filters.length ===
0
"
class="text-muted-foreground text-sm"
>
No filters configured. This action runs
@@ -552,8 +559,7 @@ const notificationActionTimestamp = (
<div
v-for="(
filter,
filterIndex
filter, filterIndex
) in createFilterState.filters"
:key="filter.id"
class="grid gap-3 rounded-md border p-3"
@@ -572,8 +578,12 @@ const notificationActionTimestamp = (
>
<option
v-for="filterAttributeOption in filterAttributeOptions"
:key="filterAttributeOption.value"
:value="filterAttributeOption.value"
:key="
filterAttributeOption.value
"
:value="
filterAttributeOption.value
"
>
{{
filterAttributeOption.label
@@ -595,8 +605,12 @@ const notificationActionTimestamp = (
>
<option
v-for="filterOperatorOption in filterOperatorOptions"
:key="filterOperatorOption.value"
:value="filterOperatorOption.value"
:key="
filterOperatorOption.value
"
:value="
filterOperatorOption.value
"
>
{{
filterOperatorOption.label
@@ -607,7 +621,11 @@ const notificationActionTimestamp = (
</div>
<div
v-if="supportsFilterValue(filter.operator)"
v-if="
supportsFilterValue(
filter.operator,
)
"
class="grid gap-2"
>
<Label
@@ -662,7 +680,9 @@ const notificationActionTimestamp = (
</div>
<InputError
:message="notificationFilterError(errors)"
:message="
notificationFilterError(errors)
"
/>
</div>
@@ -1029,8 +1049,7 @@ const notificationActionTimestamp = (
<div
v-for="(
filter,
filterIndex
filter, filterIndex
) in editFilters(notificationAction.id)"
:key="filter.id"
class="grid gap-3 rounded-md border p-3"
@@ -1049,8 +1068,12 @@ const notificationActionTimestamp = (
>
<option
v-for="filterAttributeOption in filterAttributeOptions"
:key="filterAttributeOption.value"
:value="filterAttributeOption.value"
:key="
filterAttributeOption.value
"
:value="
filterAttributeOption.value
"
>
{{
filterAttributeOption.label
@@ -1072,8 +1095,12 @@ const notificationActionTimestamp = (
>
<option
v-for="filterOperatorOption in filterOperatorOptions"
:key="filterOperatorOption.value"
:value="filterOperatorOption.value"
:key="
filterOperatorOption.value
"
:value="
filterOperatorOption.value
"
>
{{
filterOperatorOption.label
@@ -1084,7 +1111,11 @@ const notificationActionTimestamp = (
</div>
<div
v-if="supportsFilterValue(filter.operator)"
v-if="
supportsFilterValue(
filter.operator,
)
"
class="grid gap-2"
>
<Label
@@ -1144,7 +1175,9 @@ const notificationActionTimestamp = (
</div>
<InputError
:message="notificationFilterError(errors)"
:message="
notificationFilterError(errors)
"
/>
</div>