mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 21:04:37 +03:00
UI and filter fixes (#2686)
* Use primitive string in recommendation row props * Use unique keys in recommendation rows The keys for the cards used while loading clash with the ids of the actual cards, causing a list unique key warning. * List filter alignment tweaks * Rework list hook filtering * Internationalise checksum correctly
This commit is contained in:
@@ -2,7 +2,7 @@ import React, { PropsWithChildren } from "react";
|
||||
|
||||
interface IProps {
|
||||
className?: string;
|
||||
header: String;
|
||||
header: string;
|
||||
link: JSX.Element;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { FormattedMessage } from "react-intl";
|
||||
interface IProps {
|
||||
isTouch: boolean;
|
||||
filter: ListFilterModel;
|
||||
header: String;
|
||||
header: string;
|
||||
}
|
||||
|
||||
export const GalleryRecommendationRow: FunctionComponent<IProps> = (
|
||||
@@ -41,7 +41,10 @@ export const GalleryRecommendationRow: FunctionComponent<IProps> = (
|
||||
>
|
||||
{result.loading
|
||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||
<div key={i} className="gallery-skeleton skeleton-card"></div>
|
||||
<div
|
||||
key={`_${i}`}
|
||||
className="gallery-skeleton skeleton-card"
|
||||
></div>
|
||||
))
|
||||
: result.data?.findGalleries.galleries.map((g) => (
|
||||
<GalleryCard key={g.id} gallery={g} zoomIndex={1} />
|
||||
|
||||
@@ -10,7 +10,7 @@ import { ImageCard } from "./ImageCard";
|
||||
interface IProps {
|
||||
isTouch: boolean;
|
||||
filter: ListFilterModel;
|
||||
header: String;
|
||||
header: string;
|
||||
}
|
||||
|
||||
export const ImageRecommendationRow: FunctionComponent<IProps> = (
|
||||
@@ -41,7 +41,7 @@ export const ImageRecommendationRow: FunctionComponent<IProps> = (
|
||||
>
|
||||
{result.loading
|
||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||
<div key={i} className="image-skeleton skeleton-card"></div>
|
||||
<div key={`_${i}`} className="image-skeleton skeleton-card"></div>
|
||||
))
|
||||
: result.data?.findImages.images.map((i) => (
|
||||
<ImageCard key={i.id} image={i} zoomIndex={1} />
|
||||
|
||||
@@ -217,8 +217,8 @@ export const ListFilter: React.FC<IListFilterProps> = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="d-flex mb-1">
|
||||
<div className="mr-2 flex-grow-1 query-text-field-group">
|
||||
<div className="mb-2 mr-2 d-flex">
|
||||
<div className="flex-grow-1 query-text-field-group">
|
||||
<FormControl
|
||||
ref={queryRef}
|
||||
placeholder={`${intl.formatMessage({ id: "actions.search" })}…`}
|
||||
@@ -240,7 +240,7 @@ export const ListFilter: React.FC<IListFilterProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ButtonGroup className="mr-2 mb-1">
|
||||
<ButtonGroup className="mr-2 mb-2">
|
||||
<Dropdown>
|
||||
<OverlayTrigger
|
||||
placement="top"
|
||||
@@ -277,7 +277,7 @@ export const ListFilter: React.FC<IListFilterProps> = ({
|
||||
</OverlayTrigger>
|
||||
</ButtonGroup>
|
||||
|
||||
<Dropdown as={ButtonGroup} className="mr-2 mb-1">
|
||||
<Dropdown as={ButtonGroup} className="mr-2 mb-2">
|
||||
<InputGroup.Prepend>
|
||||
<Dropdown.Toggle variant="secondary">
|
||||
{currentSortBy
|
||||
@@ -322,13 +322,13 @@ export const ListFilter: React.FC<IListFilterProps> = ({
|
||||
)}
|
||||
</Dropdown>
|
||||
|
||||
<div>
|
||||
<div className="mb-2">
|
||||
<Form.Control
|
||||
as="select"
|
||||
ref={perPageSelect}
|
||||
onChange={(e) => onChangePageSize(e.target.value)}
|
||||
value={filter.itemsPerPage.toString()}
|
||||
className="btn-secondary mx-1 mb-1"
|
||||
className="btn-secondary"
|
||||
>
|
||||
{pageSizeOptions.map((s) => (
|
||||
<option value={s.value} key={s.value}>
|
||||
|
||||
@@ -100,7 +100,7 @@ export const ListOperationButtons: React.FC<IListOperationButtonsProps> = ({
|
||||
|
||||
if (buttons.length > 0) {
|
||||
return (
|
||||
<ButtonGroup className="ml-2 mb-1">
|
||||
<ButtonGroup className="ml-2 mb-2">
|
||||
{buttons.map((button) => {
|
||||
return (
|
||||
<OverlayTrigger
|
||||
@@ -176,7 +176,7 @@ export const ListOperationButtons: React.FC<IListOperationButtonsProps> = ({
|
||||
|
||||
if (options.length > 0) {
|
||||
return (
|
||||
<Dropdown className="mb-1">
|
||||
<Dropdown>
|
||||
<Dropdown.Toggle variant="secondary" id="more-menu">
|
||||
<Icon icon={faEllipsisH} />
|
||||
</Dropdown.Toggle>
|
||||
@@ -192,7 +192,7 @@ export const ListOperationButtons: React.FC<IListOperationButtonsProps> = ({
|
||||
<>
|
||||
{maybeRenderButtons()}
|
||||
|
||||
<div className="mx-2">{renderMore()}</div>
|
||||
<div className="mx-2 mb-2">{renderMore()}</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -110,7 +110,7 @@ export const ListViewOptions: React.FC<IListViewOptionsProps> = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<ButtonGroup>
|
||||
<ButtonGroup className="mb-2">
|
||||
{displayModeOptions.map((option) => (
|
||||
<OverlayTrigger
|
||||
key={option}
|
||||
@@ -140,9 +140,9 @@ export const ListViewOptions: React.FC<IListViewOptionsProps> = ({
|
||||
function maybeRenderZoom() {
|
||||
if (onSetZoom && displayMode === DisplayMode.Grid) {
|
||||
return (
|
||||
<div className="align-middle">
|
||||
<div className="ml-2 mb-2 d-none d-sm-inline-flex">
|
||||
<Form.Control
|
||||
className="zoom-slider d-none d-sm-inline-flex ml-3"
|
||||
className="zoom-slider ml-1"
|
||||
type="range"
|
||||
min={minZoom}
|
||||
max={maxZoom}
|
||||
@@ -158,7 +158,7 @@ export const ListViewOptions: React.FC<IListViewOptionsProps> = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<ButtonGroup>{maybeRenderDisplayModeOptions()}</ButtonGroup>
|
||||
{maybeRenderDisplayModeOptions()}
|
||||
{maybeRenderZoom()}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -10,7 +10,7 @@ import { FormattedMessage } from "react-intl";
|
||||
interface IProps {
|
||||
isTouch: boolean;
|
||||
filter: ListFilterModel;
|
||||
header: String;
|
||||
header: string;
|
||||
}
|
||||
|
||||
export const MovieRecommendationRow: React.FC<IProps> = (props: IProps) => {
|
||||
@@ -39,7 +39,7 @@ export const MovieRecommendationRow: React.FC<IProps> = (props: IProps) => {
|
||||
>
|
||||
{result.loading
|
||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||
<div key={i} className="movie-skeleton skeleton-card"></div>
|
||||
<div key={`_${i}`} className="movie-skeleton skeleton-card"></div>
|
||||
))
|
||||
: result.data?.findMovies.movies.map((m) => (
|
||||
<MovieCard key={m.id} movie={m} />
|
||||
|
||||
@@ -10,7 +10,7 @@ import { FormattedMessage } from "react-intl";
|
||||
interface IProps {
|
||||
isTouch: boolean;
|
||||
filter: ListFilterModel;
|
||||
header: String;
|
||||
header: string;
|
||||
}
|
||||
|
||||
export const PerformerRecommendationRow: FunctionComponent<IProps> = (
|
||||
@@ -41,7 +41,10 @@ export const PerformerRecommendationRow: FunctionComponent<IProps> = (
|
||||
>
|
||||
{result.loading
|
||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||
<div key={i} className="performer-skeleton skeleton-card"></div>
|
||||
<div
|
||||
key={`_${i}`}
|
||||
className="performer-skeleton skeleton-card"
|
||||
></div>
|
||||
))
|
||||
: result.data?.findPerformers.performers.map((p) => (
|
||||
<PerformerCard key={p.id} performer={p} />
|
||||
|
||||
@@ -11,7 +11,7 @@ import { FormattedMessage } from "react-intl";
|
||||
interface IProps {
|
||||
isTouch: boolean;
|
||||
filter: ListFilterModel;
|
||||
header: String;
|
||||
header: string;
|
||||
}
|
||||
|
||||
export const SceneRecommendationRow: FunctionComponent<IProps> = (
|
||||
@@ -46,7 +46,7 @@ export const SceneRecommendationRow: FunctionComponent<IProps> = (
|
||||
>
|
||||
{result.loading
|
||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||
<div key={i} className="scene-skeleton skeleton-card"></div>
|
||||
<div key={`_${i}`} className="scene-skeleton skeleton-card"></div>
|
||||
))
|
||||
: result.data?.findScenes.scenes.map((scene, index) => (
|
||||
<SceneCard
|
||||
|
||||
@@ -10,7 +10,7 @@ import { FormattedMessage } from "react-intl";
|
||||
interface IProps {
|
||||
isTouch: boolean;
|
||||
filter: ListFilterModel;
|
||||
header: String;
|
||||
header: string;
|
||||
}
|
||||
|
||||
export const StudioRecommendationRow: FunctionComponent<IProps> = (
|
||||
@@ -41,7 +41,10 @@ export const StudioRecommendationRow: FunctionComponent<IProps> = (
|
||||
>
|
||||
{result.loading
|
||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||
<div key={i} className="studio-skeleton skeleton-card"></div>
|
||||
<div
|
||||
key={`_${i}`}
|
||||
className="studio-skeleton skeleton-card"
|
||||
></div>
|
||||
))
|
||||
: result.data?.findStudios.studios.map((s) => (
|
||||
<StudioCard key={s.id} studio={s} hideParent={true} />
|
||||
|
||||
@@ -10,7 +10,7 @@ import { FormattedMessage } from "react-intl";
|
||||
interface IProps {
|
||||
isTouch: boolean;
|
||||
filter: ListFilterModel;
|
||||
header: String;
|
||||
header: string;
|
||||
}
|
||||
|
||||
export const TagRecommendationRow: FunctionComponent<IProps> = (
|
||||
@@ -41,7 +41,7 @@ export const TagRecommendationRow: FunctionComponent<IProps> = (
|
||||
>
|
||||
{result.loading
|
||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||
<div key={i} className="tag-skeleton skeleton-card"></div>
|
||||
<div key={`_${i}`} className="tag-skeleton skeleton-card"></div>
|
||||
))
|
||||
: result.data?.findTags.tags.map((p) => (
|
||||
<TagCard key={p.id} tag={p} zoomIndex={0} />
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import clone from "lodash-es/clone";
|
||||
import cloneDeep from "lodash-es/cloneDeep";
|
||||
import isEqual from "lodash-es/isEqual";
|
||||
import queryString from "query-string";
|
||||
import React, {
|
||||
useCallback,
|
||||
@@ -169,7 +170,7 @@ interface IRenderListProps {
|
||||
filter: ListFilterModel;
|
||||
filterOptions: ListFilterOptions;
|
||||
onChangePage: (page: number) => void;
|
||||
updateQueryParams: (filter: ListFilterModel) => void;
|
||||
updateFilter: (filter: ListFilterModel) => void;
|
||||
}
|
||||
|
||||
const RenderList = <
|
||||
@@ -190,7 +191,7 @@ const RenderList = <
|
||||
selectable,
|
||||
renderEditDialog,
|
||||
renderDeleteDialog,
|
||||
updateQueryParams,
|
||||
updateFilter,
|
||||
filterDialog,
|
||||
persistState,
|
||||
}: IListHookOptions<QueryResult, QueryData> &
|
||||
@@ -342,11 +343,11 @@ const RenderList = <
|
||||
function onChangeZoom(newZoomIndex: number) {
|
||||
const newFilter = cloneDeep(filter);
|
||||
newFilter.zoomIndex = newZoomIndex;
|
||||
updateQueryParams(newFilter);
|
||||
updateFilter(newFilter);
|
||||
}
|
||||
|
||||
async function onOperationClicked(o: IListHookOperation<QueryResult>) {
|
||||
await o.onClick(result, filter, selectedIds);
|
||||
function onOperationClicked(o: IListHookOperation<QueryResult>) {
|
||||
o.onClick(result, filter, selectedIds);
|
||||
if (o.postRefetch) {
|
||||
result.refetch();
|
||||
}
|
||||
@@ -437,7 +438,7 @@ const RenderList = <
|
||||
function onChangeDisplayMode(displayMode: DisplayMode) {
|
||||
const newFilter = cloneDeep(filter);
|
||||
newFilter.displayMode = displayMode;
|
||||
updateQueryParams(newFilter);
|
||||
updateFilter(newFilter);
|
||||
}
|
||||
|
||||
function onAddCriterion(
|
||||
@@ -464,7 +465,7 @@ const RenderList = <
|
||||
});
|
||||
|
||||
newFilter.currentPage = 1;
|
||||
updateQueryParams(newFilter);
|
||||
updateFilter(newFilter);
|
||||
setEditingCriterion(undefined);
|
||||
setNewCriterion(false);
|
||||
}
|
||||
@@ -475,7 +476,7 @@ const RenderList = <
|
||||
(criterion) => criterion.getId() !== removedCriterion.getId()
|
||||
);
|
||||
newFilter.currentPage = 1;
|
||||
updateQueryParams(newFilter);
|
||||
updateFilter(newFilter);
|
||||
}
|
||||
|
||||
function updateCriteria(c: Criterion<CriterionValue>[]) {
|
||||
@@ -491,9 +492,9 @@ const RenderList = <
|
||||
|
||||
const content = (
|
||||
<div>
|
||||
<ButtonToolbar className="align-items-center justify-content-center mb-2">
|
||||
<ButtonToolbar className="justify-content-center">
|
||||
<ListFilter
|
||||
onFilterUpdate={updateQueryParams}
|
||||
onFilterUpdate={updateFilter}
|
||||
filter={filter}
|
||||
filterOptions={filterOptions}
|
||||
openFilterDialog={() => setNewCriterion(true)}
|
||||
@@ -563,29 +564,32 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
|
||||
const history = useHistory();
|
||||
const location = useLocation();
|
||||
const [interfaceState, setInterfaceState] = useInterfaceLocalForage();
|
||||
// If persistState is false we don't care about forage and consider it initialised
|
||||
const [forageInitialised, setForageInitialised] = useState(
|
||||
!options.persistState
|
||||
);
|
||||
const [filterInitialised, setFilterInitialised] = useState(false);
|
||||
// Store initial pathname to prevent hooks from operating outside this page
|
||||
const originalPathName = useRef(location.pathname);
|
||||
const persistanceKey = options.persistanceKey ?? options.filterMode;
|
||||
|
||||
const defaultSort = options.defaultSort ?? filterOptions.defaultSortBy;
|
||||
const defaultDisplayMode = filterOptions.displayModeOptions[0];
|
||||
const [filter, setFilter] = useState<ListFilterModel>(
|
||||
new ListFilterModel(
|
||||
const createNewFilter = useCallback(() => {
|
||||
return new ListFilterModel(
|
||||
options.filterMode,
|
||||
queryString.parse(location.search),
|
||||
queryString.parse(history.location.search),
|
||||
defaultSort,
|
||||
defaultDisplayMode,
|
||||
options.defaultZoomIndex
|
||||
)
|
||||
);
|
||||
}, [
|
||||
options.filterMode,
|
||||
history,
|
||||
defaultSort,
|
||||
defaultDisplayMode,
|
||||
options.defaultZoomIndex,
|
||||
]);
|
||||
const [filter, setFilter] = useState<ListFilterModel>(createNewFilter);
|
||||
|
||||
const updateInterfaceConfig = useCallback(
|
||||
(updatedFilter: ListFilterModel, level: PersistanceLevel) => {
|
||||
if (level === PersistanceLevel.VIEW) {
|
||||
const updateSavedFilter = useCallback(
|
||||
(updatedFilter: ListFilterModel) => {
|
||||
setInterfaceState((prevState) => {
|
||||
if (!prevState.queryConfig) {
|
||||
prevState.queryConfig = {};
|
||||
@@ -606,7 +610,6 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
},
|
||||
[persistanceKey, setInterfaceState]
|
||||
);
|
||||
@@ -617,54 +620,38 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
|
||||
} = useFindDefaultFilter(options.filterMode);
|
||||
|
||||
const updateQueryParams = useCallback(
|
||||
(listFilter: ListFilterModel) => {
|
||||
setFilter(listFilter);
|
||||
const newLocation = { ...location };
|
||||
newLocation.search = listFilter.makeQueryParameters();
|
||||
history.replace(newLocation);
|
||||
if (options.persistState) {
|
||||
updateInterfaceConfig(listFilter, options.persistState);
|
||||
(newFilter: ListFilterModel) => {
|
||||
const newParams = newFilter.makeQueryParameters();
|
||||
history.replace({ ...history.location, search: newParams });
|
||||
},
|
||||
[history]
|
||||
);
|
||||
|
||||
const updateFilter = useCallback(
|
||||
(newFilter: ListFilterModel) => {
|
||||
setFilter(newFilter);
|
||||
updateQueryParams(newFilter);
|
||||
if (options.persistState === PersistanceLevel.VIEW) {
|
||||
updateSavedFilter(newFilter);
|
||||
}
|
||||
},
|
||||
[setFilter, history, location, options.persistState, updateInterfaceConfig]
|
||||
[options.persistState, updateSavedFilter, updateQueryParams]
|
||||
);
|
||||
|
||||
// 'Startup' hook, initialises the filters
|
||||
useEffect(() => {
|
||||
if (
|
||||
// defer processing this until forage is initialised and
|
||||
// default filter is loaded
|
||||
interfaceState.loading ||
|
||||
defaultFilterLoading ||
|
||||
// Only update query params on page the hook was mounted on
|
||||
history.location.pathname !== originalPathName.current
|
||||
)
|
||||
return;
|
||||
// Only run once
|
||||
if (filterInitialised) return;
|
||||
|
||||
if (!forageInitialised) setForageInitialised(true);
|
||||
let newFilter = filter.clone();
|
||||
|
||||
const newFilter = filter.clone();
|
||||
let update = false;
|
||||
if (options.persistState === PersistanceLevel.ALL) {
|
||||
// only set default filter if query params are empty
|
||||
if (!history.location.search) {
|
||||
// wait until default filter is loaded
|
||||
if (defaultFilterLoading) return;
|
||||
|
||||
// Compare constructed filter with current filter.
|
||||
// If different it's the result of navigation, and we update the filter.
|
||||
if (
|
||||
history.location.search &&
|
||||
history.location.search !== `?${filter.makeQueryParameters()}`
|
||||
) {
|
||||
newFilter.configureFromQueryParameters(
|
||||
queryString.parse(history.location.search)
|
||||
);
|
||||
update = true;
|
||||
}
|
||||
|
||||
// if default query is set and no search params are set, then
|
||||
// load the default query
|
||||
// #1512 - use default query only if persistState is ALL
|
||||
if (
|
||||
options.persistState === PersistanceLevel.ALL &&
|
||||
!location.search &&
|
||||
defaultFilter?.findDefaultFilter
|
||||
) {
|
||||
if (defaultFilter?.findDefaultFilter) {
|
||||
newFilter.currentPage = 1;
|
||||
try {
|
||||
newFilter.configureFromQueryParameters(
|
||||
@@ -676,50 +663,75 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
|
||||
}
|
||||
// #1507 - reset random seed when loaded
|
||||
newFilter.randomSeed = -1;
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
} else if (options.persistState === PersistanceLevel.VIEW) {
|
||||
// wait until forage is initialised
|
||||
if (interfaceState.loading) return;
|
||||
|
||||
// set the display type if persisted
|
||||
const storedQuery = interfaceState.data?.queryConfig?.[persistanceKey];
|
||||
|
||||
if (options.persistState === PersistanceLevel.VIEW && storedQuery) {
|
||||
const storedFilter = queryString.parse(storedQuery.filter);
|
||||
|
||||
if (storedFilter.disp !== undefined) {
|
||||
const displayMode = Number.parseInt(storedFilter.disp as string, 10);
|
||||
if (displayMode !== newFilter.displayMode) {
|
||||
newFilter.displayMode = displayMode;
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (update) {
|
||||
setFilter(newFilter);
|
||||
updateQueryParams(newFilter);
|
||||
}
|
||||
|
||||
setFilterInitialised(true);
|
||||
}, [
|
||||
defaultSort,
|
||||
defaultDisplayMode,
|
||||
filterInitialised,
|
||||
filter,
|
||||
interfaceState,
|
||||
history,
|
||||
location.search,
|
||||
options.persistState,
|
||||
updateQueryParams,
|
||||
defaultFilter,
|
||||
defaultFilterLoading,
|
||||
interfaceState,
|
||||
persistanceKey,
|
||||
forageInitialised,
|
||||
options.persistState,
|
||||
]);
|
||||
|
||||
// This hook runs on every page location change (ie navigation),
|
||||
// and updates the filter accordingly.
|
||||
useEffect(() => {
|
||||
if (!filterInitialised) return;
|
||||
|
||||
// Only update on page the hook was mounted on
|
||||
if (location.pathname !== originalPathName.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Re-init filters on empty new query params
|
||||
if (!location.search) {
|
||||
setFilter(createNewFilter);
|
||||
setFilterInitialised(false);
|
||||
return;
|
||||
}
|
||||
|
||||
setFilter((prevFilter) => {
|
||||
let newFilter = prevFilter.clone();
|
||||
newFilter.configureFromQueryParameters(
|
||||
queryString.parse(location.search)
|
||||
);
|
||||
if (!isEqual(newFilter, prevFilter)) {
|
||||
return newFilter;
|
||||
} else {
|
||||
return prevFilter;
|
||||
}
|
||||
});
|
||||
}, [filterInitialised, createNewFilter, location]);
|
||||
|
||||
const onChangePage = useCallback(
|
||||
(page: number) => {
|
||||
const newFilter = cloneDeep(filter);
|
||||
newFilter.currentPage = page;
|
||||
updateQueryParams(newFilter);
|
||||
updateFilter(newFilter);
|
||||
window.scrollTo(0, 0);
|
||||
},
|
||||
[filter, updateQueryParams]
|
||||
[filter, updateFilter]
|
||||
);
|
||||
|
||||
const renderFilter = useMemo(() => {
|
||||
@@ -731,10 +743,10 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
|
||||
filter: renderFilter,
|
||||
filterOptions,
|
||||
onChangePage,
|
||||
updateQueryParams,
|
||||
updateFilter,
|
||||
});
|
||||
|
||||
const template = !forageInitialised ? (
|
||||
const template = !filterInitialised ? (
|
||||
<LoadingIndicator />
|
||||
) : (
|
||||
<>{contentTemplate}</>
|
||||
|
||||
@@ -53,7 +53,7 @@ export function makeCriteria(type: CriterionType = "none") {
|
||||
case "path":
|
||||
case "checksum":
|
||||
return new StringCriterion(
|
||||
new MandatoryStringCriterionOption(type, type)
|
||||
new MandatoryStringCriterionOption("media_info.checksum", type, type)
|
||||
);
|
||||
case "oshash":
|
||||
return new StringCriterion(
|
||||
@@ -134,7 +134,7 @@ export function makeCriteria(type: CriterionType = "none") {
|
||||
case "sceneChecksum":
|
||||
case "galleryChecksum":
|
||||
return new StringCriterion(
|
||||
new StringCriterionOption("checksum", type, "checksum")
|
||||
new StringCriterionOption("media_info.checksum", type, "checksum")
|
||||
);
|
||||
case "phash":
|
||||
return new StringCriterion(PhashCriterionOption);
|
||||
|
||||
Reference in New Issue
Block a user