Skip to content

Commit e9d5178

Browse files
committed
WIP - Filter Builder.
1 parent c124c2a commit e9d5178

File tree

5 files changed

+67
-37
lines changed

5 files changed

+67
-37
lines changed

src/Exceptionless.Web/ClientApp/src/lib/components/faceted-filter/faceted-filter-builder.svelte

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
<script lang="ts">
22
import { createEventDispatcher } from 'svelte';
33
import type { Readable } from 'svelte/store';
4+
import { toast } from 'svelte-sonner';
45
56
import IconAddCircleOutline from '~icons/mdi/add-circle-outline';
6-
import IconCheck from '~icons/mdi/check';
77
88
import * as Command from '$comp/ui/command';
99
import * as Popover from '$comp/ui/popover';
1010
import { Button } from '$comp/ui/button';
1111
import type { IFilter } from '$comp/filters/filters';
12-
import { cn } from '$lib/utils';
1312
import type { FacetedFilter } from '.';
1413
1514
const dispatch = createEventDispatcher();
@@ -25,12 +24,7 @@
2524
2625
function onFacetSelected(facet: FacetedFilter) {
2726
if (visible.includes(facet.filter.key)) {
28-
visible = visible.filter((key) => key !== facet.filter.key);
29-
30-
if (!facet.filter.isEmpty()) {
31-
facet.filter.reset();
32-
onFilterChanged(facet.filter);
33-
}
27+
toast.error(`Only one ${facet.title} filter can be applied at a time.`);
3428
} else {
3529
visible = [...visible, facet.filter.key];
3630
}
@@ -78,19 +72,7 @@
7872
<Command.Empty>No results found.</Command.Empty>
7973
<Command.Group>
8074
{#each $facets as facet (facet.filter.key)}
81-
<Command.Item value={facet.filter.key} onSelect={() => onFacetSelected(facet)}>
82-
<div
83-
class={cn(
84-
'mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary',
85-
visible.includes(facet.filter.key) ? 'bg-primary text-primary-foreground' : 'opacity-50 [&_svg]:invisible'
86-
)}
87-
>
88-
<IconCheck className={cn('h-4 w-4')} />
89-
</div>
90-
<span>
91-
{facet.title}
92-
</span>
93-
</Command.Item>
75+
<Command.Item value={facet.filter.key} onSelect={() => onFacetSelected(facet)}>{facet.title}</Command.Item>
9476
{/each}
9577
</Command.Group>
9678
{#if visible.length > 0}

src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/DateFacetedFilter.svelte

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
{ value: '', label: 'All Time' }
1717
];
1818
19+
if (isCustomDate(filter)) {
20+
options.push({ value: filter.value as string, label: filter.value as string });
21+
}
22+
1923
let value = filter.value as string;
2024
function onChanged() {
2125
filter.value = value;
@@ -26,6 +30,18 @@
2630
filter.value = value;
2731
dispatch('remove', filter);
2832
}
33+
34+
function isCustomDate(filter: DateFilter) {
35+
if (filter.value === undefined) {
36+
return false;
37+
}
38+
39+
if (filter.value === '' || (typeof filter.value === 'string' && filter.value.startsWith('last'))) {
40+
return false;
41+
}
42+
43+
return true;
44+
}
2945
</script>
3046

3147
<DropDownFacetedFilter {title} bind:value {options} on:changed={onChanged} on:remove={onRemove}></DropDownFacetedFilter>

src/Exceptionless.Web/ClientApp/src/lib/components/filters/facets/index.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,19 @@ export function toFacetedFilters(filters: IFilter[]): FacetedFilter[] {
1919
switch (filter.type) {
2020
case 'boolean': {
2121
const booleanFilter = filter as BooleanFilter;
22-
return { title: booleanFilter.term as string, component: BooleanFacetedFilter, filter };
22+
return { title: (booleanFilter.term as string) ?? 'Boolean', component: BooleanFacetedFilter, filter };
2323
}
2424
case 'date': {
2525
const dateFilter = filter as DateFilter;
26-
const title = dateFilter.term === 'date' ? 'Date Range' : dateFilter.term;
26+
const title = dateFilter.term === 'date' ? 'Date Range' : dateFilter.term ?? 'Date';
2727
return { title, component: DateFacetedFilter, filter };
2828
}
2929
case 'keyword': {
3030
return { title: 'Keyword', component: KeywordFacetedFilter, filter };
3131
}
3232
case 'number': {
3333
const numberFilter = filter as NumberFilter;
34-
return { title: numberFilter.term as string, component: NumberFacetedFilter, filter: numberFilter };
34+
return { title: (numberFilter.term as string) ?? 'Number', component: NumberFacetedFilter, filter: numberFilter };
3535
}
3636
case 'organization': {
3737
return { title: 'Organization', component: OrganizationFacetedFilter, filter };
@@ -50,14 +50,14 @@ export function toFacetedFilters(filters: IFilter[]): FacetedFilter[] {
5050
}
5151
case 'string': {
5252
const stringFilter = filter as StringFilter;
53-
return { title: stringFilter.term as string, component: StringFacetedFilter, filter };
53+
return { title: (stringFilter.term as string) ?? 'String', component: StringFacetedFilter, filter };
5454
}
5555
case 'type': {
56-
return { title: 'Type' as string, component: TypeFacetedFilter, filter };
56+
return { title: 'Type', component: TypeFacetedFilter, filter };
5757
}
5858
case 'version': {
5959
const versionFilter = filter as VersionFilter;
60-
return { title: versionFilter.term as string, component: VersionFacetedFilter, filter };
60+
return { title: (versionFilter.term as string) ?? 'Version', component: VersionFacetedFilter, filter };
6161
}
6262
default: {
6363
throw new Error(`Unknown filter type: ${filter.type}`);

src/Exceptionless.Web/ClientApp/src/lib/components/filters/filters.ts

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export interface IFilter {
1212

1313
export class BooleanFilter implements IFilter {
1414
constructor(
15-
public term: string,
15+
public term?: string,
1616
public value?: boolean
1717
) {}
1818

@@ -31,6 +31,10 @@ export class BooleanFilter implements IFilter {
3131
}
3232

3333
public toFilter(): string {
34+
if (this.term === undefined) {
35+
return '';
36+
}
37+
3438
if (this.value === undefined) {
3539
return `_missing_:${this.term}`;
3640
}
@@ -41,7 +45,7 @@ export class BooleanFilter implements IFilter {
4145

4246
export class DateFilter implements IFilter {
4347
constructor(
44-
public term: string,
48+
public term?: string,
4549
public value?: Date | string
4650
) {}
4751

@@ -60,6 +64,10 @@ export class DateFilter implements IFilter {
6064
}
6165

6266
public toFilter(): string {
67+
if (this.term === undefined) {
68+
return '';
69+
}
70+
6371
if (this.value === undefined) {
6472
return `_missing_:${this.term}`;
6573
}
@@ -97,7 +105,7 @@ export class KeywordFilter implements IFilter {
97105

98106
export class NumberFilter implements IFilter {
99107
constructor(
100-
public term: string,
108+
public term?: string,
101109
public value?: number
102110
) {}
103111

@@ -116,6 +124,10 @@ export class NumberFilter implements IFilter {
116124
}
117125

118126
public toFilter(): string {
127+
if (this.term === undefined) {
128+
return '';
129+
}
130+
119131
if (this.value === undefined) {
120132
return `_missing_:${this.term}`;
121133
}
@@ -268,7 +280,7 @@ export class StatusFilter implements IFilter {
268280

269281
export class StringFilter implements IFilter {
270282
constructor(
271-
public term: string,
283+
public term?: string,
272284
public value?: string
273285
) {}
274286

@@ -287,6 +299,10 @@ export class StringFilter implements IFilter {
287299
}
288300

289301
public toFilter(): string {
302+
if (this.term === undefined) {
303+
return '';
304+
}
305+
290306
if (this.value === undefined) {
291307
return `_missing_:${this.term}`;
292308
}
@@ -327,7 +343,7 @@ export class TypeFilter implements IFilter {
327343

328344
export class VersionFilter implements IFilter {
329345
constructor(
330-
public term: string,
346+
public term?: string,
331347
public value?: string
332348
) {}
333349

@@ -346,6 +362,10 @@ export class VersionFilter implements IFilter {
346362
}
347363

348364
public toFilter(): string {
365+
if (this.term === undefined) {
366+
return '';
367+
}
368+
349369
if (this.value === undefined) {
350370
return `_missing_:${this.term}`;
351371
}

src/Exceptionless.Web/ClientApp/src/routes/(app)/+page.svelte

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,13 @@
2222
OrganizationFilter,
2323
ProjectFilter,
2424
DateFilter,
25-
setFilter
25+
setFilter,
26+
BooleanFilter,
27+
NumberFilter,
28+
ReferenceFilter,
29+
SessionFilter,
30+
StringFilter,
31+
VersionFilter
2632
} from '$comp/filters/filters';
2733
import CustomEventMessage from '$comp/messaging/CustomEventMessage.svelte';
2834
import { toFacetedFilters } from '$comp/filters/facets';
@@ -34,12 +40,19 @@
3440
3541
const limit = persisted<number>('events.limit', 10);
3642
const defaultFilters = [
37-
new OrganizationFilter(''),
38-
new ProjectFilter('', []),
43+
new OrganizationFilter(),
44+
new ProjectFilter(undefined, []),
3945
new StatusFilter([]),
4046
new TypeFilter([]),
4147
new DateFilter('date', 'last week'),
42-
new KeywordFilter('')
48+
new DateFilter(),
49+
new StringFilter(),
50+
new BooleanFilter(),
51+
new NumberFilter(),
52+
new ReferenceFilter(),
53+
new SessionFilter(),
54+
new VersionFilter(),
55+
new KeywordFilter()
4356
];
4457
const filters = persisted<IFilter[]>('events.filters', defaultFilters, { serializer: new FilterSerializer() });
4558
$filters.push(...defaultFilters.filter((df) => !$filters.some((f) => f.key === df.key)));
@@ -61,7 +74,6 @@
6174
} else {
6275
filters.set(processFilterRules($filters.filter((f) => f.key !== detail.key)));
6376
}
64-
console.log('filters', $filters)
6577
}
6678
6779
function processFilterRules(filters: IFilter[], changed?: IFilter): IFilter[] {

0 commit comments

Comments
 (0)