Skip to content

Commit 0197e28

Browse files
committed
Added Mark Fixed dialog
1 parent 98e6028 commit 0197e28

File tree

6 files changed

+134
-33
lines changed

6 files changed

+134
-33
lines changed

src/Exceptionless.Web/ClientApp/src/lib/features/stacks/components/StackOptionsDropdownMenu.svelte

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@
1010
1111
import { mutateAddStackReference, mutateMarkStackAsCritical, mutateMarkStackAsNotCritical, promoteStackToExternal, removeStack } from '../api.svelte';
1212
import { Stack } from '../models';
13-
import AddStackReferenceDialog from './AddStackReferenceDialog.svelte';
14-
import RemoveStackDialog from './RemoveStackDialog.svelte';
13+
import AddStackReferenceDialog from './dialogs/AddStackReferenceDialog.svelte';
14+
import RemoveStackDialog from './dialogs/RemoveStackDialog.svelte';
1515
1616
interface Props {
1717
stack: Stack;
1818
}
1919
2020
let { stack }: Props = $props();
21-
let openRemoveStackDialog = $state<boolean>(false);
2221
let openAddStackReferenceDialog = $state<boolean>(false);
22+
let openRemoveStackDialog = $state<boolean>(false);
2323
2424
const addStackReference = mutateAddStackReference({
2525
get id() {
@@ -130,5 +130,5 @@
130130
</DropdownMenu.Content>
131131
</DropdownMenu.Root>
132132

133-
<RemoveStackDialog bind:open={openRemoveStackDialog} {remove} />
134133
<AddStackReferenceDialog bind:open={openAddStackReferenceDialog} save={addReference} />
134+
<RemoveStackDialog bind:open={openRemoveStackDialog} {remove} />

src/Exceptionless.Web/ClientApp/src/lib/features/stacks/components/StackStatusDropdownMenu.svelte

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
66
import { mutateStackFixedStatus, mutateStackSnoozedStatus, mutateStackStatus } from '../api.svelte';
77
import { Stack, StackStatus } from '../models';
8+
import MarkStackFixedInVersionDialog from './dialogs/MarkStackFixedInVersionDialog.svelte';
89
910
interface Props {
1011
stack: Stack;
@@ -22,6 +23,7 @@
2223
{ label: 'Discarded', value: StackStatus.Discarded }
2324
];
2425
26+
let openMarkStackFixedInVersionDialog = $state<boolean>(false);
2527
let selected = $derived((items.find((item) => item.value === stack?.status) || items[items.length - 1]) as Item);
2628
2729
const updateStackFixedStatus = mutateStackFixedStatus({
@@ -50,18 +52,7 @@
5052
await updateStackStatus.mutateAsync(StackStatus.Open);
5153
}
5254
53-
async function updateFixed() {
54-
if (stack.status === StackStatus.Fixed) {
55-
return;
56-
}
57-
58-
// .markFixed()
59-
// .then(function (version) {
60-
// return stackService
61-
// .markFixed(vm._stackId, version)
62-
// .then(onSuccess, onFailure)
63-
// .catch(function (e) {});
64-
const version = undefined;
55+
async function updateFixed(version?: string) {
6556
await updateStackFixedStatus.mutateAsync(version);
6657
}
6758
@@ -125,7 +116,7 @@
125116
<DropdownMenu.GroupHeading>Update Status</DropdownMenu.GroupHeading>
126117
<DropdownMenu.Separator />
127118
<DropdownMenu.Item title="Mark this stack as open" onclick={() => updateOpen()}>Open</DropdownMenu.Item>
128-
<DropdownMenu.Item title="Mark this stack as fixed" onclick={() => updateFixed()}>Fixed</DropdownMenu.Item>
119+
<DropdownMenu.Item title="Mark this stack as fixed" onclick={() => (openMarkStackFixedInVersionDialog = true)}>Fixed</DropdownMenu.Item>
129120
<DropdownMenu.Sub>
130121
<DropdownMenu.SubTrigger title="Hide this stack from reports and mutes occurrence notifications" onclick={() => updateSnooze()}
131122
>Snoozed</DropdownMenu.SubTrigger
@@ -144,3 +135,5 @@
144135
</DropdownMenu.Group>
145136
</DropdownMenu.Content>
146137
</DropdownMenu.Root>
138+
139+
<MarkStackFixedInVersionDialog bind:open={openMarkStackFixedInVersionDialog} save={updateFixed} />

src/Exceptionless.Web/ClientApp/src/lib/features/stacks/components/AddStackReferenceDialog.svelte renamed to src/Exceptionless.Web/ClientApp/src/lib/features/stacks/components/dialogs/AddStackReferenceDialog.svelte

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
<script lang="ts">
2-
import * as Dialog from '$comp/ui/dialog';
2+
import { P } from '$comp/typography';
3+
import * as AlertDialog from '$comp/ui/alert-dialog';
34
import * as Form from '$comp/ui/form';
45
import { Input } from '$comp/ui/input';
56
import { defaults, superForm } from 'sveltekit-superforms';
67
import { classvalidatorClient } from 'sveltekit-superforms/adapters';
78
8-
import { ReferenceLinkForm } from '../models';
9+
import { ReferenceLinkForm } from '../../models';
910
1011
interface Props {
1112
open: boolean;
@@ -31,15 +32,15 @@
3132
const { enhance, form: formData } = form;
3233
</script>
3334

34-
<Dialog.Root bind:open onOpenChange={() => form.reset()}>
35-
<Dialog.Content class="sm:max-w-[425px]">
35+
<AlertDialog.Root bind:open onOpenChange={() => form.reset()}>
36+
<AlertDialog.Content class="sm:max-w-[425px]">
3637
<form method="POST" use:enhance>
37-
<Dialog.Header>
38-
<Dialog.Title>Add Reference Link</Dialog.Title>
39-
<Dialog.Description>Add a reference link to an external resource.</Dialog.Description>
40-
</Dialog.Header>
38+
<AlertDialog.Header>
39+
<AlertDialog.Title>Add Reference Link</AlertDialog.Title>
40+
<AlertDialog.Description>Add a reference link to an external resource.</AlertDialog.Description>
41+
</AlertDialog.Header>
4142

42-
<div class="py-4">
43+
<P class="pb-4">
4344
<Form.Field {form} name="url">
4445
<Form.Control>
4546
{#snippet children({ props })}
@@ -50,11 +51,12 @@
5051
<Form.Description />
5152
<Form.FieldErrors />
5253
</Form.Field>
53-
</div>
54+
</P>
5455

55-
<Dialog.Footer>
56-
<Form.Button>Save Reference Link</Form.Button>
57-
</Dialog.Footer>
56+
<AlertDialog.Footer>
57+
<AlertDialog.Cancel>Cancel</AlertDialog.Cancel>
58+
<AlertDialog.Action>Save Reference Link</AlertDialog.Action>
59+
</AlertDialog.Footer>
5860
</form>
59-
</Dialog.Content>
60-
</Dialog.Root>
61+
</AlertDialog.Content>
62+
</AlertDialog.Root>
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<script lang="ts">
2+
import { A, P } from '$comp/typography';
3+
import * as AlertDialog from '$comp/ui/alert-dialog';
4+
import * as Form from '$comp/ui/form';
5+
import { Input } from '$comp/ui/input';
6+
import { defaults, superForm } from 'sveltekit-superforms';
7+
import { classvalidatorClient } from 'sveltekit-superforms/adapters';
8+
import { debounce } from 'throttle-debounce';
9+
import IconDocumentation from '~icons/mdi/help-circle';
10+
11+
import { FixedInVersionForm } from '../../models';
12+
13+
interface Props {
14+
open: boolean;
15+
save: (version?: string) => Promise<void>;
16+
}
17+
18+
let { open = $bindable(), save }: Props = $props();
19+
20+
const form = superForm(defaults(new FixedInVersionForm(), classvalidatorClient(FixedInVersionForm)), {
21+
dataType: 'json',
22+
onChange() {
23+
debouncedUpdateVersionToSemanticVersion();
24+
},
25+
onSubmit() {
26+
updateVersionToSemanticVersion();
27+
},
28+
async onUpdate({ form }) {
29+
if (!form.valid) {
30+
return;
31+
}
32+
33+
await save(form.data.version);
34+
open = false;
35+
},
36+
SPA: true,
37+
validators: classvalidatorClient(FixedInVersionForm)
38+
});
39+
40+
const { enhance, form: formData } = form;
41+
42+
const debouncedUpdateVersionToSemanticVersion = debounce(1000, updateVersionToSemanticVersion);
43+
function updateVersionToSemanticVersion() {
44+
const version = $formData.version;
45+
const isVersionRegex = /^(\d+)\.(\d+)\.?(\d+)?\.?(\d+)?$/;
46+
if (!version || !isVersionRegex.test(version)) {
47+
return;
48+
}
49+
50+
let transformedInput = '';
51+
const isTwoPartVersion = /^(\d+)\.(\d+)$/;
52+
const isFourPartVersion = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;
53+
if (isTwoPartVersion.test(version)) {
54+
transformedInput = version.replace(isTwoPartVersion, '$1.$2.0');
55+
} else if (isFourPartVersion.test(version)) {
56+
transformedInput = version.replace(isFourPartVersion, '$1.$2.$3-$4');
57+
}
58+
59+
if (transformedInput !== '') {
60+
$formData.version = transformedInput;
61+
}
62+
}
63+
</script>
64+
65+
<AlertDialog.Root bind:open onOpenChange={() => form.reset()}>
66+
<AlertDialog.Content class="sm:max-w-[425px]">
67+
<form method="POST" use:enhance>
68+
<AlertDialog.Header>
69+
<AlertDialog.Title>Mark Fixed</AlertDialog.Title>
70+
<AlertDialog.Description
71+
>Marks the stack as fixed. This will also prevent error occurrences from being displayed in the dashboard.</AlertDialog.Description
72+
>
73+
</AlertDialog.Header>
74+
75+
<P class="pb-4">
76+
<strong>Optional:</strong> Please enter the version in which the stack has been fixed. Any submitted occurrences with a lower version will not
77+
cause a regression.
78+
<A class="inline-flex" href="https://exceptionless.com/docs/versioning/" target="_blank" title="Versioning Documentation"
79+
><IconDocumentation /></A
80+
>
81+
</P>
82+
83+
<Form.Field {form} name="version">
84+
<Form.Control>
85+
{#snippet children({ props })}
86+
<Form.Label>Version</Form.Label>
87+
<Input {...props} bind:value={$formData.version} type="text" placeholder="Optional Semantic Version (Example: 1.2.3)" />
88+
{/snippet}
89+
</Form.Control>
90+
<Form.Description />
91+
<Form.FieldErrors />
92+
</Form.Field>
93+
94+
<AlertDialog.Footer>
95+
<AlertDialog.Cancel>Cancel</AlertDialog.Cancel>
96+
<AlertDialog.Action>Mark Fixed</AlertDialog.Action>
97+
</AlertDialog.Footer>
98+
</form>
99+
</AlertDialog.Content>
100+
</AlertDialog.Root>

src/Exceptionless.Web/ClientApp/src/lib/features/stacks/components/RemoveStackDialog.svelte renamed to src/Exceptionless.Web/ClientApp/src/lib/features/stacks/components/dialogs/RemoveStackDialog.svelte

File renamed without changes.

src/Exceptionless.Web/ClientApp/src/lib/features/stacks/models.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
export { Stack, StackStatus } from '$generated/api';
2-
import { IsUrl } from 'class-validator';
2+
import { IsOptional, IsSemVer, IsUrl } from 'class-validator';
3+
4+
export class FixedInVersionForm {
5+
@IsOptional()
6+
@IsSemVer()
7+
version?: string;
8+
}
39

410
export class ReferenceLinkForm {
511
@IsUrl({ require_tld: false })

0 commit comments

Comments
 (0)