mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 12:24:38 +03:00
Prettier
This commit is contained in:
@@ -1,9 +1,7 @@
|
||||
import React from "react";
|
||||
import { Table } from "react-bootstrap";
|
||||
import { Link } from "react-router-dom";
|
||||
import {
|
||||
FindGalleriesQueryResult,
|
||||
} from "src/core/generated-graphql";
|
||||
import { FindGalleriesQueryResult } from "src/core/generated-graphql";
|
||||
import { useGalleriesList } from "src/hooks";
|
||||
import { ListFilterModel } from "src/models/list-filter/filter";
|
||||
import { DisplayMode } from "src/models/list-filter/types";
|
||||
@@ -38,7 +36,10 @@ export const GalleryList: React.FC = () => {
|
||||
<td>
|
||||
<Link to={`/galleries/${gallery.id}`}>
|
||||
{gallery.files.length > 0 ? (
|
||||
<img alt={gallery.title ?? ''} src={`${gallery.files[0].path}?thumb=true`} />
|
||||
<img
|
||||
alt={gallery.title ?? ""}
|
||||
src={`${gallery.files[0].path}?thumb=true`}
|
||||
/>
|
||||
) : (
|
||||
undefined
|
||||
)}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { FunctionComponent, useState } from "react";
|
||||
import Lightbox from 'react-images';
|
||||
import Lightbox from "react-images";
|
||||
import Gallery from "react-photo-gallery";
|
||||
import * as GQL from "src/core/generated-graphql";
|
||||
|
||||
@@ -30,8 +30,8 @@ export const GalleryViewer: FunctionComponent<IProps> = ({ gallery }) => {
|
||||
}
|
||||
|
||||
const photos = gallery.files.map(file => ({
|
||||
src: file.path ?? '',
|
||||
caption: file.name ?? ''
|
||||
src: file.path ?? "",
|
||||
caption: file.name ?? ""
|
||||
}));
|
||||
const thumbs = gallery.files.map(file => ({
|
||||
src: `${file.path}?thumb=true` || "",
|
||||
@@ -48,7 +48,9 @@ export const GalleryViewer: FunctionComponent<IProps> = ({ gallery }) => {
|
||||
onClickPrev={gotoPrevious}
|
||||
onClickNext={gotoNext}
|
||||
currentImage={currentImage}
|
||||
onClickImage={() => window.open(photos[currentImage].src ?? '', "_blank")}
|
||||
onClickImage={() =>
|
||||
window.open(photos[currentImage].src ?? "", "_blank")
|
||||
}
|
||||
isOpen={lightboxIsOpen}
|
||||
width={9999}
|
||||
/>
|
||||
|
||||
@@ -4,7 +4,13 @@ import { StashService } from "src/core/StashService";
|
||||
|
||||
export const SettingsAboutPanel: React.FC = () => {
|
||||
const { data, error, loading } = StashService.useVersion();
|
||||
const { data: dataLatest, error: errorLatest, loading: loadingLatest, refetch, networkStatus } = StashService.useLatestVersion();
|
||||
const {
|
||||
data: dataLatest,
|
||||
error: errorLatest,
|
||||
loading: loadingLatest,
|
||||
refetch,
|
||||
networkStatus
|
||||
} = StashService.useLatestVersion();
|
||||
|
||||
function maybeRenderTag() {
|
||||
if (!data || !data.version || !data.version.version) {
|
||||
@@ -19,28 +25,34 @@ export const SettingsAboutPanel: React.FC = () => {
|
||||
}
|
||||
|
||||
function maybeRenderLatestVersion() {
|
||||
if (!dataLatest || !dataLatest.latestversion || !dataLatest.latestversion.shorthash || !dataLatest.latestversion.url) { return; }
|
||||
if (
|
||||
!dataLatest ||
|
||||
!dataLatest.latestversion ||
|
||||
!dataLatest.latestversion.shorthash ||
|
||||
!dataLatest.latestversion.url
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (!data || !data.version || !data.version.hash) {
|
||||
return (
|
||||
<>{dataLatest.latestversion.shorthash}</>
|
||||
);
|
||||
return <>{dataLatest.latestversion.shorthash}</>;
|
||||
}
|
||||
|
||||
if (data.version.hash !== dataLatest.latestversion.shorthash) {
|
||||
return (
|
||||
<>
|
||||
<strong>{dataLatest.latestversion.shorthash} [NEW] </strong><a href={dataLatest.latestversion.url}>Download</a>
|
||||
<strong>{dataLatest.latestversion.shorthash} [NEW] </strong>
|
||||
<a href={dataLatest.latestversion.url}>Download</a>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>{dataLatest.latestversion.shorthash}</>
|
||||
);
|
||||
return <>{dataLatest.latestversion.shorthash}</>;
|
||||
}
|
||||
|
||||
function renderLatestVersion() {
|
||||
if (!data || !data.version || !data.version.version) { return; } // if there is no "version" latest version check is obviously not supported
|
||||
if (!data || !data.version || !data.version.version) {
|
||||
return;
|
||||
} // if there is no "version" latest version check is obviously not supported
|
||||
return (
|
||||
<Table>
|
||||
<tbody>
|
||||
@@ -49,7 +61,9 @@ export const SettingsAboutPanel: React.FC = () => {
|
||||
<td>{maybeRenderLatestVersion()} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><Button onClick={() => refetch()}>Check for new version</Button></td>
|
||||
<td>
|
||||
<Button onClick={() => refetch()}>Check for new version</Button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</Table>
|
||||
@@ -84,16 +98,54 @@ export const SettingsAboutPanel: React.FC = () => {
|
||||
<Table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Stash home at <a href="https://github.com/stashapp/stash" rel="noopener noreferrer" target="_blank">Github</a></td>
|
||||
<td>
|
||||
Stash home at{" "}
|
||||
<a
|
||||
href="https://github.com/stashapp/stash"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Github
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Stash <a href="https://github.com/stashapp/stash/wiki" rel="noopener noreferrer" target="_blank">Wiki</a> page</td>
|
||||
<td>
|
||||
Stash{" "}
|
||||
<a
|
||||
href="https://github.com/stashapp/stash/wiki"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Wiki
|
||||
</a>{" "}
|
||||
page
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Join our <a href="https://discord.gg/2TsNFKt" rel="noopener noreferrer" target="_blank">Discord</a> channel</td>
|
||||
<td>
|
||||
Join our{" "}
|
||||
<a
|
||||
href="https://discord.gg/2TsNFKt"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Discord
|
||||
</a>{" "}
|
||||
channel
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Support us through <a href="https://opencollective.com/stashapp" rel="noopener noreferrer" target="_blank">Open Collective</a></td>
|
||||
<td>
|
||||
Support us through{" "}
|
||||
<a
|
||||
href="https://opencollective.com/stashapp"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Open Collective
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</Table>
|
||||
@@ -101,7 +153,11 @@ export const SettingsAboutPanel: React.FC = () => {
|
||||
{error && <span>{error.message}</span>}
|
||||
{errorLatest && <span>{errorLatest.message}</span>}
|
||||
{renderVersion()}
|
||||
{!dataLatest || loadingLatest || networkStatus === 4 ? <Spinner animation="border" variant="light" /> : <>{renderLatestVersion()}</>}
|
||||
{!dataLatest || loadingLatest || networkStatus === 4 ? (
|
||||
<Spinner animation="border" variant="light" />
|
||||
) : (
|
||||
<>{renderLatestVersion()}</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -56,7 +56,9 @@ export const SettingsConfigurationPanel: React.FC = () => {
|
||||
setDatabasePath(conf.general.databasePath);
|
||||
setGeneratedPath(conf.general.generatedPath);
|
||||
setMaxTranscodeSize(conf.general.maxTranscodeSize ?? undefined);
|
||||
setMaxStreamingTranscodeSize(conf.general.maxStreamingTranscodeSize ?? undefined);
|
||||
setMaxStreamingTranscodeSize(
|
||||
conf.general.maxStreamingTranscodeSize ?? undefined
|
||||
);
|
||||
setUsername(conf.general.username);
|
||||
setPassword(conf.general.password);
|
||||
setLogFile(conf.general.logFile ?? undefined);
|
||||
|
||||
@@ -24,10 +24,8 @@ interface IProps {
|
||||
onImageChange: (event: React.FormEvent<HTMLInputElement>) => void;
|
||||
|
||||
// TODO: only for performers. make generic
|
||||
scrapers?: Pick<GQL.Scraper, 'id' | 'name'>[];
|
||||
onDisplayScraperDialog?: (
|
||||
scraper: Pick<GQL.Scraper, 'id' | 'name'>
|
||||
) => void;
|
||||
scrapers?: Pick<GQL.Scraper, "id" | "name">[];
|
||||
onDisplayScraperDialog?: (scraper: Pick<GQL.Scraper, "id" | "name">) => void;
|
||||
}
|
||||
|
||||
export const DetailsEditNavbar: React.FC<IProps> = (props: IProps) => {
|
||||
@@ -95,9 +93,7 @@ export const DetailsEditNavbar: React.FC<IProps> = (props: IProps) => {
|
||||
? props.scrapers.map(s => (
|
||||
<Button
|
||||
variant="link"
|
||||
onClick={() =>
|
||||
props.onDisplayScraperDialog?.(s)
|
||||
}
|
||||
onClick={() => props.onDisplayScraperDialog?.(s)}
|
||||
>
|
||||
{s.name}
|
||||
</Button>
|
||||
|
||||
@@ -11,13 +11,14 @@ interface IProps {
|
||||
}
|
||||
|
||||
export const DurationInput: React.FC<IProps> = (props: IProps) => {
|
||||
const [value, setValue] = useState<string>(DurationUtils.secondsToString(props.numericValue));
|
||||
const [value, setValue] = useState<string>(
|
||||
DurationUtils.secondsToString(props.numericValue)
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setValue(DurationUtils.secondsToString(props.numericValue));
|
||||
}, [props.numericValue]);
|
||||
|
||||
|
||||
function increment() {
|
||||
let seconds = DurationUtils.stringToSeconds(value);
|
||||
seconds += 1;
|
||||
@@ -66,7 +67,9 @@ export const DurationInput: React.FC<IProps> = (props: IProps) => {
|
||||
disabled={props.disabled}
|
||||
value={value}
|
||||
onChange={(e: any) => setValue(e.target.value)}
|
||||
onBlur={() => props.onValueChange(DurationUtils.stringToSeconds(value))}
|
||||
onBlur={() =>
|
||||
props.onValueChange(DurationUtils.stringToSeconds(value))
|
||||
}
|
||||
placeholder="hh:mm:ss"
|
||||
/>
|
||||
<InputGroup.Append>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import React from 'react';
|
||||
import { Spinner } from 'react-bootstrap';
|
||||
import React from "react";
|
||||
import { Spinner } from "react-bootstrap";
|
||||
|
||||
interface ILoadingProps {
|
||||
message: string;
|
||||
}
|
||||
|
||||
const CLASSNAME = 'LoadingIndicator';
|
||||
const CLASSNAME = "LoadingIndicator";
|
||||
const CLASSNAME_MESSAGE = `${CLASSNAME}-message`;
|
||||
|
||||
const LoadingIndicator: React.FC<ILoadingProps> = ({ message }) => (
|
||||
@@ -13,9 +13,7 @@ const LoadingIndicator: React.FC<ILoadingProps> = ({ message }) => (
|
||||
<Spinner animation="border" role="status">
|
||||
<span className="sr-only">Loading...</span>
|
||||
</Spinner>
|
||||
<h4 className={CLASSNAME_MESSAGE}>
|
||||
{ message }
|
||||
</h4>
|
||||
<h4 className={CLASSNAME_MESSAGE}>{message}</h4>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
@@ -41,7 +41,9 @@ interface ISceneGallerySelect {
|
||||
initialId?: string;
|
||||
sceneId: string;
|
||||
onSelect: (
|
||||
item: GQL.ValidGalleriesForSceneQuery["validGalleriesForScene"][0] | undefined
|
||||
item:
|
||||
| GQL.ValidGalleriesForSceneQuery["validGalleriesForScene"][0]
|
||||
| undefined
|
||||
) => void;
|
||||
}
|
||||
|
||||
@@ -78,9 +80,7 @@ export const SceneGallerySelect: React.FC<ISceneGallerySelect> = props => {
|
||||
|
||||
interface IScrapePerformerSuggestProps {
|
||||
scraperId: string;
|
||||
onSelectPerformer: (
|
||||
performer: GQL.ScrapedPerformerDataFragment
|
||||
) => void;
|
||||
onSelectPerformer: (performer: GQL.ScrapedPerformerDataFragment) => void;
|
||||
placeholder?: string;
|
||||
}
|
||||
export const ScrapePerformerSuggest: React.FC<IScrapePerformerSuggestProps> = props => {
|
||||
@@ -105,8 +105,7 @@ export const ScrapePerformerSuggest: React.FC<IScrapePerformerSuggestProps> = pr
|
||||
const onChange = (selectedItems: ValueType<Option>) => {
|
||||
const name = getSelectedValues(selectedItems)[0];
|
||||
const performer = performers.find(p => p.name === name);
|
||||
if(performer)
|
||||
props.onSelectPerformer(performer)
|
||||
if (performer) props.onSelectPerformer(performer);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -14,4 +14,4 @@ export { DetailsEditNavbar } from "./DetailsEditNavbar";
|
||||
export { DurationInput } from "./DurationInput";
|
||||
export { TagLink } from "./TagLink";
|
||||
export { HoverPopover } from "./HoverPopover";
|
||||
export { default as LoadingIndicator } from './LoadingIndicator';
|
||||
export { default as LoadingIndicator } from "./LoadingIndicator";
|
||||
|
||||
@@ -5,11 +5,9 @@ import { LoadingIndicator } from "src/components/Shared";
|
||||
export const Stats: React.FC = () => {
|
||||
const { data, error, loading } = StashService.useStats();
|
||||
|
||||
if (loading || !data)
|
||||
return <LoadingIndicator message="Loading..." />
|
||||
if (loading || !data) return <LoadingIndicator message="Loading..." />;
|
||||
|
||||
if (error)
|
||||
return <span>error.message</span> ;
|
||||
if (error) return <span>error.message</span>;
|
||||
|
||||
return (
|
||||
<div className="w-75 m-auto">
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import React from "react";
|
||||
import {
|
||||
FindStudiosQueryResult
|
||||
} from "src/core/generated-graphql";
|
||||
import { FindStudiosQueryResult } from "src/core/generated-graphql";
|
||||
import { useStudiosList } from "src/hooks";
|
||||
import { ListFilterModel } from "src/models/list-filter/filter";
|
||||
import { DisplayMode } from "src/models/list-filter/types";
|
||||
|
||||
@@ -183,7 +183,7 @@ export const AddFilter: React.FC<IAddFilterProps> = (
|
||||
numericValue={criterion.value ? criterion.value : 0}
|
||||
onValueChange={onChangedDuration}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Form.Control
|
||||
|
||||
@@ -249,7 +249,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
||||
value={props.filter.searchTerm}
|
||||
onChange={onChangeQuery}
|
||||
className="filter-item"
|
||||
style={{ width: 'inherit' }}
|
||||
style={{ width: "inherit" }}
|
||||
/>
|
||||
<Form.Control
|
||||
as="select"
|
||||
|
||||
@@ -36,7 +36,8 @@ export const PerformerCard: React.FC<IPerformerCardProps> = (
|
||||
<div className="card-section">
|
||||
<h5 className="text-truncate">{props.performer.name}</h5>
|
||||
{age !== 0 ? <div className="text-muted">{ageString}</div> : ""}
|
||||
<div className="text-muted">Stars in {props.performer.scene_count}{" "}
|
||||
<div className="text-muted">
|
||||
Stars in {props.performer.scene_count}{" "}
|
||||
<Link to={NavUtils.makePerformerScenesUrl(props.performer)}>
|
||||
scenes
|
||||
</Link>
|
||||
|
||||
@@ -5,16 +5,14 @@ import { Button, Spinner, Tabs, Tab } from "react-bootstrap";
|
||||
import { useParams, useHistory } from "react-router-dom";
|
||||
import * as GQL from "src/core/generated-graphql";
|
||||
import { StashService } from "src/core/StashService";
|
||||
import {
|
||||
Icon,
|
||||
} from "src/components/Shared";
|
||||
import { useToast } from 'src/hooks';
|
||||
import { Icon } from "src/components/Shared";
|
||||
import { useToast } from "src/hooks";
|
||||
import { TextUtils } from "src/utils";
|
||||
import Lightbox from 'react-images';
|
||||
import Lightbox from "react-images";
|
||||
import { IconName } from "@fortawesome/fontawesome-svg-core";
|
||||
import { PerformerDetailsPanel } from './PerformerDetailsPanel';
|
||||
import { PerformerOperationsPanel } from './PerformerOperationsPanel';
|
||||
import { PerformerScenesPanel } from './PerformerScenesPanel';
|
||||
import { PerformerDetailsPanel } from "./PerformerDetailsPanel";
|
||||
import { PerformerOperationsPanel } from "./PerformerOperationsPanel";
|
||||
import { PerformerScenesPanel } from "./PerformerScenesPanel";
|
||||
|
||||
export const Performer: React.FC = () => {
|
||||
const Toast = useToast();
|
||||
@@ -23,7 +21,9 @@ export const Performer: React.FC = () => {
|
||||
const isNew = id === "new";
|
||||
|
||||
// Performer state
|
||||
const [performer, setPerformer] = useState<Partial<GQL.PerformerDataFragment>>({});
|
||||
const [performer, setPerformer] = useState<
|
||||
Partial<GQL.PerformerDataFragment>
|
||||
>({});
|
||||
const [imagePreview, setImagePreview] = useState<string>();
|
||||
const [lightboxIsOpen, setLightboxIsOpen] = useState(false);
|
||||
|
||||
@@ -35,7 +35,6 @@ export const Performer: React.FC = () => {
|
||||
const [createPerformer] = StashService.usePerformerCreate();
|
||||
const [deletePerformer] = StashService.usePerformerDestroy();
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
setIsLoading(false);
|
||||
if (data?.findPerformer) setPerformer(data.findPerformer);
|
||||
@@ -54,15 +53,23 @@ export const Performer: React.FC = () => {
|
||||
|
||||
if (error) return <div>{error.message}</div>;
|
||||
|
||||
async function onSave(performerInput: Partial<GQL.PerformerCreateInput> | Partial<GQL.PerformerUpdateInput>) {
|
||||
async function onSave(
|
||||
performerInput:
|
||||
| Partial<GQL.PerformerCreateInput>
|
||||
| Partial<GQL.PerformerUpdateInput>
|
||||
) {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
if (!isNew) {
|
||||
const result = await updatePerformer({variables: performerInput as GQL.PerformerUpdateInput});
|
||||
const result = await updatePerformer({
|
||||
variables: performerInput as GQL.PerformerUpdateInput
|
||||
});
|
||||
if (result.data?.performerUpdate)
|
||||
setPerformer(result.data?.performerUpdate);
|
||||
} else {
|
||||
const result = await createPerformer({variables: performerInput as GQL.PerformerCreateInput});
|
||||
const result = await createPerformer({
|
||||
variables: performerInput as GQL.PerformerCreateInput
|
||||
});
|
||||
if (result.data?.performerCreate) {
|
||||
setPerformer(result.data.performerCreate);
|
||||
history.push(`/performers/${result.data.performerCreate.id}`);
|
||||
@@ -165,7 +172,7 @@ export const Performer: React.FC = () => {
|
||||
<Icon icon={icon} />
|
||||
</a>
|
||||
</Button>
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,7 +182,8 @@ export const Performer: React.FC = () => {
|
||||
<Button
|
||||
className={performer.favorite ? "favorite" : "not-favorite"}
|
||||
onClick={() => setFavorite(!performer.favorite)}
|
||||
><Icon icon="heart" />
|
||||
>
|
||||
<Icon icon="heart" />
|
||||
</Button>
|
||||
{maybeRenderURL(performer.url ?? undefined)}
|
||||
{/* TODO - render instagram and twitter links with icons */}
|
||||
@@ -188,7 +196,7 @@ export const Performer: React.FC = () => {
|
||||
return (
|
||||
<div className="columns is-multiline no-spacing">
|
||||
<div className="column is-half details-image-container">
|
||||
<img className="performer" src={imagePreview} alt='Performer' />
|
||||
<img className="performer" src={imagePreview} alt="Performer" />
|
||||
</div>
|
||||
<div className="column is-half details-detail-container">
|
||||
{renderTabs()}
|
||||
@@ -216,7 +224,7 @@ export const Performer: React.FC = () => {
|
||||
<div id="performer-page">
|
||||
<div className="details-image-container">
|
||||
<Button variant="link" onClick={openLightbox}>
|
||||
<img className="performer" src={imagePreview} alt='Performer' />
|
||||
<img className="performer" src={imagePreview} alt="Performer" />
|
||||
</Button>
|
||||
</div>
|
||||
<div className="performer-head">
|
||||
@@ -229,9 +237,7 @@ export const Performer: React.FC = () => {
|
||||
</div>
|
||||
|
||||
<div className="performer-body">
|
||||
<div className="details-detail-container">
|
||||
{renderTabs()}
|
||||
</div>
|
||||
<div className="details-detail-container">{renderTabs()}</div>
|
||||
</div>
|
||||
</div>
|
||||
<Lightbox
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
/* eslint-disable react/no-this-in-sfc */
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Button, Form, Popover, OverlayTrigger, Spinner, Table } from "react-bootstrap";
|
||||
import {
|
||||
Button,
|
||||
Form,
|
||||
Popover,
|
||||
OverlayTrigger,
|
||||
Spinner,
|
||||
Table
|
||||
} from "react-bootstrap";
|
||||
import * as GQL from "src/core/generated-graphql";
|
||||
import { StashService } from "src/core/StashService";
|
||||
import {
|
||||
Icon,
|
||||
Modal,
|
||||
ScrapePerformerSuggest
|
||||
} from "src/components/Shared";
|
||||
import { Icon, Modal, ScrapePerformerSuggest } from "src/components/Shared";
|
||||
import { ImageUtils, TableUtils } from "src/utils";
|
||||
import { useToast } from "src/hooks";
|
||||
|
||||
@@ -16,20 +19,34 @@ interface IPerformerDetails {
|
||||
performer: Partial<GQL.PerformerDataFragment>;
|
||||
isNew?: boolean;
|
||||
isEditing?: boolean;
|
||||
onSave?: (performer: Partial<GQL.PerformerCreateInput> | Partial<GQL.PerformerUpdateInput>) => void;
|
||||
onSave?: (
|
||||
performer:
|
||||
| Partial<GQL.PerformerCreateInput>
|
||||
| Partial<GQL.PerformerUpdateInput>
|
||||
) => void;
|
||||
onDelete?: () => void;
|
||||
onImageChange?: (image: string) => void;
|
||||
}
|
||||
|
||||
export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({ performer, isNew, isEditing, onSave, onDelete, onImageChange }) => {
|
||||
export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({
|
||||
performer,
|
||||
isNew,
|
||||
isEditing,
|
||||
onSave,
|
||||
onDelete,
|
||||
onImageChange
|
||||
}) => {
|
||||
const Toast = useToast();
|
||||
|
||||
// Editing state
|
||||
const [isDisplayingScraperDialog, setIsDisplayingScraperDialog] = useState<GQL.Scraper>();
|
||||
const [scrapePerformerDetails, setScrapePerformerDetails] = useState<GQL.ScrapedPerformerDataFragment>();
|
||||
const [isDisplayingScraperDialog, setIsDisplayingScraperDialog] = useState<
|
||||
GQL.Scraper
|
||||
>();
|
||||
const [scrapePerformerDetails, setScrapePerformerDetails] = useState<
|
||||
GQL.ScrapedPerformerDataFragment
|
||||
>();
|
||||
const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState<boolean>(false);
|
||||
|
||||
|
||||
// Editing performer state
|
||||
const [image, setImage] = useState<string>();
|
||||
const [name, setName] = useState<string>();
|
||||
@@ -55,7 +72,6 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({ performer,
|
||||
const Scrapers = StashService.useListPerformerScrapers();
|
||||
const [queryableScrapers, setQueryableScrapers] = useState<GQL.Scraper[]>([]);
|
||||
|
||||
|
||||
function updatePerformerEditState(
|
||||
state: Partial<GQL.PerformerDataFragment | GQL.ScrapedPerformer>
|
||||
) {
|
||||
@@ -91,19 +107,17 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({ performer,
|
||||
}
|
||||
}
|
||||
|
||||
if (isEditing)
|
||||
ImageUtils.usePasteImage(onImageLoad);
|
||||
if (isEditing) ImageUtils.usePasteImage(onImageLoad);
|
||||
|
||||
useEffect(() => {
|
||||
const newQueryableScrapers = (Scrapers?.data?.listPerformerScrapers ?? []).filter(s => (
|
||||
s.performer?.supported_scrapes.includes(GQL.ScrapeType.Name)
|
||||
));
|
||||
const newQueryableScrapers = (
|
||||
Scrapers?.data?.listPerformerScrapers ?? []
|
||||
).filter(s => s.performer?.supported_scrapes.includes(GQL.ScrapeType.Name));
|
||||
|
||||
setQueryableScrapers(newQueryableScrapers);
|
||||
}, [Scrapers]);
|
||||
|
||||
if (isLoading)
|
||||
return <Spinner animation="border" variant="light" />;
|
||||
if (isLoading) return <Spinner animation="border" variant="light" />;
|
||||
|
||||
function getPerformerInput() {
|
||||
const performerInput: Partial<
|
||||
@@ -138,9 +152,7 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({ performer,
|
||||
ImageUtils.onImageChange(event, onImageLoad);
|
||||
}
|
||||
|
||||
function onDisplayFreeOnesDialog(
|
||||
scraper: GQL.Scraper
|
||||
) {
|
||||
function onDisplayFreeOnesDialog(scraper: GQL.Scraper) {
|
||||
setIsDisplayingScraperDialog(scraper);
|
||||
}
|
||||
|
||||
@@ -212,9 +224,7 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({ performer,
|
||||
? queryableScrapers.map(s => (
|
||||
<Button
|
||||
variant="link"
|
||||
onClick={() =>
|
||||
onDisplayFreeOnesDialog(s)
|
||||
}
|
||||
onClick={() => onDisplayFreeOnesDialog(s)}
|
||||
>
|
||||
{s.name}
|
||||
</Button>
|
||||
@@ -299,15 +309,30 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({ performer,
|
||||
if (isEditing) {
|
||||
return (
|
||||
<>
|
||||
<Button className="edit-button" variant="primary" onClick={() => onSave?.(getPerformerInput())}>Save</Button>
|
||||
{!isNew ? <Button className="edit-button" variant="danger" onClick={() => setIsDeleteAlertOpen(true)}>Delete</Button> : ''}
|
||||
<Button
|
||||
className="edit-button"
|
||||
variant="primary"
|
||||
onClick={() => onSave?.(getPerformerInput())}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
{!isNew ? (
|
||||
<Button
|
||||
className="edit-button"
|
||||
variant="danger"
|
||||
onClick={() => setIsDeleteAlertOpen(true)}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
{renderScraperMenu()}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function renderDeleteAlert() {
|
||||
return (
|
||||
<Modal
|
||||
@@ -316,34 +341,50 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({ performer,
|
||||
accept={{ text: "Delete", variant: "danger", onClick: onDelete }}
|
||||
cancel={{ onClick: () => setIsDeleteAlertOpen(false) }}
|
||||
>
|
||||
<p>
|
||||
Are you sure you want to delete {name}?
|
||||
</p>
|
||||
<p>Are you sure you want to delete {name}?</p>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
function renderImageInput() {
|
||||
if (!isEditing) { return; }
|
||||
if (!isEditing) {
|
||||
return;
|
||||
}
|
||||
return (
|
||||
<tr>
|
||||
<td>Image</td>
|
||||
<td><Form.Control type="file" onChange={onImageChangeHandler} accept=".jpg,.jpeg" /></td>
|
||||
<td>
|
||||
<Form.Control
|
||||
type="file"
|
||||
onChange={onImageChangeHandler}
|
||||
accept=".jpg,.jpeg"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function maybeRenderName() {
|
||||
if (isEditing) {
|
||||
return TableUtils.renderInputGroup(
|
||||
{title: "Name", value: name, isEditing: !!isEditing, placeholder: "Name", onChange: setName});
|
||||
return TableUtils.renderInputGroup({
|
||||
title: "Name",
|
||||
value: name,
|
||||
isEditing: !!isEditing,
|
||||
placeholder: "Name",
|
||||
onChange: setName
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function maybeRenderAliases() {
|
||||
if (isEditing) {
|
||||
return TableUtils.renderInputGroup(
|
||||
{title: "Aliases", value: aliases, isEditing: !!isEditing, placeholder: "Aliases", onChange: setAliases});
|
||||
return TableUtils.renderInputGroup({
|
||||
title: "Aliases",
|
||||
value: aliases,
|
||||
isEditing: !!isEditing,
|
||||
placeholder: "Aliases",
|
||||
onChange: setAliases
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import {
|
||||
Button,
|
||||
} from "react-bootstrap";
|
||||
import { Button } from "react-bootstrap";
|
||||
import React from "react";
|
||||
import * as GQL from "src/core/generated-graphql";
|
||||
import { StashService } from "src/core/StashService";
|
||||
import { useToast } from "src/hooks";
|
||||
|
||||
interface IPerformerOperationsProps {
|
||||
performer: Partial<GQL.PerformerDataFragment>
|
||||
performer: Partial<GQL.PerformerDataFragment>;
|
||||
}
|
||||
|
||||
export const PerformerOperationsPanel: React.FC<IPerformerOperationsProps> = ({ performer }) => {
|
||||
export const PerformerOperationsPanel: React.FC<IPerformerOperationsProps> = ({
|
||||
performer
|
||||
}) => {
|
||||
const Toast = useToast();
|
||||
|
||||
async function onAutoTag() {
|
||||
|
||||
@@ -5,25 +5,30 @@ import { ListFilterModel } from "src/models/list-filter/filter";
|
||||
import { SceneList } from "../../scenes/SceneList";
|
||||
|
||||
interface IPerformerDetailsProps {
|
||||
performer: Partial<GQL.PerformerDataFragment>
|
||||
performer: Partial<GQL.PerformerDataFragment>;
|
||||
}
|
||||
|
||||
export const PerformerScenesPanel: React.FC<IPerformerDetailsProps> = ({ performer }) => {
|
||||
|
||||
export const PerformerScenesPanel: React.FC<IPerformerDetailsProps> = ({
|
||||
performer
|
||||
}) => {
|
||||
function filterHook(filter: ListFilterModel) {
|
||||
const performerValue = { id: performer.id!, label: performer.name! };
|
||||
// if performers is already present, then we modify it, otherwise add
|
||||
let performerCriterion = filter.criteria.find((c) => {
|
||||
let performerCriterion = filter.criteria.find(c => {
|
||||
return c.type === "performers";
|
||||
});
|
||||
|
||||
if (performerCriterion &&
|
||||
if (
|
||||
performerCriterion &&
|
||||
(performerCriterion.modifier === GQL.CriterionModifier.IncludesAll ||
|
||||
performerCriterion.modifier === GQL.CriterionModifier.Includes)) {
|
||||
performerCriterion.modifier === GQL.CriterionModifier.Includes)
|
||||
) {
|
||||
// add the performer if not present
|
||||
if (!performerCriterion.value.find((p : any) => {
|
||||
if (
|
||||
!performerCriterion.value.find((p: any) => {
|
||||
return p.id === performer.id;
|
||||
})) {
|
||||
})
|
||||
) {
|
||||
performerCriterion.value.push(performerValue);
|
||||
}
|
||||
|
||||
@@ -38,10 +43,5 @@ export const PerformerScenesPanel: React.FC<IPerformerDetailsProps> = ({ perform
|
||||
return filter;
|
||||
}
|
||||
|
||||
return (
|
||||
<SceneList
|
||||
subComponent
|
||||
filterHook={filterHook}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return <SceneList subComponent filterHook={filterHook} />;
|
||||
};
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import _ from "lodash";
|
||||
import React from "react";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import {
|
||||
FindPerformersQueryResult,
|
||||
} from "src/core/generated-graphql";
|
||||
import { FindPerformersQueryResult } from "src/core/generated-graphql";
|
||||
import { StashService } from "src/core/StashService";
|
||||
import { usePerformersList } from "src/hooks";
|
||||
import { ListFilterModel } from "src/models/list-filter/filter";
|
||||
|
||||
@@ -24,7 +24,8 @@ export const SceneCard: React.FC<ISceneCardProps> = (
|
||||
});
|
||||
|
||||
const config = StashService.useConfiguration();
|
||||
const showStudioAsText = config?.data?.configuration.interface.showStudioAsText ?? false;
|
||||
const showStudioAsText =
|
||||
config?.data?.configuration.interface.showStudioAsText ?? false;
|
||||
|
||||
function maybeRenderRatingBanner() {
|
||||
if (!props.scene.rating) {
|
||||
@@ -221,7 +222,13 @@ export const SceneCard: React.FC<ISceneCardProps> = (
|
||||
: TextUtils.fileNameFromPath(props.scene.path)}
|
||||
</h4>
|
||||
<span>{props.scene.date}</span>
|
||||
<p>{TextUtils.truncate(props.scene.details ?? "", 100, "... (continued)")}</p>
|
||||
<p>
|
||||
{TextUtils.truncate(
|
||||
props.scene.details ?? "",
|
||||
100,
|
||||
"... (continued)"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{maybeRenderPopoverButtonGroup()}
|
||||
|
||||
@@ -57,9 +57,9 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
|
||||
const [deleteScene] = StashService.useSceneDestroy(getSceneDeleteInput());
|
||||
|
||||
useEffect(() => {
|
||||
const newQueryableScrapers = (Scrapers?.data?.listSceneScrapers ?? []).filter(s => (
|
||||
s.scene?.supported_scrapes.includes(GQL.ScrapeType.Fragment)
|
||||
));
|
||||
const newQueryableScrapers = (
|
||||
Scrapers?.data?.listSceneScrapers ?? []
|
||||
).filter(s => s.scene?.supported_scrapes.includes(GQL.ScrapeType.Fragment));
|
||||
|
||||
setQueryableScrapers(newQueryableScrapers);
|
||||
}, [Scrapers]);
|
||||
@@ -202,9 +202,7 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
|
||||
ImageUtils.onImageChange(event, onImageLoad);
|
||||
}
|
||||
|
||||
async function onScrapeClicked(
|
||||
scraper: GQL.Scraper
|
||||
) {
|
||||
async function onScrapeClicked(scraper: GQL.Scraper) {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const result = await StashService.queryScrapeScene(
|
||||
@@ -418,7 +416,11 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
|
||||
</Button>
|
||||
<Collapse in={isCoverImageOpen}>
|
||||
<div>
|
||||
<img className="scene-cover" src={coverImagePreview} alt="Scene cover" />
|
||||
<img
|
||||
className="scene-cover"
|
||||
src={coverImagePreview}
|
||||
alt="Scene cover"
|
||||
/>
|
||||
<Form.Group className="test" controlId="cover">
|
||||
<Form.Control
|
||||
type="file"
|
||||
|
||||
@@ -38,7 +38,9 @@ export const SceneFileInfoPanel: React.FC<ISceneFileInfoPanelProps> = (
|
||||
<tr>
|
||||
<td>Stream</td>
|
||||
<td>
|
||||
<a href={props.scene.paths.stream ?? ''}>{props.scene.paths.stream}</a>{" "}
|
||||
<a href={props.scene.paths.stream ?? ""}>
|
||||
{props.scene.paths.stream}
|
||||
</a>{" "}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
@@ -51,7 +53,9 @@ export const SceneFileInfoPanel: React.FC<ISceneFileInfoPanelProps> = (
|
||||
return (
|
||||
<tr>
|
||||
<td>File Size</td>
|
||||
<td>{TextUtils.fileSize(parseInt(props.scene.file.size ?? '0', 10))}</td>
|
||||
<td>
|
||||
{TextUtils.fileSize(parseInt(props.scene.file.size ?? "0", 10))}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -114,12 +114,16 @@ class SceneParserResult {
|
||||
public studioId: ParserResult<string> = new ParserResult();
|
||||
public tags: ParserResult<GQL.Tag[]> = new ParserResult();
|
||||
public tagIds: ParserResult<string[]> = new ParserResult();
|
||||
public performers: ParserResult<Partial<GQL.Performer>[]> = new ParserResult();
|
||||
public performers: ParserResult<
|
||||
Partial<GQL.Performer>[]
|
||||
> = new ParserResult();
|
||||
public performerIds: ParserResult<string[]> = new ParserResult();
|
||||
|
||||
public scene: GQL.SlimSceneDataFragment;
|
||||
|
||||
constructor(result: GQL.ParseSceneFilenamesQuery["parseSceneFilenames"]["results"][0]) {
|
||||
constructor(
|
||||
result: GQL.ParseSceneFilenamesQuery["parseSceneFilenames"]["results"][0]
|
||||
) {
|
||||
this.scene = result.scene;
|
||||
|
||||
this.id = this.scene.id;
|
||||
@@ -141,12 +145,15 @@ class SceneParserResult {
|
||||
|
||||
if (result.performer_ids) {
|
||||
this.performers.setValue(
|
||||
(result.performer_ids ?? []).map(p => ({
|
||||
(result.performer_ids ?? []).map(
|
||||
p =>
|
||||
({
|
||||
id: p,
|
||||
name: "",
|
||||
favorite: false,
|
||||
image_path: ""
|
||||
} as GQL.Performer))
|
||||
} as GQL.Performer)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -343,7 +350,9 @@ export const SceneFilenameParser: React.FC = () => {
|
||||
}, [parserInput]);
|
||||
|
||||
const parseResults = useCallback(
|
||||
(results: GQL.ParseSceneFilenamesQuery["parseSceneFilenames"]["results"]) => {
|
||||
(
|
||||
results: GQL.ParseSceneFilenamesQuery["parseSceneFilenames"]["results"]
|
||||
) => {
|
||||
if (results) {
|
||||
const result = results
|
||||
.map(r => {
|
||||
@@ -897,7 +906,9 @@ export const SceneFilenameParser: React.FC = () => {
|
||||
fieldName="Title"
|
||||
className="parser-field-title"
|
||||
parserResult={props.scene.title}
|
||||
onSetChanged={set => onTitleChanged(set, props.scene.title.value ?? undefined)}
|
||||
onSetChanged={set =>
|
||||
onTitleChanged(set, props.scene.title.value ?? undefined)
|
||||
}
|
||||
onValueChanged={value => onTitleChanged(props.scene.title.set, value)}
|
||||
renderOriginalInputField={renderOriginalInputGroup}
|
||||
renderNewInputField={renderNewInputGroup}
|
||||
@@ -907,7 +918,9 @@ export const SceneFilenameParser: React.FC = () => {
|
||||
fieldName="Date"
|
||||
className="parser-field-date"
|
||||
parserResult={props.scene.date}
|
||||
onSetChanged={set => onDateChanged(set, props.scene.date.value ?? undefined)}
|
||||
onSetChanged={set =>
|
||||
onDateChanged(set, props.scene.date.value ?? undefined)
|
||||
}
|
||||
onValueChanged={value => onDateChanged(props.scene.date.set, value)}
|
||||
renderOriginalInputField={renderOriginalInputGroup}
|
||||
renderNewInputField={renderNewInputGroup}
|
||||
@@ -919,7 +932,10 @@ export const SceneFilenameParser: React.FC = () => {
|
||||
parserResult={props.scene.performerIds}
|
||||
originalParserResult={props.scene.performers}
|
||||
onSetChanged={set =>
|
||||
onPerformerIdsChanged(set, props.scene.performerIds.value ?? undefined)
|
||||
onPerformerIdsChanged(
|
||||
set,
|
||||
props.scene.performerIds.value ?? undefined
|
||||
)
|
||||
}
|
||||
onValueChanged={value =>
|
||||
onPerformerIdsChanged(props.scene.performerIds.set, value)
|
||||
@@ -933,7 +949,9 @@ export const SceneFilenameParser: React.FC = () => {
|
||||
className="parser-field-tags"
|
||||
parserResult={props.scene.tagIds}
|
||||
originalParserResult={props.scene.tags}
|
||||
onSetChanged={set => onTagIdsChanged(set, props.scene.tagIds.value ?? undefined)}
|
||||
onSetChanged={set =>
|
||||
onTagIdsChanged(set, props.scene.tagIds.value ?? undefined)
|
||||
}
|
||||
onValueChanged={value =>
|
||||
onTagIdsChanged(props.scene.tagIds.set, value)
|
||||
}
|
||||
|
||||
@@ -19,7 +19,10 @@ interface ISceneList {
|
||||
filterHook?: (filter: ListFilterModel) => ListFilterModel;
|
||||
}
|
||||
|
||||
export const SceneList: React.FC<ISceneList> = ({ subComponent, filterHook }) => {
|
||||
export const SceneList: React.FC<ISceneList> = ({
|
||||
subComponent,
|
||||
filterHook
|
||||
}) => {
|
||||
const history = useHistory();
|
||||
const otherOperations = [
|
||||
{
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import _ from "lodash";
|
||||
import React from "react";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import {
|
||||
FindSceneMarkersQueryResult
|
||||
} from "src/core/generated-graphql";
|
||||
import { FindSceneMarkersQueryResult } from "src/core/generated-graphql";
|
||||
import { StashService } from "src/core/StashService";
|
||||
import { NavUtils } from "src/utils";
|
||||
import { useSceneMarkersList } from "src/hooks";
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import ApolloClient from "apollo-client";
|
||||
import { WebSocketLink } from "apollo-link-ws";
|
||||
import { InMemoryCache } from "apollo-cache-inmemory";
|
||||
import { HttpLink } from 'apollo-link-http';
|
||||
import { split } from 'apollo-link';
|
||||
import { HttpLink } from "apollo-link-http";
|
||||
import { split } from "apollo-link";
|
||||
import { getMainDefinition } from "apollo-utilities";
|
||||
import { ListFilterModel } from "../models/list-filter/filter";
|
||||
import * as GQL from "./generated-graphql";
|
||||
@@ -45,7 +45,10 @@ export class StashService {
|
||||
const link = split(
|
||||
({ query }) => {
|
||||
const definition = getMainDefinition(query);
|
||||
return definition.kind === "OperationDefinition" && definition.operation === "subscription";
|
||||
return (
|
||||
definition.kind === "OperationDefinition" &&
|
||||
definition.operation === "subscription"
|
||||
);
|
||||
},
|
||||
wsLink,
|
||||
httpLink
|
||||
@@ -267,7 +270,9 @@ export class StashService {
|
||||
return GQL.useAllStudiosForFilterQuery();
|
||||
}
|
||||
public static useValidGalleriesForScene(sceneId: string) {
|
||||
return GQL.useValidGalleriesForSceneQuery({ variables: { scene_id: sceneId } });
|
||||
return GQL.useValidGalleriesForSceneQuery({
|
||||
variables: { scene_id: sceneId }
|
||||
});
|
||||
}
|
||||
public static useStats() {
|
||||
return GQL.useStatsQuery();
|
||||
@@ -275,8 +280,12 @@ export class StashService {
|
||||
public static useVersion() {
|
||||
return GQL.useVersionQuery();
|
||||
}
|
||||
public static useLatestVersion() { return GQL.useLatestVersionQuery({ notifyOnNetworkStatusChange: true, errorPolicy: 'ignore' }); }
|
||||
|
||||
public static useLatestVersion() {
|
||||
return GQL.useLatestVersionQuery({
|
||||
notifyOnNetworkStatusChange: true,
|
||||
errorPolicy: "ignore"
|
||||
});
|
||||
}
|
||||
|
||||
public static useConfiguration() {
|
||||
return GQL.useConfigurationQuery();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -77,7 +77,7 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
|
||||
const [filter, setFilter] = useState<ListFilterModel>(
|
||||
new ListFilterModel(
|
||||
options.filterMode,
|
||||
options.subComponent ? '' : queryString.parse(history.location.search)
|
||||
options.subComponent ? "" : queryString.parse(history.location.search)
|
||||
)
|
||||
);
|
||||
const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
|
||||
@@ -318,8 +318,10 @@ export const useScenesList = (props: IListHookOptions<FindScenesQueryResult>) =>
|
||||
...props,
|
||||
filterMode: FilterMode.Scenes,
|
||||
useData: StashService.useFindScenes,
|
||||
getData: (result: FindScenesQueryResult) => result?.data?.findScenes?.scenes ?? [],
|
||||
getCount: (result: FindScenesQueryResult) => result?.data?.findScenes?.count ?? 0
|
||||
getData: (result: FindScenesQueryResult) =>
|
||||
result?.data?.findScenes?.scenes ?? [],
|
||||
getCount: (result: FindScenesQueryResult) =>
|
||||
result?.data?.findScenes?.count ?? 0
|
||||
});
|
||||
|
||||
export const useSceneMarkersList = (
|
||||
@@ -335,7 +337,9 @@ export const useSceneMarkersList = (
|
||||
result?.data?.findSceneMarkers?.count ?? 0
|
||||
});
|
||||
|
||||
export const useGalleriesList = (props: IListHookOptions<FindGalleriesQueryResult>) =>
|
||||
export const useGalleriesList = (
|
||||
props: IListHookOptions<FindGalleriesQueryResult>
|
||||
) =>
|
||||
useList<FindGalleriesQueryResult, GalleryDataFragment>({
|
||||
...props,
|
||||
filterMode: FilterMode.Galleries,
|
||||
@@ -346,16 +350,22 @@ export const useGalleriesList = (props: IListHookOptions<FindGalleriesQueryResul
|
||||
result?.data?.findGalleries?.count ?? 0
|
||||
});
|
||||
|
||||
export const useStudiosList = (props: IListHookOptions<FindStudiosQueryResult>) =>
|
||||
export const useStudiosList = (
|
||||
props: IListHookOptions<FindStudiosQueryResult>
|
||||
) =>
|
||||
useList<FindStudiosQueryResult, StudioDataFragment>({
|
||||
...props,
|
||||
filterMode: FilterMode.Studios,
|
||||
useData: StashService.useFindStudios,
|
||||
getData: (result: FindStudiosQueryResult) => result?.data?.findStudios?.studios ?? [],
|
||||
getCount: (result: FindStudiosQueryResult) => result?.data?.findStudios?.count ?? 0
|
||||
getData: (result: FindStudiosQueryResult) =>
|
||||
result?.data?.findStudios?.studios ?? [],
|
||||
getCount: (result: FindStudiosQueryResult) =>
|
||||
result?.data?.findStudios?.count ?? 0
|
||||
});
|
||||
|
||||
export const usePerformersList = (props: IListHookOptions<FindPerformersQueryResult>) =>
|
||||
export const usePerformersList = (
|
||||
props: IListHookOptions<FindPerformersQueryResult>
|
||||
) =>
|
||||
useList<FindPerformersQueryResult, PerformerDataFragment>({
|
||||
...props,
|
||||
filterMode: FilterMode.Performers,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable consistent-return */
|
||||
|
||||
import { CriterionModifier } from "src/core/generated-graphql";
|
||||
import { DurationUtils } from 'src/utils';
|
||||
import { DurationUtils } from "src/utils";
|
||||
import { ILabeledId, ILabeledValue } from "../types";
|
||||
|
||||
export type CriterionType =
|
||||
@@ -38,7 +38,8 @@ export abstract class Criterion<Option = any, Value = any> {
|
||||
return "Rating";
|
||||
case "resolution":
|
||||
return "Resolution";
|
||||
case "duration": return "Duration";
|
||||
case "duration":
|
||||
return "Duration";
|
||||
case "favorite":
|
||||
return "Favorite";
|
||||
case "hasMarkers":
|
||||
@@ -149,7 +150,10 @@ export abstract class Criterion<Option = any, Value = any> {
|
||||
|
||||
let valueString = "";
|
||||
|
||||
if (this.modifier !== CriterionModifier.IsNull && this.modifier !== CriterionModifier.NotNull) {
|
||||
if (
|
||||
this.modifier !== CriterionModifier.IsNull &&
|
||||
this.modifier !== CriterionModifier.NotNull
|
||||
) {
|
||||
valueString = this.getLabelValue();
|
||||
}
|
||||
|
||||
@@ -268,7 +272,7 @@ export class DurationCriterion extends Criterion<number, number> {
|
||||
Criterion.getModifierOption(CriterionModifier.Equals),
|
||||
Criterion.getModifierOption(CriterionModifier.NotEquals),
|
||||
Criterion.getModifierOption(CriterionModifier.GreaterThan),
|
||||
Criterion.getModifierOption(CriterionModifier.LessThan),
|
||||
Criterion.getModifierOption(CriterionModifier.LessThan)
|
||||
];
|
||||
public options: number[] | undefined;
|
||||
public value: number = 0;
|
||||
|
||||
@@ -2,10 +2,7 @@ import * as GQL from "src/core/generated-graphql";
|
||||
import { ILabeledId } from "../types";
|
||||
import { Criterion, CriterionType, ICriterionOption } from "./criterion";
|
||||
|
||||
export class TagsCriterion extends Criterion<
|
||||
GQL.Tag,
|
||||
ILabeledId[]
|
||||
> {
|
||||
export class TagsCriterion extends Criterion<GQL.Tag, ILabeledId[]> {
|
||||
public type: CriterionType;
|
||||
public parameterName: string;
|
||||
public modifier = GQL.CriterionModifier.IncludesAll;
|
||||
|
||||
@@ -25,7 +25,8 @@ export function makeCriteria(type: CriterionType = "none") {
|
||||
return new RatingCriterion();
|
||||
case "resolution":
|
||||
return new ResolutionCriterion();
|
||||
case "duration": return new DurationCriterion(type, type);
|
||||
case "duration":
|
||||
return new DurationCriterion(type, type);
|
||||
case "favorite":
|
||||
return new FavoriteCriterion();
|
||||
case "hasMarkers":
|
||||
@@ -41,7 +42,8 @@ export function makeCriteria(type: CriterionType = "none") {
|
||||
case "studios":
|
||||
return new StudiosCriterion();
|
||||
|
||||
case "birth_year": return new NumberCriterion(type, type);
|
||||
case "birth_year":
|
||||
return new NumberCriterion(type, type);
|
||||
case "age": {
|
||||
const ret = new NumberCriterion(type, type);
|
||||
// null/not null doesn't make sense for these criteria
|
||||
|
||||
@@ -299,7 +299,10 @@ export class ListFilterModel {
|
||||
}
|
||||
case "duration": {
|
||||
const durationCrit = criterion as DurationCriterion;
|
||||
result.duration = { value: durationCrit.value, modifier: durationCrit.modifier }
|
||||
result.duration = {
|
||||
value: durationCrit.value,
|
||||
modifier: durationCrit.modifier
|
||||
};
|
||||
break;
|
||||
}
|
||||
case "hasMarkers":
|
||||
|
||||
@@ -12,7 +12,7 @@ const secondsToString = (seconds : number) => {
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
const stringToSeconds = (v: string) => {
|
||||
if (!v) {
|
||||
@@ -43,7 +43,7 @@ const stringToSeconds = (v : string) => {
|
||||
}
|
||||
|
||||
return seconds;
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
secondsToString,
|
||||
|
||||
@@ -2,4 +2,4 @@ export { default as ImageUtils } from "./image";
|
||||
export { default as NavUtils } from "./navigation";
|
||||
export { default as TableUtils } from "./table";
|
||||
export { default as TextUtils } from "./text";
|
||||
export { default as DurationUtils } from './duration';
|
||||
export { default as DurationUtils } from "./duration";
|
||||
|
||||
@@ -55,8 +55,8 @@ const renderInputGroup = (options: {
|
||||
placeholder?: string;
|
||||
value: string | undefined;
|
||||
isEditing: boolean;
|
||||
asURL?: boolean,
|
||||
urlPrefix?: string,
|
||||
asURL?: boolean;
|
||||
urlPrefix?: string;
|
||||
onChange: (value: string) => void;
|
||||
}) => (
|
||||
<tr>
|
||||
|
||||
Reference in New Issue
Block a user