mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 20:34:37 +03:00
Improve client-side graphql scalar types (#4511)
* Add types to graphql scalars * Upgrade dependencies * Override UI config type * Remove all IUIConfig casts * Add tableColumns to IUIConfig * Add BoolMap type, set strictScalars * Add PluginConfigMap * Replace any with unknown * Add SavedObjectFilter and SavedUIOptions * Remove unused items from CriterionType
This commit is contained in:
@@ -23,7 +23,7 @@ export class CaptionCriterion extends StringCriterion {
|
||||
super(CaptionsCriterionOption);
|
||||
}
|
||||
|
||||
protected toCriterionInput() {
|
||||
public toCriterionInput() {
|
||||
const value = valueToCode(this.value) ?? "";
|
||||
|
||||
return {
|
||||
|
||||
@@ -25,7 +25,7 @@ export class CircumcisedCriterion extends MultiStringCriterion {
|
||||
super(CircumcisedCriterionOption);
|
||||
}
|
||||
|
||||
protected toCriterionInput(): CircumcisionCriterionInput {
|
||||
public toCriterionInput(): CircumcisionCriterionInput {
|
||||
const value = this.value.map((v) =>
|
||||
stringToCircumcised(v)
|
||||
) as CircumisedEnum[];
|
||||
|
||||
@@ -36,7 +36,7 @@ export type CriterionValue =
|
||||
| ITimestampValue
|
||||
| IPhashDistanceValue;
|
||||
|
||||
export interface IEncodedCriterion<T extends CriterionValue> {
|
||||
export interface ISavedCriterion<T extends CriterionValue> {
|
||||
modifier: CriterionModifier;
|
||||
value: T | undefined;
|
||||
}
|
||||
@@ -142,29 +142,22 @@ export abstract class Criterion<V extends CriterionValue> {
|
||||
return JSON.stringify(encodedCriterion);
|
||||
}
|
||||
|
||||
public setFromEncodedCriterion(encodedCriterion: IEncodedCriterion<V>) {
|
||||
if (
|
||||
encodedCriterion.value !== undefined &&
|
||||
encodedCriterion.value !== null
|
||||
) {
|
||||
this.value = encodedCriterion.value;
|
||||
public setFromSavedCriterion(criterion: ISavedCriterion<V>) {
|
||||
if (criterion.value !== undefined && criterion.value !== null) {
|
||||
this.value = criterion.value;
|
||||
}
|
||||
this.modifier = encodedCriterion.modifier;
|
||||
this.modifier = criterion.modifier;
|
||||
}
|
||||
|
||||
public apply(outputFilter: Record<string, unknown>) {
|
||||
outputFilter[this.criterionOption.type] = this.toCriterionInput();
|
||||
}
|
||||
|
||||
protected toCriterionInput(): unknown {
|
||||
public toCriterionInput(): unknown {
|
||||
return {
|
||||
value: this.value,
|
||||
modifier: this.modifier,
|
||||
};
|
||||
}
|
||||
|
||||
public toSavedFilter(outputFilter: Record<string, unknown>) {
|
||||
outputFilter[this.criterionOption.type] = {
|
||||
public toSavedCriterion(): ISavedCriterion<V> {
|
||||
return {
|
||||
value: this.value,
|
||||
modifier: this.modifier,
|
||||
};
|
||||
@@ -261,7 +254,7 @@ export class ILabeledIdCriterion extends Criterion<ILabeledId[]> {
|
||||
return this.value.map((v) => v.label).join(", ");
|
||||
}
|
||||
|
||||
protected toCriterionInput(): MultiCriterionInput {
|
||||
public toCriterionInput(): MultiCriterionInput {
|
||||
return {
|
||||
value: this.value.map((v) => v.id),
|
||||
modifier: this.modifier,
|
||||
@@ -311,10 +304,10 @@ export class IHierarchicalLabeledIdCriterion extends Criterion<IHierarchicalLabe
|
||||
}
|
||||
}
|
||||
|
||||
public setFromEncodedCriterion(
|
||||
encodedCriterion: IEncodedCriterion<IHierarchicalLabelValue>
|
||||
public setFromSavedCriterion(
|
||||
criterion: ISavedCriterion<IHierarchicalLabelValue>
|
||||
) {
|
||||
const { modifier, value } = encodedCriterion;
|
||||
const { modifier, value } = criterion;
|
||||
|
||||
if (value !== undefined) {
|
||||
this.value = {
|
||||
@@ -351,7 +344,7 @@ export class IHierarchicalLabeledIdCriterion extends Criterion<IHierarchicalLabe
|
||||
return `${labels} (+${this.value.depth > 0 ? this.value.depth : "all"})`;
|
||||
}
|
||||
|
||||
protected toCriterionInput(): HierarchicalMultiCriterionInput {
|
||||
public toCriterionInput(): HierarchicalMultiCriterionInput {
|
||||
let excludes: string[] = [];
|
||||
|
||||
// if modifier is equals, depth must be 0
|
||||
@@ -551,7 +544,7 @@ export function createBooleanCriterionOption(
|
||||
}
|
||||
|
||||
export class BooleanCriterion extends StringCriterion {
|
||||
protected toCriterionInput(): boolean {
|
||||
public toCriterionInput(): boolean {
|
||||
return this.value === "true";
|
||||
}
|
||||
|
||||
@@ -578,7 +571,7 @@ export class StringBooleanCriterionOption extends CriterionOption {
|
||||
}
|
||||
|
||||
export class StringBooleanCriterion extends StringCriterion {
|
||||
protected toCriterionInput(): string {
|
||||
public toCriterionInput(): string {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@@ -694,7 +687,7 @@ export class NumberCriterion extends Criterion<INumberValue> {
|
||||
}
|
||||
}
|
||||
|
||||
protected toCriterionInput(): IntCriterionInput {
|
||||
public toCriterionInput(): IntCriterionInput {
|
||||
return {
|
||||
modifier: this.modifier,
|
||||
value: this.value?.value ?? 0,
|
||||
@@ -761,7 +754,7 @@ export class DurationCriterion extends Criterion<INumberValue> {
|
||||
super(type, { value: undefined, value2: undefined });
|
||||
}
|
||||
|
||||
protected toCriterionInput(): IntCriterionInput {
|
||||
public toCriterionInput(): IntCriterionInput {
|
||||
return {
|
||||
modifier: this.modifier,
|
||||
value: this.value?.value ?? 0,
|
||||
@@ -841,7 +834,7 @@ export class DateCriterion extends Criterion<IDateValue> {
|
||||
};
|
||||
}
|
||||
|
||||
protected toCriterionInput(): DateCriterionInput {
|
||||
public toCriterionInput(): DateCriterionInput {
|
||||
return {
|
||||
modifier: this.modifier,
|
||||
value: this.value?.value,
|
||||
@@ -940,7 +933,7 @@ export class TimestampCriterion extends Criterion<ITimestampValue> {
|
||||
};
|
||||
}
|
||||
|
||||
protected toCriterionInput(): TimestampCriterionInput {
|
||||
public toCriterionInput(): TimestampCriterionInput {
|
||||
return {
|
||||
modifier: this.modifier,
|
||||
value: this.transformValueToInput(this.value.value),
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
import { genderStrings, stringToGender } from "src/utils/gender";
|
||||
import {
|
||||
CriterionOption,
|
||||
IEncodedCriterion,
|
||||
ISavedCriterion,
|
||||
MultiStringCriterion,
|
||||
} from "./criterion";
|
||||
|
||||
@@ -29,7 +29,7 @@ export class GenderCriterion extends MultiStringCriterion {
|
||||
super(GenderCriterionOption);
|
||||
}
|
||||
|
||||
protected toCriterionInput(): GenderCriterionInput {
|
||||
public toCriterionInput(): GenderCriterionInput {
|
||||
const value = this.value.map((v) => stringToGender(v)) as GenderEnum[];
|
||||
|
||||
return {
|
||||
@@ -38,17 +38,15 @@ export class GenderCriterion extends MultiStringCriterion {
|
||||
};
|
||||
}
|
||||
|
||||
public setFromEncodedCriterion(
|
||||
encodedCriterion: IEncodedCriterion<string[]>
|
||||
) {
|
||||
public setFromSavedCriterion(criterion: ISavedCriterion<string[]>) {
|
||||
// backwards compatibility - if the value is a string, convert it to an array
|
||||
if (typeof encodedCriterion.value === "string") {
|
||||
encodedCriterion = {
|
||||
...encodedCriterion,
|
||||
value: [encodedCriterion.value],
|
||||
if (typeof criterion.value === "string") {
|
||||
criterion = {
|
||||
...criterion,
|
||||
value: [criterion.value],
|
||||
};
|
||||
}
|
||||
|
||||
super.setFromEncodedCriterion(encodedCriterion);
|
||||
super.setFromSavedCriterion(criterion);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { CriterionType } from "../types";
|
||||
import { CriterionOption, StringCriterion, Option } from "./criterion";
|
||||
|
||||
export class IsMissingCriterion extends StringCriterion {
|
||||
protected toCriterionInput(): string {
|
||||
public toCriterionInput(): string {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
} from "src/core/generated-graphql";
|
||||
|
||||
export class OrientationCriterion extends MultiStringCriterion {
|
||||
protected toCriterionInput(): OrientationCriterionInput {
|
||||
public toCriterionInput(): OrientationCriterionInput {
|
||||
return {
|
||||
value: this.value
|
||||
.map((v) => stringToOrientation(v))
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
MultiCriterionInput,
|
||||
} from "src/core/generated-graphql";
|
||||
import { ILabeledId, ILabeledValueListValue } from "../types";
|
||||
import { Criterion, CriterionOption, IEncodedCriterion } from "./criterion";
|
||||
import { Criterion, CriterionOption, ISavedCriterion } from "./criterion";
|
||||
|
||||
const modifierOptions = [
|
||||
CriterionModifier.IncludesAll,
|
||||
@@ -49,10 +49,10 @@ export class PerformersCriterion extends Criterion<ILabeledValueListValue> {
|
||||
}
|
||||
}
|
||||
|
||||
public setFromEncodedCriterion(
|
||||
encodedCriterion: IEncodedCriterion<ILabeledId[] | ILabeledValueListValue>
|
||||
public setFromSavedCriterion(
|
||||
criterion: ISavedCriterion<ILabeledId[] | ILabeledValueListValue>
|
||||
) {
|
||||
const { modifier, value } = encodedCriterion;
|
||||
const { modifier, value } = criterion;
|
||||
|
||||
// #3619 - the format of performer value was changed from an array
|
||||
// to an object. Check for both formats.
|
||||
@@ -80,7 +80,7 @@ export class PerformersCriterion extends Criterion<ILabeledValueListValue> {
|
||||
return this.value.items.map((v) => v.label).join(", ");
|
||||
}
|
||||
|
||||
protected toCriterionInput(): MultiCriterionInput {
|
||||
public toCriterionInput(): MultiCriterionInput {
|
||||
let excludes: string[] = [];
|
||||
if (this.value.excluded) {
|
||||
excludes = this.value.excluded.map((v) => v.id);
|
||||
|
||||
@@ -42,7 +42,7 @@ export class PhashCriterion extends Criterion<IPhashDistanceValue> {
|
||||
}
|
||||
}
|
||||
|
||||
protected toCriterionInput(): PhashDistanceCriterionInput {
|
||||
public toCriterionInput(): PhashDistanceCriterionInput {
|
||||
return {
|
||||
value: this.value.value,
|
||||
modifier: this.modifier,
|
||||
@@ -62,7 +62,7 @@ export class DuplicatedCriterion extends StringCriterion {
|
||||
super(DuplicatedCriterionOption);
|
||||
}
|
||||
|
||||
protected toCriterionInput(): PHashDuplicationCriterionInput {
|
||||
public toCriterionInput(): PHashDuplicationCriterionInput {
|
||||
return {
|
||||
duplicated: this.value === "true",
|
||||
};
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
} from "src/core/generated-graphql";
|
||||
import { INumberValue } from "../types";
|
||||
import { Criterion, CriterionOption } from "./criterion";
|
||||
import { IUIConfig } from "src/core/config";
|
||||
|
||||
const modifierOptions = [
|
||||
CriterionModifier.Equals,
|
||||
@@ -25,9 +24,7 @@ const modifierOptions = [
|
||||
];
|
||||
|
||||
function getRatingSystemOptions(config?: ConfigDataFragment) {
|
||||
return (
|
||||
(config?.ui as IUIConfig)?.ratingSystemOptions ?? defaultRatingSystemOptions
|
||||
);
|
||||
return config?.ui.ratingSystemOptions ?? defaultRatingSystemOptions;
|
||||
}
|
||||
|
||||
export const RatingCriterionOption = new CriterionOption({
|
||||
@@ -58,7 +55,7 @@ export class RatingCriterion extends Criterion<INumberValue> {
|
||||
}
|
||||
}
|
||||
|
||||
protected toCriterionInput(): IntCriterionInput {
|
||||
public toCriterionInput(): IntCriterionInput {
|
||||
return {
|
||||
modifier: this.modifier,
|
||||
value: this.value.value ?? 0,
|
||||
|
||||
@@ -32,7 +32,7 @@ class BaseResolutionCriterionOption extends CriterionOption {
|
||||
}
|
||||
|
||||
class BaseResolutionCriterion extends StringCriterion {
|
||||
protected toCriterionInput(): ResolutionCriterionInput | undefined {
|
||||
public toCriterionInput(): ResolutionCriterionInput | undefined {
|
||||
const value = stringToResolution(this.value);
|
||||
|
||||
if (value !== undefined) {
|
||||
|
||||
@@ -43,7 +43,7 @@ export class StashIDCriterion extends Criterion<IStashIDValue> {
|
||||
}
|
||||
}
|
||||
|
||||
protected toCriterionInput(): StashIdCriterionInput {
|
||||
public toCriterionInput(): StashIdCriterionInput {
|
||||
return {
|
||||
endpoint: this.value.endpoint,
|
||||
stash_id: this.value.stashID,
|
||||
|
||||
@@ -5,9 +5,18 @@ import {
|
||||
SavedFilterDataFragment,
|
||||
SortDirectionEnum,
|
||||
} from "src/core/generated-graphql";
|
||||
import { Criterion, CriterionValue } from "./criteria/criterion";
|
||||
import {
|
||||
Criterion,
|
||||
CriterionValue,
|
||||
ISavedCriterion,
|
||||
} from "./criteria/criterion";
|
||||
import { getFilterOptions } from "./factory";
|
||||
import { CriterionType, DisplayMode } from "./types";
|
||||
import {
|
||||
CriterionType,
|
||||
DisplayMode,
|
||||
SavedObjectFilter,
|
||||
SavedUIOptions,
|
||||
} from "./types";
|
||||
|
||||
interface IDecodedParams {
|
||||
perPage?: number;
|
||||
@@ -127,9 +136,12 @@ export class ListFilterModel {
|
||||
if (params.c !== undefined) {
|
||||
for (const jsonString of params.c) {
|
||||
try {
|
||||
const encodedCriterion = JSON.parse(jsonString);
|
||||
const criterion = this.makeCriterion(encodedCriterion.type);
|
||||
criterion.setFromEncodedCriterion(encodedCriterion);
|
||||
const { type: criterionType, ...savedCriterion } =
|
||||
JSON.parse(jsonString);
|
||||
|
||||
const criterion = this.makeCriterion(criterionType);
|
||||
criterion.setFromSavedCriterion(savedCriterion);
|
||||
|
||||
this.criteria.push(criterion);
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line no-console
|
||||
@@ -261,8 +273,7 @@ export class ListFilterModel {
|
||||
this.sortBy = "random";
|
||||
this.randomSeed = Number.parseInt(match[1], 10);
|
||||
}
|
||||
this.sortDirection =
|
||||
(findFilter?.direction as SortDirectionEnum) ?? this.sortDirection;
|
||||
this.sortDirection = findFilter?.direction ?? this.sortDirection;
|
||||
this.searchTerm = findFilter?.q ?? this.searchTerm;
|
||||
|
||||
this.displayMode = uiOptions?.display_mode ?? this.displayMode;
|
||||
@@ -272,11 +283,11 @@ export class ListFilterModel {
|
||||
|
||||
this.criteria = [];
|
||||
if (objectFilter) {
|
||||
Object.keys(objectFilter).forEach((key) => {
|
||||
const criterion = this.makeCriterion(key as CriterionType);
|
||||
criterion.setFromEncodedCriterion(objectFilter[key]);
|
||||
for (const [k, v] of Object.entries(objectFilter)) {
|
||||
const criterion = this.makeCriterion(k as CriterionType);
|
||||
criterion.setFromSavedCriterion(v as ISavedCriterion<CriterionValue>);
|
||||
this.criteria.push(criterion);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,31 +364,6 @@ export class ListFilterModel {
|
||||
};
|
||||
}
|
||||
|
||||
public makeSavedFilterJSON() {
|
||||
const encodedCriteria: string[] = this.criteria.map((criterion) =>
|
||||
criterion.toJSON()
|
||||
);
|
||||
|
||||
const result = {
|
||||
perPage: this.itemsPerPage,
|
||||
sortby: this.getSortBy(),
|
||||
sortdir:
|
||||
this.sortBy === "date"
|
||||
? this.sortDirection === SortDirectionEnum.Asc
|
||||
? "asc"
|
||||
: undefined
|
||||
: this.sortDirection === SortDirectionEnum.Desc
|
||||
? "desc"
|
||||
: undefined,
|
||||
disp: this.displayMode,
|
||||
q: this.searchTerm || undefined,
|
||||
z: this.zoomIndex,
|
||||
c: encodedCriteria,
|
||||
};
|
||||
|
||||
return JSON.stringify(result);
|
||||
}
|
||||
|
||||
public makeQueryParameters(): string {
|
||||
const query: string[] = [];
|
||||
const params = this.getEncodedParams();
|
||||
@@ -424,8 +410,6 @@ export class ListFilterModel {
|
||||
return option.makeCriterion(this.config);
|
||||
}
|
||||
|
||||
// TODO: These don't support multiple of the same criteria, only the last one set is used.
|
||||
|
||||
public makeFindFilter(): FindFilterType {
|
||||
return {
|
||||
q: this.searchTerm,
|
||||
@@ -438,23 +422,21 @@ export class ListFilterModel {
|
||||
|
||||
public makeFilter() {
|
||||
const output: Record<string, unknown> = {};
|
||||
this.criteria.forEach((criterion) => {
|
||||
criterion.apply(output);
|
||||
});
|
||||
|
||||
for (const c of this.criteria) {
|
||||
output[c.criterionOption.type] = c.toCriterionInput();
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
public makeSavedFindFilter() {
|
||||
const output: Record<string, unknown> = {};
|
||||
this.criteria.forEach((criterion) => {
|
||||
criterion.toSavedFilter(output);
|
||||
});
|
||||
|
||||
public makeSavedFilter() {
|
||||
const output: SavedObjectFilter = {};
|
||||
for (const c of this.criteria) {
|
||||
output[c.criterionOption.type] = c.toSavedCriterion();
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
public makeUIOptions(): Record<string, unknown> {
|
||||
public makeSavedUIOptions(): SavedUIOptions {
|
||||
return {
|
||||
display_mode: this.displayMode,
|
||||
zoom_index: this.zoomIndex,
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
import { CriterionValue, ISavedCriterion } from "./criteria/criterion";
|
||||
|
||||
export type SavedObjectFilter = {
|
||||
[K in CriterionType]?: ISavedCriterion<CriterionValue>;
|
||||
};
|
||||
|
||||
export type SavedUIOptions = {
|
||||
display_mode?: DisplayMode;
|
||||
zoom_index?: number;
|
||||
};
|
||||
|
||||
// NOTE: add new enum values to the end, to ensure existing data
|
||||
// is not impacted
|
||||
export enum DisplayMode {
|
||||
@@ -114,7 +125,6 @@ export interface IOptionType {
|
||||
|
||||
export type CriterionType =
|
||||
| "path"
|
||||
| "rating"
|
||||
| "rating100"
|
||||
| "organized"
|
||||
| "o_counter"
|
||||
@@ -141,7 +151,6 @@ export type CriterionType =
|
||||
| "country"
|
||||
| "hair_color"
|
||||
| "eye_color"
|
||||
| "height"
|
||||
| "height_cm"
|
||||
| "weight"
|
||||
| "measurements"
|
||||
@@ -162,7 +171,6 @@ export type CriterionType =
|
||||
| "performer_count"
|
||||
| "death_year"
|
||||
| "url"
|
||||
| "stash_id"
|
||||
| "interactive"
|
||||
| "interactive_speed"
|
||||
| "captions"
|
||||
|
||||
Reference in New Issue
Block a user