mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 04:44:37 +03:00
Custom fields filter UI (#5632)
* Refactor criteria and criterion options * Add custom fields filtering in UI
This commit is contained in:
@@ -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: [
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
|
||||
|
||||
109
ui/v2.5/src/models/list-filter/criteria/custom-fields.ts
Normal file
109
ui/v2.5/src/models/list-filter/criteria/custom-fields.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -220,4 +220,5 @@ export type CriterionType =
|
||||
| "photographer"
|
||||
| "disambiguation"
|
||||
| "has_chapters"
|
||||
| "sort_name";
|
||||
| "sort_name"
|
||||
| "custom_fields";
|
||||
|
||||
Reference in New Issue
Block a user