mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 20:34:37 +03:00
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:
@@ -44,13 +44,27 @@ const intlFormats = {
|
||||
},
|
||||
};
|
||||
|
||||
function languageMessageString(language: string) {
|
||||
return language.replace(/-/, "");
|
||||
}
|
||||
|
||||
export const App: React.FC = () => {
|
||||
const config = useConfiguration();
|
||||
const { data: systemStatusData } = useSystemStatus();
|
||||
const language = config.data?.configuration?.interface?.language ?? "en-GB";
|
||||
const messageLanguage = language.replace(/-/, "");
|
||||
const defaultLocale = "en-GB";
|
||||
const language =
|
||||
config.data?.configuration?.interface?.language ?? defaultLocale;
|
||||
const defaultMessageLanguage = languageMessageString(defaultLocale);
|
||||
const messageLanguage = languageMessageString(language);
|
||||
|
||||
// use en-GB as default messages if any messages aren't found in the chosen language
|
||||
const mergedMessages = {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const messages = flattenMessages((locales as any)[messageLanguage]);
|
||||
...(locales as any)[defaultMessageLanguage],
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
...(locales as any)[messageLanguage],
|
||||
};
|
||||
const messages = flattenMessages(mergedMessages);
|
||||
|
||||
const setupMatch = useRouteMatch(["/setup", "/migrate"]);
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
* Added [DLNA server](/settings?tab=dlna). ([#1364](https://github.com/stashapp/stash/pull/1364))
|
||||
|
||||
### 🎨 Improvements
|
||||
* Filter modifiers and sort by options are now sorted alphabetically. ([#1406](https://github.com/stashapp/stash/pull/1406))
|
||||
* Add `CreatedAt` and `UpdatedAt` (and `FileModTime` where applicable) to API objects. ([#1421](https://github.com/stashapp/stash/pull/1421))
|
||||
* Add Studios Performer filter criterion. ([#1405](https://github.com/stashapp/stash/pull/1405))
|
||||
* Add `subtractDays` post-process scraper action. ([#1399](https://github.com/stashapp/stash/pull/1399))
|
||||
|
||||
@@ -22,7 +22,7 @@ export const GalleryAddPanel: React.FC<IGalleryAddProps> = ({ gallery }) => {
|
||||
};
|
||||
// if galleries is already present, then we modify it, otherwise add
|
||||
let galleryCriterion = filter.criteria.find((c) => {
|
||||
return c.type === "galleries";
|
||||
return c.criterionOption.value === "galleries";
|
||||
}) as GalleriesCriterion;
|
||||
|
||||
if (
|
||||
|
||||
@@ -24,7 +24,7 @@ export const GalleryImagesPanel: React.FC<IGalleryDetailsProps> = ({
|
||||
};
|
||||
// if galleries is already present, then we modify it, otherwise add
|
||||
let galleryCriterion = filter.criteria.find((c) => {
|
||||
return c.type === "galleries";
|
||||
return c.criterionOption.value === "galleries";
|
||||
}) as GalleriesCriterion;
|
||||
|
||||
if (
|
||||
|
||||
@@ -5,20 +5,24 @@ import Mousetrap from "mousetrap";
|
||||
import { Icon, FilterSelect, DurationInput } from "src/components/Shared";
|
||||
import { CriterionModifier } from "src/core/generated-graphql";
|
||||
import {
|
||||
Criterion,
|
||||
CriterionType,
|
||||
DurationCriterion,
|
||||
CriterionValue,
|
||||
Criterion,
|
||||
} from "src/models/list-filter/criteria/criterion";
|
||||
import { NoneCriterion } from "src/models/list-filter/criteria/none";
|
||||
import { makeCriteria } from "src/models/list-filter/criteria/utils";
|
||||
import { ListFilterModel } from "src/models/list-filter/filter";
|
||||
import { makeCriteria } from "src/models/list-filter/criteria/factory";
|
||||
import { ListFilterOptions } from "src/models/list-filter/filter-options";
|
||||
import { useIntl } from "react-intl";
|
||||
import { CriterionType } from "src/models/list-filter/types";
|
||||
|
||||
interface IAddFilterProps {
|
||||
onAddCriterion: (criterion: Criterion, oldId?: string) => void;
|
||||
onAddCriterion: (
|
||||
criterion: Criterion<CriterionValue>,
|
||||
oldId?: string
|
||||
) => void;
|
||||
onCancel: () => void;
|
||||
filter: ListFilterModel;
|
||||
editingCriterion?: Criterion;
|
||||
filterOptions: ListFilterOptions;
|
||||
editingCriterion?: Criterion<CriterionValue>;
|
||||
}
|
||||
|
||||
export const AddFilter: React.FC<IAddFilterProps> = (
|
||||
@@ -27,10 +31,14 @@ export const AddFilter: React.FC<IAddFilterProps> = (
|
||||
const defaultValue = useRef<string | number | undefined>();
|
||||
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [criterion, setCriterion] = useState<Criterion>(new NoneCriterion());
|
||||
const [criterion, setCriterion] = useState<Criterion<CriterionValue>>(
|
||||
new NoneCriterion()
|
||||
);
|
||||
|
||||
const valueStage = useRef<CriterionValue>(criterion.value);
|
||||
|
||||
const intl = useIntl();
|
||||
|
||||
// configure keyboard shortcuts
|
||||
useEffect(() => {
|
||||
Mousetrap.bind("f", () => setIsOpen(true));
|
||||
@@ -114,7 +122,7 @@ export const AddFilter: React.FC<IAddFilterProps> = (
|
||||
}
|
||||
|
||||
const maybeRenderFilterPopoverContents = () => {
|
||||
if (criterion.type === "none") {
|
||||
if (criterion.criterionOption.value === "none") {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -149,19 +157,19 @@ export const AddFilter: React.FC<IAddFilterProps> = (
|
||||
|
||||
if (Array.isArray(criterion.value)) {
|
||||
if (
|
||||
criterion.type !== "performers" &&
|
||||
criterion.type !== "studios" &&
|
||||
criterion.type !== "parent_studios" &&
|
||||
criterion.type !== "tags" &&
|
||||
criterion.type !== "sceneTags" &&
|
||||
criterion.type !== "performerTags" &&
|
||||
criterion.type !== "movies"
|
||||
criterion.criterionOption.value !== "performers" &&
|
||||
criterion.criterionOption.value !== "studios" &&
|
||||
criterion.criterionOption.value !== "parent_studios" &&
|
||||
criterion.criterionOption.value !== "tags" &&
|
||||
criterion.criterionOption.value !== "sceneTags" &&
|
||||
criterion.criterionOption.value !== "performerTags" &&
|
||||
criterion.criterionOption.value !== "movies"
|
||||
)
|
||||
return;
|
||||
|
||||
return (
|
||||
<FilterSelect
|
||||
type={criterion.type}
|
||||
type={criterion.criterionOption.value}
|
||||
isMulti
|
||||
onSelect={(items) => {
|
||||
const newCriterion = _.cloneDeep(criterion);
|
||||
@@ -223,18 +231,28 @@ export const AddFilter: React.FC<IAddFilterProps> = (
|
||||
if (props.editingCriterion) {
|
||||
return;
|
||||
}
|
||||
|
||||
const options = props.filterOptions.criterionOptions
|
||||
.map((c) => {
|
||||
return {
|
||||
value: c.value,
|
||||
text: intl.formatMessage({ id: c.messageID }),
|
||||
};
|
||||
})
|
||||
.sort((a, b) => a.text.localeCompare(b.text));
|
||||
|
||||
return (
|
||||
<Form.Group controlId="filter">
|
||||
<Form.Label>Filter</Form.Label>
|
||||
<Form.Control
|
||||
as="select"
|
||||
onChange={onChangedCriteriaType}
|
||||
value={criterion.type}
|
||||
value={criterion.criterionOption.value}
|
||||
className="btn-secondary"
|
||||
>
|
||||
{props.filter.criterionOptions.map((c) => (
|
||||
{options.map((c) => (
|
||||
<option key={c.value} value={c.value}>
|
||||
{c.label}
|
||||
{c.text}
|
||||
</option>
|
||||
))}
|
||||
</Form.Control>
|
||||
@@ -263,7 +281,10 @@ export const AddFilter: React.FC<IAddFilterProps> = (
|
||||
</div>
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
<Button onClick={onAddFilter} disabled={criterion.type === "none"}>
|
||||
<Button
|
||||
onClick={onAddFilter}
|
||||
disabled={criterion.criterionOption.value === "none"}
|
||||
>
|
||||
{title}
|
||||
</Button>
|
||||
</Modal.Footer>
|
||||
|
||||
@@ -16,10 +16,15 @@ import {
|
||||
} from "react-bootstrap";
|
||||
|
||||
import { Icon } from "src/components/Shared";
|
||||
import { Criterion } from "src/models/list-filter/criteria/criterion";
|
||||
import { ListFilterModel } from "src/models/list-filter/filter";
|
||||
import { DisplayMode } from "src/models/list-filter/types";
|
||||
import { useFocus } from "src/utils";
|
||||
import { ListFilterOptions } from "src/models/list-filter/filter-options";
|
||||
import { useIntl } from "react-intl";
|
||||
import {
|
||||
Criterion,
|
||||
CriterionValue,
|
||||
} from "src/models/list-filter/criteria/criterion";
|
||||
import { AddFilter } from "./AddFilter";
|
||||
|
||||
interface IListFilterOperation {
|
||||
@@ -38,6 +43,7 @@ interface IListFilterProps {
|
||||
onDelete?: () => void;
|
||||
otherOperations?: IListFilterOperation[];
|
||||
filter: ListFilterModel;
|
||||
filterOptions: ListFilterOptions;
|
||||
itemsSelected?: boolean;
|
||||
}
|
||||
|
||||
@@ -58,9 +64,11 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
||||
}, 500);
|
||||
|
||||
const [editingCriterion, setEditingCriterion] = useState<
|
||||
Criterion | undefined
|
||||
Criterion<CriterionValue> | undefined
|
||||
>(undefined);
|
||||
|
||||
const intl = useIntl();
|
||||
|
||||
useEffect(() => {
|
||||
Mousetrap.bind("/", (e) => {
|
||||
setQueryFocus();
|
||||
@@ -69,17 +77,17 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
||||
|
||||
Mousetrap.bind("r", () => onReshuffleRandomSort());
|
||||
Mousetrap.bind("v g", () => {
|
||||
if (props.filter.displayModeOptions.includes(DisplayMode.Grid)) {
|
||||
if (props.filterOptions.displayModeOptions.includes(DisplayMode.Grid)) {
|
||||
onChangeDisplayMode(DisplayMode.Grid);
|
||||
}
|
||||
});
|
||||
Mousetrap.bind("v l", () => {
|
||||
if (props.filter.displayModeOptions.includes(DisplayMode.List)) {
|
||||
if (props.filterOptions.displayModeOptions.includes(DisplayMode.List)) {
|
||||
onChangeDisplayMode(DisplayMode.List);
|
||||
}
|
||||
});
|
||||
Mousetrap.bind("v w", () => {
|
||||
if (props.filter.displayModeOptions.includes(DisplayMode.Wall)) {
|
||||
if (props.filterOptions.displayModeOptions.includes(DisplayMode.Wall)) {
|
||||
onChangeDisplayMode(DisplayMode.Wall);
|
||||
}
|
||||
});
|
||||
@@ -160,9 +168,9 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
||||
props.onFilterUpdate(newFilter);
|
||||
}
|
||||
|
||||
function onChangeSortBy(event: React.MouseEvent<HTMLAnchorElement>) {
|
||||
function onChangeSortBy(eventKey: string | null) {
|
||||
const newFilter = _.cloneDeep(props.filter);
|
||||
newFilter.sortBy = event.currentTarget.text;
|
||||
newFilter.sortBy = eventKey ?? undefined;
|
||||
newFilter.currentPage = 1;
|
||||
props.onFilterUpdate(newFilter);
|
||||
}
|
||||
@@ -180,7 +188,10 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
||||
props.onFilterUpdate(newFilter);
|
||||
}
|
||||
|
||||
function onAddCriterion(criterion: Criterion, oldId?: string) {
|
||||
function onAddCriterion(
|
||||
criterion: Criterion<CriterionValue>,
|
||||
oldId?: string
|
||||
) {
|
||||
const newFilter = _.cloneDeep(props.filter);
|
||||
|
||||
// Find if we are editing an existing criteria, then modify that. Or create a new one.
|
||||
@@ -208,7 +219,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
||||
setEditingCriterion(undefined);
|
||||
}
|
||||
|
||||
function onRemoveCriterion(removedCriterion: Criterion) {
|
||||
function onRemoveCriterion(removedCriterion: Criterion<CriterionValue>) {
|
||||
const newFilter = _.cloneDeep(props.filter);
|
||||
newFilter.criteria = newFilter.criteria.filter(
|
||||
(criterion) => criterion.getId() !== removedCriterion.getId()
|
||||
@@ -218,7 +229,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
||||
}
|
||||
|
||||
let removedCriterionId = "";
|
||||
function onRemoveCriterionTag(criterion?: Criterion) {
|
||||
function onRemoveCriterionTag(criterion?: Criterion<CriterionValue>) {
|
||||
if (!criterion) {
|
||||
return;
|
||||
}
|
||||
@@ -227,7 +238,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
||||
onRemoveCriterion(criterion);
|
||||
}
|
||||
|
||||
function onClickCriterionTag(criterion?: Criterion) {
|
||||
function onClickCriterionTag(criterion?: Criterion<CriterionValue>) {
|
||||
if (!criterion || removedCriterionId !== "") {
|
||||
return;
|
||||
}
|
||||
@@ -235,13 +246,22 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
||||
}
|
||||
|
||||
function renderSortByOptions() {
|
||||
return props.filter.sortByOptions.map((option) => (
|
||||
return props.filterOptions.sortByOptions
|
||||
.map((o) => {
|
||||
return {
|
||||
message: intl.formatMessage({ id: o.messageID }),
|
||||
value: o.value,
|
||||
};
|
||||
})
|
||||
.sort((a, b) => a.message.localeCompare(b.message))
|
||||
.map((option) => (
|
||||
<Dropdown.Item
|
||||
onClick={onChangeSortBy}
|
||||
key={option}
|
||||
onSelect={onChangeSortBy}
|
||||
key={option.value}
|
||||
className="bg-secondary text-white"
|
||||
eventKey={option.value}
|
||||
>
|
||||
{option}
|
||||
{option.message}
|
||||
</Dropdown.Item>
|
||||
));
|
||||
}
|
||||
@@ -272,7 +292,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
||||
}
|
||||
}
|
||||
|
||||
return props.filter.displayModeOptions.map((option) => (
|
||||
return props.filterOptions.displayModeOptions.map((option) => (
|
||||
<OverlayTrigger
|
||||
key={option}
|
||||
overlay={
|
||||
@@ -298,7 +318,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
||||
key={criterion.getId()}
|
||||
onClick={() => onClickCriterionTag(criterion)}
|
||||
>
|
||||
{criterion.getLabel()}
|
||||
{criterion.getLabel(intl)}
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() => onRemoveCriterionTag(criterion)}
|
||||
@@ -450,6 +470,10 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
||||
}
|
||||
|
||||
function render() {
|
||||
const currentSortBy = props.filterOptions.sortByOptions.find(
|
||||
(o) => o.value === props.filter.sortBy
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ButtonToolbar className="align-items-center justify-content-center mb-2">
|
||||
@@ -465,7 +489,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
||||
|
||||
<InputGroup.Append>
|
||||
<AddFilter
|
||||
filter={props.filter}
|
||||
filterOptions={props.filterOptions}
|
||||
onAddCriterion={onAddCriterion}
|
||||
onCancel={onCancelAddCriterion}
|
||||
editingCriterion={editingCriterion}
|
||||
@@ -475,7 +499,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
||||
|
||||
<Dropdown as={ButtonGroup} className="mr-2">
|
||||
<Dropdown.Toggle split variant="secondary" id="more-menu">
|
||||
{props.filter.sortBy}
|
||||
{intl.formatMessage({ id: currentSortBy?.messageID })}
|
||||
</Dropdown.Toggle>
|
||||
<Dropdown.Menu className="bg-secondary text-white">
|
||||
{renderSortByOptions()}
|
||||
|
||||
@@ -13,7 +13,7 @@ export const MovieScenesPanel: React.FC<IMovieScenesPanel> = ({ movie }) => {
|
||||
const movieValue = { id: movie.id!, label: movie.name! };
|
||||
// if movie is already present, then we modify it, otherwise add
|
||||
let movieCriterion = filter.criteria.find((c) => {
|
||||
return c.type === "movies";
|
||||
return c.criterionOption.value === "movies";
|
||||
}) as MoviesCriterion;
|
||||
|
||||
if (
|
||||
|
||||
@@ -11,13 +11,16 @@ import {
|
||||
TruncatedText,
|
||||
} from "src/components/Shared";
|
||||
import { Button, ButtonGroup } from "react-bootstrap";
|
||||
import { Criterion } from "src/models/list-filter/criteria/criterion";
|
||||
import {
|
||||
Criterion,
|
||||
CriterionValue,
|
||||
} from "src/models/list-filter/criteria/criterion";
|
||||
import { PopoverCountButton } from "../Shared/PopoverCountButton";
|
||||
|
||||
export interface IPerformerCardExtraCriteria {
|
||||
scenes: Criterion[];
|
||||
images: Criterion[];
|
||||
galleries: Criterion[];
|
||||
scenes: Criterion<CriterionValue>[];
|
||||
images: Criterion<CriterionValue>[];
|
||||
galleries: Criterion<CriterionValue>[];
|
||||
}
|
||||
|
||||
interface IPerformerCardProps {
|
||||
|
||||
@@ -22,7 +22,6 @@ import { ScenePlayer } from "src/components/ScenePlayer";
|
||||
import { TextUtils, JWUtils } from "src/utils";
|
||||
import Mousetrap from "mousetrap";
|
||||
import { ListFilterModel } from "src/models/list-filter/filter";
|
||||
import { FilterMode } from "src/models/list-filter/types";
|
||||
import { SceneQueue } from "src/models/sceneQueue";
|
||||
import { QueueViewer } from "./QueueViewer";
|
||||
import { SceneMarkersPanel } from "./SceneMarkersPanel";
|
||||
@@ -220,10 +219,7 @@ export const Scene: React.FC = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const filterCopy = Object.assign(
|
||||
new ListFilterModel(FilterMode.Scenes),
|
||||
sceneQueue.query
|
||||
);
|
||||
const filterCopy = Object.assign(new ListFilterModel(), sceneQueue.query);
|
||||
const newStart = queueStart - filterCopy.itemsPerPage;
|
||||
filterCopy.currentPage = Math.ceil(newStart / filterCopy.itemsPerPage);
|
||||
const query = await queryFindScenes(filterCopy);
|
||||
@@ -244,10 +240,7 @@ export const Scene: React.FC = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const filterCopy = Object.assign(
|
||||
new ListFilterModel(FilterMode.Scenes),
|
||||
sceneQueue.query
|
||||
);
|
||||
const filterCopy = Object.assign(new ListFilterModel(), sceneQueue.query);
|
||||
const newStart = queueStart + queueScenes.length;
|
||||
filterCopy.currentPage = Math.ceil(newStart / filterCopy.itemsPerPage);
|
||||
const query = await queryFindScenes(filterCopy);
|
||||
@@ -284,10 +277,7 @@ export const Scene: React.FC = () => {
|
||||
const pages = Math.ceil(queueTotal / query.itemsPerPage);
|
||||
const page = Math.floor(Math.random() * pages) + 1;
|
||||
const index = Math.floor(Math.random() * query.itemsPerPage);
|
||||
const filterCopy = Object.assign(
|
||||
new ListFilterModel(FilterMode.Scenes),
|
||||
sceneQueue.query
|
||||
);
|
||||
const filterCopy = Object.assign(new ListFilterModel(), sceneQueue.query);
|
||||
filterCopy.currentPage = page;
|
||||
const queryResults = await queryFindScenes(filterCopy);
|
||||
if (queryResults.data.findScenes.scenes.length > index) {
|
||||
|
||||
@@ -15,7 +15,7 @@ export const StudioChildrenPanel: React.FC<IStudioChildrenPanel> = ({
|
||||
const studioValue = { id: studio.id!, label: studio.name! };
|
||||
// if studio is already present, then we modify it, otherwise add
|
||||
let parentStudioCriterion = filter.criteria.find((c) => {
|
||||
return c.type === "parent_studios";
|
||||
return c.criterionOption.value === "parent_studios";
|
||||
}) as ParentStudiosCriterion;
|
||||
|
||||
if (
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import React from "react";
|
||||
import * as GQL from "src/core/generated-graphql";
|
||||
import { ListFilterModel } from "src/models/list-filter/filter";
|
||||
import { TagsCriterion } from "src/models/list-filter/criteria/tags";
|
||||
import {
|
||||
TagsCriterion,
|
||||
TagsCriterionOption,
|
||||
} from "src/models/list-filter/criteria/tags";
|
||||
import { SceneMarkerList } from "src/components/Scenes/SceneMarkerList";
|
||||
|
||||
interface ITagMarkersPanel {
|
||||
@@ -13,7 +16,7 @@ export const TagMarkersPanel: React.FC<ITagMarkersPanel> = ({ tag }) => {
|
||||
const tagValue = { id: tag.id!, label: tag.name! };
|
||||
// if tag is already present, then we modify it, otherwise add
|
||||
let tagCriterion = filter.criteria.find((c) => {
|
||||
return c.type === "tags";
|
||||
return c.criterionOption.value === "tags";
|
||||
}) as TagsCriterion;
|
||||
|
||||
if (
|
||||
@@ -33,7 +36,7 @@ export const TagMarkersPanel: React.FC<ITagMarkersPanel> = ({ tag }) => {
|
||||
tagCriterion.modifier = GQL.CriterionModifier.IncludesAll;
|
||||
} else {
|
||||
// overwrite
|
||||
tagCriterion = new TagsCriterion("tags");
|
||||
tagCriterion = new TagsCriterion(TagsCriterionOption);
|
||||
tagCriterion.value = [tagValue];
|
||||
filter.criteria.push(tagCriterion);
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ export const useFindGalleries = (filter: ListFilterModel) =>
|
||||
GQL.useFindGalleriesQuery({
|
||||
variables: {
|
||||
filter: filter.makeFindFilter(),
|
||||
gallery_filter: filter.makeGalleryFilter(),
|
||||
gallery_filter: filter.makeFilter(),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -56,7 +56,7 @@ export const queryFindGalleries = (filter: ListFilterModel) =>
|
||||
query: GQL.FindGalleriesDocument,
|
||||
variables: {
|
||||
filter: filter.makeFindFilter(),
|
||||
gallery_filter: filter.makeImageFilter(),
|
||||
gallery_filter: filter.makeFilter(),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -64,7 +64,7 @@ export const useFindScenes = (filter: ListFilterModel) =>
|
||||
GQL.useFindScenesQuery({
|
||||
variables: {
|
||||
filter: filter.makeFindFilter(),
|
||||
scene_filter: filter.makeSceneFilter(),
|
||||
scene_filter: filter.makeFilter(),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -73,7 +73,7 @@ export const queryFindScenes = (filter: ListFilterModel) =>
|
||||
query: GQL.FindScenesDocument,
|
||||
variables: {
|
||||
filter: filter.makeFindFilter(),
|
||||
scene_filter: filter.makeSceneFilter(),
|
||||
scene_filter: filter.makeFilter(),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -89,7 +89,7 @@ export const useFindSceneMarkers = (filter: ListFilterModel) =>
|
||||
GQL.useFindSceneMarkersQuery({
|
||||
variables: {
|
||||
filter: filter.makeFindFilter(),
|
||||
scene_marker_filter: filter.makeSceneMarkerFilter(),
|
||||
scene_marker_filter: filter.makeFilter(),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -98,7 +98,7 @@ export const queryFindSceneMarkers = (filter: ListFilterModel) =>
|
||||
query: GQL.FindSceneMarkersDocument,
|
||||
variables: {
|
||||
filter: filter.makeFindFilter(),
|
||||
scene_marker_filter: filter.makeSceneMarkerFilter(),
|
||||
scene_marker_filter: filter.makeFilter(),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -106,7 +106,7 @@ export const useFindImages = (filter: ListFilterModel) =>
|
||||
GQL.useFindImagesQuery({
|
||||
variables: {
|
||||
filter: filter.makeFindFilter(),
|
||||
image_filter: filter.makeImageFilter(),
|
||||
image_filter: filter.makeFilter(),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -115,7 +115,7 @@ export const queryFindImages = (filter: ListFilterModel) =>
|
||||
query: GQL.FindImagesDocument,
|
||||
variables: {
|
||||
filter: filter.makeFindFilter(),
|
||||
image_filter: filter.makeImageFilter(),
|
||||
image_filter: filter.makeFilter(),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -123,7 +123,7 @@ export const useFindStudios = (filter: ListFilterModel) =>
|
||||
GQL.useFindStudiosQuery({
|
||||
variables: {
|
||||
filter: filter.makeFindFilter(),
|
||||
studio_filter: filter.makeStudioFilter(),
|
||||
studio_filter: filter.makeFilter(),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -132,7 +132,7 @@ export const queryFindStudios = (filter: ListFilterModel) =>
|
||||
query: GQL.FindStudiosDocument,
|
||||
variables: {
|
||||
filter: filter.makeFindFilter(),
|
||||
studio_filter: filter.makeStudioFilter(),
|
||||
studio_filter: filter.makeFilter(),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -140,7 +140,7 @@ export const useFindMovies = (filter: ListFilterModel) =>
|
||||
GQL.useFindMoviesQuery({
|
||||
variables: {
|
||||
filter: filter.makeFindFilter(),
|
||||
movie_filter: filter.makeMovieFilter(),
|
||||
movie_filter: filter.makeFilter(),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -149,7 +149,7 @@ export const queryFindMovies = (filter: ListFilterModel) =>
|
||||
query: GQL.FindMoviesDocument,
|
||||
variables: {
|
||||
filter: filter.makeFindFilter(),
|
||||
movie_filter: filter.makeMovieFilter(),
|
||||
movie_filter: filter.makeFilter(),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -157,7 +157,7 @@ export const useFindPerformers = (filter: ListFilterModel) =>
|
||||
GQL.useFindPerformersQuery({
|
||||
variables: {
|
||||
filter: filter.makeFindFilter(),
|
||||
performer_filter: filter.makePerformerFilter(),
|
||||
performer_filter: filter.makeFilter(),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -165,7 +165,7 @@ export const useFindTags = (filter: ListFilterModel) =>
|
||||
GQL.useFindTagsQuery({
|
||||
variables: {
|
||||
filter: filter.makeFindFilter(),
|
||||
tag_filter: filter.makeTagFilter(),
|
||||
tag_filter: filter.makeFilter(),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -174,7 +174,7 @@ export const queryFindTags = (filter: ListFilterModel) =>
|
||||
query: GQL.FindTagsDocument,
|
||||
variables: {
|
||||
filter: filter.makeFindFilter(),
|
||||
tag_filter: filter.makeTagFilter(),
|
||||
tag_filter: filter.makeFilter(),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -183,7 +183,7 @@ export const queryFindPerformers = (filter: ListFilterModel) =>
|
||||
query: GQL.FindPerformersDocument,
|
||||
variables: {
|
||||
filter: filter.makeFindFilter(),
|
||||
performer_filter: filter.makePerformerFilter(),
|
||||
performer_filter: filter.makeFilter(),
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ export const performerFilterHook = (
|
||||
const performerValue = { id: performer.id!, label: performer.name! };
|
||||
// if performers is already present, then we modify it, otherwise add
|
||||
let performerCriterion = filter.criteria.find((c) => {
|
||||
return c.type === "performers";
|
||||
return c.criterionOption.value === "performers";
|
||||
}) as PerformersCriterion;
|
||||
|
||||
if (
|
||||
|
||||
@@ -7,7 +7,7 @@ export const studioFilterHook = (studio: Partial<GQL.StudioDataFragment>) => {
|
||||
const studioValue = { id: studio.id!, label: studio.name! };
|
||||
// if studio is already present, then we modify it, otherwise add
|
||||
let studioCriterion = filter.criteria.find((c) => {
|
||||
return c.type === "studios";
|
||||
return c.criterionOption.value === "studios";
|
||||
}) as StudiosCriterion;
|
||||
|
||||
if (
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import * as GQL from "src/core/generated-graphql";
|
||||
import { TagsCriterion } from "src/models/list-filter/criteria/tags";
|
||||
import {
|
||||
TagsCriterion,
|
||||
TagsCriterionOption,
|
||||
} from "src/models/list-filter/criteria/tags";
|
||||
import { ListFilterModel } from "src/models/list-filter/filter";
|
||||
|
||||
export const tagFilterHook = (tag: GQL.TagDataFragment) => {
|
||||
@@ -7,7 +10,7 @@ export const tagFilterHook = (tag: GQL.TagDataFragment) => {
|
||||
const tagValue = { id: tag.id, label: tag.name };
|
||||
// if tag is already present, then we modify it, otherwise add
|
||||
let tagCriterion = filter.criteria.find((c) => {
|
||||
return c.type === "tags";
|
||||
return c.criterionOption.value === "tags";
|
||||
}) as TagsCriterion;
|
||||
|
||||
if (
|
||||
@@ -27,7 +30,7 @@ export const tagFilterHook = (tag: GQL.TagDataFragment) => {
|
||||
tagCriterion.modifier = GQL.CriterionModifier.IncludesAll;
|
||||
} else {
|
||||
// overwrite
|
||||
tagCriterion = new TagsCriterion("tags");
|
||||
tagCriterion = new TagsCriterion(TagsCriterionOption);
|
||||
tagCriterion.value = [tagValue];
|
||||
filter.criteria.push(tagCriterion);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ import {
|
||||
} from "src/core/StashService";
|
||||
import { ListFilterModel } from "src/models/list-filter/filter";
|
||||
import { FilterMode } from "src/models/list-filter/types";
|
||||
import { ListFilterOptions } from "src/models/list-filter/filter-options";
|
||||
import { getFilterOptions } from "src/models/list-filter/factory";
|
||||
|
||||
const getSelectedData = <I extends IDataItem>(
|
||||
result: I[],
|
||||
@@ -141,6 +143,7 @@ interface IQuery<T extends IQueryResult, T2 extends IDataItem> {
|
||||
|
||||
interface IRenderListProps {
|
||||
filter: ListFilterModel;
|
||||
filterOptions: ListFilterOptions;
|
||||
onChangePage: (page: number) => void;
|
||||
updateQueryParams: (filter: ListFilterModel) => void;
|
||||
}
|
||||
@@ -151,6 +154,7 @@ const RenderList = <
|
||||
>({
|
||||
defaultZoomIndex,
|
||||
filter,
|
||||
filterOptions,
|
||||
onChangePage,
|
||||
addKeybinds,
|
||||
useData,
|
||||
@@ -406,6 +410,7 @@ const RenderList = <
|
||||
onEdit={renderEditDialog ? onEdit : undefined}
|
||||
onDelete={renderDeleteDialog ? onDelete : undefined}
|
||||
filter={filter}
|
||||
filterOptions={filterOptions}
|
||||
/>
|
||||
{isEditDialogOpen &&
|
||||
renderEditDialog &&
|
||||
@@ -432,6 +437,8 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
|
||||
options: IListHookOptions<QueryResult, QueryData> &
|
||||
IQuery<QueryResult, QueryData>
|
||||
): IListHookData => {
|
||||
const filterOptions = getFilterOptions(options.filterMode);
|
||||
|
||||
const history = useHistory();
|
||||
const location = useLocation();
|
||||
const [interfaceState, setInterfaceState] = useInterfaceLocalForage();
|
||||
@@ -445,9 +452,8 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
|
||||
|
||||
const [filter, setFilter] = useState<ListFilterModel>(
|
||||
new ListFilterModel(
|
||||
options.filterMode,
|
||||
queryString.parse(location.search),
|
||||
options.defaultSort
|
||||
options.defaultSort ?? filterOptions.defaultSortBy
|
||||
)
|
||||
);
|
||||
|
||||
@@ -509,7 +515,7 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
|
||||
}
|
||||
: activeFilter;
|
||||
|
||||
const newFilter = new ListFilterModel(options.filterMode, query);
|
||||
const newFilter = new ListFilterModel(query);
|
||||
|
||||
// Compare constructed filter with current filter.
|
||||
// If different it's the result of navigation, and we update the filter.
|
||||
@@ -569,6 +575,7 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
|
||||
const { contentTemplate, onSelectChange } = RenderList({
|
||||
...options,
|
||||
filter: renderFilter,
|
||||
filterOptions,
|
||||
onChangePage,
|
||||
updateQueryParams,
|
||||
});
|
||||
|
||||
3
ui/v2.5/src/locale/README.md
Normal file
3
ui/v2.5/src/locale/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Use `en-GB.json` by default. This should have _all_ message IDs in it. Only add to other json files if the value is different to `en-GB` since it will fall back to use it if the message ID is not found in the chosen language.
|
||||
|
||||
Try to keep message IDs in alphabetical order for ease of reference.
|
||||
@@ -1,20 +1,85 @@
|
||||
{
|
||||
"age": "Age",
|
||||
"aliases": "Aliases",
|
||||
"average_resolution": "Average Resolution",
|
||||
"birth_year": "Birth Year",
|
||||
"birthdate": "Birthdate",
|
||||
"bitrate": "Bit Rate",
|
||||
"career_length": "Career Length",
|
||||
"country": "Country",
|
||||
"created_at": "Created At",
|
||||
"criterion_modifier": {
|
||||
"equals": "is",
|
||||
"not_equals": "is not",
|
||||
"greater_than": "is greater than",
|
||||
"less_than": "is less than",
|
||||
"is_null": "is null",
|
||||
"not_null": "is not null",
|
||||
"includes": "includes",
|
||||
"includes_all": "includes all",
|
||||
"excludes": "excludes",
|
||||
"matches_regex": "matches regex",
|
||||
"not_matches_regex": "not matches regex"
|
||||
},
|
||||
"date": "Date",
|
||||
"death_year": "Death Year",
|
||||
"developmentVersion": "Development Version",
|
||||
"donate": "Donate",
|
||||
"duration": "Duration",
|
||||
"ethnicity": "Ethnicity",
|
||||
"eye_color": "Eye Colour",
|
||||
"fake_tits": "Fake Tits",
|
||||
"favourite": "Favourite",
|
||||
"file_mod_time": "File Modification Time",
|
||||
"filesize": "File Size",
|
||||
"framerate": "Frame Rate",
|
||||
"galleries": "Galleries",
|
||||
"gallery_count": "Gallery Count",
|
||||
"gender": "Gender",
|
||||
"hair_color": "Hair Colour",
|
||||
"hasMarkers": "Has Markers",
|
||||
"height": "Height",
|
||||
"image_count": "Image Count",
|
||||
"images": "Images",
|
||||
"images-size": "Images size",
|
||||
"galleries": "Galleries",
|
||||
"isMissing": "Is Missing",
|
||||
"interactive": "Interactive",
|
||||
"library-size": "Library size",
|
||||
"marker_count": "Marker Count",
|
||||
"markers": "Markers",
|
||||
"measurements": "Measurements",
|
||||
"movie_scene_number": "Movie Scene Number",
|
||||
"movies": "Movies",
|
||||
"name": "Name",
|
||||
"new": "New",
|
||||
"none": "None",
|
||||
"o_counter": "O-Counter",
|
||||
"organized": "Organised",
|
||||
"parent_studios": "Parent Studios",
|
||||
"path": "Path",
|
||||
"performerTags": "Performer Tags",
|
||||
"performer_count": "Performer Count",
|
||||
"performers": "Performers",
|
||||
"piercings": "Piercings",
|
||||
"random": "Random",
|
||||
"rating": "Rating",
|
||||
"resolution": "Resolution",
|
||||
"sceneTagger": "Scene Tagger",
|
||||
"sceneTags": "Scene Tags",
|
||||
"scene_count": "Scene Count",
|
||||
"scene_id": "Scene ID",
|
||||
"scenes": "Scenes",
|
||||
"scenes-size": "Scenes size",
|
||||
"scenes_updated_at": "Scene Updated At",
|
||||
"seconds": "Seconds",
|
||||
"stash_id": "Stash ID",
|
||||
"studios": "Studios",
|
||||
"tag_count": "Tag Count",
|
||||
"tags": "Tags",
|
||||
"tattoos": "Tattoos",
|
||||
"title": "Title",
|
||||
"up-dir": "Up a directory",
|
||||
"favourite": "FAVOURITE",
|
||||
"sceneTagger": "Scene Tagger",
|
||||
"donate": "Donate"
|
||||
"updated_at": "Updated At",
|
||||
"url": "URL",
|
||||
"weight": "Weight"
|
||||
}
|
||||
@@ -1,20 +1,6 @@
|
||||
{
|
||||
"developmentVersion": "Development Version",
|
||||
"images": "Images",
|
||||
"images-size": "Images size",
|
||||
"galleries": "Galleries",
|
||||
"library-size": "Library size",
|
||||
"markers": "Markers",
|
||||
"movies": "Movies",
|
||||
"new": "New",
|
||||
"organized": "Organized",
|
||||
"performers": "Performers",
|
||||
"scenes": "Scenes",
|
||||
"scenes-size": "Scenes size",
|
||||
"studios": "Studios",
|
||||
"tags": "Tags",
|
||||
"up-dir": "Up a directory",
|
||||
"favourite": "FAVORITE",
|
||||
"sceneTagger": "Scene Tagger",
|
||||
"donate": "Donate"
|
||||
"eye_color": "Eye Color",
|
||||
"favourite": "Favorite",
|
||||
"hair_color": "Hair Color",
|
||||
"organized": "Organized"
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"developmentVersion": "開發版本",
|
||||
"donate": "贊助",
|
||||
"favourite": "最愛",
|
||||
"images": "圖片",
|
||||
"images-size": "圖片大小",
|
||||
"galleries": "圖庫",
|
||||
@@ -11,10 +13,8 @@
|
||||
"performers": "演員",
|
||||
"scenes": "場景",
|
||||
"scenes-size": "場景收藏大小",
|
||||
"sceneTagger": "標記場景",
|
||||
"studios": "工作室",
|
||||
"tags": "標籤",
|
||||
"up-dir": "往上一層",
|
||||
"favourite": "最愛",
|
||||
"sceneTagger": "標記場景",
|
||||
"donate": "贊助"
|
||||
"up-dir": "往上一層"
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
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[] = [
|
||||
constructor() {
|
||||
super(SceneIsMissingCriterionOption, [
|
||||
"title",
|
||||
"details",
|
||||
"url",
|
||||
@@ -20,33 +28,38 @@ export class SceneIsMissingCriterion extends IsMissingCriterion {
|
||||
"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[] = [
|
||||
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[] = [
|
||||
constructor() {
|
||||
super(PerformerIsMissingCriterionOption, [
|
||||
"url",
|
||||
"twitter",
|
||||
"instagram",
|
||||
@@ -65,17 +78,20 @@ export class PerformerIsMissingCriterion extends IsMissingCriterion {
|
||||
"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[] = [
|
||||
constructor() {
|
||||
super(GalleryIsMissingCriterionOption, [
|
||||
"title",
|
||||
"details",
|
||||
"url",
|
||||
@@ -84,40 +100,46 @@ export class GalleryIsMissingCriterion extends IsMissingCriterion {
|
||||
"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",
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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 "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
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[] = [
|
||||
|
||||
constructor(type: CriterionOption) {
|
||||
super(type, [
|
||||
"144p",
|
||||
"240p",
|
||||
"360p",
|
||||
@@ -19,21 +19,62 @@ export class ResolutionCriterion extends Criterion {
|
||||
"5k",
|
||||
"6k",
|
||||
"8k",
|
||||
];
|
||||
public value: string = "";
|
||||
]);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
);
|
||||
|
||||
31
ui/v2.5/src/models/list-filter/factory.ts
Normal file
31
ui/v2.5/src/models/list-filter/factory.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
37
ui/v2.5/src/models/list-filter/filter-options.ts
Normal file
37
ui/v2.5/src/models/list-filter/filter-options.ts
Normal 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
63
ui/v2.5/src/models/list-filter/galleries.ts
Normal file
63
ui/v2.5/src/models/list-filter/galleries.ts
Normal 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
|
||||
);
|
||||
51
ui/v2.5/src/models/list-filter/images.ts
Normal file
51
ui/v2.5/src/models/list-filter/images.ts
Normal 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
|
||||
);
|
||||
31
ui/v2.5/src/models/list-filter/movies.ts
Normal file
31
ui/v2.5/src/models/list-filter/movies.ts
Normal 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
|
||||
);
|
||||
77
ui/v2.5/src/models/list-filter/performers.ts
Normal file
77
ui/v2.5/src/models/list-filter/performers.ts
Normal 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
|
||||
);
|
||||
28
ui/v2.5/src/models/list-filter/scene-markers.ts
Normal file
28
ui/v2.5/src/models/list-filter/scene-markers.ts
Normal 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
|
||||
);
|
||||
73
ui/v2.5/src/models/list-filter/scenes.ts
Normal file
73
ui/v2.5/src/models/list-filter/scenes.ts
Normal 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
|
||||
);
|
||||
45
ui/v2.5/src/models/list-filter/studios.ts
Normal file
45
ui/v2.5/src/models/list-filter/studios.ts
Normal 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
|
||||
);
|
||||
52
ui/v2.5/src/models/list-filter/tags.ts
Normal file
52
ui/v2.5/src/models/list-filter/tags.ts
Normal 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
|
||||
);
|
||||
@@ -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";
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -5,13 +5,21 @@ import {
|
||||
StudiosCriterion,
|
||||
ParentStudiosCriterion,
|
||||
} from "src/models/list-filter/criteria/studios";
|
||||
import { TagsCriterion } from "src/models/list-filter/criteria/tags";
|
||||
import {
|
||||
TagsCriterion,
|
||||
TagsCriterionOption,
|
||||
} from "src/models/list-filter/criteria/tags";
|
||||
import { ListFilterModel } from "src/models/list-filter/filter";
|
||||
import { FilterMode } from "src/models/list-filter/types";
|
||||
import { MoviesCriterion } from "src/models/list-filter/criteria/movies";
|
||||
import { Criterion } from "src/models/list-filter/criteria/criterion";
|
||||
import {
|
||||
Criterion,
|
||||
CriterionValue,
|
||||
} from "src/models/list-filter/criteria/criterion";
|
||||
|
||||
function addExtraCriteria(dest: Criterion[], src?: Criterion[]) {
|
||||
function addExtraCriteria(
|
||||
dest: Criterion<CriterionValue>[],
|
||||
src?: Criterion<CriterionValue>[]
|
||||
) {
|
||||
if (src && src.length > 0) {
|
||||
dest.push(...src);
|
||||
}
|
||||
@@ -19,10 +27,10 @@ function addExtraCriteria(dest: Criterion[], src?: Criterion[]) {
|
||||
|
||||
const makePerformerScenesUrl = (
|
||||
performer: Partial<GQL.PerformerDataFragment>,
|
||||
extraCriteria?: Criterion[]
|
||||
extraCriteria?: Criterion<CriterionValue>[]
|
||||
) => {
|
||||
if (!performer.id) return "#";
|
||||
const filter = new ListFilterModel(FilterMode.Scenes);
|
||||
const filter = new ListFilterModel();
|
||||
const criterion = new PerformersCriterion();
|
||||
criterion.value = [
|
||||
{ id: performer.id, label: performer.name || `Performer ${performer.id}` },
|
||||
@@ -34,10 +42,10 @@ const makePerformerScenesUrl = (
|
||||
|
||||
const makePerformerImagesUrl = (
|
||||
performer: Partial<GQL.PerformerDataFragment>,
|
||||
extraCriteria?: Criterion[]
|
||||
extraCriteria?: Criterion<CriterionValue>[]
|
||||
) => {
|
||||
if (!performer.id) return "#";
|
||||
const filter = new ListFilterModel(FilterMode.Images);
|
||||
const filter = new ListFilterModel();
|
||||
const criterion = new PerformersCriterion();
|
||||
criterion.value = [
|
||||
{ id: performer.id, label: performer.name || `Performer ${performer.id}` },
|
||||
@@ -49,10 +57,10 @@ const makePerformerImagesUrl = (
|
||||
|
||||
const makePerformerGalleriesUrl = (
|
||||
performer: Partial<GQL.PerformerDataFragment>,
|
||||
extraCriteria?: Criterion[]
|
||||
extraCriteria?: Criterion<CriterionValue>[]
|
||||
) => {
|
||||
if (!performer.id) return "#";
|
||||
const filter = new ListFilterModel(FilterMode.Galleries);
|
||||
const filter = new ListFilterModel();
|
||||
const criterion = new PerformersCriterion();
|
||||
criterion.value = [
|
||||
{ id: performer.id, label: performer.name || `Performer ${performer.id}` },
|
||||
@@ -66,7 +74,7 @@ const makePerformersCountryUrl = (
|
||||
performer: Partial<GQL.PerformerDataFragment>
|
||||
) => {
|
||||
if (!performer.id) return "#";
|
||||
const filter = new ListFilterModel(FilterMode.Performers);
|
||||
const filter = new ListFilterModel();
|
||||
const criterion = new CountryCriterion();
|
||||
criterion.value = `${performer.country}`;
|
||||
filter.criteria.push(criterion);
|
||||
@@ -75,7 +83,7 @@ const makePerformersCountryUrl = (
|
||||
|
||||
const makeStudioScenesUrl = (studio: Partial<GQL.StudioDataFragment>) => {
|
||||
if (!studio.id) return "#";
|
||||
const filter = new ListFilterModel(FilterMode.Scenes);
|
||||
const filter = new ListFilterModel();
|
||||
const criterion = new StudiosCriterion();
|
||||
criterion.value = [
|
||||
{ id: studio.id, label: studio.name || `Studio ${studio.id}` },
|
||||
@@ -86,7 +94,7 @@ const makeStudioScenesUrl = (studio: Partial<GQL.StudioDataFragment>) => {
|
||||
|
||||
const makeStudioImagesUrl = (studio: Partial<GQL.StudioDataFragment>) => {
|
||||
if (!studio.id) return "#";
|
||||
const filter = new ListFilterModel(FilterMode.Images);
|
||||
const filter = new ListFilterModel();
|
||||
const criterion = new StudiosCriterion();
|
||||
criterion.value = [
|
||||
{ id: studio.id, label: studio.name || `Studio ${studio.id}` },
|
||||
@@ -97,7 +105,7 @@ const makeStudioImagesUrl = (studio: Partial<GQL.StudioDataFragment>) => {
|
||||
|
||||
const makeStudioGalleriesUrl = (studio: Partial<GQL.StudioDataFragment>) => {
|
||||
if (!studio.id) return "#";
|
||||
const filter = new ListFilterModel(FilterMode.Galleries);
|
||||
const filter = new ListFilterModel();
|
||||
const criterion = new StudiosCriterion();
|
||||
criterion.value = [
|
||||
{ id: studio.id, label: studio.name || `Studio ${studio.id}` },
|
||||
@@ -108,7 +116,7 @@ const makeStudioGalleriesUrl = (studio: Partial<GQL.StudioDataFragment>) => {
|
||||
|
||||
const makeChildStudiosUrl = (studio: Partial<GQL.StudioDataFragment>) => {
|
||||
if (!studio.id) return "#";
|
||||
const filter = new ListFilterModel(FilterMode.Studios);
|
||||
const filter = new ListFilterModel();
|
||||
const criterion = new ParentStudiosCriterion();
|
||||
criterion.value = [
|
||||
{ id: studio.id, label: studio.name || `Studio ${studio.id}` },
|
||||
@@ -119,7 +127,7 @@ const makeChildStudiosUrl = (studio: Partial<GQL.StudioDataFragment>) => {
|
||||
|
||||
const makeMovieScenesUrl = (movie: Partial<GQL.MovieDataFragment>) => {
|
||||
if (!movie.id) return "#";
|
||||
const filter = new ListFilterModel(FilterMode.Scenes);
|
||||
const filter = new ListFilterModel();
|
||||
const criterion = new MoviesCriterion();
|
||||
criterion.value = [
|
||||
{ id: movie.id, label: movie.name || `Movie ${movie.id}` },
|
||||
@@ -130,8 +138,8 @@ const makeMovieScenesUrl = (movie: Partial<GQL.MovieDataFragment>) => {
|
||||
|
||||
const makeTagScenesUrl = (tag: Partial<GQL.TagDataFragment>) => {
|
||||
if (!tag.id) return "#";
|
||||
const filter = new ListFilterModel(FilterMode.Scenes);
|
||||
const criterion = new TagsCriterion("tags");
|
||||
const filter = new ListFilterModel();
|
||||
const criterion = new TagsCriterion(TagsCriterionOption);
|
||||
criterion.value = [{ id: tag.id, label: tag.name || `Tag ${tag.id}` }];
|
||||
filter.criteria.push(criterion);
|
||||
return `/scenes?${filter.makeQueryParameters()}`;
|
||||
@@ -139,8 +147,8 @@ const makeTagScenesUrl = (tag: Partial<GQL.TagDataFragment>) => {
|
||||
|
||||
const makeTagPerformersUrl = (tag: Partial<GQL.TagDataFragment>) => {
|
||||
if (!tag.id) return "#";
|
||||
const filter = new ListFilterModel(FilterMode.Performers);
|
||||
const criterion = new TagsCriterion("tags");
|
||||
const filter = new ListFilterModel();
|
||||
const criterion = new TagsCriterion(TagsCriterionOption);
|
||||
criterion.value = [{ id: tag.id, label: tag.name || `Tag ${tag.id}` }];
|
||||
filter.criteria.push(criterion);
|
||||
return `/performers?${filter.makeQueryParameters()}`;
|
||||
@@ -148,8 +156,8 @@ const makeTagPerformersUrl = (tag: Partial<GQL.TagDataFragment>) => {
|
||||
|
||||
const makeTagSceneMarkersUrl = (tag: Partial<GQL.TagDataFragment>) => {
|
||||
if (!tag.id) return "#";
|
||||
const filter = new ListFilterModel(FilterMode.SceneMarkers);
|
||||
const criterion = new TagsCriterion("tags");
|
||||
const filter = new ListFilterModel();
|
||||
const criterion = new TagsCriterion(TagsCriterionOption);
|
||||
criterion.value = [{ id: tag.id, label: tag.name || `Tag ${tag.id}` }];
|
||||
filter.criteria.push(criterion);
|
||||
return `/scenes/markers?${filter.makeQueryParameters()}`;
|
||||
@@ -157,8 +165,8 @@ const makeTagSceneMarkersUrl = (tag: Partial<GQL.TagDataFragment>) => {
|
||||
|
||||
const makeTagGalleriesUrl = (tag: Partial<GQL.TagDataFragment>) => {
|
||||
if (!tag.id) return "#";
|
||||
const filter = new ListFilterModel(FilterMode.Galleries);
|
||||
const criterion = new TagsCriterion("tags");
|
||||
const filter = new ListFilterModel();
|
||||
const criterion = new TagsCriterion(TagsCriterionOption);
|
||||
criterion.value = [{ id: tag.id, label: tag.name || `Tag ${tag.id}` }];
|
||||
filter.criteria.push(criterion);
|
||||
return `/galleries?${filter.makeQueryParameters()}`;
|
||||
@@ -166,8 +174,8 @@ const makeTagGalleriesUrl = (tag: Partial<GQL.TagDataFragment>) => {
|
||||
|
||||
const makeTagImagesUrl = (tag: Partial<GQL.TagDataFragment>) => {
|
||||
if (!tag.id) return "#";
|
||||
const filter = new ListFilterModel(FilterMode.Images);
|
||||
const criterion = new TagsCriterion("tags");
|
||||
const filter = new ListFilterModel();
|
||||
const criterion = new TagsCriterion(TagsCriterionOption);
|
||||
criterion.value = [{ id: tag.id, label: tag.name || `Tag ${tag.id}` }];
|
||||
filter.criteria.push(criterion);
|
||||
return `/images?${filter.makeQueryParameters()}`;
|
||||
|
||||
Reference in New Issue
Block a user