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:
DingDongSoLong4
2022-06-22 07:45:47 +02:00
committed by GitHub
parent 3b4b20e9b2
commit 63e1bbf35d
13 changed files with 171 additions and 150 deletions

View File

@@ -2,7 +2,7 @@ import React, { PropsWithChildren } from "react";
interface IProps { interface IProps {
className?: string; className?: string;
header: String; header: string;
link: JSX.Element; link: JSX.Element;
} }

View File

@@ -10,7 +10,7 @@ import { FormattedMessage } from "react-intl";
interface IProps { interface IProps {
isTouch: boolean; isTouch: boolean;
filter: ListFilterModel; filter: ListFilterModel;
header: String; header: string;
} }
export const GalleryRecommendationRow: FunctionComponent<IProps> = ( export const GalleryRecommendationRow: FunctionComponent<IProps> = (
@@ -41,7 +41,10 @@ export const GalleryRecommendationRow: FunctionComponent<IProps> = (
> >
{result.loading {result.loading
? [...Array(props.filter.itemsPerPage)].map((i) => ( ? [...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) => ( : result.data?.findGalleries.galleries.map((g) => (
<GalleryCard key={g.id} gallery={g} zoomIndex={1} /> <GalleryCard key={g.id} gallery={g} zoomIndex={1} />

View File

@@ -10,7 +10,7 @@ import { ImageCard } from "./ImageCard";
interface IProps { interface IProps {
isTouch: boolean; isTouch: boolean;
filter: ListFilterModel; filter: ListFilterModel;
header: String; header: string;
} }
export const ImageRecommendationRow: FunctionComponent<IProps> = ( export const ImageRecommendationRow: FunctionComponent<IProps> = (
@@ -41,7 +41,7 @@ export const ImageRecommendationRow: FunctionComponent<IProps> = (
> >
{result.loading {result.loading
? [...Array(props.filter.itemsPerPage)].map((i) => ( ? [...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) => ( : result.data?.findImages.images.map((i) => (
<ImageCard key={i.id} image={i} zoomIndex={1} /> <ImageCard key={i.id} image={i} zoomIndex={1} />

View File

@@ -217,8 +217,8 @@ export const ListFilter: React.FC<IListFilterProps> = ({
return ( return (
<> <>
<div className="d-flex mb-1"> <div className="mb-2 mr-2 d-flex">
<div className="mr-2 flex-grow-1 query-text-field-group"> <div className="flex-grow-1 query-text-field-group">
<FormControl <FormControl
ref={queryRef} ref={queryRef}
placeholder={`${intl.formatMessage({ id: "actions.search" })}…`} placeholder={`${intl.formatMessage({ id: "actions.search" })}…`}
@@ -240,7 +240,7 @@ export const ListFilter: React.FC<IListFilterProps> = ({
</div> </div>
</div> </div>
<ButtonGroup className="mr-2 mb-1"> <ButtonGroup className="mr-2 mb-2">
<Dropdown> <Dropdown>
<OverlayTrigger <OverlayTrigger
placement="top" placement="top"
@@ -277,7 +277,7 @@ export const ListFilter: React.FC<IListFilterProps> = ({
</OverlayTrigger> </OverlayTrigger>
</ButtonGroup> </ButtonGroup>
<Dropdown as={ButtonGroup} className="mr-2 mb-1"> <Dropdown as={ButtonGroup} className="mr-2 mb-2">
<InputGroup.Prepend> <InputGroup.Prepend>
<Dropdown.Toggle variant="secondary"> <Dropdown.Toggle variant="secondary">
{currentSortBy {currentSortBy
@@ -322,13 +322,13 @@ export const ListFilter: React.FC<IListFilterProps> = ({
)} )}
</Dropdown> </Dropdown>
<div> <div className="mb-2">
<Form.Control <Form.Control
as="select" as="select"
ref={perPageSelect} ref={perPageSelect}
onChange={(e) => onChangePageSize(e.target.value)} onChange={(e) => onChangePageSize(e.target.value)}
value={filter.itemsPerPage.toString()} value={filter.itemsPerPage.toString()}
className="btn-secondary mx-1 mb-1" className="btn-secondary"
> >
{pageSizeOptions.map((s) => ( {pageSizeOptions.map((s) => (
<option value={s.value} key={s.value}> <option value={s.value} key={s.value}>

View File

@@ -100,7 +100,7 @@ export const ListOperationButtons: React.FC<IListOperationButtonsProps> = ({
if (buttons.length > 0) { if (buttons.length > 0) {
return ( return (
<ButtonGroup className="ml-2 mb-1"> <ButtonGroup className="ml-2 mb-2">
{buttons.map((button) => { {buttons.map((button) => {
return ( return (
<OverlayTrigger <OverlayTrigger
@@ -176,7 +176,7 @@ export const ListOperationButtons: React.FC<IListOperationButtonsProps> = ({
if (options.length > 0) { if (options.length > 0) {
return ( return (
<Dropdown className="mb-1"> <Dropdown>
<Dropdown.Toggle variant="secondary" id="more-menu"> <Dropdown.Toggle variant="secondary" id="more-menu">
<Icon icon={faEllipsisH} /> <Icon icon={faEllipsisH} />
</Dropdown.Toggle> </Dropdown.Toggle>
@@ -192,7 +192,7 @@ export const ListOperationButtons: React.FC<IListOperationButtonsProps> = ({
<> <>
{maybeRenderButtons()} {maybeRenderButtons()}
<div className="mx-2">{renderMore()}</div> <div className="mx-2 mb-2">{renderMore()}</div>
</> </>
); );
}; };

View File

@@ -110,7 +110,7 @@ export const ListViewOptions: React.FC<IListViewOptionsProps> = ({
} }
return ( return (
<ButtonGroup> <ButtonGroup className="mb-2">
{displayModeOptions.map((option) => ( {displayModeOptions.map((option) => (
<OverlayTrigger <OverlayTrigger
key={option} key={option}
@@ -140,9 +140,9 @@ export const ListViewOptions: React.FC<IListViewOptionsProps> = ({
function maybeRenderZoom() { function maybeRenderZoom() {
if (onSetZoom && displayMode === DisplayMode.Grid) { if (onSetZoom && displayMode === DisplayMode.Grid) {
return ( return (
<div className="align-middle"> <div className="ml-2 mb-2 d-none d-sm-inline-flex">
<Form.Control <Form.Control
className="zoom-slider d-none d-sm-inline-flex ml-3" className="zoom-slider ml-1"
type="range" type="range"
min={minZoom} min={minZoom}
max={maxZoom} max={maxZoom}
@@ -158,7 +158,7 @@ export const ListViewOptions: React.FC<IListViewOptionsProps> = ({
return ( return (
<> <>
<ButtonGroup>{maybeRenderDisplayModeOptions()}</ButtonGroup> {maybeRenderDisplayModeOptions()}
{maybeRenderZoom()} {maybeRenderZoom()}
</> </>
); );

View File

@@ -10,7 +10,7 @@ import { FormattedMessage } from "react-intl";
interface IProps { interface IProps {
isTouch: boolean; isTouch: boolean;
filter: ListFilterModel; filter: ListFilterModel;
header: String; header: string;
} }
export const MovieRecommendationRow: React.FC<IProps> = (props: IProps) => { export const MovieRecommendationRow: React.FC<IProps> = (props: IProps) => {
@@ -39,7 +39,7 @@ export const MovieRecommendationRow: React.FC<IProps> = (props: IProps) => {
> >
{result.loading {result.loading
? [...Array(props.filter.itemsPerPage)].map((i) => ( ? [...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) => ( : result.data?.findMovies.movies.map((m) => (
<MovieCard key={m.id} movie={m} /> <MovieCard key={m.id} movie={m} />

View File

@@ -10,7 +10,7 @@ import { FormattedMessage } from "react-intl";
interface IProps { interface IProps {
isTouch: boolean; isTouch: boolean;
filter: ListFilterModel; filter: ListFilterModel;
header: String; header: string;
} }
export const PerformerRecommendationRow: FunctionComponent<IProps> = ( export const PerformerRecommendationRow: FunctionComponent<IProps> = (
@@ -41,7 +41,10 @@ export const PerformerRecommendationRow: FunctionComponent<IProps> = (
> >
{result.loading {result.loading
? [...Array(props.filter.itemsPerPage)].map((i) => ( ? [...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) => ( : result.data?.findPerformers.performers.map((p) => (
<PerformerCard key={p.id} performer={p} /> <PerformerCard key={p.id} performer={p} />

View File

@@ -11,7 +11,7 @@ import { FormattedMessage } from "react-intl";
interface IProps { interface IProps {
isTouch: boolean; isTouch: boolean;
filter: ListFilterModel; filter: ListFilterModel;
header: String; header: string;
} }
export const SceneRecommendationRow: FunctionComponent<IProps> = ( export const SceneRecommendationRow: FunctionComponent<IProps> = (
@@ -46,7 +46,7 @@ export const SceneRecommendationRow: FunctionComponent<IProps> = (
> >
{result.loading {result.loading
? [...Array(props.filter.itemsPerPage)].map((i) => ( ? [...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) => ( : result.data?.findScenes.scenes.map((scene, index) => (
<SceneCard <SceneCard

View File

@@ -10,7 +10,7 @@ import { FormattedMessage } from "react-intl";
interface IProps { interface IProps {
isTouch: boolean; isTouch: boolean;
filter: ListFilterModel; filter: ListFilterModel;
header: String; header: string;
} }
export const StudioRecommendationRow: FunctionComponent<IProps> = ( export const StudioRecommendationRow: FunctionComponent<IProps> = (
@@ -41,7 +41,10 @@ export const StudioRecommendationRow: FunctionComponent<IProps> = (
> >
{result.loading {result.loading
? [...Array(props.filter.itemsPerPage)].map((i) => ( ? [...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) => ( : result.data?.findStudios.studios.map((s) => (
<StudioCard key={s.id} studio={s} hideParent={true} /> <StudioCard key={s.id} studio={s} hideParent={true} />

View File

@@ -10,7 +10,7 @@ import { FormattedMessage } from "react-intl";
interface IProps { interface IProps {
isTouch: boolean; isTouch: boolean;
filter: ListFilterModel; filter: ListFilterModel;
header: String; header: string;
} }
export const TagRecommendationRow: FunctionComponent<IProps> = ( export const TagRecommendationRow: FunctionComponent<IProps> = (
@@ -41,7 +41,7 @@ export const TagRecommendationRow: FunctionComponent<IProps> = (
> >
{result.loading {result.loading
? [...Array(props.filter.itemsPerPage)].map((i) => ( ? [...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) => ( : result.data?.findTags.tags.map((p) => (
<TagCard key={p.id} tag={p} zoomIndex={0} /> <TagCard key={p.id} tag={p} zoomIndex={0} />

View File

@@ -1,5 +1,6 @@
import clone from "lodash-es/clone"; import clone from "lodash-es/clone";
import cloneDeep from "lodash-es/cloneDeep"; import cloneDeep from "lodash-es/cloneDeep";
import isEqual from "lodash-es/isEqual";
import queryString from "query-string"; import queryString from "query-string";
import React, { import React, {
useCallback, useCallback,
@@ -169,7 +170,7 @@ interface IRenderListProps {
filter: ListFilterModel; filter: ListFilterModel;
filterOptions: ListFilterOptions; filterOptions: ListFilterOptions;
onChangePage: (page: number) => void; onChangePage: (page: number) => void;
updateQueryParams: (filter: ListFilterModel) => void; updateFilter: (filter: ListFilterModel) => void;
} }
const RenderList = < const RenderList = <
@@ -190,7 +191,7 @@ const RenderList = <
selectable, selectable,
renderEditDialog, renderEditDialog,
renderDeleteDialog, renderDeleteDialog,
updateQueryParams, updateFilter,
filterDialog, filterDialog,
persistState, persistState,
}: IListHookOptions<QueryResult, QueryData> & }: IListHookOptions<QueryResult, QueryData> &
@@ -342,11 +343,11 @@ const RenderList = <
function onChangeZoom(newZoomIndex: number) { function onChangeZoom(newZoomIndex: number) {
const newFilter = cloneDeep(filter); const newFilter = cloneDeep(filter);
newFilter.zoomIndex = newZoomIndex; newFilter.zoomIndex = newZoomIndex;
updateQueryParams(newFilter); updateFilter(newFilter);
} }
async function onOperationClicked(o: IListHookOperation<QueryResult>) { function onOperationClicked(o: IListHookOperation<QueryResult>) {
await o.onClick(result, filter, selectedIds); o.onClick(result, filter, selectedIds);
if (o.postRefetch) { if (o.postRefetch) {
result.refetch(); result.refetch();
} }
@@ -437,7 +438,7 @@ const RenderList = <
function onChangeDisplayMode(displayMode: DisplayMode) { function onChangeDisplayMode(displayMode: DisplayMode) {
const newFilter = cloneDeep(filter); const newFilter = cloneDeep(filter);
newFilter.displayMode = displayMode; newFilter.displayMode = displayMode;
updateQueryParams(newFilter); updateFilter(newFilter);
} }
function onAddCriterion( function onAddCriterion(
@@ -464,7 +465,7 @@ const RenderList = <
}); });
newFilter.currentPage = 1; newFilter.currentPage = 1;
updateQueryParams(newFilter); updateFilter(newFilter);
setEditingCriterion(undefined); setEditingCriterion(undefined);
setNewCriterion(false); setNewCriterion(false);
} }
@@ -475,7 +476,7 @@ const RenderList = <
(criterion) => criterion.getId() !== removedCriterion.getId() (criterion) => criterion.getId() !== removedCriterion.getId()
); );
newFilter.currentPage = 1; newFilter.currentPage = 1;
updateQueryParams(newFilter); updateFilter(newFilter);
} }
function updateCriteria(c: Criterion<CriterionValue>[]) { function updateCriteria(c: Criterion<CriterionValue>[]) {
@@ -491,9 +492,9 @@ const RenderList = <
const content = ( const content = (
<div> <div>
<ButtonToolbar className="align-items-center justify-content-center mb-2"> <ButtonToolbar className="justify-content-center">
<ListFilter <ListFilter
onFilterUpdate={updateQueryParams} onFilterUpdate={updateFilter}
filter={filter} filter={filter}
filterOptions={filterOptions} filterOptions={filterOptions}
openFilterDialog={() => setNewCriterion(true)} openFilterDialog={() => setNewCriterion(true)}
@@ -563,50 +564,52 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
const history = useHistory(); const history = useHistory();
const location = useLocation(); const location = useLocation();
const [interfaceState, setInterfaceState] = useInterfaceLocalForage(); const [interfaceState, setInterfaceState] = useInterfaceLocalForage();
// If persistState is false we don't care about forage and consider it initialised const [filterInitialised, setFilterInitialised] = useState(false);
const [forageInitialised, setForageInitialised] = useState(
!options.persistState
);
// Store initial pathname to prevent hooks from operating outside this page // Store initial pathname to prevent hooks from operating outside this page
const originalPathName = useRef(location.pathname); const originalPathName = useRef(location.pathname);
const persistanceKey = options.persistanceKey ?? options.filterMode; const persistanceKey = options.persistanceKey ?? options.filterMode;
const defaultSort = options.defaultSort ?? filterOptions.defaultSortBy; const defaultSort = options.defaultSort ?? filterOptions.defaultSortBy;
const defaultDisplayMode = filterOptions.displayModeOptions[0]; const defaultDisplayMode = filterOptions.displayModeOptions[0];
const [filter, setFilter] = useState<ListFilterModel>( const createNewFilter = useCallback(() => {
new ListFilterModel( return new ListFilterModel(
options.filterMode, options.filterMode,
queryString.parse(location.search), queryString.parse(history.location.search),
defaultSort, defaultSort,
defaultDisplayMode, defaultDisplayMode,
options.defaultZoomIndex options.defaultZoomIndex
) );
); }, [
options.filterMode,
history,
defaultSort,
defaultDisplayMode,
options.defaultZoomIndex,
]);
const [filter, setFilter] = useState<ListFilterModel>(createNewFilter);
const updateInterfaceConfig = useCallback( const updateSavedFilter = useCallback(
(updatedFilter: ListFilterModel, level: PersistanceLevel) => { (updatedFilter: ListFilterModel) => {
if (level === PersistanceLevel.VIEW) { setInterfaceState((prevState) => {
setInterfaceState((prevState) => { if (!prevState.queryConfig) {
if (!prevState.queryConfig) { prevState.queryConfig = {};
prevState.queryConfig = {}; }
} return {
return { ...prevState,
...prevState, queryConfig: {
queryConfig: { ...prevState.queryConfig,
...prevState.queryConfig, [persistanceKey]: {
[persistanceKey]: { ...prevState.queryConfig[persistanceKey],
...prevState.queryConfig[persistanceKey], filter: queryString.stringify({
filter: queryString.stringify({ ...queryString.parse(
...queryString.parse( prevState.queryConfig[persistanceKey]?.filter ?? ""
prevState.queryConfig[persistanceKey]?.filter ?? "" ),
), disp: updatedFilter.displayMode,
disp: updatedFilter.displayMode, }),
}),
},
}, },
}; },
}); };
} });
}, },
[persistanceKey, setInterfaceState] [persistanceKey, setInterfaceState]
); );
@@ -617,109 +620,118 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
} = useFindDefaultFilter(options.filterMode); } = useFindDefaultFilter(options.filterMode);
const updateQueryParams = useCallback( const updateQueryParams = useCallback(
(listFilter: ListFilterModel) => { (newFilter: ListFilterModel) => {
setFilter(listFilter); const newParams = newFilter.makeQueryParameters();
const newLocation = { ...location }; history.replace({ ...history.location, search: newParams });
newLocation.search = listFilter.makeQueryParameters();
history.replace(newLocation);
if (options.persistState) {
updateInterfaceConfig(listFilter, options.persistState);
}
}, },
[setFilter, history, location, options.persistState, updateInterfaceConfig] [history]
); );
useEffect(() => { const updateFilter = useCallback(
if ( (newFilter: ListFilterModel) => {
// defer processing this until forage is initialised and setFilter(newFilter);
// default filter is loaded updateQueryParams(newFilter);
interfaceState.loading || if (options.persistState === PersistanceLevel.VIEW) {
defaultFilterLoading || updateSavedFilter(newFilter);
// Only update query params on page the hook was mounted on
history.location.pathname !== originalPathName.current
)
return;
if (!forageInitialised) setForageInitialised(true);
const newFilter = filter.clone();
let update = false;
// 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
) {
newFilter.currentPage = 1;
try {
newFilter.configureFromQueryParameters(
JSON.parse(defaultFilter.findDefaultFilter.filter)
);
} catch (err) {
console.log(err);
// ignore
} }
// #1507 - reset random seed when loaded },
newFilter.randomSeed = -1; [options.persistState, updateSavedFilter, updateQueryParams]
update = true; );
}
// set the display type if persisted // 'Startup' hook, initialises the filters
const storedQuery = interfaceState.data?.queryConfig?.[persistanceKey]; useEffect(() => {
// Only run once
if (filterInitialised) return;
if (options.persistState === PersistanceLevel.VIEW && storedQuery) { let newFilter = filter.clone();
const storedFilter = queryString.parse(storedQuery.filter);
if (storedFilter.disp !== undefined) { if (options.persistState === PersistanceLevel.ALL) {
const displayMode = Number.parseInt(storedFilter.disp as string, 10); // only set default filter if query params are empty
if (displayMode !== newFilter.displayMode) { if (!history.location.search) {
// wait until default filter is loaded
if (defaultFilterLoading) return;
if (defaultFilter?.findDefaultFilter) {
newFilter.currentPage = 1;
try {
newFilter.configureFromQueryParameters(
JSON.parse(defaultFilter.findDefaultFilter.filter)
);
} catch (err) {
console.log(err);
// ignore
}
// #1507 - reset random seed when loaded
newFilter.randomSeed = -1;
}
}
} else if (options.persistState === PersistanceLevel.VIEW) {
// wait until forage is initialised
if (interfaceState.loading) return;
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);
newFilter.displayMode = displayMode; newFilter.displayMode = displayMode;
update = true;
} }
} }
} }
setFilter(newFilter);
updateQueryParams(newFilter);
if (update) { setFilterInitialised(true);
updateQueryParams(newFilter);
}
}, [ }, [
defaultSort, filterInitialised,
defaultDisplayMode,
filter, filter,
interfaceState,
history, history,
location.search, options.persistState,
updateQueryParams, updateQueryParams,
defaultFilter, defaultFilter,
defaultFilterLoading, defaultFilterLoading,
interfaceState,
persistanceKey, 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( const onChangePage = useCallback(
(page: number) => { (page: number) => {
const newFilter = cloneDeep(filter); const newFilter = cloneDeep(filter);
newFilter.currentPage = page; newFilter.currentPage = page;
updateQueryParams(newFilter); updateFilter(newFilter);
window.scrollTo(0, 0); window.scrollTo(0, 0);
}, },
[filter, updateQueryParams] [filter, updateFilter]
); );
const renderFilter = useMemo(() => { const renderFilter = useMemo(() => {
@@ -731,10 +743,10 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
filter: renderFilter, filter: renderFilter,
filterOptions, filterOptions,
onChangePage, onChangePage,
updateQueryParams, updateFilter,
}); });
const template = !forageInitialised ? ( const template = !filterInitialised ? (
<LoadingIndicator /> <LoadingIndicator />
) : ( ) : (
<>{contentTemplate}</> <>{contentTemplate}</>

View File

@@ -53,7 +53,7 @@ export function makeCriteria(type: CriterionType = "none") {
case "path": case "path":
case "checksum": case "checksum":
return new StringCriterion( return new StringCriterion(
new MandatoryStringCriterionOption(type, type) new MandatoryStringCriterionOption("media_info.checksum", type, type)
); );
case "oshash": case "oshash":
return new StringCriterion( return new StringCriterion(
@@ -134,7 +134,7 @@ export function makeCriteria(type: CriterionType = "none") {
case "sceneChecksum": case "sceneChecksum":
case "galleryChecksum": case "galleryChecksum":
return new StringCriterion( return new StringCriterion(
new StringCriterionOption("checksum", type, "checksum") new StringCriterionOption("media_info.checksum", type, "checksum")
); );
case "phash": case "phash":
return new StringCriterion(PhashCriterionOption); return new StringCriterion(PhashCriterionOption);