summaryrefslogtreecommitdiffstatshomepage
path: root/frontend
diff options
context:
space:
mode:
authorWolfgang Müller2025-02-20 13:40:40 +0100
committerWolfgang Müller2025-02-20 19:48:37 +0100
commit9c460c6db7e6a4e7f8ed3e8d93032c7ef070efee (patch)
tree69146def4fbc08f7fa4ad3bb37035a53d283b48a /frontend
parentf90f3604cf161a82336ed1f81967933adedfeb96 (diff)
downloadhircine-9c460c6db7e6a4e7f8ed3e8d93032c7ef070efee.tar.gz
Add filter for association counts
This will replace the old 'empty' filter on comic associations and introduce a generic way of matching against association counts, along with support for different operators like 'greater than' or 'lower than'. Models that did not previously have a way of matching against their associates (like filtering for Artists that have N comics associated with them) now gain that functionality. For now the frontend keeps the simpler approach of allowing the user to only filter for empty associations, but we nonetheless need to adjust the 'empty' field to instead be linked to the new 'count' field.
Diffstat (limited to 'frontend')
-rw-r--r--frontend/src/gql/graphql.ts25
-rw-r--r--frontend/src/lib/Enums.ts7
-rw-r--r--frontend/src/lib/Filter.svelte.ts25
3 files changed, 49 insertions, 8 deletions
diff --git a/frontend/src/gql/graphql.ts b/frontend/src/gql/graphql.ts
index bd001f3..63f2c55 100644
--- a/frontend/src/gql/graphql.ts
+++ b/frontend/src/gql/graphql.ts
@@ -122,6 +122,7 @@ export type Artist = {
};
export type ArtistFilter = {
+ comics?: InputMaybe<BasicCountFilter>;
name?: InputMaybe<StringFilter>;
};
@@ -164,10 +165,14 @@ export type ArtistsUpsertInput = {
export type AssociationFilter = {
all?: InputMaybe<Array<Scalars['Int']['input']>>;
any?: InputMaybe<Array<Scalars['Int']['input']>>;
- empty?: InputMaybe<Scalars['Boolean']['input']>;
+ count?: InputMaybe<CountFilter>;
exact?: InputMaybe<Array<Scalars['Int']['input']>>;
};
+export type BasicCountFilter = {
+ count: CountFilter;
+};
+
export enum Category {
Artbook = 'ARTBOOK',
Comic = 'COMIC',
@@ -203,6 +208,7 @@ export type Character = {
};
export type CharacterFilter = {
+ comics?: InputMaybe<BasicCountFilter>;
name?: InputMaybe<StringFilter>;
};
@@ -249,6 +255,7 @@ export type Circle = {
};
export type CircleFilter = {
+ comics?: InputMaybe<BasicCountFilter>;
name?: InputMaybe<StringFilter>;
};
@@ -396,6 +403,11 @@ export type ComicTotals = {
worlds: Scalars['Int']['output'];
};
+export type CountFilter = {
+ operator?: InputMaybe<Operator>;
+ value: Scalars['Int']['input'];
+};
+
export type CoverInput = {
id: Scalars['Int']['input'];
};
@@ -862,6 +874,7 @@ export type Namespace = {
export type NamespaceFilter = {
name?: InputMaybe<StringFilter>;
+ tags?: InputMaybe<BasicCountFilter>;
};
export type NamespaceFilterInput = {
@@ -905,6 +918,12 @@ export enum OnMissing {
Ignore = 'IGNORE'
}
+export enum Operator {
+ Equal = 'EQUAL',
+ GreaterThan = 'GREATER_THAN',
+ LowerThan = 'LOWER_THAN'
+}
+
export type Page = {
__typename?: 'Page';
comicId?: Maybe<Scalars['Int']['output']>;
@@ -1153,11 +1172,12 @@ export type Tag = {
export type TagAssociationFilter = {
all?: InputMaybe<Array<Scalars['String']['input']>>;
any?: InputMaybe<Array<Scalars['String']['input']>>;
- empty?: InputMaybe<Scalars['Boolean']['input']>;
+ count?: InputMaybe<CountFilter>;
exact?: InputMaybe<Array<Scalars['String']['input']>>;
};
export type TagFilter = {
+ comics?: InputMaybe<BasicCountFilter>;
name?: InputMaybe<StringFilter>;
namespaces?: InputMaybe<AssociationFilter>;
};
@@ -1324,6 +1344,7 @@ export type World = {
};
export type WorldFilter = {
+ comics?: InputMaybe<BasicCountFilter>;
name?: InputMaybe<StringFilter>;
};
diff --git a/frontend/src/lib/Enums.ts b/frontend/src/lib/Enums.ts
index 3264de4..db9fb86 100644
--- a/frontend/src/lib/Enums.ts
+++ b/frontend/src/lib/Enums.ts
@@ -10,6 +10,7 @@ import {
Language,
Layout,
NamespaceSort,
+ Operator,
Rating,
TagSort,
UpdateMode,
@@ -125,6 +126,12 @@ export const UpdateModeLabel: Record<UpdateMode, string> = {
[UpdateMode.Replace]: 'Replace'
};
+export const OperatorLabel: Record<Operator, string> = {
+ [Operator.Equal]: 'Equal',
+ [Operator.GreaterThan]: 'Greater than',
+ [Operator.LowerThan]: 'Lower than,'
+};
+
export const LanguageLabel: Record<Language, string> = {
[Language.Ab]: 'Abkhazian',
[Language.Aa]: 'Afar',
diff --git a/frontend/src/lib/Filter.svelte.ts b/frontend/src/lib/Filter.svelte.ts
index 6183f06..e73f497 100644
--- a/frontend/src/lib/Filter.svelte.ts
+++ b/frontend/src/lib/Filter.svelte.ts
@@ -1,4 +1,5 @@
import {
+ Operator,
type ArchiveFilter,
type ArchiveFilterInput,
type ComicFilter,
@@ -30,7 +31,7 @@ type AssocFilter<T, K extends Key> = Filter<
any?: T[] | null;
all?: T[] | null;
exact?: T[] | null;
- empty?: boolean | null;
+ count?: { value: number; operator?: Operator | null } | null;
},
K
>;
@@ -62,10 +63,6 @@ class ComplexMember<K extends Key> {
if (this.values.length > 0) {
filter[this.key] = { [this.mode]: this.values };
}
-
- if (this.empty) {
- filter[this.key] = { ...filter[this.key], empty: this.empty };
- }
}
}
@@ -80,7 +77,9 @@ export class Association<K extends Key> extends ComplexMember<K> {
}
const prop = filter[key];
- this.empty = prop?.empty;
+ this.empty =
+ prop?.count?.value === 0 &&
+ (prop.count.operator === undefined || prop.count.operator === Operator.Equal);
if (prop?.all && prop.all.length > 0) {
this.mode = 'all';
@@ -93,6 +92,13 @@ export class Association<K extends Key> extends ComplexMember<K> {
this.values = prop.exact;
}
}
+
+ integrate(filter: AssocFilter<unknown, K>) {
+ super.integrate(filter);
+ if (this.empty) {
+ filter[this.key] = { ...filter[this.key], count: { value: 0, operator: Operator.Equal } };
+ }
+ }
}
export class Enum<K extends Key> extends ComplexMember<K> {
@@ -112,6 +118,13 @@ export class Enum<K extends Key> extends ComplexMember<K> {
this.values = prop.any;
}
}
+
+ integrate(filter: EnumFilter<K>) {
+ super.integrate(filter);
+ if (this.empty) {
+ filter[this.key] = { ...filter[this.key], empty: this.empty };
+ }
+ }
}
class Bool<K extends Key> {