mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 20:34:37 +03:00
Fixes
This commit is contained in:
@@ -60,6 +60,7 @@
|
|||||||
"@types/query-string": "6.3.0",
|
"@types/query-string": "6.3.0",
|
||||||
"@types/react": "16.9.15",
|
"@types/react": "16.9.15",
|
||||||
"@types/react-dom": "16.9.4",
|
"@types/react-dom": "16.9.4",
|
||||||
|
"@types/react-images": "^0.5.1",
|
||||||
"@types/react-router-bootstrap": "^0.24.5",
|
"@types/react-router-bootstrap": "^0.24.5",
|
||||||
"@types/react-router-dom": "5.1.3",
|
"@types/react-router-dom": "5.1.3",
|
||||||
"@types/react-select": "^3.0.8",
|
"@types/react-select": "^3.0.8",
|
||||||
|
|||||||
@@ -3,17 +3,12 @@ import { Table } from 'react-bootstrap';
|
|||||||
import { QueryHookResult } from "react-apollo-hooks";
|
import { QueryHookResult } from "react-apollo-hooks";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { FindGalleriesQuery, FindGalleriesVariables } from "src/core/generated-graphql";
|
import { FindGalleriesQuery, FindGalleriesVariables } from "src/core/generated-graphql";
|
||||||
import { ListHook } from "src/hooks";
|
import { useGalleriesList } from "src/hooks";
|
||||||
import { IBaseProps } from "src/models/base-props";
|
|
||||||
import { ListFilterModel } from "src/models/list-filter/filter";
|
import { ListFilterModel } from "src/models/list-filter/filter";
|
||||||
import { DisplayMode, FilterMode } from "src/models/list-filter/types";
|
import { DisplayMode } from "src/models/list-filter/types";
|
||||||
|
|
||||||
interface IProps extends IBaseProps {}
|
export const GalleryList: React.FC = () => {
|
||||||
|
const listData = useGalleriesList({
|
||||||
export const GalleryList: React.FC<IProps> = (props: IProps) => {
|
|
||||||
const listData = ListHook.useList({
|
|
||||||
filterMode: FilterMode.Galleries,
|
|
||||||
props,
|
|
||||||
renderContent,
|
renderContent,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { Nav, Navbar, Button } from "react-bootstrap";
|
|
||||||
import { LinkContainer } from 'react-router-bootstrap';
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { Nav, Navbar, Button } from "react-bootstrap";
|
||||||
|
import { IconName } from '@fortawesome/fontawesome-svg-core';
|
||||||
|
import { LinkContainer } from 'react-router-bootstrap';
|
||||||
import { Link, useLocation } from "react-router-dom";
|
import { Link, useLocation } from "react-router-dom";
|
||||||
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { Icon } from 'src/components/Shared'
|
||||||
import { IconName } from '@fortawesome/fontawesome-svg-core';
|
|
||||||
|
|
||||||
interface IMenuItem {
|
interface IMenuItem {
|
||||||
text: string;
|
text: string;
|
||||||
@@ -74,7 +74,7 @@ export const MainNavbar: React.FC = () => {
|
|||||||
key={i.href}
|
key={i.href}
|
||||||
>
|
>
|
||||||
<Button variant="secondary">
|
<Button variant="secondary">
|
||||||
<FontAwesomeIcon icon={i.icon} />
|
<Icon icon={i.icon} />
|
||||||
{i.text}
|
{i.text}
|
||||||
</Button>
|
</Button>
|
||||||
</LinkContainer>
|
</LinkContainer>
|
||||||
@@ -86,7 +86,7 @@ export const MainNavbar: React.FC = () => {
|
|||||||
exact={true}
|
exact={true}
|
||||||
to="/settings">
|
to="/settings">
|
||||||
<Button variant="secondary">
|
<Button variant="secondary">
|
||||||
<FontAwesomeIcon icon="cog" />
|
<Icon icon="cog" />
|
||||||
</Button>
|
</Button>
|
||||||
</LinkContainer>
|
</LinkContainer>
|
||||||
</Nav>
|
</Nav>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { Button, ButtonGroup, InputGroup, Form } from 'react-bootstrap';
|
import { Button, ButtonGroup, InputGroup, Form } from 'react-bootstrap';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { Icon } from 'src/components/Shared'
|
||||||
import { TextUtils } from "src/utils";
|
import { TextUtils } from "src/utils";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
@@ -83,13 +83,13 @@ export const DurationInput: React.FC<IProps> = (props: IProps) => {
|
|||||||
disabled={props.disabled}
|
disabled={props.disabled}
|
||||||
onClick={() => increment()}
|
onClick={() => increment()}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon="chevron-up" />
|
<Icon icon="chevron-up" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
disabled={props.disabled}
|
disabled={props.disabled}
|
||||||
onClick={() => decrement()}
|
onClick={() => decrement()}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon="chevron-down" />
|
<Icon icon="chevron-down" />
|
||||||
</Button>
|
</Button>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
)
|
)
|
||||||
@@ -107,7 +107,7 @@ export const DurationInput: React.FC<IProps> = (props: IProps) => {
|
|||||||
<Button
|
<Button
|
||||||
onClick={() => onReset()}
|
onClick={() => onReset()}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon="clock" />
|
<Icon icon="clock" />
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,13 @@
|
|||||||
import React, { FunctionComponent } from "react";
|
import React from "react";
|
||||||
import { QueryHookResult } from "react-apollo-hooks";
|
import { QueryHookResult } from "react-apollo-hooks";
|
||||||
import { FindStudiosQuery, FindStudiosVariables } from "src/core/generated-graphql";
|
import { FindStudiosQuery, FindStudiosVariables } from "src/core/generated-graphql";
|
||||||
import { ListHook } from "src/hooks";
|
import { useStudiosList } from "src/hooks";
|
||||||
import { IBaseProps } from "src/models/base-props";
|
|
||||||
import { ListFilterModel } from "src/models/list-filter/filter";
|
import { ListFilterModel } from "src/models/list-filter/filter";
|
||||||
import { DisplayMode, FilterMode } from "src/models/list-filter/types";
|
import { DisplayMode } from "src/models/list-filter/types";
|
||||||
import { StudioCard } from "./StudioCard";
|
import { StudioCard } from "./StudioCard";
|
||||||
|
|
||||||
interface IProps extends IBaseProps {}
|
export const StudioList: React.FC = () => {
|
||||||
|
const listData = useStudiosList({
|
||||||
export const StudioList: FunctionComponent<IProps> = (props: IProps) => {
|
|
||||||
const listData = ListHook.useList({
|
|
||||||
filterMode: FilterMode.Studios,
|
|
||||||
props,
|
|
||||||
renderContent,
|
renderContent,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ interface IPaginationProps {
|
|||||||
currentPage: number;
|
currentPage: number;
|
||||||
totalItems: number;
|
totalItems: number;
|
||||||
onChangePage: (page: number) => void;
|
onChangePage: (page: number) => void;
|
||||||
|
loading?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IPaginationState {
|
interface IPaginationState {
|
||||||
@@ -27,6 +28,8 @@ export class Pagination extends React.Component<IPaginationProps, IPaginationSta
|
|||||||
}
|
}
|
||||||
|
|
||||||
public componentDidUpdate(prevProps: IPaginationProps) {
|
public componentDidUpdate(prevProps: IPaginationProps) {
|
||||||
|
if (this.props.loading)
|
||||||
|
return;
|
||||||
if (this.props.totalItems !== prevProps.totalItems || this.props.itemsPerPage !== prevProps.itemsPerPage) {
|
if (this.props.totalItems !== prevProps.totalItems || this.props.itemsPerPage !== prevProps.itemsPerPage) {
|
||||||
this.setPage(this.props.currentPage);
|
this.setPage(this.props.currentPage);
|
||||||
}
|
}
|
||||||
@@ -81,7 +84,7 @@ export class Pagination extends React.Component<IPaginationProps, IPaginationSta
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getPagerState(totalItems: number, currentPage: number, pageSize: number) {
|
private getPagerState(totalItems: number, currentPage: number, pageSize: number) {
|
||||||
const totalPages = Math.ceil(totalItems / pageSize);
|
const totalPages = Math.max(Math.ceil(totalItems / pageSize), 1);
|
||||||
|
|
||||||
let startPage: number;
|
let startPage: number;
|
||||||
let endPage: number;
|
let endPage: number;
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { QueryHookResult } from "react-apollo-hooks";
|
import { QueryHookResult } from "react-apollo-hooks";
|
||||||
|
import { useHistory } from 'react-router-dom';
|
||||||
import { FindPerformersQuery, FindPerformersVariables } from "src/core/generated-graphql";
|
import { FindPerformersQuery, FindPerformersVariables } from "src/core/generated-graphql";
|
||||||
import { StashService } from "src/core/StashService";
|
import { StashService } from "src/core/StashService";
|
||||||
import { ListHook } from "src/hooks";
|
import { usePerformersList } from "src/hooks";
|
||||||
import { IBaseProps } from "src/models/base-props";
|
|
||||||
import { ListFilterModel } from "src/models/list-filter/filter";
|
import { ListFilterModel } from "src/models/list-filter/filter";
|
||||||
import { DisplayMode, FilterMode } from "src/models/list-filter/types";
|
import { DisplayMode } from "src/models/list-filter/types";
|
||||||
import { PerformerCard } from "./PerformerCard";
|
import { PerformerCard } from "./PerformerCard";
|
||||||
import { PerformerListTable } from "./PerformerListTable";
|
import { PerformerListTable } from "./PerformerListTable";
|
||||||
|
|
||||||
interface IPerformerListProps extends IBaseProps {}
|
export const PerformerList: React.FC = () => {
|
||||||
|
const history = useHistory();
|
||||||
export const PerformerList: React.FC<IPerformerListProps> = (props: IPerformerListProps) => {
|
|
||||||
const otherOperations = [
|
const otherOperations = [
|
||||||
{
|
{
|
||||||
text: "Open Random",
|
text: "Open Random",
|
||||||
@@ -20,9 +19,7 @@ export const PerformerList: React.FC<IPerformerListProps> = (props: IPerformerLi
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const listData = ListHook.useList({
|
const listData = usePerformersList({
|
||||||
filterMode: FilterMode.Performers,
|
|
||||||
props,
|
|
||||||
otherOperations: otherOperations,
|
otherOperations: otherOperations,
|
||||||
renderContent,
|
renderContent,
|
||||||
});
|
});
|
||||||
@@ -37,7 +34,7 @@ export const PerformerList: React.FC<IPerformerListProps> = (props: IPerformerLi
|
|||||||
const singleResult = await StashService.queryFindPerformers(filterCopy);
|
const singleResult = await StashService.queryFindPerformers(filterCopy);
|
||||||
if (singleResult && singleResult.data && singleResult.data.findPerformers && singleResult.data.findPerformers.performers.length === 1) {
|
if (singleResult && singleResult.data && singleResult.data.findPerformers && singleResult.data.findPerformers.performers.length === 1) {
|
||||||
let id = singleResult!.data!.findPerformers!.performers[0]!.id;
|
let id = singleResult!.data!.findPerformers!.performers[0]!.id;
|
||||||
props.history.push("/performers/" + id);
|
history.push("/performers/" + id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,19 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { QueryHookResult } from "react-apollo-hooks";
|
import { QueryHookResult } from "react-apollo-hooks";
|
||||||
|
import { useHistory } from 'react-router-dom';
|
||||||
import { FindScenesQuery, FindScenesVariables, SlimSceneDataFragment } from "src/core/generated-graphql";
|
import { FindScenesQuery, FindScenesVariables, SlimSceneDataFragment } from "src/core/generated-graphql";
|
||||||
import { StashService } from "src/core/StashService";
|
import { StashService } from "src/core/StashService";
|
||||||
import { ListHook } from "src/hooks";
|
import { useScenesList } from "src/hooks";
|
||||||
import { IBaseProps } from "src/models/base-props";
|
|
||||||
import { ListFilterModel } from "src/models/list-filter/filter";
|
import { ListFilterModel } from "src/models/list-filter/filter";
|
||||||
import { DisplayMode, FilterMode } from "src/models/list-filter/types";
|
import { DisplayMode } from "src/models/list-filter/types";
|
||||||
import { WallPanel } from "../Wall/WallPanel";
|
import { WallPanel } from "../Wall/WallPanel";
|
||||||
import { SceneCard } from "./SceneCard";
|
import { SceneCard } from "./SceneCard";
|
||||||
import { SceneListTable } from "./SceneListTable";
|
import { SceneListTable } from "./SceneListTable";
|
||||||
import { SceneSelectedOptions } from "./SceneSelectedOptions";
|
import { SceneSelectedOptions } from "./SceneSelectedOptions";
|
||||||
|
|
||||||
interface ISceneListProps extends IBaseProps {}
|
export const SceneList: React.FC = () => {
|
||||||
|
const history = useHistory();
|
||||||
export const SceneList: React.FC<ISceneListProps> = (props: ISceneListProps) => {
|
|
||||||
const otherOperations = [
|
const otherOperations = [
|
||||||
{
|
{
|
||||||
text: "Play Random",
|
text: "Play Random",
|
||||||
@@ -22,9 +21,7 @@ export const SceneList: React.FC<ISceneListProps> = (props: ISceneListProps) =>
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const listData = ListHook.useList({
|
const listData = useScenesList({
|
||||||
filterMode: FilterMode.Scenes,
|
|
||||||
props,
|
|
||||||
zoomable: true,
|
zoomable: true,
|
||||||
otherOperations: otherOperations,
|
otherOperations: otherOperations,
|
||||||
renderContent,
|
renderContent,
|
||||||
@@ -44,7 +41,7 @@ export const SceneList: React.FC<ISceneListProps> = (props: ISceneListProps) =>
|
|||||||
if (singleResult && singleResult.data && singleResult.data.findScenes && singleResult.data.findScenes.scenes.length === 1) {
|
if (singleResult && singleResult.data && singleResult.data.findScenes && singleResult.data.findScenes.scenes.length === 1) {
|
||||||
let id = singleResult!.data!.findScenes!.scenes[0].id;
|
let id = singleResult!.data!.findScenes!.scenes[0].id;
|
||||||
// navigate to the scene player page
|
// navigate to the scene player page
|
||||||
props.history.push("/scenes/" + id + "?autoplay=true");
|
history.push("/scenes/" + id + "?autoplay=true");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,24 @@
|
|||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { QueryHookResult } from "react-apollo-hooks";
|
import { QueryHookResult } from "react-apollo-hooks";
|
||||||
|
import { useHistory } from 'react-router-dom';
|
||||||
import { FindSceneMarkersQuery, FindSceneMarkersVariables } from "src/core/generated-graphql";
|
import { FindSceneMarkersQuery, FindSceneMarkersVariables } from "src/core/generated-graphql";
|
||||||
import { StashService } from "src/core/StashService";
|
import { StashService } from "src/core/StashService";
|
||||||
import { NavUtils } from "src/utils";
|
import { NavUtils } from "src/utils";
|
||||||
import { ListHook } from "src/hooks";
|
import { useSceneMarkersList } from "src/hooks";
|
||||||
import { IBaseProps } from "src/models/base-props";
|
|
||||||
import { ListFilterModel } from "src/models/list-filter/filter";
|
import { ListFilterModel } from "src/models/list-filter/filter";
|
||||||
import { DisplayMode, FilterMode } from "src/models/list-filter/types";
|
import { DisplayMode } from "src/models/list-filter/types";
|
||||||
import { WallPanel } from "../Wall/WallPanel";
|
import { WallPanel } from "../Wall/WallPanel";
|
||||||
|
|
||||||
interface IProps extends IBaseProps {}
|
export const SceneMarkerList: React.FC = () => {
|
||||||
|
const history = useHistory();
|
||||||
export const SceneMarkerList: React.FC<IProps> = (props: IProps) => {
|
|
||||||
const otherOperations = [{
|
const otherOperations = [{
|
||||||
text: "Play Random",
|
text: "Play Random",
|
||||||
onClick: playRandom
|
onClick: playRandom
|
||||||
}];
|
}];
|
||||||
|
|
||||||
const listData = ListHook.useList({
|
const listData = useSceneMarkersList({
|
||||||
filterMode: FilterMode.SceneMarkers,
|
|
||||||
otherOperations: otherOperations,
|
otherOperations: otherOperations,
|
||||||
props,
|
|
||||||
renderContent,
|
renderContent,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -38,7 +35,7 @@ export const SceneMarkerList: React.FC<IProps> = (props: IProps) => {
|
|||||||
if (singleResult && singleResult.data && singleResult.data.findSceneMarkers && singleResult.data.findSceneMarkers.scene_markers.length === 1) {
|
if (singleResult && singleResult.data && singleResult.data.findSceneMarkers && singleResult.data.findSceneMarkers.scene_markers.length === 1) {
|
||||||
// navigate to the scene player page
|
// navigate to the scene player page
|
||||||
let url = NavUtils.makeSceneMarkerUrl(singleResult.data.findSceneMarkers.scene_markers[0])
|
let url = NavUtils.makeSceneMarkerUrl(singleResult.data.findSceneMarkers.scene_markers[0])
|
||||||
props.history.push(url);
|
history.push(url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,310 +1,333 @@
|
|||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Spinner } from 'react-bootstrap';
|
import { Spinner } from 'react-bootstrap';
|
||||||
import { QueryHookResult } from "react-apollo-hooks";
|
import { QueryHookResult } from "react-apollo-hooks";
|
||||||
|
import { ApolloError } from 'apollo-client';
|
||||||
|
import { useHistory } from 'react-router-dom';
|
||||||
|
import {
|
||||||
|
FindScenesQuery,
|
||||||
|
FindScenesVariables,
|
||||||
|
SlimSceneDataFragment,
|
||||||
|
FindSceneMarkersQuery,
|
||||||
|
FindSceneMarkersVariables,
|
||||||
|
FindSceneMarkersSceneMarkers,
|
||||||
|
FindGalleriesQuery,
|
||||||
|
FindGalleriesVariables,
|
||||||
|
GalleryDataFragment,
|
||||||
|
FindStudiosQuery,
|
||||||
|
FindStudiosVariables,
|
||||||
|
StudioDataFragment,
|
||||||
|
FindPerformersQuery,
|
||||||
|
FindPerformersVariables,
|
||||||
|
PerformerDataFragment
|
||||||
|
} from 'src/core/generated-graphql';
|
||||||
import { ListFilter } from "../components/list/ListFilter";
|
import { ListFilter } from "../components/list/ListFilter";
|
||||||
import { Pagination } from "../components/list/Pagination";
|
import { Pagination } from "../components/list/Pagination";
|
||||||
import { StashService } from "../core/StashService";
|
import { StashService } from "../core/StashService";
|
||||||
import { IBaseProps } from "../models";
|
|
||||||
import { Criterion } from "../models/list-filter/criteria/criterion";
|
import { Criterion } from "../models/list-filter/criteria/criterion";
|
||||||
import { ListFilterModel } from "../models/list-filter/filter";
|
import { ListFilterModel } from "../models/list-filter/filter";
|
||||||
import { DisplayMode, FilterMode } from "../models/list-filter/types";
|
import { DisplayMode, FilterMode } from "../models/list-filter/types";
|
||||||
|
|
||||||
export interface IListHookData {
|
interface IListHookData {
|
||||||
filter: ListFilterModel;
|
filter: ListFilterModel;
|
||||||
template: JSX.Element;
|
template: JSX.Element;
|
||||||
options: IListHookOptions;
|
|
||||||
onSelectChange: (id: string, selected : boolean, shiftKey: boolean) => void;
|
onSelectChange: (id: string, selected : boolean, shiftKey: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IListHookOperation {
|
interface IListHookOperation<T> {
|
||||||
text: string;
|
text: string;
|
||||||
onClick: (result: QueryHookResult<any, any>, filter: ListFilterModel, selectedIds: Set<string>) => void;
|
onClick: (result: T, filter: ListFilterModel, selectedIds: Set<string>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IListHookOptions {
|
interface IListHookOptions<T> {
|
||||||
filterMode: FilterMode;
|
|
||||||
props: IBaseProps;
|
|
||||||
zoomable?: boolean;
|
zoomable?: boolean;
|
||||||
otherOperations?: IListHookOperation[];
|
otherOperations?: IListHookOperation<T>[];
|
||||||
renderContent: (result: QueryHookResult<any, any>, filter: ListFilterModel, selectedIds: Set<string>, zoomIndex: number) => JSX.Element | undefined;
|
renderContent: (result: T, filter: ListFilterModel, selectedIds: Set<string>, zoomIndex: number) => JSX.Element | undefined;
|
||||||
renderSelectedOptions?: (result: QueryHookResult<any, any>, selectedIds: Set<string>) => JSX.Element | undefined;
|
renderSelectedOptions?: (result: T, selectedIds: Set<string>) => JSX.Element | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ListHook {
|
interface IDataItem {
|
||||||
public static useList(options: IListHookOptions): IListHookData {
|
id: string;
|
||||||
const [filter, setFilter] = useState<ListFilterModel>(new ListFilterModel(options.filterMode));
|
}
|
||||||
const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
|
interface IQueryResult {
|
||||||
const [lastClickedId, setLastClickedId] = useState<string | undefined>(undefined);
|
error?: ApolloError;
|
||||||
const [totalCount, setTotalCount] = useState<number>(0);
|
loading: boolean;
|
||||||
const [zoomIndex, setZoomIndex] = useState<number>(1);
|
}
|
||||||
|
|
||||||
// Update the filter when the query parameters change
|
interface IQuery<T extends IQueryResult, T2 extends IDataItem> {
|
||||||
useEffect(() => {
|
filterMode: FilterMode;
|
||||||
const queryParams = queryString.parse(options.props.location.search);
|
useData: (filter: ListFilterModel) => T;
|
||||||
const newFilter = _.cloneDeep(filter);
|
getData: (data: T) => T2[];
|
||||||
newFilter.configureFromQueryParameters(queryParams);
|
getCount: (data: T) => number;
|
||||||
setFilter(newFilter);
|
}
|
||||||
|
|
||||||
// TODO: Need this side effect to update the query params properly
|
type ScenesQuery = QueryHookResult<FindScenesQuery, FindScenesVariables>;
|
||||||
filter.configureFromQueryParameters(queryParams);
|
export const useScenesList = (props:IListHookOptions<ScenesQuery>) => (
|
||||||
}, [options.props.location.search]);
|
useList<ScenesQuery, SlimSceneDataFragment>({
|
||||||
|
...props,
|
||||||
|
filterMode: FilterMode.Scenes,
|
||||||
|
useData: StashService.useFindScenes,
|
||||||
|
getData: (result:ScenesQuery) => (result?.data?.findScenes?.scenes ?? []),
|
||||||
|
getCount: (result:ScenesQuery) => (result?.data?.findScenes?.count ?? 0)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
let result: QueryHookResult<any, any>;
|
type SceneMarkersQuery = QueryHookResult<FindSceneMarkersQuery, FindSceneMarkersVariables>;
|
||||||
|
export const useSceneMarkersList = (props:IListHookOptions<SceneMarkersQuery>) => (
|
||||||
|
useList<SceneMarkersQuery, FindSceneMarkersSceneMarkers>({
|
||||||
|
...props,
|
||||||
|
filterMode: FilterMode.SceneMarkers,
|
||||||
|
useData: StashService.useFindSceneMarkers,
|
||||||
|
getData: (result:SceneMarkersQuery) => (result?.data?.findSceneMarkers?.scene_markers?? []),
|
||||||
|
getCount: (result:SceneMarkersQuery) => (result?.data?.findSceneMarkers?.count ?? 0)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
let getData: (filter : ListFilterModel) => QueryHookResult<any, any>;
|
type GalleriesQuery = QueryHookResult<FindGalleriesQuery, FindGalleriesVariables>;
|
||||||
let getItems: () => any[];
|
export const useGalleriesList = (props:IListHookOptions<GalleriesQuery>) => (
|
||||||
let getCount: () => number;
|
useList<GalleriesQuery, GalleryDataFragment>({
|
||||||
|
...props,
|
||||||
|
filterMode: FilterMode.Galleries,
|
||||||
|
useData: StashService.useFindGalleries,
|
||||||
|
getData: (result:GalleriesQuery) => (result?.data?.findGalleries?.galleries ?? []),
|
||||||
|
getCount: (result:GalleriesQuery) => (result?.data?.findGalleries?.count ?? 0)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
switch (options.filterMode) {
|
type StudiosQuery = QueryHookResult<FindStudiosQuery, FindStudiosVariables>;
|
||||||
case FilterMode.Scenes: {
|
export const useStudiosList = (props:IListHookOptions<StudiosQuery>) => (
|
||||||
getData = (filter : ListFilterModel) => { return StashService.useFindScenes(filter); }
|
useList<StudiosQuery, StudioDataFragment>({
|
||||||
getItems = () => { return !!result.data && !!result.data.findScenes ? result.data.findScenes.scenes : []; }
|
...props,
|
||||||
getCount = () => { return !!result.data && !!result.data.findScenes ? result.data.findScenes.count : 0; }
|
filterMode: FilterMode.Studios,
|
||||||
break;
|
useData: StashService.useFindStudios,
|
||||||
}
|
getData: (result:StudiosQuery) => (result?.data?.findStudios?.studios ?? []),
|
||||||
case FilterMode.SceneMarkers: {
|
getCount: (result:StudiosQuery) => (result?.data?.findStudios?.count ?? 0)
|
||||||
getData = (filter : ListFilterModel) => { return StashService.useFindSceneMarkers(filter); }
|
})
|
||||||
getItems = () => { return !!result.data && !!result.data.findSceneMarkers ? result.data.findSceneMarkers.scene_markers : []; }
|
)
|
||||||
getCount = () => { return !!result.data && !!result.data.findSceneMarkers ? result.data.findSceneMarkers.count : 0; }
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FilterMode.Galleries: {
|
|
||||||
getData = (filter : ListFilterModel) => { return StashService.useFindGalleries(filter); }
|
|
||||||
getItems = () => { return !!result.data && !!result.data.findGalleries ? result.data.findGalleries.galleries : []; }
|
|
||||||
getCount = () => { return !!result.data && !!result.data.findGalleries ? result.data.findGalleries.count : 0; }
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FilterMode.Studios: {
|
|
||||||
getData = (filter : ListFilterModel) => { return StashService.useFindStudios(filter); }
|
|
||||||
getItems = () => { return !!result.data && !!result.data.findStudios ? result.data.findStudios.studios : []; }
|
|
||||||
getCount = () => { return !!result.data && !!result.data.findStudios ? result.data.findStudios.count : 0; }
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FilterMode.Performers: {
|
|
||||||
getData = (filter : ListFilterModel) => { return StashService.useFindPerformers(filter); }
|
|
||||||
getItems = () => { return !!result.data && !!result.data.findPerformers ? result.data.findPerformers.performers : []; }
|
|
||||||
getCount = () => { return !!result.data && !!result.data.findPerformers ? result.data.findPerformers.count : 0; }
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
console.error("REMOVE DEFAULT IN LIST HOOK");
|
|
||||||
getData = (filter : ListFilterModel) => { return StashService.useFindScenes(filter); }
|
|
||||||
getItems = () => { return !!result.data && !!result.data.findScenes ? result.data.findScenes.scenes : []; }
|
|
||||||
getCount = () => { return !!result.data && !!result.data.findScenes ? result.data.findScenes.count : 0; }
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result = getData(filter);
|
type PerformersQuery = QueryHookResult<FindPerformersQuery, FindPerformersVariables>;
|
||||||
|
export const usePerformersList = (props:IListHookOptions<PerformersQuery>) => (
|
||||||
|
useList<PerformersQuery, PerformerDataFragment>({
|
||||||
|
...props,
|
||||||
|
filterMode: FilterMode.Performers,
|
||||||
|
useData: StashService.useFindPerformers,
|
||||||
|
getData: (result:PerformersQuery) => (result?.data?.findPerformers?.performers ?? []),
|
||||||
|
getCount: (result:PerformersQuery) => (result?.data?.findPerformers?.count ?? 0)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
|
||||||
setTotalCount(getCount());
|
options: (IListHookOptions<QueryResult> & IQuery<QueryResult, QueryData>)
|
||||||
|
): IListHookData => {
|
||||||
|
const history = useHistory();
|
||||||
|
const [filter, setFilter] = useState<ListFilterModel>(new ListFilterModel(options.filterMode, queryString.parse(history.location.search)));
|
||||||
|
const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
|
||||||
|
const [lastClickedId, setLastClickedId] = useState<string | undefined>();
|
||||||
|
const [zoomIndex, setZoomIndex] = useState<number>(1);
|
||||||
|
|
||||||
// select none when data changes
|
const result = options.useData(filter);
|
||||||
onSelectNone();
|
const totalCount = options.getCount(result);
|
||||||
setLastClickedId(undefined);
|
const items = options.getData(result);
|
||||||
}, [result.data])
|
|
||||||
|
|
||||||
// Update the query parameters when the data changes
|
function updateQueryParams(filter:ListFilterModel) {
|
||||||
useEffect(() => {
|
const newLocation = Object.assign({}, history.location);
|
||||||
const location = Object.assign({}, options.props.history.location);
|
newLocation.search = filter.makeQueryParameters();
|
||||||
location.search = filter.makeQueryParameters();
|
history.replace(newLocation);
|
||||||
options.props.history.replace(location);
|
|
||||||
}, [result.data, filter.displayMode]);
|
|
||||||
|
|
||||||
// Update the total count
|
|
||||||
useEffect(() => {
|
|
||||||
const newFilter = _.cloneDeep(filter);
|
|
||||||
newFilter.totalCount = totalCount;
|
|
||||||
setFilter(newFilter);
|
|
||||||
}, [totalCount]);
|
|
||||||
|
|
||||||
function onChangePageSize(pageSize: number) {
|
|
||||||
const newFilter = _.cloneDeep(filter);
|
|
||||||
newFilter.itemsPerPage = pageSize;
|
|
||||||
newFilter.currentPage = 1;
|
|
||||||
setFilter(newFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onChangeQuery(query: string) {
|
|
||||||
const newFilter = _.cloneDeep(filter);
|
|
||||||
newFilter.searchTerm = query;
|
|
||||||
newFilter.currentPage = 1;
|
|
||||||
setFilter(newFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onChangeSortDirection(sortDirection: "asc" | "desc") {
|
|
||||||
const newFilter = _.cloneDeep(filter);
|
|
||||||
newFilter.sortDirection = sortDirection;
|
|
||||||
setFilter(newFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onChangeSortBy(sortBy: string) {
|
|
||||||
const newFilter = _.cloneDeep(filter);
|
|
||||||
newFilter.sortBy = sortBy;
|
|
||||||
newFilter.currentPage = 1;
|
|
||||||
setFilter(newFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onChangeDisplayMode(displayMode: DisplayMode) {
|
|
||||||
const newFilter = _.cloneDeep(filter);
|
|
||||||
newFilter.displayMode = displayMode;
|
|
||||||
setFilter(newFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onAddCriterion(criterion: Criterion, oldId?: string) {
|
|
||||||
const newFilter = _.cloneDeep(filter);
|
|
||||||
|
|
||||||
// Find if we are editing an existing criteria, then modify that. Or create a new one.
|
|
||||||
const existingIndex = newFilter.criteria.findIndex((c) => {
|
|
||||||
// If we modified an existing criterion, then look for the old id.
|
|
||||||
const id = !!oldId ? oldId : criterion.getId();
|
|
||||||
return c.getId() === id;
|
|
||||||
});
|
|
||||||
if (existingIndex === -1) {
|
|
||||||
newFilter.criteria.push(criterion);
|
|
||||||
} else {
|
|
||||||
newFilter.criteria[existingIndex] = criterion;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove duplicate modifiers
|
|
||||||
newFilter.criteria = newFilter.criteria.filter((obj, pos, arr) => {
|
|
||||||
return arr.map((mapObj: any) => mapObj.getId()).indexOf(obj.getId()) === pos;
|
|
||||||
});
|
|
||||||
|
|
||||||
newFilter.currentPage = 1;
|
|
||||||
setFilter(newFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onRemoveCriterion(removedCriterion: Criterion) {
|
|
||||||
const newFilter = _.cloneDeep(filter);
|
|
||||||
newFilter.criteria = newFilter.criteria.filter((criterion) => criterion.getId() !== removedCriterion.getId());
|
|
||||||
newFilter.currentPage = 1;
|
|
||||||
setFilter(newFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onChangePage(page: number) {
|
|
||||||
const newFilter = _.cloneDeep(filter);
|
|
||||||
newFilter.currentPage = page;
|
|
||||||
setFilter(newFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onSelectChange(id: string, selected : boolean, shiftKey: boolean) {
|
|
||||||
if (shiftKey) {
|
|
||||||
multiSelect(id, selected);
|
|
||||||
} else {
|
|
||||||
singleSelect(id, selected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function singleSelect(id: string, selected: boolean) {
|
|
||||||
setLastClickedId(id);
|
|
||||||
|
|
||||||
const newSelectedIds = _.clone(selectedIds);
|
|
||||||
if (selected) {
|
|
||||||
newSelectedIds.add(id);
|
|
||||||
} else {
|
|
||||||
newSelectedIds.delete(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
setSelectedIds(newSelectedIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
function multiSelect(id: string, selected : boolean) {
|
|
||||||
let startIndex = 0;
|
|
||||||
let thisIndex = -1;
|
|
||||||
|
|
||||||
if (!!lastClickedId) {
|
|
||||||
startIndex = getItems().findIndex((item) => {
|
|
||||||
return item.id === lastClickedId;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
thisIndex = getItems().findIndex((item) => {
|
|
||||||
return item.id === id;
|
|
||||||
});
|
|
||||||
|
|
||||||
selectRange(startIndex, thisIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectRange(startIndex : number, endIndex : number) {
|
|
||||||
if (startIndex > endIndex) {
|
|
||||||
let tmp = startIndex;
|
|
||||||
startIndex = endIndex;
|
|
||||||
endIndex = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
const subset = getItems().slice(startIndex, endIndex + 1);
|
|
||||||
const newSelectedIds : Set<string> = new Set();
|
|
||||||
|
|
||||||
subset.forEach((item) => {
|
|
||||||
newSelectedIds.add(item.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
setSelectedIds(newSelectedIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onSelectAll() {
|
|
||||||
const newSelectedIds : Set<string> = new Set();
|
|
||||||
getItems().forEach((item) => {
|
|
||||||
newSelectedIds.add(item.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
setSelectedIds(newSelectedIds);
|
|
||||||
setLastClickedId(undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onSelectNone() {
|
|
||||||
const newSelectedIds : Set<string> = new Set();
|
|
||||||
setSelectedIds(newSelectedIds);
|
|
||||||
setLastClickedId(undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onChangeZoom(newZoomIndex : number) {
|
|
||||||
setZoomIndex(newZoomIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
const otherOperations = options.otherOperations ? options.otherOperations.map((o) => {
|
|
||||||
return {
|
|
||||||
text: o.text,
|
|
||||||
onClick: () => {
|
|
||||||
o.onClick(result, filter, selectedIds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}) : undefined;
|
|
||||||
|
|
||||||
const template = (
|
|
||||||
<div>
|
|
||||||
<ListFilter
|
|
||||||
onChangePageSize={onChangePageSize}
|
|
||||||
onChangeQuery={onChangeQuery}
|
|
||||||
onChangeSortDirection={onChangeSortDirection}
|
|
||||||
onChangeSortBy={onChangeSortBy}
|
|
||||||
onChangeDisplayMode={onChangeDisplayMode}
|
|
||||||
onAddCriterion={onAddCriterion}
|
|
||||||
onRemoveCriterion={onRemoveCriterion}
|
|
||||||
onSelectAll={onSelectAll}
|
|
||||||
onSelectNone={onSelectNone}
|
|
||||||
zoomIndex={options.zoomable ? zoomIndex : undefined}
|
|
||||||
onChangeZoom={options.zoomable ? onChangeZoom : undefined}
|
|
||||||
otherOperations={otherOperations}
|
|
||||||
filter={filter}
|
|
||||||
/>
|
|
||||||
{options.renderSelectedOptions && selectedIds.size > 0 ? options.renderSelectedOptions(result, selectedIds) : undefined}
|
|
||||||
{result.loading ? <Spinner animation="border" variant="light" /> : undefined}
|
|
||||||
{result.error ? <h1>{result.error.message}</h1> : undefined}
|
|
||||||
{options.renderContent(result, filter, selectedIds, zoomIndex)}
|
|
||||||
<Pagination
|
|
||||||
itemsPerPage={filter.itemsPerPage}
|
|
||||||
currentPage={filter.currentPage}
|
|
||||||
totalItems={totalCount}
|
|
||||||
onChangePage={onChangePage}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
return { filter, template, options, onSelectChange };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onChangePageSize(pageSize: number) {
|
||||||
|
const newFilter = _.cloneDeep(filter);
|
||||||
|
newFilter.itemsPerPage = pageSize;
|
||||||
|
newFilter.currentPage = 1;
|
||||||
|
setFilter(newFilter);
|
||||||
|
updateQueryParams(newFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onChangeQuery(query: string) {
|
||||||
|
const newFilter = _.cloneDeep(filter);
|
||||||
|
newFilter.searchTerm = query;
|
||||||
|
newFilter.currentPage = 1;
|
||||||
|
setFilter(newFilter);
|
||||||
|
updateQueryParams(newFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onChangeSortDirection(sortDirection: "asc" | "desc") {
|
||||||
|
const newFilter = _.cloneDeep(filter);
|
||||||
|
newFilter.sortDirection = sortDirection;
|
||||||
|
setFilter(newFilter);
|
||||||
|
updateQueryParams(newFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onChangeSortBy(sortBy: string) {
|
||||||
|
const newFilter = _.cloneDeep(filter);
|
||||||
|
newFilter.sortBy = sortBy;
|
||||||
|
newFilter.currentPage = 1;
|
||||||
|
setFilter(newFilter);
|
||||||
|
updateQueryParams(newFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onChangeDisplayMode(displayMode: DisplayMode) {
|
||||||
|
const newFilter = _.cloneDeep(filter);
|
||||||
|
newFilter.displayMode = displayMode;
|
||||||
|
setFilter(newFilter);
|
||||||
|
updateQueryParams(newFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onAddCriterion(criterion: Criterion, oldId?: string) {
|
||||||
|
const newFilter = _.cloneDeep(filter);
|
||||||
|
|
||||||
|
// Find if we are editing an existing criteria, then modify that. Or create a new one.
|
||||||
|
const existingIndex = newFilter.criteria.findIndex((c) => {
|
||||||
|
// If we modified an existing criterion, then look for the old id.
|
||||||
|
const id = !!oldId ? oldId : criterion.getId();
|
||||||
|
return c.getId() === id;
|
||||||
|
});
|
||||||
|
if (existingIndex === -1) {
|
||||||
|
newFilter.criteria.push(criterion);
|
||||||
|
} else {
|
||||||
|
newFilter.criteria[existingIndex] = criterion;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove duplicate modifiers
|
||||||
|
newFilter.criteria = newFilter.criteria.filter((obj, pos, arr) => {
|
||||||
|
return arr.map((mapObj: any) => mapObj.getId()).indexOf(obj.getId()) === pos;
|
||||||
|
});
|
||||||
|
|
||||||
|
newFilter.currentPage = 1;
|
||||||
|
setFilter(newFilter);
|
||||||
|
updateQueryParams(newFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onRemoveCriterion(removedCriterion: Criterion) {
|
||||||
|
const newFilter = _.cloneDeep(filter);
|
||||||
|
newFilter.criteria = newFilter.criteria.filter((criterion) => criterion.getId() !== removedCriterion.getId());
|
||||||
|
newFilter.currentPage = 1;
|
||||||
|
setFilter(newFilter);
|
||||||
|
updateQueryParams(newFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onChangePage(page: number) {
|
||||||
|
const newFilter = _.cloneDeep(filter);
|
||||||
|
newFilter.currentPage = page;
|
||||||
|
setFilter(newFilter);
|
||||||
|
updateQueryParams(newFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSelectChange(id: string, selected : boolean, shiftKey: boolean) {
|
||||||
|
if (shiftKey) {
|
||||||
|
multiSelect(id);
|
||||||
|
} else {
|
||||||
|
singleSelect(id, selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function singleSelect(id: string, selected: boolean) {
|
||||||
|
setLastClickedId(id);
|
||||||
|
|
||||||
|
const newSelectedIds = _.clone(selectedIds);
|
||||||
|
if (selected) {
|
||||||
|
newSelectedIds.add(id);
|
||||||
|
} else {
|
||||||
|
newSelectedIds.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
setSelectedIds(newSelectedIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
function multiSelect(id: string) {
|
||||||
|
let startIndex = 0;
|
||||||
|
let thisIndex = -1;
|
||||||
|
|
||||||
|
if (lastClickedId) {
|
||||||
|
startIndex = items.findIndex((item) => {
|
||||||
|
return item.id === lastClickedId;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
thisIndex = items.findIndex((item) => {
|
||||||
|
return item.id === id;
|
||||||
|
});
|
||||||
|
|
||||||
|
selectRange(startIndex, thisIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectRange(startIndex : number, endIndex : number) {
|
||||||
|
if (startIndex > endIndex) {
|
||||||
|
let tmp = startIndex;
|
||||||
|
startIndex = endIndex;
|
||||||
|
endIndex = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
const subset = items.slice(startIndex, endIndex + 1);
|
||||||
|
const newSelectedIds : Set<string> = new Set();
|
||||||
|
|
||||||
|
subset.forEach((item) => {
|
||||||
|
newSelectedIds.add(item.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
setSelectedIds(newSelectedIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSelectAll() {
|
||||||
|
const newSelectedIds : Set<string> = new Set();
|
||||||
|
items.forEach((item) => {
|
||||||
|
newSelectedIds.add(item.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
setSelectedIds(newSelectedIds);
|
||||||
|
setLastClickedId(undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSelectNone() {
|
||||||
|
const newSelectedIds : Set<string> = new Set();
|
||||||
|
setSelectedIds(newSelectedIds);
|
||||||
|
setLastClickedId(undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onChangeZoom(newZoomIndex : number) {
|
||||||
|
setZoomIndex(newZoomIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
const otherOperations = options.otherOperations ? options.otherOperations.map((o) => {
|
||||||
|
return {
|
||||||
|
text: o.text,
|
||||||
|
onClick: () => {
|
||||||
|
o.onClick(result, filter, selectedIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}) : undefined;
|
||||||
|
|
||||||
|
const template = (
|
||||||
|
<div>
|
||||||
|
<ListFilter
|
||||||
|
onChangePageSize={onChangePageSize}
|
||||||
|
onChangeQuery={onChangeQuery}
|
||||||
|
onChangeSortDirection={onChangeSortDirection}
|
||||||
|
onChangeSortBy={onChangeSortBy}
|
||||||
|
onChangeDisplayMode={onChangeDisplayMode}
|
||||||
|
onAddCriterion={onAddCriterion}
|
||||||
|
onRemoveCriterion={onRemoveCriterion}
|
||||||
|
onSelectAll={onSelectAll}
|
||||||
|
onSelectNone={onSelectNone}
|
||||||
|
zoomIndex={options.zoomable ? zoomIndex : undefined}
|
||||||
|
onChangeZoom={options.zoomable ? onChangeZoom : undefined}
|
||||||
|
otherOperations={otherOperations}
|
||||||
|
filter={filter}
|
||||||
|
/>
|
||||||
|
{options.renderSelectedOptions && selectedIds.size > 0 ? options.renderSelectedOptions(result, selectedIds) : undefined}
|
||||||
|
{result.loading ? <Spinner animation="border" variant="light" /> : undefined}
|
||||||
|
{result.error ? <h1>{result.error.message}</h1> : undefined}
|
||||||
|
{options.renderContent(result, filter, selectedIds, zoomIndex)}
|
||||||
|
<Pagination
|
||||||
|
itemsPerPage={filter.itemsPerPage}
|
||||||
|
currentPage={filter.currentPage}
|
||||||
|
totalItems={totalCount}
|
||||||
|
onChangePage={onChangePage}
|
||||||
|
loading={result.loading}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
return { filter, template, onSelectChange };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export { default as useToast } from './Toast';
|
export { default as useToast } from './Toast';
|
||||||
export { useInterfaceLocalForage } from './LocalForage';
|
export { useInterfaceLocalForage } from './LocalForage';
|
||||||
export { VideoHoverHook } from './VideoHover';
|
export { VideoHoverHook } from './VideoHover';
|
||||||
export { ListHook } from './ListHook';
|
export { useScenesList, useSceneMarkersList, useGalleriesList, useStudiosList, usePerformersList } from './ListHook';
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
export * from "./base-props";
|
export * from "./base-props";
|
||||||
export * from "./types";
|
|
||||||
|
|||||||
@@ -45,9 +45,8 @@ export class ListFilterModel {
|
|||||||
public displayModeOptions: DisplayMode[] = [];
|
public displayModeOptions: DisplayMode[] = [];
|
||||||
public criterionOptions: ICriterionOption[] = [];
|
public criterionOptions: ICriterionOption[] = [];
|
||||||
public criteria: Array<Criterion<any, any>> = [];
|
public criteria: Array<Criterion<any, any>> = [];
|
||||||
public totalCount: number = 0;
|
|
||||||
|
|
||||||
public constructor(filterMode: FilterMode) {
|
public constructor(filterMode: FilterMode, rawParms?: any) {
|
||||||
switch (filterMode) {
|
switch (filterMode) {
|
||||||
case FilterMode.Scenes:
|
case FilterMode.Scenes:
|
||||||
if (!!this.sortBy === false) { this.sortBy = "date"; }
|
if (!!this.sortBy === false) { this.sortBy = "date"; }
|
||||||
@@ -142,6 +141,8 @@ export class ListFilterModel {
|
|||||||
}
|
}
|
||||||
if (!!this.displayMode === false) { this.displayMode = this.displayModeOptions[0]; }
|
if (!!this.displayMode === false) { this.displayMode = this.displayModeOptions[0]; }
|
||||||
this.sortByOptions = [...this.sortByOptions, "created_at", "updated_at"];
|
this.sortByOptions = [...this.sortByOptions, "created_at", "updated_at"];
|
||||||
|
if(rawParms)
|
||||||
|
this.configureFromQueryParameters(rawParms);
|
||||||
}
|
}
|
||||||
|
|
||||||
public configureFromQueryParameters(rawParms: any) {
|
public configureFromQueryParameters(rawParms: any) {
|
||||||
|
|||||||
5
ui/v2.5/src/models/react-images.d.ts
vendored
5
ui/v2.5/src/models/react-images.d.ts
vendored
@@ -1,5 +0,0 @@
|
|||||||
declare module "react-images" {
|
|
||||||
// typing module default export as `any` will allow you to access its members without compiler warning
|
|
||||||
var Lightbox: any;
|
|
||||||
export default Lightbox;
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export type HTMLInputProps = React.InputHTMLAttributes<HTMLInputElement>;
|
|
||||||
@@ -1559,6 +1559,13 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/react" "*"
|
"@types/react" "*"
|
||||||
|
|
||||||
|
"@types/react-images@^0.5.1":
|
||||||
|
version "0.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/react-images/-/react-images-0.5.1.tgz#e00ccce7221a03ed7b43072cefdc0e5a66fc5a08"
|
||||||
|
integrity sha512-n2guyR+kblfNEAr1TA3GnrpEdt0/2dHxMOFaFcCgI62NRQaQClaNdgidsim3JRVWLlUiWilDjzZnJUSR0kMncQ==
|
||||||
|
dependencies:
|
||||||
|
"@types/react" "*"
|
||||||
|
|
||||||
"@types/react-router-bootstrap@^0.24.5":
|
"@types/react-router-bootstrap@^0.24.5":
|
||||||
version "0.24.5"
|
version "0.24.5"
|
||||||
resolved "https://registry.yarnpkg.com/@types/react-router-bootstrap/-/react-router-bootstrap-0.24.5.tgz#9257ba3dfb01cda201aac9fa05cde3eb09ea5b27"
|
resolved "https://registry.yarnpkg.com/@types/react-router-bootstrap/-/react-router-bootstrap-0.24.5.tgz#9257ba3dfb01cda201aac9fa05cde3eb09ea5b27"
|
||||||
|
|||||||
Reference in New Issue
Block a user