Fix various console errors and graphql loading issues (#760)

* Refactor listhook to resolve loading issues
* Fix graphql loading race conditions
* Various console spam
* Fix scene card overlay hierarchy
* Fix modal and manual borders
This commit is contained in:
InfiniteTF 2020-08-28 08:33:19 +02:00 committed by GitHub
parent 9a84726128
commit fef16d7e09
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 345 additions and 325 deletions

View file

@ -132,7 +132,7 @@ export const Manual: React.FC<IManualProps> = ({ show, onClose }) => {
<Nav variant="pills" className="flex-column">
{content.map((c) => {
return (
<Nav.Item>
<Nav.Item key={`${c.key}-nav`}>
<Nav.Link className={c.className} eventKey={c.key}>
{c.title}
</Nav.Link>
@ -146,7 +146,11 @@ export const Manual: React.FC<IManualProps> = ({ show, onClose }) => {
<Tab.Content>
{content.map((c) => {
return (
<Tab.Pane eventKey={c.key} onClick={interceptLinkClick}>
<Tab.Pane
eventKey={c.key}
key={`${c.key}-pane`}
onClick={interceptLinkClick}
>
<Page page={c.content} />
</Tab.Pane>
);

View file

@ -1,18 +1,17 @@
.manual {
background-color: #30404d;
color: $text-color;
.close {
color: $text-color;
}
.manual-container {
&-container {
padding-left: 1px;
padding-right: 5px;
}
.modal-header,
.modal-body {
&-header,
&-body {
background-color: #30404d;
color: $text-color;
overflow-y: hidden;
@ -21,22 +20,22 @@
.indent-1 {
padding-left: 2rem;
}
}
.manual .manual-content,
.manual .manual-toc {
max-height: calc(100vh - 10rem);
overflow-y: auto;
}
@media (max-width: 992px) {
.manual .modal-body {
.manual-content,
.manual-toc {
max-height: calc(100vh - 10rem);
overflow-y: auto;
}
.manual-content,
.manual-toc {
max-height: inherit;
overflow-y: hidden;
@media (max-width: 992px) {
.modal-body {
overflow-y: auto;
.manual-content,
.manual-toc {
max-height: inherit;
overflow-y: hidden;
}
}
}
}

View file

@ -285,6 +285,10 @@ export const Performer: React.FC = () => {
const photos = [{ src: activeImage, caption: "Image" }];
if (!performer.id) {
return <LoadingIndicator />;
}
return (
<div id="performer-page" className="row">
<div className="image-container col-md-4 text-center">

View file

@ -102,7 +102,7 @@ export const SceneCard: React.FC<ISceneCardProps> = (
if (props.scene.performers.length <= 0) return;
const popoverContent = props.scene.performers.map((performer) => (
<div className="performer-tag-container row" key="performer">
<div className="performer-tag-container row" key={performer.id}>
<Link
to={`/performers/${performer.id}`}
className="performer-tag col m-auto zoom-2"
@ -151,7 +151,11 @@ export const SceneCard: React.FC<ISceneCardProps> = (
));
return (
<HoverPopover placement="bottom" content={popoverContent}>
<HoverPopover
placement="bottom"
content={popoverContent}
className="tag-tooltip"
>
<Button className="minimal">
<Icon icon="film" />
<span>{props.scene.movies.length}</span>
@ -285,26 +289,28 @@ export const SceneCard: React.FC<ISceneCardProps> = (
}}
/>
<Link
to={`/scenes/${props.scene.id}`}
className="scene-card-link"
onClick={handleSceneClick}
onDragStart={handleDrag}
onDragOver={handleDragOver}
draggable={props.selecting}
>
{maybeRenderRatingBanner()}
{maybeRenderSceneStudioOverlay()}
{maybeRenderSceneSpecsOverlay()}
<video
loop
className={cx("scene-card-video", { portrait: isPortrait() })}
poster={props.scene.paths.screenshot || ""}
ref={hoverHandler.videoEl}
<div className="video-section">
<Link
to={`/scenes/${props.scene.id}`}
className="scene-card-link"
onClick={handleSceneClick}
onDragStart={handleDrag}
onDragOver={handleDragOver}
draggable={props.selecting}
>
{previewPath ? <source src={previewPath} /> : ""}
</video>
</Link>
{maybeRenderRatingBanner()}
{maybeRenderSceneSpecsOverlay()}
<video
loop
className={cx("scene-card-video", { portrait: isPortrait() })}
poster={props.scene.paths.screenshot || ""}
ref={hoverHandler.videoEl}
>
{previewPath ? <source src={previewPath} /> : ""}
</video>
</Link>
{maybeRenderSceneStudioOverlay()}
</div>
<div className="card-section">
<h5 className="card-section-title">
{props.scene.title

View file

@ -99,6 +99,7 @@ export const RatingStars: React.FC<IRatingStarsProps> = (
onFocus={() => onMouseOver(rating)}
onBlur={() => onMouseOut(rating)}
title={getTooltip(rating)}
key={`star-${rating}`}
>
<Icon
icon={[getIconPrefix(rating), "star"]}

View file

@ -13,6 +13,10 @@
}
}
.video-section {
position: relative;
}
.card-section {
margin-bottom: 0;
padding: 0.5rem 1rem 0 1rem;
@ -174,10 +178,6 @@ textarea.scene-description {
padding: 0;
}
&-link {
position: relative;
}
.scene-card-check {
left: 0.5rem;
margin-top: -12px;

View file

@ -455,8 +455,10 @@ export const SettingsConfigurationPanel: React.FC = () => {
className="col col-sm-6 text-input"
type="number"
value={previewSegments.toString()}
onInput={(e: React.FormEvent<HTMLInputElement>) =>
setPreviewSegments(Number.parseInt(e.currentTarget.value, 10))
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setPreviewSegments(
Number.parseInt(e.currentTarget.value || "0", 10)
)
}
/>
<Form.Text className="text-muted">
@ -470,9 +472,9 @@ export const SettingsConfigurationPanel: React.FC = () => {
className="col col-sm-6 text-input"
type="number"
value={previewSegmentDuration.toString()}
onInput={(e: React.FormEvent<HTMLInputElement>) =>
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setPreviewSegmentDuration(
Number.parseFloat(e.currentTarget.value)
Number.parseFloat(e.currentTarget.value || "0")
)
}
/>
@ -583,8 +585,10 @@ export const SettingsConfigurationPanel: React.FC = () => {
className="col col-sm-6 text-input"
type="number"
value={maxSessionAge.toString()}
onInput={(e: React.FormEvent<HTMLInputElement>) =>
setMaxSessionAge(Number.parseInt(e.currentTarget.value, 10))
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setMaxSessionAge(
Number.parseInt(e.currentTarget.value || "0", 10)
)
}
/>
<Form.Text className="text-muted">

View file

@ -66,6 +66,7 @@ export const HoverPopover: React.FC<IHoverPopover> = ({
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
id="popover"
className="hover-popover-content"
>
{content}
</Popover>

View file

@ -1,6 +1,7 @@
import { Badge } from "react-bootstrap";
import React from "react";
import { Link } from "react-router-dom";
import cx from "classnames";
import {
PerformerDataFragment,
SceneMarkerDataFragment,
@ -43,7 +44,7 @@ export const TagLink: React.FC<IProps> = (props: IProps) => {
: TextUtils.fileNameFromPath(props.scene.path ?? "");
}
return (
<Badge className={`tag-item ${props.className}`} variant="secondary">
<Badge className={cx("tag-item", props.className)} variant="secondary">
<Link to={link}>{title}</Link>
</Badge>
);

View file

@ -128,3 +128,8 @@ button.collapse-button.btn-primary:not(:disabled):not(.disabled):active {
box-shadow: none;
color: #f5f8fa;
}
.hover-popover-content {
max-width: 32rem;
text-align: center;
}

View file

@ -102,7 +102,7 @@ export const Studio: React.FC = () => {
const imageEncoding = ImageUtils.usePasteImage(onImageLoad, isEditing);
if (!isNew && !isEditing) {
if (!data?.findStudio || loading) return <LoadingIndicator />;
if (!data?.findStudio || loading || !studio.id) return <LoadingIndicator />;
if (error) return <div>{error.message}</div>;
}

View file

@ -36,7 +36,7 @@ export const Tag: React.FC = () => {
const [name, setName] = useState<string>();
// Tag state
const [tag, setTag] = useState<Partial<GQL.TagDataFragment>>({});
const [tag, setTag] = useState<GQL.TagDataFragment | undefined>();
const [imagePreview, setImagePreview] = useState<string>();
const { data, error, loading } = useFindTag(id);
@ -71,11 +71,11 @@ export const Tag: React.FC = () => {
};
});
function updateTagEditState(state: Partial<GQL.TagDataFragment>) {
function updateTagEditState(state: GQL.TagDataFragment) {
setName(state.name);
}
function updateTagData(tagData: Partial<GQL.TagDataFragment>) {
function updateTagData(tagData: GQL.TagDataFragment) {
setImage(undefined);
updateTagEditState(tagData);
setImagePreview(tagData.image_path ?? undefined);
@ -104,15 +104,17 @@ export const Tag: React.FC = () => {
}
function getTagInput() {
const input: Partial<GQL.TagCreateInput | GQL.TagUpdateInput> = {
if (!isNew) {
return {
id,
name,
image,
};
}
return {
name,
image,
};
if (!isNew) {
(input as GQL.TagUpdateInput).id = id;
}
return input;
}
async function onSave() {
@ -136,7 +138,7 @@ export const Tag: React.FC = () => {
}
async function onAutoTag() {
if (!tag.id) return;
if (!tag?.id) return;
try {
await mutateMetadataAutoTag({ tags: [tag.id] });
Toast.success({ content: "Started auto tagging" });
@ -175,13 +177,15 @@ export const Tag: React.FC = () => {
function onToggleEdit() {
setIsEditing(!isEditing);
updateTagData(tag);
if (tag) {
updateTagData(tag);
}
}
function onClearImage() {
setImage(null);
setImagePreview(
tag.image_path ? `${tag.image_path}?default=true` : undefined
tag?.image_path ? `${tag.image_path}?default=true` : undefined
);
}
@ -226,7 +230,7 @@ export const Tag: React.FC = () => {
acceptSVG
/>
</div>
{!isNew && (
{!isNew && tag && (
<div className="col col-md-8">
<Tabs
id="tag-tabs"

View file

@ -5,12 +5,12 @@ import { SceneList } from "src/components/Scenes/SceneList";
import { TagsCriterion } from "src/models/list-filter/criteria/tags";
interface ITagScenesPanel {
tag: Partial<GQL.TagDataFragment>;
tag: GQL.TagDataFragment;
}
export const TagScenesPanel: React.FC<ITagScenesPanel> = ({ tag }) => {
function filterHook(filter: ListFilterModel) {
const tagValue = { id: tag.id!, label: tag.name! };
const tagValue = { id: tag.id, label: tag.name };
// if tag is already present, then we modify it, otherwise add
let tagCriterion = filter.criteria.find((c) => {
return c.type === "tags";

View file

@ -38,6 +38,24 @@ import {
import { ListFilterModel } from "src/models/list-filter/filter";
import { FilterMode } from "src/models/list-filter/types";
const getSelectedData = <I extends IDataItem>(
result: I[],
selectedIds: Set<string>
) => {
// find the selected items from the ids
const selectedResults: I[] = [];
selectedIds.forEach((id) => {
const item = result.find((s) => s.id === id);
if (item) {
selectedResults.push(item);
}
});
return selectedResults;
};
interface IListHookData {
filter: ListFilterModel;
template: JSX.Element;
@ -99,34 +117,45 @@ interface IQuery<T extends IQueryResult, T2 extends IDataItem> {
filterMode: FilterMode;
useData: (filter: ListFilterModel) => T;
getData: (data: T) => T2[];
getSelectedData: (data: T, selectedIds: Set<string>) => T2[];
getCount: (data: T) => number;
}
const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
options: IListHookOptions<QueryResult, QueryData> &
IQuery<QueryResult, QueryData>
): IListHookData => {
const [interfaceState, setInterfaceState] = useInterfaceLocalForage();
const [forageInitialised, setForageInitialised] = useState(false);
const history = useHistory();
const location = useLocation();
const [filter, setFilter] = useState<ListFilterModel>(
new ListFilterModel(options.filterMode, queryString.parse(location.search))
);
interface IRenderListProps {
filter: ListFilterModel;
onChangePage: (page: number) => void;
updateQueryParams: (filter: ListFilterModel) => void;
}
const RenderList = <
QueryResult extends IQueryResult,
QueryData extends IDataItem
>({
defaultZoomIndex,
filter,
onChangePage,
addKeybinds,
useData,
getCount,
getData,
otherOperations,
renderContent,
zoomable,
selectable,
renderEditDialog,
renderDeleteDialog,
updateQueryParams,
}: IListHookOptions<QueryResult, QueryData> &
IQuery<QueryResult, QueryData> &
IRenderListProps) => {
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
const [lastClickedId, setLastClickedId] = useState<string | undefined>();
const [zoomIndex, setZoomIndex] = useState<number>(
options.defaultZoomIndex ?? 1
);
// Store initial pathname to prevent hooks from operating outside this page
const originalPathName = useRef(location.pathname);
const [zoomIndex, setZoomIndex] = useState<number>(defaultZoomIndex ?? 1);
const result = options.useData(getFilter());
const totalCount = options.getCount(result);
const items = options.getData(result);
const result = useData(filter);
const totalCount = getCount(result);
const items = getData(result);
useEffect(() => {
Mousetrap.bind("right", () => {
@ -140,7 +169,6 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
onChangePage(filter.currentPage - 1);
}
});
Mousetrap.bind("shift+right", () => {
const maxPage = totalCount / filter.itemsPerPage + 1;
onChangePage(Math.min(maxPage, filter.currentPage + 10));
@ -157,8 +185,8 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
});
let unbindExtras: () => void;
if (options.addKeybinds) {
unbindExtras = options.addKeybinds(result, filter, selectedIds);
if (addKeybinds) {
unbindExtras = addKeybinds(result, filter, selectedIds);
}
return () => {
@ -175,102 +203,6 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
};
});
const updateInterfaceConfig = useCallback(
(updatedFilter: ListFilterModel) => {
setInterfaceState((config) => {
const data = { ...config } as IInterfaceConfig;
data.queries = {
[options.filterMode]: {
filter: updatedFilter.makeQueryParameters(),
itemsPerPage: updatedFilter.itemsPerPage,
currentPage: updatedFilter.currentPage,
},
};
return data;
});
},
[options.filterMode, setInterfaceState]
);
useEffect(() => {
if (
interfaceState.loading ||
// Only update query params on page the hook was mounted on
history.location.pathname !== originalPathName.current
)
return;
if (!forageInitialised) setForageInitialised(true);
if (!options.persistState) return;
const storedQuery = interfaceState.data?.queries?.[options.filterMode];
if (!storedQuery) return;
const queryFilter = queryString.parse(history.location.search);
const storedFilter = queryString.parse(storedQuery.filter);
const query = history.location.search
? {
sortby: storedFilter.sortby,
sortdir: storedFilter.sortdir,
disp: storedFilter.disp,
perPage: storedFilter.perPage,
...queryFilter,
}
: storedFilter;
const newFilter = new ListFilterModel(options.filterMode, query);
// Compare constructed filter with current filter.
// If different it's the result of navigation, and we update the filter.
const newLocation = { ...history.location };
newLocation.search = newFilter.makeQueryParameters();
if (newLocation.search !== filter.makeQueryParameters()) {
setFilter(newFilter);
updateInterfaceConfig(newFilter);
}
// If constructed search is different from current, update it as well
if (newLocation.search !== location.search) {
newLocation.search = newFilter.makeQueryParameters();
history.replace(newLocation);
}
}, [
filter,
interfaceState.data,
interfaceState.loading,
history,
location.search,
options.filterMode,
forageInitialised,
updateInterfaceConfig,
options.persistState,
]);
function getFilter() {
if (!options.filterHook) {
return filter;
}
// make a copy of the filter and call the hook
const newFilter = _.cloneDeep(filter);
return options.filterHook(newFilter);
}
function updateQueryParams(listFilter: ListFilterModel) {
setFilter(listFilter);
const newLocation = { ...location };
newLocation.search = listFilter.makeQueryParameters();
history.replace(newLocation);
if (options.persistState) {
updateInterfaceConfig(listFilter);
}
}
function onChangePage(page: number) {
const newFilter = _.cloneDeep(filter);
newFilter.currentPage = page;
updateQueryParams(newFilter);
}
function singleSelect(id: string, selected: boolean) {
setLastClickedId(id);
@ -348,54 +280,21 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
setZoomIndex(newZoomIndex);
}
const otherOperations = options.otherOperations
? options.otherOperations.map((o) => {
return {
text: o.text,
onClick: () => {
o.onClick(result, filter, selectedIds);
},
isDisplayed: () => {
if (o.isDisplayed) {
return o.isDisplayed(result, filter, selectedIds);
}
const operations =
otherOperations &&
otherOperations.map((o) => ({
text: o.text,
onClick: () => {
o.onClick(result, filter, selectedIds);
},
isDisplayed: () => {
if (o.isDisplayed) {
return o.isDisplayed(result, filter, selectedIds);
}
return true;
},
};
})
: undefined;
function maybeRenderContent() {
if (!result.loading && !result.error) {
return options.renderContent(result, filter, selectedIds, zoomIndex);
}
}
function maybeRenderPaginationIndex() {
if (!result.loading && !result.error) {
return (
<PaginationIndex
itemsPerPage={filter.itemsPerPage}
currentPage={filter.currentPage}
totalItems={totalCount}
/>
);
}
}
function maybeRenderPagination() {
if (!result.loading && !result.error) {
return (
<Pagination
itemsPerPage={filter.itemsPerPage}
currentPage={filter.currentPage}
totalItems={totalCount}
onChangePage={onChangePage}
/>
);
}
}
return true;
},
}));
function onEdit() {
setIsEditDialogOpen(true);
@ -425,60 +324,189 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
result.refetch();
}
const template = (
<div>
<ListFilter
onFilterUpdate={updateQueryParams}
onSelectAll={options.selectable ? onSelectAll : undefined}
onSelectNone={options.selectable ? onSelectNone : undefined}
zoomIndex={options.zoomable ? zoomIndex : undefined}
onChangeZoom={options.zoomable ? onChangeZoom : undefined}
otherOperations={otherOperations}
itemsSelected={selectedIds.size > 0}
onEdit={options.renderEditDialog ? onEdit : undefined}
onDelete={options.renderDeleteDialog ? onDelete : undefined}
filter={filter}
/>
{isEditDialogOpen && options.renderEditDialog
? options.renderEditDialog(
options.getSelectedData(result, selectedIds),
(applied) => onEditDialogClosed(applied)
)
: undefined}
{isDeleteDialogOpen && options.renderDeleteDialog
? options.renderDeleteDialog(
options.getSelectedData(result, selectedIds),
(deleted) => onDeleteDialogClosed(deleted)
)
: undefined}
{(result.loading || !forageInitialised) && <LoadingIndicator />}
{result.error && <h1>{result.error.message}</h1>}
{maybeRenderPagination()}
{maybeRenderContent()}
{maybeRenderPaginationIndex()}
{maybeRenderPagination()}
</div>
const renderPagination = () => (
<Pagination
itemsPerPage={filter.itemsPerPage}
currentPage={filter.currentPage}
totalItems={totalCount}
onChangePage={onChangePage}
/>
);
return { filter, template, onSelectChange };
let content;
if (result.loading) {
content = <LoadingIndicator />;
} else if (result.error) {
content = <h1>{result.error.message}</h1>;
} else {
content = (
<div>
<ListFilter
onFilterUpdate={updateQueryParams}
onSelectAll={selectable ? onSelectAll : undefined}
onSelectNone={selectable ? onSelectNone : undefined}
zoomIndex={zoomable ? zoomIndex : undefined}
onChangeZoom={zoomable ? onChangeZoom : undefined}
otherOperations={operations}
itemsSelected={selectedIds.size > 0}
onEdit={renderEditDialog ? onEdit : undefined}
onDelete={renderDeleteDialog ? onDelete : undefined}
filter={filter}
/>
{isEditDialogOpen &&
renderEditDialog &&
renderEditDialog(
getSelectedData(getData(result), selectedIds),
(applied) => onEditDialogClosed(applied)
)}
{isDeleteDialogOpen &&
renderDeleteDialog &&
renderDeleteDialog(
getSelectedData(getData(result), selectedIds),
(deleted) => onDeleteDialogClosed(deleted)
)}
{renderPagination()}
{renderContent(result, filter, selectedIds, zoomIndex)}
<PaginationIndex
itemsPerPage={filter.itemsPerPage}
currentPage={filter.currentPage}
totalItems={totalCount}
/>
{renderPagination()}
</div>
);
}
return { contentTemplate: content, onSelectChange };
};
const getSelectedData = <I extends IDataItem>(
result: I[],
selectedIds: Set<string>
) => {
// find the selected items from the ids
const selectedResults: I[] = [];
const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
options: IListHookOptions<QueryResult, QueryData> &
IQuery<QueryResult, QueryData>
): IListHookData => {
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
);
// Store initial pathname to prevent hooks from operating outside this page
const originalPathName = useRef(location.pathname);
selectedIds.forEach((id) => {
const item = result.find((s) => s.id === id);
const [filter, setFilter] = useState<ListFilterModel>(
new ListFilterModel(options.filterMode, queryString.parse(location.search))
);
if (item) {
selectedResults.push(item);
const updateInterfaceConfig = useCallback(
(updatedFilter: ListFilterModel) => {
setInterfaceState((config) => {
const data = { ...config } as IInterfaceConfig;
data.queries = {
[options.filterMode]: {
filter: updatedFilter.makeQueryParameters(),
itemsPerPage: updatedFilter.itemsPerPage,
currentPage: updatedFilter.currentPage,
},
};
return data;
});
},
[options.filterMode, setInterfaceState]
);
useEffect(() => {
if (
interfaceState.loading ||
// Only update query params on page the hook was mounted on
history.location.pathname !== originalPathName.current
)
return;
if (!forageInitialised) setForageInitialised(true);
if (!options.persistState) return;
const storedQuery = interfaceState.data?.queries?.[options.filterMode];
if (!storedQuery) return;
const queryFilter = queryString.parse(history.location.search);
const storedFilter = queryString.parse(storedQuery.filter);
const query = history.location.search
? {
sortby: storedFilter.sortby,
sortdir: storedFilter.sortdir,
disp: storedFilter.disp,
perPage: storedFilter.perPage,
...queryFilter,
}
: storedFilter;
const newFilter = new ListFilterModel(options.filterMode, query);
// Compare constructed filter with current filter.
// If different it's the result of navigation, and we update the filter.
const newLocation = { ...history.location };
newLocation.search = newFilter.makeQueryParameters();
if (newLocation.search !== filter.makeQueryParameters()) {
setFilter(newFilter);
updateInterfaceConfig(newFilter);
}
// If constructed search is different from current, update it as well
if (newLocation.search !== location.search) {
newLocation.search = newFilter.makeQueryParameters();
history.replace(newLocation);
}
}, [
filter,
interfaceState.data,
interfaceState.loading,
history,
location.search,
options.filterMode,
forageInitialised,
updateInterfaceConfig,
options.persistState,
]);
function updateQueryParams(listFilter: ListFilterModel) {
setFilter(listFilter);
const newLocation = { ...location };
newLocation.search = listFilter.makeQueryParameters();
history.replace(newLocation);
if (options.persistState) {
updateInterfaceConfig(listFilter);
}
}
const onChangePage = (page: number) => {
const newFilter = _.cloneDeep(filter);
newFilter.currentPage = page;
updateQueryParams(newFilter);
};
const renderFilter = !options.filterHook
? filter
: options.filterHook(_.cloneDeep(filter));
const { contentTemplate, onSelectChange } = RenderList({
...options,
filter: renderFilter,
onChangePage,
updateQueryParams,
});
return selectedResults;
const template = !forageInitialised ? (
<LoadingIndicator />
) : (
<>{contentTemplate}</>
);
return {
filter,
template,
onSelectChange,
};
};
export const useScenesList = (
@ -492,10 +520,6 @@ export const useScenesList = (
result?.data?.findScenes?.scenes ?? [],
getCount: (result: FindScenesQueryResult) =>
result?.data?.findScenes?.count ?? 0,
getSelectedData: (
result: FindScenesQueryResult,
selectedIds: Set<string>
) => getSelectedData(result?.data?.findScenes?.scenes ?? [], selectedIds),
});
export const useSceneMarkersList = (
@ -509,14 +533,6 @@ export const useSceneMarkersList = (
result?.data?.findSceneMarkers?.scene_markers ?? [],
getCount: (result: FindSceneMarkersQueryResult) =>
result?.data?.findSceneMarkers?.count ?? 0,
getSelectedData: (
result: FindSceneMarkersQueryResult,
selectedIds: Set<string>
) =>
getSelectedData(
result?.data?.findSceneMarkers?.scene_markers ?? [],
selectedIds
),
});
export const useGalleriesList = (
@ -530,14 +546,6 @@ export const useGalleriesList = (
result?.data?.findGalleries?.galleries ?? [],
getCount: (result: FindGalleriesQueryResult) =>
result?.data?.findGalleries?.count ?? 0,
getSelectedData: (
result: FindGalleriesQueryResult,
selectedIds: Set<string>
) =>
getSelectedData(
result?.data?.findGalleries?.galleries ?? [],
selectedIds
),
});
export const useStudiosList = (
@ -551,10 +559,6 @@ export const useStudiosList = (
result?.data?.findStudios?.studios ?? [],
getCount: (result: FindStudiosQueryResult) =>
result?.data?.findStudios?.count ?? 0,
getSelectedData: (
result: FindStudiosQueryResult,
selectedIds: Set<string>
) => getSelectedData(result?.data?.findStudios?.studios ?? [], selectedIds),
});
export const usePerformersList = (
@ -568,14 +572,6 @@ export const usePerformersList = (
result?.data?.findPerformers?.performers ?? [],
getCount: (result: FindPerformersQueryResult) =>
result?.data?.findPerformers?.count ?? 0,
getSelectedData: (
result: FindPerformersQueryResult,
selectedIds: Set<string>
) =>
getSelectedData(
result?.data?.findPerformers?.performers ?? [],
selectedIds
),
});
export const useMoviesList = (
@ -589,10 +585,6 @@ export const useMoviesList = (
result?.data?.findMovies?.movies ?? [],
getCount: (result: FindMoviesQueryResult) =>
result?.data?.findMovies?.count ?? 0,
getSelectedData: (
result: FindMoviesQueryResult,
selectedIds: Set<string>
) => getSelectedData(result?.data?.findMovies?.movies ?? [], selectedIds),
});
export const useTagsList = (
@ -606,13 +598,11 @@ export const useTagsList = (
result?.data?.findTags?.tags ?? [],
getCount: (result: FindTagsQueryResult) =>
result?.data?.findTags?.count ?? 0,
getSelectedData: (result: FindTagsQueryResult, selectedIds: Set<string>) =>
getSelectedData(result?.data?.findTags?.tags ?? [], selectedIds),
});
export const showWhenSelected = (
result: FindScenesQueryResult,
filter: ListFilterModel,
_result: FindScenesQueryResult,
_filter: ListFilterModel,
selectedIds: Set<string>
) => {
return selectedIds.size > 0;

View file

@ -26,10 +26,7 @@ export const useVideoHover = (options: IVideoHoverHookOptions) => {
return;
}
if (videoTag.paused && !isPlaying.current) {
videoTag.play().catch((error) => {
// eslint-disable-next-line no-console
console.log(error.message);
});
videoTag.play().catch(() => {});
}
};

View file

@ -176,10 +176,14 @@ hr {
color: $text-color;
}
.modal-header,
.modal-body,
.modal-footer {
&-header,
&-body,
&-footer {
background-color: #30404d;
color: $text-color;
}
&-content {
background-color: transparent;
}
}