Custom fields filter UI (#5632)

* Refactor criteria and criterion options
* Add custom fields filtering in UI
This commit is contained in:
WithoutPants
2025-02-24 14:32:53 +11:00
committed by GitHub
parent 46d424fbaf
commit b6ace42973
44 changed files with 929 additions and 292 deletions

View File

@@ -1,10 +1,10 @@
import { CriterionModifier } from "src/core/generated-graphql";
import { languageMap, valueToCode } from "src/utils/caption";
import { CriterionOption, StringCriterion } from "./criterion";
import { ModifierCriterionOption, StringCriterion } from "./criterion";
const languageStrings = Array.from(languageMap.values());
export const CaptionsCriterionOption = new CriterionOption({
export const CaptionsCriterionOption = new ModifierCriterionOption({
messageID: "captions",
type: "captions",
modifierOptions: [

View File

@@ -4,9 +4,9 @@ import {
CriterionModifier,
} from "src/core/generated-graphql";
import { circumcisedStrings, stringToCircumcised } from "src/utils/circumcised";
import { CriterionOption, MultiStringCriterion } from "./criterion";
import { ModifierCriterionOption, MultiStringCriterion } from "./criterion";
export const CircumcisedCriterionOption = new CriterionOption({
export const CircumcisedCriterionOption = new ModifierCriterionOption({
messageID: "circumcised",
type: "circumcised",
modifierOptions: [

View File

@@ -57,10 +57,41 @@ const modifierMessageIDs = {
[CriterionModifier.NotBetween]: "criterion_modifier.not_between",
};
// V = criterion value type
export abstract class Criterion<V extends CriterionValue> {
export abstract class Criterion {
public criterionOption: CriterionOption;
constructor(type: CriterionOption) {
this.criterionOption = type;
}
public isValid(): boolean {
return true;
}
public clone() {
const ret = Object.assign(Object.create(Object.getPrototypeOf(this)), this);
ret.cloneValues();
return ret;
}
protected cloneValues() {}
public abstract getLabel(intl: IntlShape): string;
public getId(): string {
return `${this.criterionOption.type}`;
}
public abstract toJSON(): string;
public abstract applyToCriterionInput(input: Record<string, unknown>): void;
public abstract setFromSavedCriterion(criterion: unknown): void;
}
// V = criterion value type
export abstract class ModifierCriterion<
V extends CriterionValue
> extends Criterion {
protected _modifier!: CriterionModifier;
public get modifier(): CriterionModifier {
return this._modifier;
@@ -83,12 +114,16 @@ export abstract class Criterion<V extends CriterionValue> {
protected abstract getLabelValue(intl: IntlShape): string;
constructor(type: CriterionOption, value: V) {
this.criterionOption = type;
constructor(type: ModifierCriterionOption, value: V) {
super(type);
this.modifier = type.defaultModifier;
this.value = value;
}
public modifierCriterionOption() {
return this.criterionOption as ModifierCriterionOption;
}
public clone() {
const ret = Object.assign(Object.create(Object.getPrototypeOf(this)), this);
ret.cloneValues();
@@ -106,7 +141,10 @@ export abstract class Criterion<V extends CriterionValue> {
}
public getLabel(intl: IntlShape): string {
const modifierString = Criterion.getModifierLabel(intl, this.modifier);
const modifierString = ModifierCriterion.getModifierLabel(
intl,
this.modifier
);
let valueString = "";
if (
@@ -126,10 +164,6 @@ export abstract class Criterion<V extends CriterionValue> {
);
}
public getId(): string {
return `${this.criterionOption.type}-${this.modifier.toString()}`; // TODO add values?
}
public toJSON() {
let encodedCriterion;
if (
@@ -157,14 +191,11 @@ export abstract class Criterion<V extends CriterionValue> {
this.modifier = criterion.modifier;
}
public toCriterionInput(): unknown {
return {
value: this.value,
modifier: this.modifier,
};
public applyToCriterionInput(input: Record<string, unknown>) {
input[this.criterionOption.type] = this.toCriterionInput();
}
public toSavedCriterion(): ISavedCriterion<V> {
public toCriterionInput(): unknown {
return {
value: this.value,
modifier: this.modifier,
@@ -185,44 +216,31 @@ export type InputType =
| "galleries"
| undefined;
interface ICriterionOptionsParams {
type MakeCriterionFn = (
o: CriterionOption,
config?: ConfigDataFragment
) => Criterion;
interface ICriterionOptionParams {
messageID: string;
type: CriterionType;
inputType?: InputType;
modifierOptions?: CriterionModifier[];
defaultModifier?: CriterionModifier;
options?: Option[];
makeCriterion: MakeCriterionFn;
hidden?: boolean;
makeCriterion: (
o: CriterionOption,
config?: ConfigDataFragment
) => Criterion<CriterionValue>;
}
export class CriterionOption {
public readonly messageID: string;
public readonly type: CriterionType;
public readonly modifierOptions: CriterionModifier[];
public readonly defaultModifier: CriterionModifier;
public readonly options: Option[] | undefined;
public readonly inputType: InputType;
public readonly messageID: string;
public readonly makeCriterionFn: MakeCriterionFn;
// used for legacy criteria that are not shown in the UI
public readonly hidden: boolean = false;
public readonly makeCriterionFn: (
o: CriterionOption,
config?: ConfigDataFragment
) => Criterion<CriterionValue>;
constructor(options: ICriterionOptionsParams) {
this.messageID = options.messageID;
constructor(options: ICriterionOptionParams) {
this.type = options.type;
this.modifierOptions = options.modifierOptions ?? [];
this.defaultModifier = options.defaultModifier ?? CriterionModifier.Equals;
this.options = options.options;
this.inputType = options.inputType;
this.hidden = options.hidden ?? false;
this.messageID = options.messageID;
this.makeCriterionFn = options.makeCriterion;
this.hidden = options.hidden ?? false;
}
public makeCriterion(config?: ConfigDataFragment) {
@@ -230,13 +248,35 @@ export class CriterionOption {
}
}
export class ILabeledIdCriterionOption extends CriterionOption {
interface IModifierCriterionOptionParams extends ICriterionOptionParams {
inputType?: InputType;
modifierOptions?: CriterionModifier[];
defaultModifier?: CriterionModifier;
options?: Option[];
}
export class ModifierCriterionOption extends CriterionOption {
public readonly modifierOptions: CriterionModifier[];
public readonly defaultModifier: CriterionModifier;
public readonly options: Option[] | undefined;
public readonly inputType: InputType;
constructor(options: IModifierCriterionOptionParams) {
super(options);
this.modifierOptions = options.modifierOptions ?? [];
this.defaultModifier = options.defaultModifier ?? CriterionModifier.Equals;
this.options = options.options;
this.inputType = options.inputType;
}
}
export class ILabeledIdCriterionOption extends ModifierCriterionOption {
constructor(
messageID: string,
value: CriterionType,
includeAll: boolean,
inputType: InputType,
makeCriterion?: () => Criterion<CriterionValue>
makeCriterion?: () => ModifierCriterion<CriterionValue>
) {
const modifierOptions = [
CriterionModifier.Includes,
@@ -264,8 +304,8 @@ export class ILabeledIdCriterionOption extends CriterionOption {
}
}
export class ILabeledIdCriterion extends Criterion<ILabeledId[]> {
constructor(type: CriterionOption, value: ILabeledId[] = []) {
export class ILabeledIdCriterion extends ModifierCriterion<ILabeledId[]> {
constructor(type: ModifierCriterionOption, value: ILabeledId[] = []) {
super(type, value);
}
@@ -296,9 +336,9 @@ export class ILabeledIdCriterion extends Criterion<ILabeledId[]> {
}
}
export class IHierarchicalLabeledIdCriterion extends Criterion<IHierarchicalLabelValue> {
export class IHierarchicalLabeledIdCriterion extends ModifierCriterion<IHierarchicalLabelValue> {
constructor(
type: CriterionOption,
type: ModifierCriterionOption,
value: IHierarchicalLabelValue = {
items: [],
excluded: [],
@@ -346,14 +386,16 @@ export class IHierarchicalLabeledIdCriterion extends Criterion<IHierarchicalLabe
};
}
const modifierOptions =
(this.criterionOption as ModifierCriterionOption).modifierOptions ?? [];
// if the previous modifier was excludes, replace it with the equivalent includes criterion
// this is what is done on the backend
// only replace if excludes is not a valid modifierOption
if (
modifier === CriterionModifier.Excludes &&
this.criterionOption.modifierOptions.find(
(m) => m === CriterionModifier.Excludes
) === undefined
modifierOptions.find((m) => m === CriterionModifier.Excludes) ===
undefined
) {
this.modifier = CriterionModifier.Includes;
this.value.excluded = [...this.value.excluded, ...this.value.items];
@@ -407,7 +449,10 @@ export class IHierarchicalLabeledIdCriterion extends Criterion<IHierarchicalLabe
public getLabel(intl: IntlShape): string {
let id = "criterion_modifier.format_string";
let modifierString = Criterion.getModifierLabel(intl, this.modifier);
let modifierString = ModifierCriterion.getModifierLabel(
intl,
this.modifier
);
let valueString = "";
let excludedString = "";
@@ -419,7 +464,7 @@ export class IHierarchicalLabeledIdCriterion extends Criterion<IHierarchicalLabe
if (this.value.excluded && this.value.excluded.length > 0) {
if (this.value.items.length === 0) {
modifierString = Criterion.getModifierLabel(
modifierString = ModifierCriterion.getModifierLabel(
intl,
CriterionModifier.Excludes
);
@@ -448,11 +493,11 @@ export class IHierarchicalLabeledIdCriterion extends Criterion<IHierarchicalLabe
}
}
export class StringCriterionOption extends CriterionOption {
export class StringCriterionOption extends ModifierCriterionOption {
constructor(
messageID: string,
value: CriterionType,
makeCriterion?: () => Criterion<CriterionValue>
makeCriterion?: () => ModifierCriterion<CriterionValue>
) {
super({
messageID,
@@ -483,7 +528,7 @@ export function createStringCriterionOption(
return new StringCriterionOption(messageID ?? type, type);
}
export class MandatoryStringCriterionOption extends CriterionOption {
export class MandatoryStringCriterionOption extends ModifierCriterionOption {
constructor(messageID: string, value: CriterionType) {
super({
messageID,
@@ -510,8 +555,8 @@ export function createMandatoryStringCriterionOption(
return new MandatoryStringCriterionOption(messageID ?? value, value);
}
export class StringCriterion extends Criterion<string> {
constructor(type: CriterionOption) {
export class StringCriterion extends ModifierCriterion<string> {
constructor(type: ModifierCriterionOption) {
super(type, "");
}
@@ -528,8 +573,8 @@ export class StringCriterion extends Criterion<string> {
}
}
export abstract class MultiStringCriterion extends Criterion<string[]> {
constructor(type: CriterionOption, value: string[] = []) {
export abstract class MultiStringCriterion extends ModifierCriterion<string[]> {
constructor(type: ModifierCriterionOption, value: string[] = []) {
super(type, value);
}
@@ -550,11 +595,11 @@ export abstract class MultiStringCriterion extends Criterion<string[]> {
}
}
export class BooleanCriterionOption extends CriterionOption {
export class BooleanCriterionOption extends ModifierCriterionOption {
constructor(
messageID: string,
value: CriterionType,
makeCriterion?: () => Criterion<CriterionValue>
makeCriterion?: () => ModifierCriterion<CriterionValue>
) {
super({
messageID,
@@ -586,11 +631,11 @@ export class BooleanCriterion extends StringCriterion {
}
}
export class StringBooleanCriterionOption extends CriterionOption {
export class StringBooleanCriterionOption extends ModifierCriterionOption {
constructor(
messageID: string,
value: CriterionType,
makeCriterion?: () => Criterion<CriterionValue>
makeCriterion?: () => ModifierCriterion<CriterionValue>
) {
super({
messageID,
@@ -613,7 +658,7 @@ export class StringBooleanCriterion extends StringCriterion {
}
}
export class NumberCriterionOption extends CriterionOption {
export class NumberCriterionOption extends ModifierCriterionOption {
constructor(messageID: string, value: CriterionType) {
super({
messageID,
@@ -642,11 +687,11 @@ export function createNumberCriterionOption(
return new NumberCriterionOption(messageID ?? value, value);
}
export class NullNumberCriterionOption extends CriterionOption {
export class NullNumberCriterionOption extends ModifierCriterionOption {
constructor(
messageID: string,
value: CriterionType,
makeCriterion?: () => Criterion<CriterionValue>
makeCriterion?: MakeCriterionFn
) {
super({
messageID,
@@ -677,11 +722,11 @@ export function createNullNumberCriterionOption(
return new NullNumberCriterionOption(messageID ?? value, value);
}
export class MandatoryNumberCriterionOption extends CriterionOption {
export class MandatoryNumberCriterionOption extends ModifierCriterionOption {
constructor(
messageID: string,
value: CriterionType,
makeCriterion?: () => Criterion<CriterionValue>
makeCriterion?: () => ModifierCriterion<CriterionValue>
) {
super({
messageID,
@@ -710,8 +755,8 @@ export function createMandatoryNumberCriterionOption(
return new MandatoryNumberCriterionOption(messageID ?? value, value);
}
export class NumberCriterion extends Criterion<INumberValue> {
constructor(type: CriterionOption) {
export class NumberCriterion extends ModifierCriterion<INumberValue> {
constructor(type: ModifierCriterionOption) {
super(type, { value: undefined, value2: undefined });
}
@@ -805,8 +850,8 @@ export function createNullDurationCriterionOption(
return new NullDurationCriterionOption(messageID ?? value, value);
}
export class DurationCriterion extends Criterion<INumberValue> {
constructor(type: CriterionOption) {
export class DurationCriterion extends ModifierCriterion<INumberValue> {
constructor(type: ModifierCriterionOption) {
super(type, { value: undefined, value2: undefined });
}
@@ -860,7 +905,7 @@ export class DurationCriterion extends Criterion<INumberValue> {
}
}
export class DateCriterionOption extends CriterionOption {
export class DateCriterionOption extends ModifierCriterionOption {
constructor(messageID: string, value: CriterionType) {
super({
messageID,
@@ -886,8 +931,8 @@ export function createDateCriterionOption(value: CriterionType) {
return new DateCriterionOption(value, value);
}
export class DateCriterion extends Criterion<IDateValue> {
constructor(type: CriterionOption) {
export class DateCriterion extends ModifierCriterion<IDateValue> {
constructor(type: ModifierCriterionOption) {
super(type, { value: "", value2: undefined });
}
@@ -943,7 +988,7 @@ export class DateCriterion extends Criterion<IDateValue> {
}
}
export class TimestampCriterionOption extends CriterionOption {
export class TimestampCriterionOption extends ModifierCriterionOption {
constructor(messageID: string, value: CriterionType) {
super({
messageID,
@@ -967,7 +1012,7 @@ export function createTimestampCriterionOption(value: CriterionType) {
return new TimestampCriterionOption(value, value);
}
export class MandatoryTimestampCriterionOption extends CriterionOption {
export class MandatoryTimestampCriterionOption extends ModifierCriterionOption {
constructor(messageID: string, value: CriterionType) {
super({
messageID,
@@ -989,8 +1034,8 @@ export function createMandatoryTimestampCriterionOption(value: CriterionType) {
return new MandatoryTimestampCriterionOption(value, value);
}
export class TimestampCriterion extends Criterion<ITimestampValue> {
constructor(type: CriterionOption) {
export class TimestampCriterion extends ModifierCriterion<ITimestampValue> {
constructor(type: ModifierCriterionOption) {
super(type, { value: "", value2: undefined });
}

View File

@@ -0,0 +1,109 @@
import { IntlShape } from "react-intl";
import { Criterion, CriterionOption, ModifierCriterion } from "./criterion";
import {
CriterionModifier,
CustomFieldCriterionInput,
} from "src/core/generated-graphql";
import { cloneDeep } from "@apollo/client/utilities";
export const CustomFieldsCriterionOption = new CriterionOption({
type: "custom_fields",
messageID: "custom_fields.title",
makeCriterion: () => new CustomFieldsCriterion(),
});
export class CustomFieldsCriterion extends Criterion {
public value: CustomFieldCriterionInput[] = [];
constructor() {
super(CustomFieldsCriterionOption);
}
public isValid(): boolean {
return this.value.length > 0;
}
public applyToCriterionInput(input: Record<string, unknown>): void {
input.custom_fields = cloneDeep(this.value);
}
public getLabel(intl: IntlShape): string {
// show first criterion
if (this.value.length === 0) {
return "";
}
const first = this.value[0];
let messageID;
let valueString = "";
if (
first.modifier !== CriterionModifier.IsNull &&
first.modifier !== CriterionModifier.NotNull &&
(first.value?.length ?? 0) > 0
) {
valueString = (first.value![0] as string) ?? "";
}
const modifierString = ModifierCriterion.getModifierLabel(
intl,
first.modifier
);
const opts = {
criterion: first.field,
modifierString,
valueString,
others: "",
};
if (this.value.length === 1) {
messageID = "custom_fields.criteria_format_string";
} else {
messageID = "custom_fields.criteria_format_string_others";
opts.others = (this.value.length - 1).toString();
}
return intl.formatMessage({ id: messageID }, opts);
}
public getValueLabel(intl: IntlShape, v: CustomFieldCriterionInput): string {
let valueString = "";
if (
v.modifier !== CriterionModifier.IsNull &&
v.modifier !== CriterionModifier.NotNull &&
(v.value?.length ?? 0) > 0
) {
valueString = (v.value![0] as string) ?? "";
}
const modifierString = ModifierCriterion.getModifierLabel(intl, v.modifier);
const opts = {
criterion: v.field,
modifierString,
valueString,
others: "",
};
return intl.formatMessage(
{ id: "custom_fields.criteria_format_string" },
opts
);
}
public toJSON(): string {
const encodedCriterion = {
type: this.criterionOption.type,
value: this.value,
};
return JSON.stringify(encodedCriterion);
}
public setFromSavedCriterion(criterion: {
type: string;
value: CustomFieldCriterionInput[];
}): void {
const { value } = criterion;
this.value = cloneDeep(value);
}
}

View File

@@ -5,12 +5,12 @@ import {
} from "src/core/generated-graphql";
import { genderStrings, stringToGender } from "src/utils/gender";
import {
CriterionOption,
ModifierCriterionOption,
ISavedCriterion,
MultiStringCriterion,
} from "./criterion";
export const GenderCriterionOption = new CriterionOption({
export const GenderCriterionOption = new ModifierCriterionOption({
messageID: "gender",
type: "gender",
options: genderStrings,

View File

@@ -1,5 +1,8 @@
import { CriterionModifier } from "src/core/generated-graphql";
import { CriterionOption, IHierarchicalLabeledIdCriterion } from "./criterion";
import {
ModifierCriterionOption,
IHierarchicalLabeledIdCriterion,
} from "./criterion";
import { CriterionType } from "../types";
const inputType = "groups";
@@ -13,7 +16,7 @@ const modifierOptions = [
const defaultModifier = CriterionModifier.Includes;
class BaseGroupsCriterionOption extends CriterionOption {
class BaseGroupsCriterionOption extends ModifierCriterionOption {
constructor(messageID: string, type: CriterionType) {
super({
messageID,
@@ -44,7 +47,7 @@ export const SubGroupsCriterionOption = new BaseGroupsCriterionOption(
);
// redirects to GroupsCriterion
export const LegacyMoviesCriterionOption = new CriterionOption({
export const LegacyMoviesCriterionOption = new ModifierCriterionOption({
messageID: "groups",
type: "movies",
modifierOptions,

View File

@@ -1,6 +1,6 @@
import { CriterionModifier } from "src/core/generated-graphql";
import { CriterionType } from "../types";
import { CriterionOption, StringCriterion, Option } from "./criterion";
import { ModifierCriterionOption, StringCriterion, Option } from "./criterion";
export class IsMissingCriterion extends StringCriterion {
public toCriterionInput(): string {
@@ -8,7 +8,7 @@ export class IsMissingCriterion extends StringCriterion {
}
}
class IsMissingCriterionOption extends CriterionOption {
class IsMissingCriterionOption extends ModifierCriterionOption {
constructor(messageID: string, type: CriterionType, options: Option[]) {
super({
messageID,

View File

@@ -1,6 +1,6 @@
import { orientationStrings, stringToOrientation } from "src/utils/orientation";
import { CriterionType } from "../types";
import { CriterionOption, MultiStringCriterion } from "./criterion";
import { ModifierCriterionOption, MultiStringCriterion } from "./criterion";
import {
OrientationCriterionInput,
OrientationEnum,
@@ -16,7 +16,7 @@ export class OrientationCriterion extends MultiStringCriterion {
}
}
class BaseOrientationCriterionOption extends CriterionOption {
class BaseOrientationCriterionOption extends ModifierCriterionOption {
constructor(value: CriterionType) {
super({
messageID: value,

View File

@@ -5,7 +5,11 @@ import {
MultiCriterionInput,
} from "src/core/generated-graphql";
import { ILabeledId, ILabeledValueListValue } from "../types";
import { Criterion, CriterionOption, ISavedCriterion } from "./criterion";
import {
ModifierCriterion,
ModifierCriterionOption,
ISavedCriterion,
} from "./criterion";
const modifierOptions = [
CriterionModifier.IncludesAll,
@@ -19,7 +23,7 @@ const defaultModifier = CriterionModifier.IncludesAll;
const inputType = "performers";
export const PerformersCriterionOption = new CriterionOption({
export const PerformersCriterionOption = new ModifierCriterionOption({
messageID: "performers",
type: "performers",
modifierOptions,
@@ -28,7 +32,7 @@ export const PerformersCriterionOption = new CriterionOption({
makeCriterion: () => new PerformersCriterion(),
});
export class PerformersCriterion extends Criterion<ILabeledValueListValue> {
export class PerformersCriterion extends ModifierCriterion<ILabeledValueListValue> {
constructor() {
super(PerformersCriterionOption, { items: [], excluded: [] });
}
@@ -116,7 +120,10 @@ export class PerformersCriterion extends Criterion<ILabeledValueListValue> {
public getLabel(intl: IntlShape): string {
let id = "criterion_modifier.format_string";
let modifierString = Criterion.getModifierLabel(intl, this.modifier);
let modifierString = ModifierCriterion.getModifierLabel(
intl,
this.modifier
);
let valueString = "";
let excludedString = "";
@@ -128,7 +135,7 @@ export class PerformersCriterion extends Criterion<ILabeledValueListValue> {
if (this.value.excluded && this.value.excluded.length > 0) {
if (this.value.items.length === 0) {
modifierString = Criterion.getModifierLabel(
modifierString = ModifierCriterion.getModifierLabel(
intl,
CriterionModifier.Excludes
);

View File

@@ -6,12 +6,12 @@ import {
import { IPhashDistanceValue } from "../types";
import {
BooleanCriterionOption,
Criterion,
CriterionOption,
ModifierCriterion,
ModifierCriterionOption,
StringCriterion,
} from "./criterion";
export const PhashCriterionOption = new CriterionOption({
export const PhashCriterionOption = new ModifierCriterionOption({
messageID: "media_info.phash",
type: "phash_distance",
inputType: "text",
@@ -24,7 +24,7 @@ export const PhashCriterionOption = new CriterionOption({
makeCriterion: () => new PhashCriterion(),
});
export class PhashCriterion extends Criterion<IPhashDistanceValue> {
export class PhashCriterion extends ModifierCriterion<IPhashDistanceValue> {
constructor() {
super(PhashCriterionOption, { value: "", distance: 0 });
}

View File

@@ -10,7 +10,7 @@ import {
IntCriterionInput,
} from "src/core/generated-graphql";
import { INumberValue } from "../types";
import { Criterion, CriterionOption } from "./criterion";
import { ModifierCriterion, ModifierCriterionOption } from "./criterion";
const modifierOptions = [
CriterionModifier.Equals,
@@ -27,7 +27,7 @@ function getRatingSystemOptions(config?: ConfigDataFragment) {
return config?.ui.ratingSystemOptions ?? defaultRatingSystemOptions;
}
export const RatingCriterionOption = new CriterionOption({
export const RatingCriterionOption = new ModifierCriterionOption({
messageID: "rating",
type: "rating100",
modifierOptions,
@@ -37,7 +37,7 @@ export const RatingCriterionOption = new CriterionOption({
inputType: "number",
});
export class RatingCriterion extends Criterion<INumberValue> {
export class RatingCriterion extends ModifierCriterion<INumberValue> {
ratingSystem: RatingSystemOptions;
constructor(ratingSystem: RatingSystemOptions) {

View File

@@ -5,16 +5,16 @@ import {
import { stringToResolution, resolutionStrings } from "src/utils/resolution";
import { CriterionType } from "../types";
import {
Criterion,
CriterionOption,
ModifierCriterion,
ModifierCriterionOption,
CriterionValue,
StringCriterion,
} from "./criterion";
class BaseResolutionCriterionOption extends CriterionOption {
class BaseResolutionCriterionOption extends ModifierCriterionOption {
constructor(
value: CriterionType,
makeCriterion: () => Criterion<CriterionValue>
makeCriterion: () => ModifierCriterion<CriterionValue>
) {
super({
messageID: value,

View File

@@ -1,5 +1,5 @@
import {
CriterionOption,
ModifierCriterionOption,
ILabeledIdCriterion,
ILabeledIdCriterionOption,
} from "./criterion";
@@ -28,7 +28,7 @@ const modifierOptions = [
const defaultModifier = CriterionModifier.Includes;
export const MarkersScenesCriterionOption = new CriterionOption({
export const MarkersScenesCriterionOption = new ModifierCriterionOption({
messageID: "scenes",
type: "scenes",
modifierOptions,

View File

@@ -5,9 +5,9 @@ import {
StashIdCriterionInput,
} from "src/core/generated-graphql";
import { IStashIDValue } from "../types";
import { Criterion, CriterionOption } from "./criterion";
import { ModifierCriterion, ModifierCriterionOption } from "./criterion";
export const StashIDCriterionOption = new CriterionOption({
export const StashIDCriterionOption = new ModifierCriterionOption({
messageID: "stash_id",
type: "stash_id_endpoint",
modifierOptions: [
@@ -19,7 +19,7 @@ export const StashIDCriterionOption = new CriterionOption({
makeCriterion: () => new StashIDCriterion(),
});
export class StashIDCriterion extends Criterion<IStashIDValue> {
export class StashIDCriterion extends ModifierCriterion<IStashIDValue> {
constructor() {
super(StashIDCriterionOption, {
endpoint: "",
@@ -56,7 +56,10 @@ export class StashIDCriterion extends Criterion<IStashIDValue> {
}
public getLabel(intl: IntlShape): string {
const modifierString = Criterion.getModifierLabel(intl, this.modifier);
const modifierString = ModifierCriterion.getModifierLabel(
intl,
this.modifier
);
let valueString = "";
if (

View File

@@ -1,6 +1,6 @@
import { CriterionModifier } from "src/core/generated-graphql";
import {
CriterionOption,
ModifierCriterionOption,
IHierarchicalLabeledIdCriterion,
ILabeledIdCriterion,
ILabeledIdCriterionOption,
@@ -15,7 +15,7 @@ const modifierOptions = [
const defaultModifier = CriterionModifier.Includes;
const inputType = "studios";
export const StudiosCriterionOption = new CriterionOption({
export const StudiosCriterionOption = new ModifierCriterionOption({
messageID: "studios",
type: "studios",
modifierOptions,

View File

@@ -1,5 +1,8 @@
import { CriterionModifier } from "src/core/generated-graphql";
import { CriterionOption, IHierarchicalLabeledIdCriterion } from "./criterion";
import {
ModifierCriterionOption,
IHierarchicalLabeledIdCriterion,
} from "./criterion";
import { CriterionType } from "../types";
const defaultModifierOptions = [
@@ -20,7 +23,7 @@ const withoutEqualsModifierOptions = [
const defaultModifier = CriterionModifier.IncludesAll;
const inputType = "tags";
class BaseTagsCriterionOption extends CriterionOption {
class BaseTagsCriterionOption extends ModifierCriterionOption {
constructor(
messageID: string,
type: CriterionType,

View File

@@ -11,13 +11,9 @@ import {
ISavedCriterion,
} from "./criteria/criterion";
import { getFilterOptions } from "./factory";
import {
CriterionType,
DisplayMode,
SavedObjectFilter,
SavedUIOptions,
} from "./types";
import { CriterionType, DisplayMode, SavedUIOptions } from "./types";
import { ListFilterOptions } from "./filter-options";
import { CustomFieldsCriterion } from "./criteria/custom-fields";
interface IDecodedParams {
perPage?: number;
@@ -60,7 +56,7 @@ export class ListFilterModel {
public sortBy?: string;
public displayMode: DisplayMode = DEFAULT_PARAMS.displayMode;
public zoomIndex: number = 1;
public criteria: Array<Criterion<CriterionValue>> = [];
public criteria: Array<Criterion> = [];
public randomSeed = -1;
private defaultZoomIndex: number = 1;
@@ -446,15 +442,7 @@ export class ListFilterModel {
public makeFilter() {
const output: Record<string, unknown> = {};
for (const c of this.criteria) {
output[c.criterionOption.type] = c.toCriterionInput();
}
return output;
}
public makeSavedFilter() {
const output: SavedObjectFilter = {};
for (const c of this.criteria) {
output[c.criterionOption.type] = c.toSavedCriterion();
c.applyToCriterionInput(output);
}
return output;
}
@@ -488,6 +476,20 @@ export class ListFilterModel {
return ret;
}
public removeCustomFieldCriterion(type: CriterionType, index: number) {
const ret = this.clone();
const c = ret.criteria.find((cc) => cc.criterionOption.type === type);
if (!c) return ret;
if (c instanceof CustomFieldsCriterion) {
const newCriteria = c.value.filter((_, i) => i !== index);
c.value = newCriteria;
}
return ret;
}
public setPageSize(pageSize: number) {
const ret = this.clone();
ret.itemsPerPage = pageSize;

View File

@@ -17,6 +17,7 @@ import { ListFilterOptions } from "./filter-options";
import { CriterionType, DisplayMode } from "./types";
import { CountryCriterionOption } from "./criteria/country";
import { RatingCriterionOption } from "./criteria/rating";
import { CustomFieldsCriterionOption } from "./criteria/custom-fields";
const defaultSortBy = "name";
const sortByOptions = [
@@ -108,6 +109,7 @@ const criterionOptions = [
createDateCriterionOption("death_date"),
createMandatoryTimestampCriterionOption("created_at"),
createMandatoryTimestampCriterionOption("updated_at"),
CustomFieldsCriterionOption,
];
export const PerformerListFilterOptions = new ListFilterOptions(
defaultSortBy,

View File

@@ -220,4 +220,5 @@ export type CriterionType =
| "photographer"
| "disambiguation"
| "has_chapters"
| "sort_name";
| "sort_name"
| "custom_fields";