UI filter refactor (#1406)

* Refactor Criterion
* Separate filter options from filter
* Rename utils to factory
* Sort sort by options by alphabetical
* Refactor criterion options
* Simplify list filter options
* Refactor i8n
* Simplify ILabeledIdCriterion
This commit is contained in:
WithoutPants
2021-05-31 13:46:21 +10:00
committed by GitHub
parent c5fed1bbdc
commit 3e81d45ae9
51 changed files with 1330 additions and 1963 deletions

View File

@@ -1,16 +1,9 @@
import { CriterionModifier } from "src/core/generated-graphql";
import { Criterion, CriterionType, ICriterionOption } from "./criterion";
import { CriterionOption, StringCriterion } from "./criterion";
export class CountryCriterion extends Criterion {
public type: CriterionType = "country";
public parameterName: string = "performers";
public modifier = CriterionModifier.Equals;
public modifierOptions = [];
public options: string[] = [true.toString(), false.toString()];
public value: string = "";
}
const countryCriterionOption = new CriterionOption("country", "country");
export class CountryCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("performers");
public value: CriterionType = "country";
export class CountryCriterion extends StringCriterion {
constructor() {
super(countryCriterionOption);
}
}

View File

@@ -1,164 +1,24 @@
/* eslint-disable consistent-return */
import { CriterionModifier } from "src/core/generated-graphql";
import { IntlShape } from "react-intl";
import {
CriterionModifier,
MultiCriterionInput,
} from "src/core/generated-graphql";
import DurationUtils from "src/utils/duration";
import { ILabeledId, ILabeledValue, IOptionType } from "../types";
export type CriterionType =
| "none"
| "path"
| "rating"
| "organized"
| "o_counter"
| "resolution"
| "average_resolution"
| "duration"
| "favorite"
| "hasMarkers"
| "sceneIsMissing"
| "imageIsMissing"
| "performerIsMissing"
| "galleryIsMissing"
| "tagIsMissing"
| "studioIsMissing"
| "movieIsMissing"
| "tags"
| "sceneTags"
| "performerTags"
| "tag_count"
| "performers"
| "studios"
| "movies"
| "galleries"
| "birth_year"
| "age"
| "ethnicity"
| "country"
| "hair_color"
| "eye_color"
| "height"
| "weight"
| "measurements"
| "fake_tits"
| "career_length"
| "tattoos"
| "piercings"
| "aliases"
| "gender"
| "parent_studios"
| "scene_count"
| "marker_count"
| "image_count"
| "gallery_count"
| "performer_count"
| "death_year"
| "url"
| "stash_id"
| "interactive";
import {
CriterionType,
encodeILabeledId,
ILabeledId,
ILabeledValue,
IOptionType,
} from "../types";
type Option = string | number | IOptionType;
export type CriterionValue = string | number | ILabeledId[];
export abstract class Criterion {
public static getLabel(type: CriterionType = "none") {
switch (type) {
case "none":
return "None";
case "path":
return "Path";
case "rating":
return "Rating";
case "organized":
return "Organized";
case "o_counter":
return "O-Counter";
case "resolution":
return "Resolution";
case "average_resolution":
return "Average Resolution";
case "duration":
return "Duration";
case "favorite":
return "Favorite";
case "hasMarkers":
return "Has Markers";
case "sceneIsMissing":
case "imageIsMissing":
case "performerIsMissing":
case "galleryIsMissing":
case "tagIsMissing":
case "studioIsMissing":
case "movieIsMissing":
return "Is Missing";
case "tags":
return "Tags";
case "sceneTags":
return "Scene Tags";
case "performerTags":
return "Performer Tags";
case "tag_count":
return "Tag Count";
case "performers":
return "Performers";
case "studios":
return "Studios";
case "movies":
return "Movies";
case "galleries":
return "Galleries";
case "birth_year":
return "Birth Year";
case "death_year":
return "Death Year";
case "age":
return "Age";
case "ethnicity":
return "Ethnicity";
case "country":
return "Country";
case "hair_color":
return "Hair Color";
case "eye_color":
return "Eye Color";
case "height":
return "Height";
case "weight":
return "Weight";
case "measurements":
return "Measurements";
case "fake_tits":
return "Fake Tits";
case "career_length":
return "Career Length";
case "tattoos":
return "Tattoos";
case "piercings":
return "Piercings";
case "aliases":
return "Aliases";
case "gender":
return "Gender";
case "parent_studios":
return "Parent Studios";
case "scene_count":
return "Scene Count";
case "marker_count":
return "Marker Count";
case "image_count":
return "Image Count";
case "gallery_count":
return "Gallery Count";
case "performer_count":
return "Performer Count";
case "url":
return "URL";
case "stash_id":
return "StashID";
case "interactive":
return "Interactive";
}
}
// V = criterion value type
export abstract class Criterion<V extends CriterionValue> {
public static getModifierOption(
modifier: CriterionModifier = CriterionModifier.Equals
): ILabeledValue {
@@ -194,60 +54,62 @@ export abstract class Criterion {
}
}
public abstract type: CriterionType;
public abstract parameterName: string;
public criterionOption: CriterionOption;
public abstract modifier: CriterionModifier;
public abstract modifierOptions: ILabeledValue[];
public abstract options: Option[] | undefined;
public abstract value: CriterionValue;
public abstract value: V;
public inputType: "number" | "text" | undefined;
public getLabelValue(): string {
if (typeof this.value === "string") return this.value;
if (typeof this.value === "number") return this.value.toString();
return this.value.map((v) => v.label).join(", ");
public abstract getLabelValue(): string;
constructor(type: CriterionOption) {
this.criterionOption = type;
}
public getLabel(): string {
let modifierString: string;
public getLabel(intl: IntlShape): string {
let modifierMessageID: string;
switch (this.modifier) {
case CriterionModifier.Equals:
modifierString = "is";
modifierMessageID = "criterion_modifier.equals";
break;
case CriterionModifier.NotEquals:
modifierString = "is not";
modifierMessageID = "criterion_modifier.not_equals";
break;
case CriterionModifier.GreaterThan:
modifierString = "is greater than";
modifierMessageID = "criterion_modifier.greater_than";
break;
case CriterionModifier.LessThan:
modifierString = "is less than";
modifierMessageID = "criterion_modifier.less_than";
break;
case CriterionModifier.IsNull:
modifierString = "is null";
modifierMessageID = "criterion_modifier.is_null";
break;
case CriterionModifier.NotNull:
modifierString = "is not null";
modifierMessageID = "criterion_modifier.not_null";
break;
case CriterionModifier.Includes:
modifierString = "includes";
modifierMessageID = "criterion_modifier.includes";
break;
case CriterionModifier.IncludesAll:
modifierString = "includes all";
modifierMessageID = "criterion_modifier.includes_all";
break;
case CriterionModifier.Excludes:
modifierString = "excludes";
modifierMessageID = "criterion_modifier.excludes";
break;
case CriterionModifier.MatchesRegex:
modifierString = "matches regex";
modifierMessageID = "criterion_modifier.matches_regex";
break;
case CriterionModifier.NotMatchesRegex:
modifierString = "not matches regex";
modifierMessageID = "criterion_modifier.not_matches_regex";
break;
default:
modifierString = "";
modifierMessageID = "";
}
const modifierString = modifierMessageID
? intl.formatMessage({ id: modifierMessageID })
: "";
let valueString = "";
if (
@@ -257,47 +119,64 @@ export abstract class Criterion {
valueString = this.getLabelValue();
}
return `${Criterion.getLabel(this.type)} ${modifierString} ${valueString}`;
return `${intl.formatMessage({
id: this.criterionOption.messageID,
})} ${modifierString} ${valueString}`;
}
public getId(): string {
return `${this.parameterName}-${this.modifier.toString()}`; // TODO add values?
return `${this.criterionOption.parameterName}-${this.modifier.toString()}`; // TODO add values?
}
private static replaceSpecialCharacter(str: string, c: string) {
return str.replaceAll(c, encodeURIComponent(c));
}
public encodeValue(): CriterionValue {
// replace certain characters
if (typeof this.value === "string") {
let ret = this.value;
ret = Criterion.replaceSpecialCharacter(ret, "&");
ret = Criterion.replaceSpecialCharacter(ret, "+");
return ret;
}
public encodeValue(): V {
return this.value;
}
}
export interface ICriterionOption {
label: string;
value: CriterionType;
}
public toJSON() {
const encodedCriterion = {
type: this.criterionOption.value,
// #394 - the presence of a # symbol results in the query URL being
// malformed. We could set encode: true in the queryString.stringify
// call below, but this results in a URL that gets pretty long and ugly.
// Instead, we'll encode the criteria values.
value: this.encodeValue(),
modifier: this.modifier,
};
return JSON.stringify(encodedCriterion);
}
export class CriterionOption implements ICriterionOption {
public label: string;
public value: CriterionType;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public apply(outputFilter: Record<string, any>) {
// eslint-disable-next-line no-param-reassign
outputFilter[this.criterionOption.parameterName] = this.toCriterionInput();
}
constructor(label: string, value: CriterionType) {
this.label = label;
this.value = value;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
protected toCriterionInput(): any {
return {
value: this.value,
modifier: this.modifier,
};
}
}
export class StringCriterion extends Criterion {
public type: CriterionType;
public parameterName: string;
export class CriterionOption {
public readonly messageID: string;
public readonly value: CriterionType;
public readonly parameterName: string;
constructor(messageID: string, value: CriterionType, parameterName?: string) {
this.messageID = messageID;
this.value = value;
this.parameterName = parameterName ?? value;
}
}
export function createCriterionOption(value: CriterionType) {
return new CriterionOption(value, value);
}
export class StringCriterion extends Criterion<string> {
public modifier = CriterionModifier.Equals;
public modifierOptions = [
StringCriterion.getModifierOption(CriterionModifier.Equals),
@@ -316,18 +195,23 @@ export class StringCriterion extends Criterion {
return this.value;
}
constructor(type: CriterionType, parameterName?: string, options?: string[]) {
super();
public encodeValue() {
// replace certain characters
let ret = this.value;
ret = StringCriterion.replaceSpecialCharacter(ret, "&");
ret = StringCriterion.replaceSpecialCharacter(ret, "+");
return ret;
}
private static replaceSpecialCharacter(str: string, c: string) {
return str.replaceAll(c, encodeURIComponent(c));
}
constructor(type: CriterionOption, options?: string[]) {
super(type);
this.type = type;
this.options = options;
this.inputType = "text";
if (parameterName) {
this.parameterName = parameterName;
} else {
this.parameterName = type;
}
}
}
@@ -342,9 +226,20 @@ export class MandatoryStringCriterion extends StringCriterion {
];
}
export class NumberCriterion extends Criterion {
public type: CriterionType;
public parameterName: string;
export class BooleanCriterion extends StringCriterion {
public modifier = CriterionModifier.Equals;
public modifierOptions = [];
constructor(type: CriterionOption) {
super(type, [true.toString(), false.toString()]);
}
protected toCriterionInput(): boolean {
return this.value === "true";
}
}
export class NumberCriterion extends Criterion<number> {
public modifier = CriterionModifier.Equals;
public modifierOptions = [
Criterion.getModifierOption(CriterionModifier.Equals),
@@ -361,17 +256,51 @@ export class NumberCriterion extends Criterion {
return this.value.toString();
}
constructor(type: CriterionType, parameterName?: string, options?: number[]) {
super();
constructor(type: CriterionOption, options?: number[]) {
super(type);
this.type = type;
this.options = options;
this.inputType = "number";
}
}
if (parameterName) {
this.parameterName = parameterName;
} else {
this.parameterName = type;
export abstract class ILabeledIdCriterion extends Criterion<ILabeledId[]> {
public modifier = CriterionModifier.IncludesAll;
public modifierOptions = [
Criterion.getModifierOption(CriterionModifier.IncludesAll),
Criterion.getModifierOption(CriterionModifier.Includes),
Criterion.getModifierOption(CriterionModifier.Excludes),
];
public options: IOptionType[] = [];
public value: ILabeledId[] = [];
public getLabelValue(): string {
return this.value.map((v) => v.label).join(", ");
}
protected toCriterionInput(): MultiCriterionInput {
return {
value: this.value.map((v) => v.id),
modifier: this.modifier,
};
}
public encodeValue() {
return this.value.map((o) => {
return encodeILabeledId(o);
});
}
constructor(type: CriterionOption, includeAll: boolean) {
super(type);
if (!includeAll) {
this.modifier = CriterionModifier.Includes;
this.modifierOptions = [
Criterion.getModifierOption(CriterionModifier.Includes),
Criterion.getModifierOption(CriterionModifier.Excludes),
];
}
}
}
@@ -385,9 +314,7 @@ export class MandatoryNumberCriterion extends NumberCriterion {
];
}
export class DurationCriterion extends Criterion {
public type: CriterionType;
public parameterName: string;
export class DurationCriterion extends Criterion<number> {
public modifier = CriterionModifier.Equals;
public modifierOptions = [
Criterion.getModifierOption(CriterionModifier.Equals),
@@ -398,12 +325,10 @@ export class DurationCriterion extends Criterion {
public options: number[] | undefined;
public value: number = 0;
constructor(type: CriterionType, parameterName?: string, options?: number[]) {
super();
constructor(type: CriterionOption, options?: number[]) {
super(type);
this.type = type;
this.options = options;
this.parameterName = parameterName ?? type;
}
public getLabelValue() {

View File

@@ -1,11 +1,11 @@
/* eslint-disable consistent-return, default-case */
import {
CriterionType,
StringCriterion,
NumberCriterion,
DurationCriterion,
MandatoryStringCriterion,
MandatoryNumberCriterion,
CriterionOption,
} from "./criterion";
import { OrganizedCriterion } from "./organized";
import { FavoriteCriterion } from "./favorite";
@@ -24,10 +24,16 @@ import { PerformersCriterion } from "./performers";
import { RatingCriterion } from "./rating";
import { AverageResolutionCriterion, ResolutionCriterion } from "./resolution";
import { StudiosCriterion, ParentStudiosCriterion } from "./studios";
import { TagsCriterion } from "./tags";
import {
PerformerTagsCriterionOption,
SceneTagsCriterionOption,
TagsCriterion,
TagsCriterionOption,
} from "./tags";
import { GenderCriterion } from "./gender";
import { MoviesCriterion } from "./movies";
import { GalleriesCriterion } from "./galleries";
import { CriterionType } from "../types";
import { InteractiveCriterion } from "./interactive";
export function makeCriteria(type: CriterionType = "none") {
@@ -35,7 +41,7 @@ export function makeCriteria(type: CriterionType = "none") {
case "none":
return new NoneCriterion();
case "path":
return new MandatoryStringCriterion(type, type);
return new MandatoryStringCriterion(new CriterionOption(type, type));
case "rating":
return new RatingCriterion();
case "organized":
@@ -47,13 +53,13 @@ export function makeCriteria(type: CriterionType = "none") {
case "gallery_count":
case "performer_count":
case "tag_count":
return new MandatoryNumberCriterion(type, type);
return new MandatoryNumberCriterion(new CriterionOption(type, type));
case "resolution":
return new ResolutionCriterion();
case "average_resolution":
return new AverageResolutionCriterion();
case "duration":
return new DurationCriterion(type, type);
return new DurationCriterion(new CriterionOption(type, type));
case "favorite":
return new FavoriteCriterion();
case "hasMarkers":
@@ -73,11 +79,11 @@ export function makeCriteria(type: CriterionType = "none") {
case "movieIsMissing":
return new MovieIsMissingCriterion();
case "tags":
return new TagsCriterion("tags");
return new TagsCriterion(TagsCriterionOption);
case "sceneTags":
return new TagsCriterion("sceneTags");
return new TagsCriterion(SceneTagsCriterionOption);
case "performerTags":
return new TagsCriterion("performerTags");
return new TagsCriterion(PerformerTagsCriterionOption);
case "performers":
return new PerformersCriterion();
case "studios":
@@ -91,9 +97,9 @@ export function makeCriteria(type: CriterionType = "none") {
case "birth_year":
case "death_year":
case "weight":
return new NumberCriterion(type, type);
return new NumberCriterion(new CriterionOption(type, type));
case "age":
return new MandatoryNumberCriterion(type, type);
return new MandatoryNumberCriterion(new CriterionOption(type, type));
case "gender":
return new GenderCriterion();
case "ethnicity":
@@ -109,7 +115,7 @@ export function makeCriteria(type: CriterionType = "none") {
case "aliases":
case "url":
case "stash_id":
return new StringCriterion(type, type);
return new StringCriterion(new CriterionOption(type, type));
case "interactive":
return new InteractiveCriterion();
}

View File

@@ -1,16 +1,13 @@
import { CriterionModifier } from "src/core/generated-graphql";
import { Criterion, CriterionType, ICriterionOption } from "./criterion";
import { BooleanCriterion, CriterionOption } from "./criterion";
export class FavoriteCriterion extends Criterion {
public type: CriterionType = "favorite";
public parameterName: string = "filter_favorites";
public modifier = CriterionModifier.Equals;
public modifierOptions = [];
public options: string[] = [true.toString(), false.toString()];
public value: string = "";
}
export const FavoriteCriterionOption = new CriterionOption(
"favourite",
"favorite",
"filter_favorites"
);
export class FavoriteCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("favorite");
public value: CriterionType = "favorite";
export class FavoriteCriterion extends BooleanCriterion {
constructor() {
super(FavoriteCriterionOption);
}
}

View File

@@ -1,27 +1,9 @@
import * as GQL from "src/core/generated-graphql";
import { ILabeledId, IOptionType, encodeILabeledId } from "../types";
import { Criterion, CriterionType, ICriterionOption } from "./criterion";
import { CriterionOption, ILabeledIdCriterion } from "./criterion";
export class GalleriesCriterion extends Criterion {
public type: CriterionType = "galleries";
public parameterName: string = "galleries";
public modifier = GQL.CriterionModifier.IncludesAll;
public modifierOptions = [
Criterion.getModifierOption(GQL.CriterionModifier.IncludesAll),
Criterion.getModifierOption(GQL.CriterionModifier.Includes),
Criterion.getModifierOption(GQL.CriterionModifier.Excludes),
];
public options: IOptionType[] = [];
public value: ILabeledId[] = [];
const galleriesCriterionOption = new CriterionOption("galleries", "galleries");
public encodeValue() {
return this.value.map((o) => {
return encodeILabeledId(o);
});
export class GalleriesCriterion extends ILabeledIdCriterion {
constructor() {
super(galleriesCriterionOption, true);
}
}
export class GalleriesCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("galleries");
public value: CriterionType = "galleries";
}

View File

@@ -1,17 +1,24 @@
import { CriterionModifier } from "src/core/generated-graphql";
import { getGenderStrings } from "src/core/StashService";
import { Criterion, CriterionType, ICriterionOption } from "./criterion";
import {
CriterionModifier,
GenderCriterionInput,
} from "src/core/generated-graphql";
import { getGenderStrings, stringToGender } from "src/core/StashService";
import { CriterionOption, StringCriterion } from "./criterion";
export class GenderCriterion extends Criterion {
public type: CriterionType = "gender";
public parameterName: string = "gender";
export const GenderCriterionOption = new CriterionOption("gender", "gender");
export class GenderCriterion extends StringCriterion {
public modifier = CriterionModifier.Equals;
public modifierOptions = [];
public options: string[] = getGenderStrings();
public value: string = "";
}
export class GenderCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("gender");
public value: CriterionType = "gender";
constructor() {
super(GenderCriterionOption, getGenderStrings());
}
protected toCriterionInput(): GenderCriterionInput {
return {
value: stringToGender(this.value),
modifier: this.modifier,
};
}
}

View File

@@ -1,16 +1,17 @@
import { CriterionModifier } from "src/core/generated-graphql";
import { Criterion, CriterionType, ICriterionOption } from "./criterion";
import { CriterionOption, StringCriterion } from "./criterion";
export class HasMarkersCriterion extends Criterion {
public type: CriterionType = "hasMarkers";
public parameterName: string = "has_markers";
public modifier = CriterionModifier.Equals;
public modifierOptions = [];
public options: string[] = [true.toString(), false.toString()];
public value: string = "";
}
export const HasMarkersCriterionOption = new CriterionOption(
"hasMarkers",
"hasMarkers",
"has_markers"
);
export class HasMarkersCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("hasMarkers");
public value: CriterionType = "hasMarkers";
export class HasMarkersCriterion extends StringCriterion {
constructor() {
super(HasMarkersCriterionOption, [true.toString(), false.toString()]);
}
protected toCriterionInput(): string {
return this.value;
}
}

View File

@@ -1,16 +1,12 @@
import { CriterionModifier } from "src/core/generated-graphql";
import { Criterion, CriterionType, ICriterionOption } from "./criterion";
import { BooleanCriterion, CriterionOption } from "./criterion";
export class InteractiveCriterion extends Criterion {
public type: CriterionType = "interactive";
public parameterName: string = "interactive";
public modifier = CriterionModifier.Equals;
public modifierOptions = [];
public options: string[] = [true.toString(), false.toString()];
public value: string = "";
}
export const InteractiveCriterionOption = new CriterionOption(
"organized",
"organized"
);
export class InteractiveCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("interactive");
public value: CriterionType = "interactive";
export class InteractiveCriterion extends BooleanCriterion {
constructor() {
super(InteractiveCriterionOption);
}
}

View File

@@ -1,123 +1,145 @@
import { CriterionModifier } from "src/core/generated-graphql";
import { Criterion, CriterionType, ICriterionOption } from "./criterion";
import { CriterionOption, StringCriterion } from "./criterion";
export abstract class IsMissingCriterion extends Criterion {
public parameterName: string = "is_missing";
export abstract class IsMissingCriterion extends StringCriterion {
public modifierOptions = [];
public modifier = CriterionModifier.Equals;
public value: string = "";
protected toCriterionInput(): string {
return this.value;
}
}
export const SceneIsMissingCriterionOption = new CriterionOption(
"isMissing",
"sceneIsMissing",
"is_missing"
);
export class SceneIsMissingCriterion extends IsMissingCriterion {
public type: CriterionType = "sceneIsMissing";
public options: string[] = [
"title",
"details",
"url",
"date",
"galleries",
"studio",
"movie",
"performers",
"tags",
];
constructor() {
super(SceneIsMissingCriterionOption, [
"title",
"details",
"url",
"date",
"galleries",
"studio",
"movie",
"performers",
"tags",
"stash_id",
]);
}
}
export class SceneIsMissingCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("sceneIsMissing");
public value: CriterionType = "sceneIsMissing";
}
export const ImageIsMissingCriterionOption = new CriterionOption(
"isMissing",
"imageIsMissing",
"is_missing"
);
export class ImageIsMissingCriterion extends IsMissingCriterion {
public type: CriterionType = "imageIsMissing";
public options: string[] = [
"title",
"galleries",
"studio",
"performers",
"tags",
];
constructor() {
super(ImageIsMissingCriterionOption, [
"title",
"galleries",
"studio",
"performers",
"tags",
]);
}
}
export class ImageIsMissingCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("imageIsMissing");
public value: CriterionType = "imageIsMissing";
}
export const PerformerIsMissingCriterionOption = new CriterionOption(
"isMissing",
"performerIsMissing",
"is_missing"
);
export class PerformerIsMissingCriterion extends IsMissingCriterion {
public type: CriterionType = "performerIsMissing";
public options: string[] = [
"url",
"twitter",
"instagram",
"ethnicity",
"country",
"hair_color",
"eye_color",
"height",
"weight",
"measurements",
"fake_tits",
"career_length",
"tattoos",
"piercings",
"aliases",
"gender",
"image",
"details",
];
constructor() {
super(PerformerIsMissingCriterionOption, [
"url",
"twitter",
"instagram",
"ethnicity",
"country",
"hair_color",
"eye_color",
"height",
"weight",
"measurements",
"fake_tits",
"career_length",
"tattoos",
"piercings",
"aliases",
"gender",
"image",
"details",
"stash_id",
]);
}
}
export class PerformerIsMissingCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("performerIsMissing");
public value: CriterionType = "performerIsMissing";
}
export const GalleryIsMissingCriterionOption = new CriterionOption(
"isMissing",
"galleryIsMissing",
"is_missing"
);
export class GalleryIsMissingCriterion extends IsMissingCriterion {
public type: CriterionType = "galleryIsMissing";
public options: string[] = [
"title",
"details",
"url",
"date",
"studio",
"performers",
"tags",
"scenes",
];
constructor() {
super(GalleryIsMissingCriterionOption, [
"title",
"details",
"url",
"date",
"studio",
"performers",
"tags",
"scenes",
]);
}
}
export class GalleryIsMissingCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("galleryIsMissing");
public value: CriterionType = "galleryIsMissing";
}
export const TagIsMissingCriterionOption = new CriterionOption(
"isMissing",
"tagIsMissing",
"is_missing"
);
export class TagIsMissingCriterion extends IsMissingCriterion {
public type: CriterionType = "tagIsMissing";
public options: string[] = ["image"];
constructor() {
super(TagIsMissingCriterionOption, ["image"]);
}
}
export class TagIsMissingCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("tagIsMissing");
public value: CriterionType = "tagIsMissing";
}
export const StudioIsMissingCriterionOption = new CriterionOption(
"isMissing",
"studioIsMissing",
"is_missing"
);
export class StudioIsMissingCriterion extends IsMissingCriterion {
public type: CriterionType = "studioIsMissing";
public options: string[] = ["image", "details"];
constructor() {
super(StudioIsMissingCriterionOption, ["image", "stash_id", "details"]);
}
}
export class StudioIsMissingCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("studioIsMissing");
public value: CriterionType = "studioIsMissing";
}
export const MovieIsMissingCriterionOption = new CriterionOption(
"isMissing",
"movieIsMissing",
"is_missing"
);
export class MovieIsMissingCriterion extends IsMissingCriterion {
public type: CriterionType = "movieIsMissing";
public options: string[] = ["front_image", "back_image", "scenes"];
}
export class MovieIsMissingCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("movieIsMissing");
public value: CriterionType = "movieIsMissing";
constructor() {
super(MovieIsMissingCriterionOption, [
"front_image",
"back_image",
"scenes",
]);
}
}

View File

@@ -1,32 +1,9 @@
import { CriterionModifier } from "src/core/generated-graphql";
import { ILabeledId, encodeILabeledId } from "../types";
import { Criterion, CriterionType, ICriterionOption } from "./criterion";
import { CriterionOption, ILabeledIdCriterion } from "./criterion";
interface IOptionType {
id: string;
name?: string;
image_path?: string;
}
export const MoviesCriterionOption = new CriterionOption("movies", "movies");
export class MoviesCriterion extends Criterion {
public type: CriterionType = "movies";
public parameterName: string = "movies";
public modifier = CriterionModifier.Includes;
public modifierOptions = [
Criterion.getModifierOption(CriterionModifier.Includes),
Criterion.getModifierOption(CriterionModifier.Excludes),
];
public options: IOptionType[] = [];
public value: ILabeledId[] = [];
public encodeValue() {
return this.value.map((o) => {
return encodeILabeledId(o);
});
export class MoviesCriterion extends ILabeledIdCriterion {
constructor() {
super(MoviesCriterionOption, false);
}
}
export class MoviesCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("movies");
public value: CriterionType = "movies";
}

View File

@@ -1,16 +1,19 @@
import { CriterionModifier } from "src/core/generated-graphql";
import { Criterion, CriterionType, ICriterionOption } from "./criterion";
import { Criterion, CriterionOption } from "./criterion";
export class NoneCriterion extends Criterion {
public type: CriterionType = "none";
public parameterName: string = "";
export const NoneCriterionOption = new CriterionOption("none", "none");
export class NoneCriterion extends Criterion<string> {
public modifier = CriterionModifier.Equals;
public modifierOptions = [];
public options: undefined;
public value: string = "none";
}
export class NoneCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("none");
public value: CriterionType = "none";
constructor() {
super(NoneCriterionOption);
}
// eslint-disable-next-line class-methods-use-this
public getLabelValue(): string {
return "";
}
}

View File

@@ -1,16 +1,12 @@
import { CriterionModifier } from "src/core/generated-graphql";
import { Criterion, CriterionType, ICriterionOption } from "./criterion";
import { BooleanCriterion, CriterionOption } from "./criterion";
export class OrganizedCriterion extends Criterion {
public type: CriterionType = "organized";
public parameterName: string = "organized";
public modifier = CriterionModifier.Equals;
public modifierOptions = [];
public options: string[] = [true.toString(), false.toString()];
public value: string = "";
}
export const OrganizedCriterionOption = new CriterionOption(
"organized",
"organized"
);
export class OrganizedCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("organized");
public value: CriterionType = "organized";
export class OrganizedCriterion extends BooleanCriterion {
constructor() {
super(OrganizedCriterionOption);
}
}

View File

@@ -1,27 +1,12 @@
import { CriterionModifier } from "src/core/generated-graphql";
import { ILabeledId, IOptionType, encodeILabeledId } from "../types";
import { Criterion, CriterionType, ICriterionOption } from "./criterion";
import { CriterionOption, ILabeledIdCriterion } from "./criterion";
export class PerformersCriterion extends Criterion {
public type: CriterionType = "performers";
public parameterName: string = "performers";
public modifier = CriterionModifier.IncludesAll;
public modifierOptions = [
Criterion.getModifierOption(CriterionModifier.IncludesAll),
Criterion.getModifierOption(CriterionModifier.Includes),
Criterion.getModifierOption(CriterionModifier.Excludes),
];
public options: IOptionType[] = [];
public value: ILabeledId[] = [];
export const PerformersCriterionOption = new CriterionOption(
"performers",
"performers"
);
public encodeValue() {
return this.value.map((o) => {
return encodeILabeledId(o);
});
export class PerformersCriterion extends ILabeledIdCriterion {
constructor() {
super(PerformersCriterionOption, true);
}
}
export class PerformersCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("performers");
public value: CriterionType = "performers";
}

View File

@@ -1,9 +1,9 @@
import { CriterionModifier } from "src/core/generated-graphql";
import { Criterion, CriterionType, ICriterionOption } from "./criterion";
import { Criterion, CriterionOption, NumberCriterion } from "./criterion";
export class RatingCriterion extends Criterion {
public type: CriterionType = "rating";
public parameterName: string = "rating";
export const RatingCriterionOption = new CriterionOption("rating", "rating");
export class RatingCriterion extends NumberCriterion {
public modifier = CriterionModifier.Equals;
public modifierOptions = [
Criterion.getModifierOption(CriterionModifier.Equals),
@@ -13,11 +13,8 @@ export class RatingCriterion extends Criterion {
Criterion.getModifierOption(CriterionModifier.IsNull),
Criterion.getModifierOption(CriterionModifier.NotNull),
];
public options: number[] = [1, 2, 3, 4, 5];
public value: number = 0;
}
export class RatingCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("rating");
public value: CriterionType = "rating";
constructor() {
super(RatingCriterionOption, [1, 2, 3, 4, 5]);
}
}

View File

@@ -1,39 +1,80 @@
import { CriterionModifier } from "src/core/generated-graphql";
import { Criterion, CriterionType, ICriterionOption } from "./criterion";
import { CriterionModifier, ResolutionEnum } from "src/core/generated-graphql";
import { CriterionOption, StringCriterion } from "./criterion";
export class ResolutionCriterion extends Criterion {
public type: CriterionType = "resolution";
public parameterName: string = "resolution";
abstract class AbstractResolutionCriterion extends StringCriterion {
public modifier = CriterionModifier.Equals;
public modifierOptions = [];
public options: string[] = [
"144p",
"240p",
"360p",
"480p",
"540p",
"720p",
"1080p",
"1440p",
"4k",
"5k",
"6k",
"8k",
];
public value: string = "";
constructor(type: CriterionOption) {
super(type, [
"144p",
"240p",
"360p",
"480p",
"540p",
"720p",
"1080p",
"1440p",
"4k",
"5k",
"6k",
"8k",
]);
}
protected toCriterionInput(): ResolutionEnum | undefined {
switch (this.value) {
case "144p":
return ResolutionEnum.VeryLow;
case "240p":
return ResolutionEnum.Low;
case "360p":
return ResolutionEnum.R360P;
case "480p":
return ResolutionEnum.Standard;
case "540p":
return ResolutionEnum.WebHd;
case "720p":
return ResolutionEnum.StandardHd;
case "1080p":
return ResolutionEnum.FullHd;
case "1440p":
return ResolutionEnum.QuadHd;
case "1920p":
return ResolutionEnum.VrHd;
case "4k":
return ResolutionEnum.FourK;
case "5k":
return ResolutionEnum.FiveK;
case "6k":
return ResolutionEnum.SixK;
case "8k":
return ResolutionEnum.EightK;
// no default
}
}
}
export class ResolutionCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("resolution");
public value: CriterionType = "resolution";
export const ResolutionCriterionOption = new CriterionOption(
"resolution",
"resolution"
);
export class ResolutionCriterion extends AbstractResolutionCriterion {
public modifier = CriterionModifier.Equals;
public modifierOptions = [];
constructor() {
super(ResolutionCriterionOption);
}
}
export class AverageResolutionCriterion extends ResolutionCriterion {
public type: CriterionType = "average_resolution";
public parameterName: string = "average_resolution";
}
export const AverageResolutionCriterionOption = new CriterionOption(
"average_resolution",
"average_resolution"
);
export class AverageResolutionCriterionOption extends ResolutionCriterionOption {
public label: string = Criterion.getLabel("average_resolution");
public value: CriterionType = "average_resolution";
export class AverageResolutionCriterion extends AbstractResolutionCriterion {
constructor() {
super(AverageResolutionCriterionOption);
}
}

View File

@@ -1,36 +1,25 @@
import { CriterionModifier } from "src/core/generated-graphql";
import { ILabeledId, IOptionType, encodeILabeledId } from "../types";
import { Criterion, CriterionType, ICriterionOption } from "./criterion";
import { CriterionOption, ILabeledIdCriterion } from "./criterion";
export class StudiosCriterion extends Criterion {
public type: CriterionType = "studios";
public parameterName: string = "studios";
public modifier = CriterionModifier.Includes;
public modifierOptions = [
Criterion.getModifierOption(CriterionModifier.Includes),
Criterion.getModifierOption(CriterionModifier.Excludes),
];
public options: IOptionType[] = [];
public value: ILabeledId[] = [];
public encodeValue() {
return this.value.map((o) => {
return encodeILabeledId(o);
});
abstract class AbstractStudiosCriterion extends ILabeledIdCriterion {
constructor(type: CriterionOption) {
super(type, false);
}
}
export class StudiosCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("studios");
public value: CriterionType = "studios";
export const StudiosCriterionOption = new CriterionOption("studios", "studios");
export class StudiosCriterion extends AbstractStudiosCriterion {
constructor() {
super(StudiosCriterionOption);
}
}
export class ParentStudiosCriterion extends StudiosCriterion {
public type: CriterionType = "parent_studios";
public parameterName: string = "parents";
}
export class ParentStudiosCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("parent_studios");
public value: CriterionType = "parent_studios";
export const ParentStudiosCriterionOption = new CriterionOption(
"parent_studios",
"parent_studios",
"parents"
);
export class ParentStudiosCriterion extends AbstractStudiosCriterion {
constructor() {
super(ParentStudiosCriterionOption);
}
}

View File

@@ -1,49 +1,19 @@
import * as GQL from "src/core/generated-graphql";
import { ILabeledId, IOptionType, encodeILabeledId } from "../types";
import { Criterion, CriterionType, ICriterionOption } from "./criterion";
import { CriterionOption, ILabeledIdCriterion } from "./criterion";
export class TagsCriterion extends Criterion {
public type: CriterionType;
public parameterName: string;
public modifier = GQL.CriterionModifier.IncludesAll;
public modifierOptions = [
Criterion.getModifierOption(GQL.CriterionModifier.IncludesAll),
Criterion.getModifierOption(GQL.CriterionModifier.Includes),
Criterion.getModifierOption(GQL.CriterionModifier.Excludes),
];
public options: IOptionType[] = [];
public value: ILabeledId[] = [];
constructor(type: "tags" | "sceneTags" | "performerTags") {
super();
this.type = type;
this.parameterName = type;
if (type === "sceneTags") {
this.parameterName = "scene_tags";
}
if (type === "performerTags") {
this.parameterName = "performer_tags";
}
}
public encodeValue() {
return this.value.map((o) => {
return encodeILabeledId(o);
});
export class TagsCriterion extends ILabeledIdCriterion {
constructor(type: CriterionOption) {
super(type, true);
}
}
export class TagsCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("tags");
public value: CriterionType = "tags";
}
export class SceneTagsCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("sceneTags");
public value: CriterionType = "sceneTags";
}
export class PerformerTagsCriterionOption implements ICriterionOption {
public label: string = Criterion.getLabel("performerTags");
public value: CriterionType = "performerTags";
}
export const TagsCriterionOption = new CriterionOption("tags", "tags");
export const SceneTagsCriterionOption = new CriterionOption(
"sceneTags",
"sceneTags",
"scene_tags"
);
export const PerformerTagsCriterionOption = new CriterionOption(
"performerTags",
"performerTags",
"performer_tags"
);

View File

@@ -0,0 +1,31 @@
import { ListFilterOptions } from "./filter-options";
import { GalleryListFilterOptions } from "./galleries";
import { ImageListFilterOptions } from "./images";
import { MovieListFilterOptions } from "./movies";
import { PerformerListFilterOptions } from "./performers";
import { SceneMarkerListFilterOptions } from "./scene-markers";
import { SceneListFilterOptions } from "./scenes";
import { StudioListFilterOptions } from "./studios";
import { TagListFilterOptions } from "./tags";
import { FilterMode } from "./types";
export function getFilterOptions(mode: FilterMode): ListFilterOptions {
switch (mode) {
case FilterMode.Scenes:
return SceneListFilterOptions;
case FilterMode.Performers:
return PerformerListFilterOptions;
case FilterMode.Studios:
return StudioListFilterOptions;
case FilterMode.Galleries:
return GalleryListFilterOptions;
case FilterMode.SceneMarkers:
return SceneMarkerListFilterOptions;
case FilterMode.Movies:
return MovieListFilterOptions;
case FilterMode.Tags:
return TagListFilterOptions;
case FilterMode.Images:
return ImageListFilterOptions;
}
}

View File

@@ -0,0 +1,37 @@
import { CriterionOption } from "./criteria/criterion";
import { DisplayMode } from "./types";
interface ISortByOption {
messageID: string;
value: string;
}
export class ListFilterOptions {
public readonly defaultSortBy: string = "";
public readonly sortByOptions: ISortByOption[] = [];
public readonly displayModeOptions: DisplayMode[] = [];
public readonly criterionOptions: CriterionOption[] = [];
public static createSortBy(value: string) {
return {
messageID: value,
value,
};
}
constructor(
defaultSortBy: string,
sortByOptions: ISortByOption[],
displayModeOptions: DisplayMode[],
criterionOptions: CriterionOption[]
) {
this.defaultSortBy = defaultSortBy;
this.sortByOptions = [
...sortByOptions,
ListFilterOptions.createSortBy("created_at"),
ListFilterOptions.createSortBy("updated_at"),
];
this.displayModeOptions = displayModeOptions;
this.criterionOptions = criterionOptions;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,63 @@
import { createCriterionOption } from "./criteria/criterion";
import { GalleryIsMissingCriterionOption } from "./criteria/is-missing";
import { NoneCriterionOption } from "./criteria/none";
import { OrganizedCriterionOption } from "./criteria/organized";
import { PerformersCriterionOption } from "./criteria/performers";
import { RatingCriterionOption } from "./criteria/rating";
import { AverageResolutionCriterionOption } from "./criteria/resolution";
import { StudiosCriterionOption } from "./criteria/studios";
import {
PerformerTagsCriterionOption,
TagsCriterionOption,
} from "./criteria/tags";
import { ListFilterOptions } from "./filter-options";
import { DisplayMode } from "./types";
const defaultSortBy = "path";
const sortByOptions = [
"date",
"path",
"file_mod_time",
"tag_count",
"performer_count",
"title",
"random",
]
.map(ListFilterOptions.createSortBy)
.concat([
{
messageID: "image_count",
value: "images_count",
},
]);
const displayModeOptions = [
DisplayMode.Grid,
DisplayMode.List,
DisplayMode.Wall,
];
const criterionOptions = [
NoneCriterionOption,
createCriterionOption("path"),
RatingCriterionOption,
OrganizedCriterionOption,
AverageResolutionCriterionOption,
GalleryIsMissingCriterionOption,
TagsCriterionOption,
createCriterionOption("tag_count"),
PerformerTagsCriterionOption,
PerformersCriterionOption,
createCriterionOption("performer_count"),
createCriterionOption("image_count"),
StudiosCriterionOption,
createCriterionOption("url"),
];
export const GalleryListFilterOptions = new ListFilterOptions(
defaultSortBy,
sortByOptions,
displayModeOptions,
criterionOptions
);

View File

@@ -0,0 +1,51 @@
import { createCriterionOption } from "./criteria/criterion";
import { ImageIsMissingCriterionOption } from "./criteria/is-missing";
import { NoneCriterionOption } from "./criteria/none";
import { OrganizedCriterionOption } from "./criteria/organized";
import { PerformersCriterionOption } from "./criteria/performers";
import { RatingCriterionOption } from "./criteria/rating";
import { ResolutionCriterionOption } from "./criteria/resolution";
import { StudiosCriterionOption } from "./criteria/studios";
import {
PerformerTagsCriterionOption,
TagsCriterionOption,
} from "./criteria/tags";
import { ListFilterOptions } from "./filter-options";
import { DisplayMode } from "./types";
const defaultSortBy = "path";
const sortByOptions = [
"title",
"path",
"rating",
"o_counter",
"filesize",
"file_mod_time",
"tag_count",
"performer_count",
"random",
].map(ListFilterOptions.createSortBy);
const displayModeOptions = [DisplayMode.Grid, DisplayMode.Wall];
const criterionOptions = [
NoneCriterionOption,
createCriterionOption("path"),
RatingCriterionOption,
OrganizedCriterionOption,
createCriterionOption("o_counter"),
ResolutionCriterionOption,
ImageIsMissingCriterionOption,
TagsCriterionOption,
createCriterionOption("tag_count"),
PerformerTagsCriterionOption,
PerformersCriterionOption,
createCriterionOption("performer_count"),
StudiosCriterionOption,
];
export const ImageListFilterOptions = new ListFilterOptions(
defaultSortBy,
sortByOptions,
displayModeOptions,
criterionOptions
);

View File

@@ -0,0 +1,31 @@
import { createCriterionOption } from "./criteria/criterion";
import { MovieIsMissingCriterionOption } from "./criteria/is-missing";
import { NoneCriterionOption } from "./criteria/none";
import { StudiosCriterionOption } from "./criteria/studios";
import { ListFilterOptions } from "./filter-options";
import { DisplayMode } from "./types";
const defaultSortBy = "name";
const sortByOptions = ["name", "random"]
.map(ListFilterOptions.createSortBy)
.concat([
{
messageID: "scene_count",
value: "scenes_count",
},
]);
const displayModeOptions = [DisplayMode.Grid];
const criterionOptions = [
NoneCriterionOption,
StudiosCriterionOption,
MovieIsMissingCriterionOption,
createCriterionOption("url"),
];
export const MovieListFilterOptions = new ListFilterOptions(
defaultSortBy,
sortByOptions,
displayModeOptions,
criterionOptions
);

View File

@@ -0,0 +1,77 @@
import { createCriterionOption } from "./criteria/criterion";
import { FavoriteCriterionOption } from "./criteria/favorite";
import { GenderCriterionOption } from "./criteria/gender";
import { PerformerIsMissingCriterionOption } from "./criteria/is-missing";
import { NoneCriterionOption } from "./criteria/none";
import { RatingCriterionOption } from "./criteria/rating";
import { StudiosCriterionOption } from "./criteria/studios";
import { TagsCriterionOption } from "./criteria/tags";
import { ListFilterOptions } from "./filter-options";
import { CriterionType, DisplayMode } from "./types";
const defaultSortBy = "name";
const sortByOptions = [
"name",
"height",
"birthdate",
"tag_count",
"random",
"rating",
]
.map(ListFilterOptions.createSortBy)
.concat([
{
messageID: "scene_count",
value: "scenes_count",
},
]);
const displayModeOptions = [
DisplayMode.Grid,
DisplayMode.List,
DisplayMode.Tagger,
];
const numberCriteria: CriterionType[] = [
"birth_year",
"death_year",
"age",
"weight",
];
const stringCriteria: CriterionType[] = [
"ethnicity",
"country",
"hair_color",
"eye_color",
"height",
"measurements",
"fake_tits",
"career_length",
"tattoos",
"piercings",
"aliases",
"stash_id",
];
const criterionOptions = [
NoneCriterionOption,
FavoriteCriterionOption,
GenderCriterionOption,
PerformerIsMissingCriterionOption,
TagsCriterionOption,
RatingCriterionOption,
StudiosCriterionOption,
createCriterionOption("url"),
createCriterionOption("tag_count"),
createCriterionOption("scene_count"),
createCriterionOption("image_count"),
createCriterionOption("gallery_count"),
...numberCriteria.concat(stringCriteria).map((c) => createCriterionOption(c)),
];
export const PerformerListFilterOptions = new ListFilterOptions(
defaultSortBy,
sortByOptions,
displayModeOptions,
criterionOptions
);

View File

@@ -0,0 +1,28 @@
import { NoneCriterionOption } from "./criteria/none";
import { PerformersCriterionOption } from "./criteria/performers";
import { SceneTagsCriterionOption, TagsCriterionOption } from "./criteria/tags";
import { ListFilterOptions } from "./filter-options";
import { DisplayMode } from "./types";
const defaultSortBy = "title";
const sortByOptions = [
"title",
"seconds",
"scene_id",
"random",
"scenes_updated_at",
].map(ListFilterOptions.createSortBy);
const displayModeOptions = [DisplayMode.Wall];
const criterionOptions = [
NoneCriterionOption,
TagsCriterionOption,
SceneTagsCriterionOption,
PerformersCriterionOption,
];
export const SceneMarkerListFilterOptions = new ListFilterOptions(
defaultSortBy,
sortByOptions,
displayModeOptions,
criterionOptions
);

View File

@@ -0,0 +1,73 @@
import { createCriterionOption } from "./criteria/criterion";
import { HasMarkersCriterionOption } from "./criteria/has-markers";
import { SceneIsMissingCriterionOption } from "./criteria/is-missing";
import { MoviesCriterionOption } from "./criteria/movies";
import { NoneCriterionOption } from "./criteria/none";
import { OrganizedCriterionOption } from "./criteria/organized";
import { PerformersCriterionOption } from "./criteria/performers";
import { RatingCriterionOption } from "./criteria/rating";
import { ResolutionCriterionOption } from "./criteria/resolution";
import { StudiosCriterionOption } from "./criteria/studios";
import { InteractiveCriterionOption } from "./criteria/interactive";
import {
PerformerTagsCriterionOption,
TagsCriterionOption,
} from "./criteria/tags";
import { ListFilterOptions } from "./filter-options";
import { DisplayMode } from "./types";
const defaultSortBy = "date";
const sortByOptions = [
"title",
"path",
"rating",
"organized",
"o_counter",
"date",
"filesize",
"file_mod_time",
"duration",
"framerate",
"bitrate",
"tag_count",
"performer_count",
"random",
"movie_scene_number",
"interactive",
].map(ListFilterOptions.createSortBy);
const displayModeOptions = [
DisplayMode.Grid,
DisplayMode.List,
DisplayMode.Wall,
DisplayMode.Tagger,
];
const criterionOptions = [
NoneCriterionOption,
createCriterionOption("path"),
RatingCriterionOption,
OrganizedCriterionOption,
createCriterionOption("o_counter"),
ResolutionCriterionOption,
createCriterionOption("duration"),
HasMarkersCriterionOption,
SceneIsMissingCriterionOption,
TagsCriterionOption,
createCriterionOption("tag_count"),
PerformerTagsCriterionOption,
PerformersCriterionOption,
createCriterionOption("performer_count"),
StudiosCriterionOption,
MoviesCriterionOption,
createCriterionOption("url"),
createCriterionOption("stash_id"),
InteractiveCriterionOption,
];
export const SceneListFilterOptions = new ListFilterOptions(
defaultSortBy,
sortByOptions,
displayModeOptions,
criterionOptions
);

View File

@@ -0,0 +1,45 @@
import { createCriterionOption } from "./criteria/criterion";
import { StudioIsMissingCriterionOption } from "./criteria/is-missing";
import { NoneCriterionOption } from "./criteria/none";
import { RatingCriterionOption } from "./criteria/rating";
import { ParentStudiosCriterionOption } from "./criteria/studios";
import { ListFilterOptions } from "./filter-options";
import { DisplayMode } from "./types";
const defaultSortBy = "name";
const sortByOptions = ["name", "random", "rating"]
.map(ListFilterOptions.createSortBy)
.concat([
{
messageID: "gallery_count",
value: "galleries_count",
},
{
messageID: "image_count",
value: "images_count",
},
{
messageID: "scene_count",
value: "scenes_count",
},
]);
const displayModeOptions = [DisplayMode.Grid];
const criterionOptions = [
NoneCriterionOption,
ParentStudiosCriterionOption,
StudioIsMissingCriterionOption,
RatingCriterionOption,
createCriterionOption("scene_count"),
createCriterionOption("image_count"),
createCriterionOption("gallery_count"),
createCriterionOption("url"),
createCriterionOption("stash_id"),
];
export const StudioListFilterOptions = new ListFilterOptions(
defaultSortBy,
sortByOptions,
displayModeOptions,
criterionOptions
);

View File

@@ -0,0 +1,52 @@
import { createCriterionOption } from "./criteria/criterion";
import { TagIsMissingCriterionOption } from "./criteria/is-missing";
import { NoneCriterionOption } from "./criteria/none";
import { ListFilterOptions } from "./filter-options";
import { DisplayMode } from "./types";
const defaultSortBy = "name";
// scene markers count has been disabled for now due to performance
// issues
const sortByOptions = [
"name",
"random",
/* "scene_markers_count" */
]
.map(ListFilterOptions.createSortBy)
.concat([
{
messageID: "gallery_count",
value: "galleries_count",
},
{
messageID: "image_count",
value: "images_count",
},
{
messageID: "performer_count",
value: "performers_count",
},
{
messageID: "scene_count",
value: "scenes_count",
},
]);
const displayModeOptions = [DisplayMode.Grid, DisplayMode.List];
const criterionOptions = [
NoneCriterionOption,
TagIsMissingCriterionOption,
createCriterionOption("scene_count"),
createCriterionOption("image_count"),
createCriterionOption("gallery_count"),
createCriterionOption("performer_count"),
// marker count has been disabled for now due to performance issues
// ListFilterModel.createCriterionOption("marker_count"),
];
export const TagListFilterOptions = new ListFilterOptions(
defaultSortBy,
sortByOptions,
displayModeOptions,
criterionOptions
);

View File

@@ -1,4 +1,5 @@
// NOTE: add new enum values to the end, to ensure existing data
// is not impacted
export enum DisplayMode {
Grid,
@@ -39,3 +40,55 @@ export interface IOptionType {
name?: string;
image_path?: string;
}
export type CriterionType =
| "none"
| "path"
| "rating"
| "organized"
| "o_counter"
| "resolution"
| "average_resolution"
| "duration"
| "favorite"
| "hasMarkers"
| "sceneIsMissing"
| "imageIsMissing"
| "performerIsMissing"
| "galleryIsMissing"
| "tagIsMissing"
| "studioIsMissing"
| "movieIsMissing"
| "tags"
| "sceneTags"
| "performerTags"
| "tag_count"
| "performers"
| "studios"
| "movies"
| "galleries"
| "birth_year"
| "age"
| "ethnicity"
| "country"
| "hair_color"
| "eye_color"
| "height"
| "weight"
| "measurements"
| "fake_tits"
| "career_length"
| "tattoos"
| "piercings"
| "aliases"
| "gender"
| "parent_studios"
| "scene_count"
| "marker_count"
| "image_count"
| "gallery_count"
| "performer_count"
| "death_year"
| "url"
| "stash_id"
| "interactive";

View File

@@ -1,7 +1,7 @@
import queryString from "query-string";
import { RouteComponentProps } from "react-router-dom";
import { ListFilterModel } from "./list-filter/filter";
import { FilterMode } from "./list-filter/types";
import { SceneListFilterOptions } from "./list-filter/scenes";
interface IQueryParameters {
qsort?: string;
@@ -27,10 +27,7 @@ export class SceneQueue {
public static fromListFilterModel(filter: ListFilterModel) {
const ret = new SceneQueue();
const filterCopy = Object.assign(
new ListFilterModel(filter.filterMode),
filter
);
const filterCopy = Object.assign(new ListFilterModel(), filter);
filterCopy.itemsPerPage = 40;
ret.originalQueryPage = filter.currentPage;
@@ -98,8 +95,8 @@ export class SceneQueue {
if (parsed.qfp) {
const query = new ListFilterModel(
FilterMode.Scenes,
translated as queryString.ParsedQuery
translated as queryString.ParsedQuery,
SceneListFilterOptions.defaultSortBy
);
ret.query = query;
} else if (parsed.qs) {