diff options
author | Wolfgang Müller | 2025-02-20 15:24:42 +0100 |
---|---|---|
committer | Wolfgang Müller | 2025-02-20 19:51:39 +0100 |
commit | 8e9aa5f6286a15c818a47344fc80964f5288bb52 (patch) | |
tree | b3ef187daff345eeb918ab07900cc1c4185c53e4 /frontend/src/lib/Filter.svelte.ts | |
parent | c6bf35aea63969b90463d6e70cb02ed61e4e3270 (diff) | |
download | hircine-8e9aa5f6286a15c818a47344fc80964f5288bb52.tar.gz |
frontend: Allow filtering for orphaned associations
With the association count filters in place we may now also allow the
user to filter for associations that do not have a matching counterparts
(artists without a comic, for example).
Diffstat (limited to 'frontend/src/lib/Filter.svelte.ts')
-rw-r--r-- | frontend/src/lib/Filter.svelte.ts | 73 |
1 files changed, 68 insertions, 5 deletions
diff --git a/frontend/src/lib/Filter.svelte.ts b/frontend/src/lib/Filter.svelte.ts index e73f497..390b98a 100644 --- a/frontend/src/lib/Filter.svelte.ts +++ b/frontend/src/lib/Filter.svelte.ts @@ -4,6 +4,8 @@ import { type ArchiveFilterInput, type ComicFilter, type ComicFilterInput, + type NamespaceFilter, + type NamespaceFilterInput, type StringFilter, type TagFilter, type TagFilterInput @@ -16,10 +18,18 @@ interface FilterInput<T> { exclude?: T | null; } -interface BasicFilter { +interface NameFilter { name?: { contains?: string | null } | null; } +interface AssociationCount { + count: { value: number; operator?: Operator | null }; +} + +interface BasicFilter extends NameFilter { + comics?: AssociationCount | null; +} + export type FilterType = 'include' | 'exclude'; type FilterMode = 'any' | 'all' | 'exact'; @@ -146,6 +156,27 @@ class Bool<K extends Key> { } } +class Orphan<K extends Key> { + key: K; + value?: boolean = false; + + constructor(key: K, filter?: Filter<AssociationCount, K> | null) { + this.key = key; + + if (filter) { + this.value = + filter[key]?.count?.value === 0 && + (filter[key].count.operator === undefined || filter[key].count.operator === Operator.Equal); + } + } + + integrate(filter: Filter<AssociationCount, K>) { + if (this.value) { + filter[this.key] = { count: { value: 0, operator: Operator.Equal } }; + } + } +} + class Str<K extends Key> { key: K; contains = $state(''); @@ -177,7 +208,7 @@ export class ArchiveFilterControls extends Controls<ArchiveFilter> { path: Str<'path'>; organized: Bool<'organized'>; - constructor(filter: ArchiveFilter | null | undefined) { + constructor(filter?: ArchiveFilter | null) { super(); this.path = new Str('path', filter); @@ -223,16 +254,26 @@ export class ComicFilterControls extends Controls<ComicFilter> { } } -export class BasicFilterControls extends Controls<BasicFilter> { +export class NameFilterControls extends Controls<NameFilter> { name: Str<'name'>; - constructor(filter?: BasicFilter | null) { + constructor(filter?: NameFilter | null) { super(); this.name = new Str('name', filter); } } +export class BasicFilterControls extends NameFilterControls { + orphan: Orphan<'comics'>; + + constructor(filter?: BasicFilter | null) { + super(filter); + + this.orphan = new Orphan('comics', filter); + } +} + export class TagFilterControls extends BasicFilterControls { namespaces: Association<'namespaces'>; @@ -243,6 +284,16 @@ export class TagFilterControls extends BasicFilterControls { } } +export class NamespaceFilterControls extends NameFilterControls { + orphan: Orphan<'tags'>; + + constructor(filter?: NamespaceFilter | null) { + super(filter); + + this.orphan = new Orphan('tags', filter); + } +} + function buildFilterInput<F>(include?: F, exclude?: F) { const input: FilterInput<F> = {}; @@ -318,7 +369,7 @@ export class BasicFilterContext extends FilterContext<BasicFilter> { export class TagFilterContext extends FilterContext<TagFilter> { include: TagFilterControls; exclude: TagFilterControls; - private static ignore = ['name']; + private static ignore = ['name', 'comics']; constructor(filter: TagFilterInput) { super(); @@ -330,6 +381,18 @@ export class TagFilterContext extends FilterContext<TagFilter> { } } +export class NamespaceFilterContext extends FilterContext<NamespaceFilter> { + include: NamespaceFilterControls; + exclude: NamespaceFilterControls; + + constructor(filter: NamespaceFilterInput) { + super(); + + this.include = new NamespaceFilterControls(filter.include); + this.exclude = new NamespaceFilterControls(); + } +} + export function cycleBooleanFilter(value: boolean | undefined, tristate = true) { if (tristate) { if (value === undefined) { |