mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 21:04:37 +03:00
Refactor list filter query functionality
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import { debounce } from "lodash";
|
import { debounce } from "lodash";
|
||||||
import React, { SyntheticEvent, useCallback, useState } from "react";
|
import React, { SyntheticEvent, useCallback, useState } from "react";
|
||||||
|
import { SortDirectionEnum } from 'src/core/generated-graphql';
|
||||||
import {
|
import {
|
||||||
Badge,
|
Badge,
|
||||||
Button,
|
Button,
|
||||||
@@ -24,7 +25,7 @@ interface IListFilterOperation {
|
|||||||
interface IListFilterProps {
|
interface IListFilterProps {
|
||||||
onChangePageSize: (pageSize: number) => void;
|
onChangePageSize: (pageSize: number) => void;
|
||||||
onChangeQuery: (query: string) => void;
|
onChangeQuery: (query: string) => void;
|
||||||
onChangeSortDirection: (sortDirection: "asc" | "desc") => void;
|
onChangeSortDirection: (sortDirection: SortDirectionEnum) => void;
|
||||||
onChangeSortBy: (sortBy: string) => void;
|
onChangeSortBy: (sortBy: string) => void;
|
||||||
onChangeDisplayMode: (displayMode: DisplayMode) => void;
|
onChangeDisplayMode: (displayMode: DisplayMode) => void;
|
||||||
onAddCriterion: (criterion: Criterion, oldId?: string) => void;
|
onAddCriterion: (criterion: Criterion, oldId?: string) => void;
|
||||||
@@ -64,10 +65,10 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onChangeSortDirection() {
|
function onChangeSortDirection() {
|
||||||
if (props.filter.sortDirection === "asc") {
|
if (props.filter.sortDirection === SortDirectionEnum.Asc) {
|
||||||
props.onChangeSortDirection("desc");
|
props.onChangeSortDirection(SortDirectionEnum.Desc);
|
||||||
} else {
|
} else {
|
||||||
props.onChangeSortDirection("asc");
|
props.onChangeSortDirection(SortDirectionEnum.Asc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,7 +280,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
|||||||
<OverlayTrigger
|
<OverlayTrigger
|
||||||
overlay={
|
overlay={
|
||||||
<Tooltip id="sort-direction-tooltip">
|
<Tooltip id="sort-direction-tooltip">
|
||||||
{props.filter.sortDirection === "asc"
|
{props.filter.sortDirection === SortDirectionEnum.Asc
|
||||||
? "Ascending"
|
? "Ascending"
|
||||||
: "Descending"}
|
: "Descending"}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -288,7 +289,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
|||||||
<Button variant="secondary" onClick={onChangeSortDirection}>
|
<Button variant="secondary" onClick={onChangeSortDirection}>
|
||||||
<Icon
|
<Icon
|
||||||
icon={
|
icon={
|
||||||
props.filter.sortDirection === "asc"
|
props.filter.sortDirection === SortDirectionEnum.Asc
|
||||||
? "caret-up"
|
? "caret-up"
|
||||||
: "caret-down"
|
: "caret-down"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export const PerformerList: React.FC = () => {
|
|||||||
result: FindPerformersQueryResult,
|
result: FindPerformersQueryResult,
|
||||||
filter: ListFilterModel
|
filter: ListFilterModel
|
||||||
) {
|
) {
|
||||||
if (result.data && result.data.findPerformers) {
|
if (result.data?.findPerformers) {
|
||||||
const { count } = result.data.findPerformers;
|
const { count } = result.data.findPerformers;
|
||||||
const index = Math.floor(Math.random() * count);
|
const index = Math.floor(Math.random() * count);
|
||||||
const filterCopy = _.cloneDeep(filter);
|
const filterCopy = _.cloneDeep(filter);
|
||||||
@@ -50,7 +50,7 @@ export const PerformerList: React.FC = () => {
|
|||||||
result: FindPerformersQueryResult,
|
result: FindPerformersQueryResult,
|
||||||
filter: ListFilterModel
|
filter: ListFilterModel
|
||||||
) {
|
) {
|
||||||
if (!result.data || !result.data.findPerformers) {
|
if (!result.data?.findPerformers) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (filter.displayMode === DisplayMode.Grid) {
|
if (filter.displayMode === DisplayMode.Grid) {
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import React, { useState } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { ApolloError } from "apollo-client";
|
import { ApolloError } from "apollo-client";
|
||||||
import { useHistory } from "react-router-dom";
|
import { useHistory, useLocation } from "react-router-dom";
|
||||||
import {
|
import {
|
||||||
|
SortDirectionEnum,
|
||||||
SlimSceneDataFragment,
|
SlimSceneDataFragment,
|
||||||
SceneMarkerDataFragment,
|
SceneMarkerDataFragment,
|
||||||
GalleryDataFragment,
|
GalleryDataFragment,
|
||||||
@@ -74,10 +75,11 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
|
|||||||
options: IListHookOptions<QueryResult> & IQuery<QueryResult, QueryData>
|
options: IListHookOptions<QueryResult> & IQuery<QueryResult, QueryData>
|
||||||
): IListHookData => {
|
): IListHookData => {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
const location = useLocation();
|
||||||
const [filter, setFilter] = useState<ListFilterModel>(
|
const [filter, setFilter] = useState<ListFilterModel>(
|
||||||
new ListFilterModel(
|
new ListFilterModel(
|
||||||
options.filterMode,
|
options.filterMode,
|
||||||
options.subComponent ? "" : queryString.parse(history.location.search)
|
options.subComponent ? "" : queryString.parse(location.search)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
|
const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
|
||||||
@@ -88,6 +90,15 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
|
|||||||
const totalCount = options.getCount(result);
|
const totalCount = options.getCount(result);
|
||||||
const items = options.getData(result);
|
const items = options.getData(result);
|
||||||
|
|
||||||
|
useEffect(() => (
|
||||||
|
setFilter(
|
||||||
|
new ListFilterModel(
|
||||||
|
options.filterMode,
|
||||||
|
options.subComponent ? "" : queryString.parse(location.search)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
), [location, options.filterMode, options.subComponent]);
|
||||||
|
|
||||||
function getFilter() {
|
function getFilter() {
|
||||||
if (!options.filterHook) {
|
if (!options.filterHook) {
|
||||||
return filter;
|
return filter;
|
||||||
@@ -108,7 +119,6 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
|
|||||||
const newFilter = _.cloneDeep(filter);
|
const newFilter = _.cloneDeep(filter);
|
||||||
newFilter.itemsPerPage = pageSize;
|
newFilter.itemsPerPage = pageSize;
|
||||||
newFilter.currentPage = 1;
|
newFilter.currentPage = 1;
|
||||||
setFilter(newFilter);
|
|
||||||
updateQueryParams(newFilter);
|
updateQueryParams(newFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,14 +126,12 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
|
|||||||
const newFilter = _.cloneDeep(filter);
|
const newFilter = _.cloneDeep(filter);
|
||||||
newFilter.searchTerm = query;
|
newFilter.searchTerm = query;
|
||||||
newFilter.currentPage = 1;
|
newFilter.currentPage = 1;
|
||||||
setFilter(newFilter);
|
|
||||||
updateQueryParams(newFilter);
|
updateQueryParams(newFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onChangeSortDirection(sortDirection: "asc" | "desc") {
|
function onChangeSortDirection(sortDirection: SortDirectionEnum) {
|
||||||
const newFilter = _.cloneDeep(filter);
|
const newFilter = _.cloneDeep(filter);
|
||||||
newFilter.sortDirection = sortDirection;
|
newFilter.sortDirection = sortDirection;
|
||||||
setFilter(newFilter);
|
|
||||||
updateQueryParams(newFilter);
|
updateQueryParams(newFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,14 +139,12 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
|
|||||||
const newFilter = _.cloneDeep(filter);
|
const newFilter = _.cloneDeep(filter);
|
||||||
newFilter.sortBy = sortBy;
|
newFilter.sortBy = sortBy;
|
||||||
newFilter.currentPage = 1;
|
newFilter.currentPage = 1;
|
||||||
setFilter(newFilter);
|
|
||||||
updateQueryParams(newFilter);
|
updateQueryParams(newFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onChangeDisplayMode(displayMode: DisplayMode) {
|
function onChangeDisplayMode(displayMode: DisplayMode) {
|
||||||
const newFilter = _.cloneDeep(filter);
|
const newFilter = _.cloneDeep(filter);
|
||||||
newFilter.displayMode = displayMode;
|
newFilter.displayMode = displayMode;
|
||||||
setFilter(newFilter);
|
|
||||||
updateQueryParams(newFilter);
|
updateQueryParams(newFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +171,6 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
|
|||||||
});
|
});
|
||||||
|
|
||||||
newFilter.currentPage = 1;
|
newFilter.currentPage = 1;
|
||||||
setFilter(newFilter);
|
|
||||||
updateQueryParams(newFilter);
|
updateQueryParams(newFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,14 +180,12 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
|
|||||||
criterion => criterion.getId() !== removedCriterion.getId()
|
criterion => criterion.getId() !== removedCriterion.getId()
|
||||||
);
|
);
|
||||||
newFilter.currentPage = 1;
|
newFilter.currentPage = 1;
|
||||||
setFilter(newFilter);
|
|
||||||
updateQueryParams(newFilter);
|
updateQueryParams(newFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onChangePage(page: number) {
|
function onChangePage(page: number) {
|
||||||
const newFilter = _.cloneDeep(filter);
|
const newFilter = _.cloneDeep(filter);
|
||||||
newFilter.currentPage = page;
|
newFilter.currentPage = page;
|
||||||
setFilter(newFilter);
|
|
||||||
updateQueryParams(newFilter);
|
updateQueryParams(newFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ import { makeCriteria } from "./criteria/utils";
|
|||||||
import { DisplayMode, FilterMode } from "./types";
|
import { DisplayMode, FilterMode } from "./types";
|
||||||
|
|
||||||
interface IQueryParameters {
|
interface IQueryParameters {
|
||||||
|
items?: string;
|
||||||
sortby?: string;
|
sortby?: string;
|
||||||
sortdir?: string;
|
sortdir?: string;
|
||||||
disp?: string;
|
disp?: string;
|
||||||
@@ -56,16 +57,24 @@ interface IQueryParameters {
|
|||||||
c?: string[];
|
c?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DEFAULT_PARAMS = {
|
||||||
|
sortDirection: SortDirectionEnum.Asc,
|
||||||
|
displayMode: DisplayMode.Grid,
|
||||||
|
currentPage: 1,
|
||||||
|
itemsPerPage: 40
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// TODO: handle customCriteria
|
// TODO: handle customCriteria
|
||||||
export class ListFilterModel {
|
export class ListFilterModel {
|
||||||
public filterMode: FilterMode = FilterMode.Scenes;
|
public filterMode: FilterMode = FilterMode.Scenes;
|
||||||
public searchTerm?: string;
|
public searchTerm?: string;
|
||||||
public currentPage = 1;
|
public currentPage = DEFAULT_PARAMS.currentPage;
|
||||||
public itemsPerPage = 40;
|
public itemsPerPage = DEFAULT_PARAMS.itemsPerPage;
|
||||||
public sortDirection: "asc" | "desc" = "asc";
|
public sortDirection: SortDirectionEnum = SortDirectionEnum.Asc;
|
||||||
public sortBy?: string;
|
public sortBy?: string;
|
||||||
public sortByOptions: string[] = [];
|
public sortByOptions: string[] = [];
|
||||||
public displayMode: DisplayMode = DisplayMode.Grid;
|
public displayMode: DisplayMode = DEFAULT_PARAMS.displayMode;
|
||||||
public displayModeOptions: DisplayMode[] = [];
|
public displayModeOptions: DisplayMode[] = [];
|
||||||
public criterionOptions: ICriterionOption[] = [];
|
public criterionOptions: ICriterionOption[] = [];
|
||||||
public criteria: Array<Criterion<any, any>> = [];
|
public criteria: Array<Criterion<any, any>> = [];
|
||||||
@@ -78,9 +87,7 @@ export class ListFilterModel {
|
|||||||
public constructor(filterMode: FilterMode, rawParms?: any) {
|
public constructor(filterMode: FilterMode, rawParms?: any) {
|
||||||
switch (filterMode) {
|
switch (filterMode) {
|
||||||
case FilterMode.Scenes:
|
case FilterMode.Scenes:
|
||||||
if (!!this.sortBy === false) {
|
this.sortBy = "date";
|
||||||
this.sortBy = "date";
|
|
||||||
}
|
|
||||||
this.sortByOptions = [
|
this.sortByOptions = [
|
||||||
"title",
|
"title",
|
||||||
"path",
|
"path",
|
||||||
@@ -110,9 +117,7 @@ export class ListFilterModel {
|
|||||||
];
|
];
|
||||||
break;
|
break;
|
||||||
case FilterMode.Performers: {
|
case FilterMode.Performers: {
|
||||||
if (!!this.sortBy === false) {
|
this.sortBy = "name";
|
||||||
this.sortBy = "name";
|
|
||||||
}
|
|
||||||
this.sortByOptions = ["name", "height", "birthdate", "scenes_count"];
|
this.sortByOptions = ["name", "height", "birthdate", "scenes_count"];
|
||||||
this.displayModeOptions = [DisplayMode.Grid, DisplayMode.List];
|
this.displayModeOptions = [DisplayMode.Grid, DisplayMode.List];
|
||||||
|
|
||||||
@@ -143,25 +148,19 @@ export class ListFilterModel {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FilterMode.Studios:
|
case FilterMode.Studios:
|
||||||
if (!!this.sortBy === false) {
|
this.sortBy = "name";
|
||||||
this.sortBy = "name";
|
|
||||||
}
|
|
||||||
this.sortByOptions = ["name", "scenes_count"];
|
this.sortByOptions = ["name", "scenes_count"];
|
||||||
this.displayModeOptions = [DisplayMode.Grid];
|
this.displayModeOptions = [DisplayMode.Grid];
|
||||||
this.criterionOptions = [new NoneCriterionOption()];
|
this.criterionOptions = [new NoneCriterionOption()];
|
||||||
break;
|
break;
|
||||||
case FilterMode.Galleries:
|
case FilterMode.Galleries:
|
||||||
if (!!this.sortBy === false) {
|
this.sortBy = "path";
|
||||||
this.sortBy = "path";
|
|
||||||
}
|
|
||||||
this.sortByOptions = ["path"];
|
this.sortByOptions = ["path"];
|
||||||
this.displayModeOptions = [DisplayMode.List];
|
this.displayModeOptions = [DisplayMode.List];
|
||||||
this.criterionOptions = [new NoneCriterionOption()];
|
this.criterionOptions = [new NoneCriterionOption()];
|
||||||
break;
|
break;
|
||||||
case FilterMode.SceneMarkers:
|
case FilterMode.SceneMarkers:
|
||||||
if (!!this.sortBy === false) {
|
this.sortBy = "title";
|
||||||
this.sortBy = "title";
|
|
||||||
}
|
|
||||||
this.sortByOptions = [
|
this.sortByOptions = [
|
||||||
"title",
|
"title",
|
||||||
"seconds",
|
"seconds",
|
||||||
@@ -208,18 +207,20 @@ export class ListFilterModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (params.sortdir === "asc" || params.sortdir === "desc") {
|
this.sortDirection = params.sortdir === "desc"
|
||||||
this.sortDirection = params.sortdir;
|
? SortDirectionEnum.Desc
|
||||||
|
: SortDirectionEnum.Asc;
|
||||||
|
if (params.disp) {
|
||||||
|
this.displayMode = Number.parseInt(params.disp, 10);
|
||||||
}
|
}
|
||||||
if (params.disp !== undefined) {
|
if (params.q) {
|
||||||
this.displayMode = parseInt(params.disp, 10);
|
|
||||||
}
|
|
||||||
if (params.q !== undefined) {
|
|
||||||
this.searchTerm = params.q;
|
this.searchTerm = params.q;
|
||||||
}
|
}
|
||||||
if (params.p !== undefined) {
|
if (params.p) {
|
||||||
this.currentPage = Number(params.p);
|
this.currentPage = Number.parseInt(params.p, 10);
|
||||||
}
|
}
|
||||||
|
if (params.items)
|
||||||
|
this.itemsPerPage = Number.parseInt(params.items, 10);
|
||||||
|
|
||||||
if (params.c !== undefined) {
|
if (params.c !== undefined) {
|
||||||
this.criteria = [];
|
this.criteria = [];
|
||||||
@@ -275,11 +276,12 @@ export class ListFilterModel {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const result = {
|
const result = {
|
||||||
|
items: this.itemsPerPage !== DEFAULT_PARAMS.itemsPerPage ? this.itemsPerPage : undefined,
|
||||||
sortby: this.getSortBy(),
|
sortby: this.getSortBy(),
|
||||||
sortdir: this.sortDirection,
|
sortdir: this.sortDirection === SortDirectionEnum.Desc ? "desc" : undefined,
|
||||||
disp: this.displayMode,
|
disp: this.displayMode !== DEFAULT_PARAMS.displayMode ? this.displayMode : undefined,
|
||||||
q: this.searchTerm,
|
q: this.searchTerm,
|
||||||
p: this.currentPage,
|
p: this.currentPage !== DEFAULT_PARAMS.currentPage ? this.currentPage : undefined,
|
||||||
c: encodedCriteria
|
c: encodedCriteria
|
||||||
};
|
};
|
||||||
return queryString.stringify(result, { encode: false });
|
return queryString.stringify(result, { encode: false });
|
||||||
@@ -293,10 +295,7 @@ export class ListFilterModel {
|
|||||||
page: this.currentPage,
|
page: this.currentPage,
|
||||||
per_page: this.itemsPerPage,
|
per_page: this.itemsPerPage,
|
||||||
sort: this.getSortBy(),
|
sort: this.getSortBy(),
|
||||||
direction:
|
direction: this.sortDirection
|
||||||
this.sortDirection === "asc"
|
|
||||||
? SortDirectionEnum.Asc
|
|
||||||
: SortDirectionEnum.Desc
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user