mirror of
https://github.com/stashapp/stash.git
synced 2025-12-08 09:23:38 +01:00
Prettier
This commit is contained in:
parent
a7df23c54d
commit
a43cae43c0
33 changed files with 246 additions and 194 deletions
|
|
@ -11,7 +11,7 @@
|
||||||
"lint": "yarn lint:css && yarn lint:js",
|
"lint": "yarn lint:css && yarn lint:js",
|
||||||
"lint:js": "eslint --cache src/**/*.{ts,tsx}",
|
"lint:js": "eslint --cache src/**/*.{ts,tsx}",
|
||||||
"lint:css": "stylelint 'src/**/*.scss'",
|
"lint:css": "stylelint 'src/**/*.scss'",
|
||||||
"format": "prettier --write \"src/**/*.{js,jsx,ts,tsx}\"",
|
"format": "prettier --write \"src/**/!(generated-graphql).{js,jsx,ts,tsx}\"",
|
||||||
"gqlgen": "gql-gen --config codegen.yml",
|
"gqlgen": "gql-gen --config codegen.yml",
|
||||||
"extract": "NODE_ENV=development extract-messages -l=en,de -o src/locale -d en --flat false 'src/**/!(*.test).tsx'"
|
"extract": "NODE_ENV=development extract-messages -l=en,de -o src/locale -d en --flat false 'src/**/!(*.test).tsx'"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Route, Switch } from "react-router-dom";
|
import { Route, Switch } from "react-router-dom";
|
||||||
import { IntlProvider } from 'react-intl';
|
import { IntlProvider } from "react-intl";
|
||||||
import { ToastProvider } from "src/hooks/Toast";
|
import { ToastProvider } from "src/hooks/Toast";
|
||||||
import { library } from "@fortawesome/fontawesome-svg-core";
|
import { library } from "@fortawesome/fontawesome-svg-core";
|
||||||
import { fas } from "@fortawesome/free-solid-svg-icons";
|
import { fas } from "@fortawesome/free-solid-svg-icons";
|
||||||
|
|
||||||
import locales from 'src/locale';
|
import locales from "src/locale";
|
||||||
import { StashService } from 'src/core/StashService';
|
import { StashService } from "src/core/StashService";
|
||||||
import { flattenMessages } from 'src/utils';
|
import { flattenMessages } from "src/utils";
|
||||||
import { ErrorBoundary } from "./components/ErrorBoundary";
|
import { ErrorBoundary } from "./components/ErrorBoundary";
|
||||||
import Galleries from "./components/Galleries/Galleries";
|
import Galleries from "./components/Galleries/Galleries";
|
||||||
import { MainNavbar } from "./components/MainNavbar";
|
import { MainNavbar } from "./components/MainNavbar";
|
||||||
|
|
@ -20,13 +20,12 @@ import Studios from "./components/Studios/Studios";
|
||||||
import { TagList } from "./components/Tags/TagList";
|
import { TagList } from "./components/Tags/TagList";
|
||||||
import { SceneFilenameParser } from "./components/SceneFilenameParser/SceneFilenameParser";
|
import { SceneFilenameParser } from "./components/SceneFilenameParser/SceneFilenameParser";
|
||||||
|
|
||||||
|
|
||||||
library.add(fas);
|
library.add(fas);
|
||||||
|
|
||||||
export const App: React.FC = () => {
|
export const App: React.FC = () => {
|
||||||
const config = StashService.useConfiguration();
|
const config = StashService.useConfiguration();
|
||||||
const language = config.data?.configuration?.interface?.language ?? 'en-US';
|
const language = config.data?.configuration?.interface?.language ?? "en-US";
|
||||||
const messageLanguage = language.slice(0,2);
|
const messageLanguage = language.slice(0, 2);
|
||||||
const messages = flattenMessages((locales as any)[messageLanguage]);
|
const messages = flattenMessages((locales as any)[messageLanguage]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { debounce } from "lodash";
|
import { debounce } from "lodash";
|
||||||
import React, { SyntheticEvent, useCallback, useState } from "react";
|
import React, { SyntheticEvent, useCallback, useState } from "react";
|
||||||
import { SortDirectionEnum } from 'src/core/generated-graphql';
|
import { SortDirectionEnum } from "src/core/generated-graphql";
|
||||||
import {
|
import {
|
||||||
Badge,
|
Badge,
|
||||||
Button,
|
Button,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from "react-intl";
|
||||||
import { Nav, Navbar, Button } from "react-bootstrap";
|
import { Nav, Navbar, Button } from "react-bootstrap";
|
||||||
import { IconName } from "@fortawesome/fontawesome-svg-core";
|
import { IconName } from "@fortawesome/fontawesome-svg-core";
|
||||||
import { LinkContainer } from "react-router-bootstrap";
|
import { LinkContainer } from "react-router-bootstrap";
|
||||||
|
|
@ -60,7 +60,9 @@ export const MainNavbar: React.FC = () => {
|
||||||
""
|
""
|
||||||
) : (
|
) : (
|
||||||
<LinkContainer to={path}>
|
<LinkContainer to={path}>
|
||||||
<Button variant="primary"><FormattedMessage id="new" defaultMessage="New" /></Button>
|
<Button variant="primary">
|
||||||
|
<FormattedMessage id="new" defaultMessage="New" />
|
||||||
|
</Button>
|
||||||
</LinkContainer>
|
</LinkContainer>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,12 @@ interface IPerformerCardProps {
|
||||||
ageFromDate?: string;
|
ageFromDate?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PerformerCard: React.FC<IPerformerCardProps> = (
|
export const PerformerCard: React.FC<IPerformerCardProps> = ({
|
||||||
{ performer, ageFromDate }
|
performer,
|
||||||
) => {
|
ageFromDate
|
||||||
|
}) => {
|
||||||
const age = TextUtils.age(performer.birthdate, ageFromDate);
|
const age = TextUtils.age(performer.birthdate, ageFromDate);
|
||||||
const ageString = `${age} years old${
|
const ageString = `${age} years old${ageFromDate ? " in this scene." : "."}`;
|
||||||
ageFromDate ? " in this scene." : "."
|
|
||||||
}`;
|
|
||||||
|
|
||||||
function maybeRenderFavoriteBanner() {
|
function maybeRenderFavoriteBanner() {
|
||||||
if (performer.favorite === false) {
|
if (performer.favorite === false) {
|
||||||
|
|
@ -26,12 +25,12 @@ export const PerformerCard: React.FC<IPerformerCardProps> = (
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="performer-card">
|
<Card className="performer-card">
|
||||||
<Link
|
<Link to={`/performers/${performer.id}`}>
|
||||||
to={`/performers/${performer.id}`}
|
|
||||||
>
|
|
||||||
<img
|
<img
|
||||||
className="image-thumbnail card-image"
|
className="image-thumbnail card-image"
|
||||||
alt={performer.name ?? ''} src={performer.image_path ?? ''} />
|
alt={performer.name ?? ""}
|
||||||
|
src={performer.image_path ?? ""}
|
||||||
|
/>
|
||||||
{maybeRenderFavoriteBanner()}
|
{maybeRenderFavoriteBanner()}
|
||||||
</Link>
|
</Link>
|
||||||
<div className="card-section">
|
<div className="card-section">
|
||||||
|
|
@ -39,10 +38,7 @@ export const PerformerCard: React.FC<IPerformerCardProps> = (
|
||||||
{age !== 0 ? <div className="text-muted">{ageString}</div> : ""}
|
{age !== 0 ? <div className="text-muted">{ageString}</div> : ""}
|
||||||
<div className="text-muted">
|
<div className="text-muted">
|
||||||
Stars in {performer.scene_count}{" "}
|
Stars in {performer.scene_count}{" "}
|
||||||
<Link to={NavUtils.makePerformerScenesUrl(performer)}>
|
<Link to={NavUtils.makePerformerScenesUrl(performer)}>scenes</Link>.
|
||||||
scenes
|
|
||||||
</Link>
|
|
||||||
.
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
|
||||||
|
|
@ -296,7 +296,7 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<Form.Control
|
<Form.Control
|
||||||
value={url ?? ''}
|
value={url ?? ""}
|
||||||
readOnly={!isEditing}
|
readOnly={!isEditing}
|
||||||
plaintext={!isEditing}
|
plaintext={!isEditing}
|
||||||
placeholder="URL"
|
placeholder="URL"
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,12 @@ export const PerformerListTable: React.FC<IPerformerListTableProps> = (
|
||||||
const renderPerformerRow = (performer: GQL.PerformerDataFragment) => (
|
const renderPerformerRow = (performer: GQL.PerformerDataFragment) => (
|
||||||
<tr key={performer.id}>
|
<tr key={performer.id}>
|
||||||
<td>
|
<td>
|
||||||
<Link
|
<Link to={`/performers/${performer.id}`}>
|
||||||
to={`/performers/${performer.id}`}
|
<img
|
||||||
>
|
className="image-thumbnail"
|
||||||
<img className="image-thumbnail" alt={performer.name ?? ""} src={performer.image_path ?? ''} />
|
alt={performer.name ?? ""}
|
||||||
|
src={performer.image_path ?? ""}
|
||||||
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
</td>
|
</td>
|
||||||
<td className="text-left">
|
<td className="text-left">
|
||||||
|
|
@ -29,13 +31,12 @@ export const PerformerListTable: React.FC<IPerformerListTableProps> = (
|
||||||
</Link>
|
</Link>
|
||||||
</td>
|
</td>
|
||||||
<td>{performer.aliases ? performer.aliases : ""}</td>
|
<td>{performer.aliases ? performer.aliases : ""}</td>
|
||||||
<td>{
|
<td>
|
||||||
performer.favorite && (
|
{performer.favorite && (
|
||||||
<Button disabled className="favorite">
|
<Button disabled className="favorite">
|
||||||
<Icon icon="heart" />
|
<Icon icon="heart" />
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)}
|
||||||
}
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<Link to={NavUtils.makePerformerScenesUrl(performer)}>
|
<Link to={NavUtils.makePerformerScenesUrl(performer)}>
|
||||||
|
|
|
||||||
|
|
@ -192,9 +192,7 @@ export const ParserInput: React.FC<IParserInputProps> = (
|
||||||
checked={capitalizeTitle}
|
checked={capitalizeTitle}
|
||||||
onChange={() => setCapitalizeTitle(!capitalizeTitle)}
|
onChange={() => setCapitalizeTitle(!capitalizeTitle)}
|
||||||
/>
|
/>
|
||||||
<Form.Label htmlFor="capitalize-title">
|
<Form.Label htmlFor="capitalize-title">Capitalize title</Form.Label>
|
||||||
Capitalize title
|
|
||||||
</Form.Label>
|
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
|
|
||||||
{/* TODO - mapping stuff will go here */}
|
{/* TODO - mapping stuff will go here */}
|
||||||
|
|
@ -238,7 +236,9 @@ export const ParserInput: React.FC<IParserInputProps> = (
|
||||||
className="col-1 filter-item"
|
className="col-1 filter-item"
|
||||||
>
|
>
|
||||||
{PAGE_SIZE_OPTIONS.map(val => (
|
{PAGE_SIZE_OPTIONS.map(val => (
|
||||||
<option key={val} value={val}>{val}</option>
|
<option key={val} value={val}>
|
||||||
|
{val}
|
||||||
|
</option>
|
||||||
))}
|
))}
|
||||||
</Form.Control>
|
</Form.Control>
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
|
|
|
||||||
|
|
@ -493,7 +493,9 @@ export const SceneFilenameParser: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{elements.map((name: string) => (
|
{elements.map((name: string) => (
|
||||||
<Badge key={name} variant="secondary">{name}</Badge>
|
<Badge key={name} variant="secondary">
|
||||||
|
{name}
|
||||||
|
</Badge>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
@ -591,7 +593,9 @@ export const SceneFilenameParser: React.FC = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr className="scene-parser-row">
|
<tr className="scene-parser-row">
|
||||||
<td className="text-left parser-field-filename">{props.scene.filename}</td>
|
<td className="text-left parser-field-filename">
|
||||||
|
{props.scene.filename}
|
||||||
|
</td>
|
||||||
<SceneParserField
|
<SceneParserField
|
||||||
key="title"
|
key="title"
|
||||||
fieldName="Title"
|
fieldName="Title"
|
||||||
|
|
|
||||||
|
|
@ -205,7 +205,11 @@ export class ScenePlayerImpl extends React.Component<
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return (
|
return (
|
||||||
<HotKeys keyMap={KeyMap} handlers={this.KeyHandlers} className="row scene-player">
|
<HotKeys
|
||||||
|
keyMap={KeyMap}
|
||||||
|
handlers={this.KeyHandlers}
|
||||||
|
className="row scene-player"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
id="jwplayer-container"
|
id="jwplayer-container"
|
||||||
className="w-100 col-sm-9 m-sm-auto no-gutter"
|
className="w-100 col-sm-9 m-sm-auto no-gutter"
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
export { ScenePlayer } from './ScenePlayer';
|
export { ScenePlayer } from "./ScenePlayer";
|
||||||
|
|
|
||||||
|
|
@ -66,10 +66,15 @@ export const SceneCard: React.FC<ISceneCardProps> = (
|
||||||
return (
|
return (
|
||||||
<div className="scene-studio-overlay">
|
<div className="scene-studio-overlay">
|
||||||
<Link to={`/studios/${props.scene.studio.id}`}>
|
<Link to={`/studios/${props.scene.studio.id}`}>
|
||||||
{ showStudioAsText
|
{showStudioAsText ? (
|
||||||
? props.scene.studio.name
|
props.scene.studio.name
|
||||||
: <img className="image-thumbnail" alt={props.scene.studio.name} src={props.scene.studio.image_path ?? ''} />
|
) : (
|
||||||
}
|
<img
|
||||||
|
className="image-thumbnail"
|
||||||
|
alt={props.scene.studio.name}
|
||||||
|
src={props.scene.studio.image_path ?? ""}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
@ -101,7 +106,11 @@ export const SceneCard: React.FC<ISceneCardProps> = (
|
||||||
to={`/performers/${performer.id}`}
|
to={`/performers/${performer.id}`}
|
||||||
className="performer-tag col m-auto zoom-2"
|
className="performer-tag col m-auto zoom-2"
|
||||||
>
|
>
|
||||||
<img className="image-thumbnail" alt={performer.name ?? ''} src={performer.image_path ?? ''} />
|
<img
|
||||||
|
className="image-thumbnail"
|
||||||
|
alt={performer.name ?? ""}
|
||||||
|
src={performer.image_path ?? ""}
|
||||||
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
<TagLink key={performer.id} performer={performer} className="d-block" />
|
<TagLink key={performer.id} performer={performer} className="d-block" />
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -144,7 +153,7 @@ export const SceneCard: React.FC<ISceneCardProps> = (
|
||||||
<span>{props.scene.o_counter}</span>
|
<span>{props.scene.o_counter}</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -207,15 +216,12 @@ export const SceneCard: React.FC<ISceneCardProps> = (
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{maybeRenderSceneStudioOverlay()}
|
{maybeRenderSceneStudioOverlay()}
|
||||||
<Link
|
<Link to={`/scenes/${props.scene.id}`} className="scene-card-link">
|
||||||
to={`/scenes/${props.scene.id}`}
|
|
||||||
className="scene-card-link"
|
|
||||||
>
|
|
||||||
{maybeRenderRatingBanner()}
|
{maybeRenderRatingBanner()}
|
||||||
{maybeRenderSceneSpecsOverlay()}
|
{maybeRenderSceneSpecsOverlay()}
|
||||||
<video
|
<video
|
||||||
loop
|
loop
|
||||||
className={cx('scene-card-video', { portrait: isPortrait() })}
|
className={cx("scene-card-video", { portrait: isPortrait() })}
|
||||||
poster={props.scene.paths.screenshot || ""}
|
poster={props.scene.paths.screenshot || ""}
|
||||||
ref={videoHoverHook.videoEl}
|
ref={videoHoverHook.videoEl}
|
||||||
>
|
>
|
||||||
|
|
@ -229,13 +235,9 @@ export const SceneCard: React.FC<ISceneCardProps> = (
|
||||||
: TextUtils.fileNameFromPath(props.scene.path)}
|
: TextUtils.fileNameFromPath(props.scene.path)}
|
||||||
</h5>
|
</h5>
|
||||||
<span>{props.scene.date}</span>
|
<span>{props.scene.date}</span>
|
||||||
{ props.scene.details && (
|
{props.scene.details && (
|
||||||
<p>
|
<p>
|
||||||
{TextUtils.truncate(
|
{TextUtils.truncate(props.scene.details, 100, "... (continued)")}
|
||||||
props.scene.details,
|
|
||||||
100,
|
|
||||||
"... (continued)"
|
|
||||||
)}
|
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,24 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Button, Spinner } from 'react-bootstrap';
|
import { Button, Spinner } from "react-bootstrap";
|
||||||
import { Icon, HoverPopover, SweatDrops } from 'src/components/Shared';
|
import { Icon, HoverPopover, SweatDrops } from "src/components/Shared";
|
||||||
|
|
||||||
export interface IOCounterButtonProps {
|
export interface IOCounterButtonProps {
|
||||||
loading: boolean
|
loading: boolean;
|
||||||
value: number
|
value: number;
|
||||||
onIncrement: () => void
|
onIncrement: () => void;
|
||||||
onDecrement: () => void
|
onDecrement: () => void;
|
||||||
onReset: () => void
|
onReset: () => void;
|
||||||
onMenuOpened?: () => void
|
onMenuOpened?: () => void;
|
||||||
onMenuClosed?: () => void
|
onMenuClosed?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const OCounterButton: React.FC<IOCounterButtonProps> = (props: IOCounterButtonProps) => {
|
export const OCounterButton: React.FC<IOCounterButtonProps> = (
|
||||||
if(props.loading)
|
props: IOCounterButtonProps
|
||||||
return <Spinner animation="border" role="status" />;
|
) => {
|
||||||
|
if (props.loading) return <Spinner animation="border" role="status" />;
|
||||||
|
|
||||||
const renderButton = () => (
|
const renderButton = () => (
|
||||||
<Button
|
<Button className="minimal" onClick={props.onIncrement} variant="secondary">
|
||||||
className="minimal"
|
|
||||||
onClick={props.onIncrement}
|
|
||||||
variant="secondary"
|
|
||||||
>
|
|
||||||
<SweatDrops />
|
<SweatDrops />
|
||||||
<span className="ml-2">{props.value}</span>
|
<span className="ml-2">{props.value}</span>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -59,9 +56,9 @@ export const OCounterButton: React.FC<IOCounterButtonProps> = (props: IOCounterB
|
||||||
onOpen={props.onMenuOpened}
|
onOpen={props.onMenuOpened}
|
||||||
onClose={props.onMenuClosed}
|
onClose={props.onMenuClosed}
|
||||||
>
|
>
|
||||||
{ renderButton() }
|
{renderButton()}
|
||||||
</HoverPopover>
|
</HoverPopover>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return renderButton();
|
return renderButton();
|
||||||
}
|
};
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,14 @@ import * as GQL from "src/core/generated-graphql";
|
||||||
import { StashService } from "src/core/StashService";
|
import { StashService } from "src/core/StashService";
|
||||||
import { GalleryViewer } from "src/components/Galleries/GalleryViewer";
|
import { GalleryViewer } from "src/components/Galleries/GalleryViewer";
|
||||||
import { LoadingIndicator } from "src/components/Shared";
|
import { LoadingIndicator } from "src/components/Shared";
|
||||||
import { useToast } from 'src/hooks';
|
import { useToast } from "src/hooks";
|
||||||
import { ScenePlayer } from "src/components/ScenePlayer";
|
import { ScenePlayer } from "src/components/ScenePlayer";
|
||||||
import { ScenePerformerPanel } from "./ScenePerformerPanel";
|
import { ScenePerformerPanel } from "./ScenePerformerPanel";
|
||||||
import { SceneMarkersPanel } from "./SceneMarkersPanel";
|
import { SceneMarkersPanel } from "./SceneMarkersPanel";
|
||||||
import { SceneFileInfoPanel } from "./SceneFileInfoPanel";
|
import { SceneFileInfoPanel } from "./SceneFileInfoPanel";
|
||||||
import { SceneEditPanel } from "./SceneEditPanel";
|
import { SceneEditPanel } from "./SceneEditPanel";
|
||||||
import { SceneDetailPanel } from "./SceneDetailPanel";
|
import { SceneDetailPanel } from "./SceneDetailPanel";
|
||||||
import { OCounterButton } from './OCounterButton';
|
import { OCounterButton } from "./OCounterButton";
|
||||||
|
|
||||||
export const Scene: React.FC = () => {
|
export const Scene: React.FC = () => {
|
||||||
const { id = "new" } = useParams();
|
const { id = "new" } = useParams();
|
||||||
|
|
@ -48,46 +48,43 @@ export const Scene: React.FC = () => {
|
||||||
const modifiedScene = { ...scene } as GQL.SceneDataFragment;
|
const modifiedScene = { ...scene } as GQL.SceneDataFragment;
|
||||||
modifiedScene.o_counter = newValue;
|
modifiedScene.o_counter = newValue;
|
||||||
setScene(modifiedScene);
|
setScene(modifiedScene);
|
||||||
}
|
};
|
||||||
|
|
||||||
const onIncrementClick = async () => {
|
const onIncrementClick = async () => {
|
||||||
try {
|
try {
|
||||||
setOLoading(true);
|
setOLoading(true);
|
||||||
const result = await incrementO();
|
const result = await incrementO();
|
||||||
if(result.data)
|
if (result.data) updateOCounter(result.data.sceneIncrementO);
|
||||||
updateOCounter(result.data.sceneIncrementO);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Toast.error(e);
|
Toast.error(e);
|
||||||
} finally {
|
} finally {
|
||||||
setOLoading(false);
|
setOLoading(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const onDecrementClick = async () => {
|
const onDecrementClick = async () => {
|
||||||
try {
|
try {
|
||||||
setOLoading(true);
|
setOLoading(true);
|
||||||
const result = await decrementO();
|
const result = await decrementO();
|
||||||
if(result.data)
|
if (result.data) updateOCounter(result.data.sceneDecrementO);
|
||||||
updateOCounter(result.data.sceneDecrementO);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Toast.error(e);
|
Toast.error(e);
|
||||||
} finally {
|
} finally {
|
||||||
setOLoading(false);
|
setOLoading(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const onResetClick = async () => {
|
const onResetClick = async () => {
|
||||||
try {
|
try {
|
||||||
setOLoading(true);
|
setOLoading(true);
|
||||||
const result = await resetO();
|
const result = await resetO();
|
||||||
if(result.data)
|
if (result.data) updateOCounter(result.data.sceneResetO);
|
||||||
updateOCounter(result.data.sceneResetO);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Toast.error(e);
|
Toast.error(e);
|
||||||
} finally {
|
} finally {
|
||||||
setOLoading(false);
|
setOLoading(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
function onClickMarker(marker: GQL.SceneMarkerDataFragment) {
|
function onClickMarker(marker: GQL.SceneMarkerDataFragment) {
|
||||||
setTimestamp(marker.seconds);
|
setTimestamp(marker.seconds);
|
||||||
|
|
|
||||||
|
|
@ -48,9 +48,7 @@ export const SceneDetailPanel: React.FC<ISceneDetailProps> = props => {
|
||||||
</div>
|
</div>
|
||||||
<div className="col-4 offset-2">
|
<div className="col-4 offset-2">
|
||||||
{props.scene.studio && (
|
{props.scene.studio && (
|
||||||
<Link
|
<Link to={`/studios/${props.scene.studio.id}`}>
|
||||||
to={`/studios/${props.scene.studio.id}`}
|
|
||||||
>
|
|
||||||
<img
|
<img
|
||||||
src={props.scene.studio.image_path ?? ""}
|
src={props.scene.studio.image_path ?? ""}
|
||||||
alt={`${props.scene.studio.name} logo`}
|
alt={`${props.scene.studio.name} logo`}
|
||||||
|
|
|
||||||
|
|
@ -157,7 +157,12 @@ export const SceneMarkerForm: React.FC<ISceneMarkerForm> = ({
|
||||||
<Button variant="primary" type="submit">
|
<Button variant="primary" type="submit">
|
||||||
Submit
|
Submit
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="secondary" type="button" onClick={onClose} className="ml-2">
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
type="button"
|
||||||
|
onClick={onClose}
|
||||||
|
className="ml-2"
|
||||||
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
{editingMarker && (
|
{editingMarker && (
|
||||||
|
|
|
||||||
|
|
@ -11,27 +11,30 @@ interface ISceneListTableProps {
|
||||||
export const SceneListTable: React.FC<ISceneListTableProps> = (
|
export const SceneListTable: React.FC<ISceneListTableProps> = (
|
||||||
props: ISceneListTableProps
|
props: ISceneListTableProps
|
||||||
) => {
|
) => {
|
||||||
const renderTags = (tags: GQL.Tag[]) => (
|
const renderTags = (tags: GQL.Tag[]) =>
|
||||||
tags.map(tag => (
|
tags.map(tag => (
|
||||||
<Link key={tag.id} to={NavUtils.makeTagScenesUrl(tag)}>
|
<Link key={tag.id} to={NavUtils.makeTagScenesUrl(tag)}>
|
||||||
<h6>{tag.name}</h6>
|
<h6>{tag.name}</h6>
|
||||||
</Link>
|
</Link>
|
||||||
))
|
));
|
||||||
);
|
|
||||||
|
|
||||||
const renderPerformers = (performers: Partial<GQL.Performer>[]) => (
|
const renderPerformers = (performers: Partial<GQL.Performer>[]) =>
|
||||||
performers.map(performer => (
|
performers.map(performer => (
|
||||||
<Link key={performer.id} to={NavUtils.makePerformerScenesUrl(performer)} />
|
<Link
|
||||||
))
|
key={performer.id}
|
||||||
);
|
to={NavUtils.makePerformerScenesUrl(performer)}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
|
||||||
const renderSceneRow = (scene: GQL.SlimSceneDataFragment) => (
|
const renderSceneRow = (scene: GQL.SlimSceneDataFragment) => (
|
||||||
<tr key={scene.id}>
|
<tr key={scene.id}>
|
||||||
<td>
|
<td>
|
||||||
<Link
|
<Link to={`/scenes/${scene.id}`}>
|
||||||
to={`/scenes/${scene.id}`}
|
<img
|
||||||
>
|
className="image-thumbnail"
|
||||||
<img className="image-thumbnail" alt={scene.title ?? ''} src={scene.paths.screenshot ?? ''} />
|
alt={scene.title ?? ""}
|
||||||
|
src={scene.paths.screenshot ?? ""}
|
||||||
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
</td>
|
</td>
|
||||||
<td className="text-left">
|
<td className="text-left">
|
||||||
|
|
@ -42,17 +45,21 @@ export const SceneListTable: React.FC<ISceneListTableProps> = (
|
||||||
</Link>
|
</Link>
|
||||||
</td>
|
</td>
|
||||||
<td>{scene.rating ? scene.rating : ""}</td>
|
<td>{scene.rating ? scene.rating : ""}</td>
|
||||||
<td>{scene.file.duration && TextUtils.secondsToTimestamp(scene.file.duration) }</td>
|
<td>
|
||||||
|
{scene.file.duration &&
|
||||||
|
TextUtils.secondsToTimestamp(scene.file.duration)}
|
||||||
|
</td>
|
||||||
<td>{renderTags(scene.tags)}</td>
|
<td>{renderTags(scene.tags)}</td>
|
||||||
<td>{renderPerformers(scene.performers)}</td>
|
<td>{renderPerformers(scene.performers)}</td>
|
||||||
<td>{ scene.studio && (
|
<td>
|
||||||
<Link to={NavUtils.makeStudioScenesUrl(scene.studio)}>
|
{scene.studio && (
|
||||||
<h6>{scene.studio.name}</h6>
|
<Link to={NavUtils.makeStudioScenesUrl(scene.studio)}>
|
||||||
</Link>
|
<h6>{scene.studio.name}</h6>
|
||||||
)}
|
</Link>
|
||||||
|
)}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
)
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="row table-list col col-lg-8 mx-auto">
|
<div className="row table-list col col-lg-8 mx-auto">
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ export const SettingsInterfacePanel: React.FC = () => {
|
||||||
const [showStudioAsText, setShowStudioAsText] = useState<boolean>(false);
|
const [showStudioAsText, setShowStudioAsText] = useState<boolean>(false);
|
||||||
const [css, setCSS] = useState<string>();
|
const [css, setCSS] = useState<string>();
|
||||||
const [cssEnabled, setCSSEnabled] = useState<boolean>(false);
|
const [cssEnabled, setCSSEnabled] = useState<boolean>(false);
|
||||||
const [language, setLanguage] = useState<string>('en');
|
const [language, setLanguage] = useState<string>("en");
|
||||||
|
|
||||||
const [updateInterfaceConfig] = StashService.useConfigureInterface({
|
const [updateInterfaceConfig] = StashService.useConfigureInterface({
|
||||||
soundOnPreview,
|
soundOnPreview,
|
||||||
|
|
@ -36,7 +36,7 @@ export const SettingsInterfacePanel: React.FC = () => {
|
||||||
setShowStudioAsText(iCfg?.showStudioAsText ?? false);
|
setShowStudioAsText(iCfg?.showStudioAsText ?? false);
|
||||||
setCSS(iCfg?.css ?? "");
|
setCSS(iCfg?.css ?? "");
|
||||||
setCSSEnabled(iCfg?.cssEnabled ?? false);
|
setCSSEnabled(iCfg?.cssEnabled ?? false);
|
||||||
setLanguage(iCfg?.language ?? 'en-US');
|
setLanguage(iCfg?.language ?? "en-US");
|
||||||
}, [config]);
|
}, [config]);
|
||||||
|
|
||||||
async function onSave() {
|
async function onSave() {
|
||||||
|
|
@ -50,10 +50,8 @@ export const SettingsInterfacePanel: React.FC = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(error)
|
if (error) return <h1>{error.message}</h1>;
|
||||||
return <h1>{error.message}</h1>;
|
if (loading) return <LoadingIndicator />;
|
||||||
if(loading)
|
|
||||||
return <LoadingIndicator />;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -64,7 +62,9 @@ export const SettingsInterfacePanel: React.FC = () => {
|
||||||
as="select"
|
as="select"
|
||||||
className="col-4"
|
className="col-4"
|
||||||
value={language}
|
value={language}
|
||||||
onChange={(e:React.FormEvent<HTMLSelectElement>) => setLanguage(e.currentTarget.value)}
|
onChange={(e: React.FormEvent<HTMLSelectElement>) =>
|
||||||
|
setLanguage(e.currentTarget.value)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<option value="en-US">English (United States)</option>
|
<option value="en-US">English (United States)</option>
|
||||||
<option value="en-GB">English (United Kingdom)</option>
|
<option value="en-GB">English (United Kingdom)</option>
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ export const HoverPopover: React.FC<IHoverPopover> = ({
|
||||||
const handleMouseEnter = useCallback(() => {
|
const handleMouseEnter = useCallback(() => {
|
||||||
window.clearTimeout(leaveTimer.current);
|
window.clearTimeout(leaveTimer.current);
|
||||||
enterTimer.current = window.setTimeout(() => {
|
enterTimer.current = window.setTimeout(() => {
|
||||||
setShow(true)
|
setShow(true);
|
||||||
onOpen?.();
|
onOpen?.();
|
||||||
}, enterDelay);
|
}, enterDelay);
|
||||||
}, [enterDelay, onOpen]);
|
}, [enterDelay, onOpen]);
|
||||||
|
|
@ -37,7 +37,7 @@ export const HoverPopover: React.FC<IHoverPopover> = ({
|
||||||
const handleMouseLeave = useCallback(() => {
|
const handleMouseLeave = useCallback(() => {
|
||||||
window.clearTimeout(enterTimer.current);
|
window.clearTimeout(enterTimer.current);
|
||||||
leaveTimer.current = window.setTimeout(() => {
|
leaveTimer.current = window.setTimeout(() => {
|
||||||
setShow(false)
|
setShow(false);
|
||||||
onClose?.();
|
onClose?.();
|
||||||
}, leaveDelay);
|
}, leaveDelay);
|
||||||
}, [leaveDelay, onClose]);
|
}, [leaveDelay, onClose]);
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,11 @@ interface IIcon {
|
||||||
}
|
}
|
||||||
|
|
||||||
const Icon: React.FC<IIcon> = ({ icon, className, color }) => (
|
const Icon: React.FC<IIcon> = ({ icon, className, color }) => (
|
||||||
<FontAwesomeIcon icon={icon} className={`fa-icon ${className}`} color={color} />
|
<FontAwesomeIcon
|
||||||
|
icon={icon}
|
||||||
|
className={`fa-icon ${className}`}
|
||||||
|
color={color}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
export default Icon;
|
export default Icon;
|
||||||
|
|
|
||||||
|
|
@ -343,7 +343,7 @@ const SelectComponent: React.FC<ISelectProps & ITypeProps> = ({
|
||||||
}),
|
}),
|
||||||
multiValueRemove: (base: CSSProperties, state: any) => ({
|
multiValueRemove: (base: CSSProperties, state: any) => ({
|
||||||
...base,
|
...base,
|
||||||
color: state.isFocused ? base.color: '#333333'
|
color: state.isFocused ? base.color : "#333333"
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,22 @@
|
||||||
import React from 'react';
|
import React from "react";
|
||||||
|
|
||||||
export const SweatDrops = () => (
|
export const SweatDrops = () => (
|
||||||
<span>
|
<span>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="1em" height="1em" style={{transform: "rotate(360deg)"}} preserveAspectRatio="xMidYMid meet" viewBox="0 0 36 36">
|
<svg
|
||||||
<path fill="currentColor" d="M22.855.758L7.875 7.024l12.537 9.733c2.633 2.224 6.377 2.937 9.77 1.518c4.826-2.018 7.096-7.576 5.072-12.413C33.232 1.024 27.68-1.261 22.855.758zm-9.962 17.924L2.05 10.284L.137 23.529a7.993 7.993 0 0 0 2.958 7.803a8.001 8.001 0 0 0 9.798-12.65zm15.339 7.015l-8.156-4.69l-.033 9.223c-.088 2 .904 3.98 2.75 5.041a5.462 5.462 0 0 0 7.479-2.051c1.499-2.644.589-6.013-2.04-7.523z" />
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||||
|
aria-hidden="true"
|
||||||
|
focusable="false"
|
||||||
|
width="1em"
|
||||||
|
height="1em"
|
||||||
|
style={{ transform: "rotate(360deg)" }}
|
||||||
|
preserveAspectRatio="xMidYMid meet"
|
||||||
|
viewBox="0 0 36 36"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill="currentColor"
|
||||||
|
d="M22.855.758L7.875 7.024l12.537 9.733c2.633 2.224 6.377 2.937 9.77 1.518c4.826-2.018 7.096-7.576 5.072-12.413C33.232 1.024 27.68-1.261 22.855.758zm-9.962 17.924L2.05 10.284L.137 23.529a7.993 7.993 0 0 0 2.958 7.803a8.001 8.001 0 0 0 9.798-12.65zm15.339 7.015l-8.156-4.69l-.033 9.223c-.088 2 .904 3.98 2.75 5.041a5.462 5.462 0 0 0 7.479-2.051c1.499-2.644.589-6.013-2.04-7.523z"
|
||||||
|
/>
|
||||||
<rect x="0" y="0" width="36" height="36" fill="rgba(0, 0, 0, 0)" />
|
<rect x="0" y="0" width="36" height="36" fill="rgba(0, 0, 0, 0)" />
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
||||||
|
|
@ -16,4 +16,4 @@ export { TagLink } from "./TagLink";
|
||||||
export { HoverPopover } from "./HoverPopover";
|
export { HoverPopover } from "./HoverPopover";
|
||||||
export { default as LoadingIndicator } from "./LoadingIndicator";
|
export { default as LoadingIndicator } from "./LoadingIndicator";
|
||||||
export { ImageInput } from "./ImageInput";
|
export { ImageInput } from "./ImageInput";
|
||||||
export { SweatDrops } from './SweatDrops';
|
export { SweatDrops } from "./SweatDrops";
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { StashService } from "src/core/StashService";
|
import { StashService } from "src/core/StashService";
|
||||||
import { FormattedMessage, FormattedNumber } from 'react-intl';
|
import { FormattedMessage, FormattedNumber } from "react-intl";
|
||||||
import { LoadingIndicator } from "src/components/Shared";
|
import { LoadingIndicator } from "src/components/Shared";
|
||||||
|
|
||||||
export const Stats: React.FC = () => {
|
export const Stats: React.FC = () => {
|
||||||
|
|
@ -17,9 +17,7 @@ export const Stats: React.FC = () => {
|
||||||
<div className="flex-grow-1">
|
<div className="flex-grow-1">
|
||||||
<div>
|
<div>
|
||||||
<p className="heading">
|
<p className="heading">
|
||||||
<FormattedMessage
|
<FormattedMessage id="scenes" defaultMessage="Scenes" />
|
||||||
id="scenes"
|
|
||||||
defaultMessage="Scenes" />
|
|
||||||
</p>
|
</p>
|
||||||
<p className="title">
|
<p className="title">
|
||||||
<FormattedNumber value={data.stats.scene_count} />
|
<FormattedNumber value={data.stats.scene_count} />
|
||||||
|
|
@ -29,9 +27,7 @@ export const Stats: React.FC = () => {
|
||||||
<div className="flex-grow-1">
|
<div className="flex-grow-1">
|
||||||
<div>
|
<div>
|
||||||
<p className="heading">
|
<p className="heading">
|
||||||
<FormattedMessage
|
<FormattedMessage id="galleries" defaultMessage="Galleries" />
|
||||||
id="galleries"
|
|
||||||
defaultMessage="Galleries" />
|
|
||||||
</p>
|
</p>
|
||||||
<p className="title">
|
<p className="title">
|
||||||
<FormattedNumber value={data.stats.gallery_count} />
|
<FormattedNumber value={data.stats.gallery_count} />
|
||||||
|
|
@ -41,9 +37,7 @@ export const Stats: React.FC = () => {
|
||||||
<div className="flex-grow-1">
|
<div className="flex-grow-1">
|
||||||
<div>
|
<div>
|
||||||
<p className="heading">
|
<p className="heading">
|
||||||
<FormattedMessage
|
<FormattedMessage id="performers" defaultMessage="Performers" />
|
||||||
id="performers"
|
|
||||||
defaultMessage="Performers" />
|
|
||||||
</p>
|
</p>
|
||||||
<p className="title">
|
<p className="title">
|
||||||
<FormattedNumber value={data.stats.performer_count} />
|
<FormattedNumber value={data.stats.performer_count} />
|
||||||
|
|
@ -53,9 +47,7 @@ export const Stats: React.FC = () => {
|
||||||
<div className="flex-grow-1">
|
<div className="flex-grow-1">
|
||||||
<div>
|
<div>
|
||||||
<p className="heading">
|
<p className="heading">
|
||||||
<FormattedMessage
|
<FormattedMessage id="studios" defaultMessage="Studios" />
|
||||||
id="studios"
|
|
||||||
defaultMessage="Studios" />
|
|
||||||
</p>
|
</p>
|
||||||
<p className="title">
|
<p className="title">
|
||||||
<FormattedNumber value={data.stats.studio_count} />
|
<FormattedNumber value={data.stats.studio_count} />
|
||||||
|
|
@ -65,9 +57,7 @@ export const Stats: React.FC = () => {
|
||||||
<div className="flex-grow-1">
|
<div className="flex-grow-1">
|
||||||
<div>
|
<div>
|
||||||
<p className="heading">
|
<p className="heading">
|
||||||
<FormattedMessage
|
<FormattedMessage id="tags" defaultMessage="Tags" />
|
||||||
id="tags"
|
|
||||||
defaultMessage="Tags" />
|
|
||||||
</p>
|
</p>
|
||||||
<p className="title">
|
<p className="title">
|
||||||
<FormattedNumber value={data.stats.tag_count} />
|
<FormattedNumber value={data.stats.tag_count} />
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,11 @@ export const StudioCard: React.FC<IProps> = ({ studio }) => {
|
||||||
return (
|
return (
|
||||||
<Card className="studio-card">
|
<Card className="studio-card">
|
||||||
<Link to={`/studios/${studio.id}`} className="studio-card-header">
|
<Link to={`/studios/${studio.id}`} className="studio-card-header">
|
||||||
<img className="studio-card-image" alt={studio.name} src={studio.image_path ?? ""} />
|
<img
|
||||||
|
className="studio-card-image"
|
||||||
|
alt={studio.name}
|
||||||
|
src={studio.image_path ?? ""}
|
||||||
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
<div className="card-section">
|
<div className="card-section">
|
||||||
<h5 className="text-truncate">{studio.name}</h5>
|
<h5 className="text-truncate">{studio.name}</h5>
|
||||||
|
|
|
||||||
|
|
@ -103,16 +103,26 @@ export const TagList: React.FC = () => {
|
||||||
{tag.name}
|
{tag.name}
|
||||||
</Button>
|
</Button>
|
||||||
<div className="ml-auto">
|
<div className="ml-auto">
|
||||||
<Button variant="secondary" className="tag-list-button" onClick={() => onAutoTag(tag)}>
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
className="tag-list-button"
|
||||||
|
onClick={() => onAutoTag(tag)}
|
||||||
|
>
|
||||||
Auto Tag
|
Auto Tag
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="secondary" className="tag-list-button">
|
<Button variant="secondary" className="tag-list-button">
|
||||||
<Link to={NavUtils.makeTagScenesUrl(tag)} className="tag-list-anchor">
|
<Link
|
||||||
|
to={NavUtils.makeTagScenesUrl(tag)}
|
||||||
|
className="tag-list-anchor"
|
||||||
|
>
|
||||||
Scenes: {tag.scene_count}
|
Scenes: {tag.scene_count}
|
||||||
</Link>
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="secondary" className="tag-list-button">
|
<Button variant="secondary" className="tag-list-button">
|
||||||
<Link to={NavUtils.makeTagSceneMarkersUrl(tag)} className="tag-list-anchor">
|
<Link
|
||||||
|
to={NavUtils.makeTagSceneMarkersUrl(tag)}
|
||||||
|
className="tag-list-anchor"
|
||||||
|
>
|
||||||
Markers: {tag.scene_marker_count}
|
Markers: {tag.scene_marker_count}
|
||||||
</Link>
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,9 @@ export const WallItem: React.FC<IWallItemProps> = (props: IWallItemProps) => {
|
||||||
)}`
|
)}`
|
||||||
);
|
);
|
||||||
const thisTags = props.sceneMarker.tags.map(tag => (
|
const thisTags = props.sceneMarker.tags.map(tag => (
|
||||||
<span key={tag.id} className="wall-tag">{tag.name}</span>
|
<span key={tag.id} className="wall-tag">
|
||||||
|
{tag.name}
|
||||||
|
</span>
|
||||||
));
|
));
|
||||||
thisTags.unshift(
|
thisTags.unshift(
|
||||||
<span key={props.sceneMarker.primary_tag.id} className="wall-tag">
|
<span key={props.sceneMarker.primary_tag.id} className="wall-tag">
|
||||||
|
|
|
||||||
|
|
@ -371,19 +371,19 @@ export class StashService {
|
||||||
|
|
||||||
public static useSceneIncrementO(id: string) {
|
public static useSceneIncrementO(id: string) {
|
||||||
return GQL.useSceneIncrementOMutation({
|
return GQL.useSceneIncrementOMutation({
|
||||||
variables: {id}
|
variables: { id }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static useSceneDecrementO(id: string) {
|
public static useSceneDecrementO(id: string) {
|
||||||
return GQL.useSceneDecrementOMutation({
|
return GQL.useSceneDecrementOMutation({
|
||||||
variables: {id}
|
variables: { id }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static useSceneResetO(id: string) {
|
public static useSceneResetO(id: string) {
|
||||||
return GQL.useSceneResetOMutation({
|
return GQL.useSceneResetOMutation({
|
||||||
variables: {id}
|
variables: { id }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import {
|
||||||
FindStudiosQueryResult,
|
FindStudiosQueryResult,
|
||||||
FindPerformersQueryResult
|
FindPerformersQueryResult
|
||||||
} from "src/core/generated-graphql";
|
} from "src/core/generated-graphql";
|
||||||
import { useInterfaceLocalForage } from 'src/hooks/LocalForage';
|
import { useInterfaceLocalForage } from "src/hooks/LocalForage";
|
||||||
import { LoadingIndicator } from "src/components/Shared";
|
import { LoadingIndicator } from "src/components/Shared";
|
||||||
import { ListFilter } from "src/components/List/ListFilter";
|
import { ListFilter } from "src/components/List/ListFilter";
|
||||||
import { Pagination } from "src/components/List/Pagination";
|
import { Pagination } from "src/components/List/Pagination";
|
||||||
|
|
@ -94,19 +94,16 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
|
||||||
const items = options.getData(result);
|
const items = options.getData(result);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(!forageInitialised.current && !interfaceForage.loading) {
|
if (!forageInitialised.current && !interfaceForage.loading) {
|
||||||
forageInitialised.current = true;
|
forageInitialised.current = true;
|
||||||
|
|
||||||
// Don't use query parameters for sub-components
|
// Don't use query parameters for sub-components
|
||||||
if(options.subComponent)
|
if (options.subComponent) return;
|
||||||
return;
|
|
||||||
// Don't read localForage if page already had query parameters
|
// Don't read localForage if page already had query parameters
|
||||||
if(history.location.search)
|
if (history.location.search) return;
|
||||||
return;
|
|
||||||
|
|
||||||
const queryData = interfaceForage.data?.queries[options.filterMode];
|
const queryData = interfaceForage.data?.queries[options.filterMode];
|
||||||
if(!queryData)
|
if (!queryData) return;
|
||||||
return;
|
|
||||||
|
|
||||||
const newFilter = new ListFilterModel(
|
const newFilter = new ListFilterModel(
|
||||||
options.filterMode,
|
options.filterMode,
|
||||||
|
|
@ -119,11 +116,16 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
|
||||||
newLocation.search = queryData.filter;
|
newLocation.search = queryData.filter;
|
||||||
history.replace(newLocation);
|
history.replace(newLocation);
|
||||||
}
|
}
|
||||||
}, [interfaceForage.data, interfaceForage.loading, history, options.subComponent, options.filterMode]);
|
}, [
|
||||||
|
interfaceForage.data,
|
||||||
|
interfaceForage.loading,
|
||||||
|
history,
|
||||||
|
options.subComponent,
|
||||||
|
options.filterMode
|
||||||
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(options.subComponent)
|
if (options.subComponent) return;
|
||||||
return;
|
|
||||||
|
|
||||||
const newFilter = new ListFilterModel(
|
const newFilter = new ListFilterModel(
|
||||||
options.filterMode,
|
options.filterMode,
|
||||||
|
|
@ -131,8 +133,8 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
|
||||||
);
|
);
|
||||||
setFilter(newFilter);
|
setFilter(newFilter);
|
||||||
|
|
||||||
if(forageInitialised.current) {
|
if (forageInitialised.current) {
|
||||||
setInterfaceForage((d) => {
|
setInterfaceForage(d => {
|
||||||
const dataClone = _.cloneDeep(d);
|
const dataClone = _.cloneDeep(d);
|
||||||
dataClone!.queries[options.filterMode] = {
|
dataClone!.queries[options.filterMode] = {
|
||||||
filter: location.search,
|
filter: location.search,
|
||||||
|
|
@ -323,9 +325,9 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
let template;
|
let template;
|
||||||
if(result.loading || !forageInitialised.current) {
|
if (result.loading || !forageInitialised.current) {
|
||||||
template = <LoadingIndicator />;
|
template = <LoadingIndicator />;
|
||||||
} else if(result.error) {
|
} else if (result.error) {
|
||||||
template = <h1>{result.error.message}</h1>;
|
template = <h1>{result.error.message}</h1>;
|
||||||
} else {
|
} else {
|
||||||
template = (
|
template = (
|
||||||
|
|
|
||||||
|
|
@ -50,14 +50,17 @@ function useLocalForage(item: string): ILocalForage<ValidTypes> {
|
||||||
runAsync();
|
runAsync();
|
||||||
});
|
});
|
||||||
|
|
||||||
return {data: json, setData: setJson, error: err, loading: !loaded};
|
return { data: json, setData: setJson, error: err, loading: !loaded };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useInterfaceLocalForage(): [ILocalForage<IInterfaceConfig | undefined>, Dispatch<SetStateAction<IInterfaceConfig | undefined>>] {
|
export function useInterfaceLocalForage(): [
|
||||||
|
ILocalForage<IInterfaceConfig | undefined>,
|
||||||
|
Dispatch<SetStateAction<IInterfaceConfig | undefined>>
|
||||||
|
] {
|
||||||
const result = useLocalForage("interface");
|
const result = useLocalForage("interface");
|
||||||
|
|
||||||
let returnVal = result;
|
let returnVal = result;
|
||||||
if(!result.data?.queries) {
|
if (!result.data?.queries) {
|
||||||
returnVal = {
|
returnVal = {
|
||||||
...result,
|
...result,
|
||||||
data: {
|
data: {
|
||||||
|
|
@ -67,5 +70,5 @@ export function useInterfaceLocalForage(): [ILocalForage<IInterfaceConfig | unde
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return [returnVal, result.setData];;
|
return [returnVal, result.setData];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import en from './en.json';
|
import en from "./en.json";
|
||||||
import de from './de.json';
|
import de from "./de.json";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
en,
|
en,
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,6 @@ const DEFAULT_PARAMS = {
|
||||||
itemsPerPage: 40
|
itemsPerPage: 40
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// TODO: handle customCriteria
|
// TODO: handle customCriteria
|
||||||
export class ListFilterModel {
|
export class ListFilterModel {
|
||||||
public filterMode: FilterMode = FilterMode.Scenes;
|
public filterMode: FilterMode = FilterMode.Scenes;
|
||||||
|
|
@ -209,9 +208,10 @@ export class ListFilterModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.sortDirection = params.sortdir === "desc"
|
this.sortDirection =
|
||||||
? SortDirectionEnum.Desc
|
params.sortdir === "desc"
|
||||||
: SortDirectionEnum.Asc;
|
? SortDirectionEnum.Desc
|
||||||
|
: SortDirectionEnum.Asc;
|
||||||
if (params.disp) {
|
if (params.disp) {
|
||||||
this.displayMode = Number.parseInt(params.disp, 10);
|
this.displayMode = Number.parseInt(params.disp, 10);
|
||||||
}
|
}
|
||||||
|
|
@ -221,8 +221,7 @@ export class ListFilterModel {
|
||||||
if (params.p) {
|
if (params.p) {
|
||||||
this.currentPage = Number.parseInt(params.p, 10);
|
this.currentPage = Number.parseInt(params.p, 10);
|
||||||
}
|
}
|
||||||
if (params.items)
|
if (params.items) this.itemsPerPage = Number.parseInt(params.items, 10);
|
||||||
this.itemsPerPage = Number.parseInt(params.items, 10);
|
|
||||||
|
|
||||||
if (params.c !== undefined) {
|
if (params.c !== undefined) {
|
||||||
this.criteria = [];
|
this.criteria = [];
|
||||||
|
|
@ -249,7 +248,7 @@ export class ListFilterModel {
|
||||||
// #321 - set the random seed if it is not set
|
// #321 - set the random seed if it is not set
|
||||||
if (this.randomSeed === -1) {
|
if (this.randomSeed === -1) {
|
||||||
// generate 8-digit seed
|
// generate 8-digit seed
|
||||||
this.randomSeed = Math.floor(Math.random() * (10 ** 8));
|
this.randomSeed = Math.floor(Math.random() * 10 ** 8);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.randomSeed = -1;
|
this.randomSeed = -1;
|
||||||
|
|
@ -278,12 +277,22 @@ export class ListFilterModel {
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = {
|
const result = {
|
||||||
items: this.itemsPerPage !== DEFAULT_PARAMS.itemsPerPage ? this.itemsPerPage : undefined,
|
items:
|
||||||
|
this.itemsPerPage !== DEFAULT_PARAMS.itemsPerPage
|
||||||
|
? this.itemsPerPage
|
||||||
|
: undefined,
|
||||||
sortby: this.getSortBy(),
|
sortby: this.getSortBy(),
|
||||||
sortdir: this.sortDirection === SortDirectionEnum.Desc ? "desc" : undefined,
|
sortdir:
|
||||||
disp: this.displayMode !== DEFAULT_PARAMS.displayMode ? this.displayMode : undefined,
|
this.sortDirection === SortDirectionEnum.Desc ? "desc" : undefined,
|
||||||
|
disp:
|
||||||
|
this.displayMode !== DEFAULT_PARAMS.displayMode
|
||||||
|
? this.displayMode
|
||||||
|
: undefined,
|
||||||
q: this.searchTerm,
|
q: this.searchTerm,
|
||||||
p: this.currentPage !== DEFAULT_PARAMS.currentPage ? this.currentPage : undefined,
|
p:
|
||||||
|
this.currentPage !== DEFAULT_PARAMS.currentPage
|
||||||
|
? this.currentPage
|
||||||
|
: undefined,
|
||||||
c: encodedCriteria
|
c: encodedCriteria
|
||||||
};
|
};
|
||||||
return queryString.stringify(result, { encode: false });
|
return queryString.stringify(result, { encode: false });
|
||||||
|
|
@ -315,7 +324,10 @@ export class ListFilterModel {
|
||||||
}
|
}
|
||||||
case "o_counter": {
|
case "o_counter": {
|
||||||
const oCounterCrit = criterion as NumberCriterion;
|
const oCounterCrit = criterion as NumberCriterion;
|
||||||
result.o_counter = { value: oCounterCrit.value, modifier: oCounterCrit.modifier };
|
result.o_counter = {
|
||||||
|
value: oCounterCrit.value,
|
||||||
|
modifier: oCounterCrit.modifier
|
||||||
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "resolution": {
|
case "resolution": {
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
const flattenMessages = ((nestedMessages:any, prefix = '') => {
|
const flattenMessages = (nestedMessages: any, prefix = "") => {
|
||||||
if (nestedMessages === null) {
|
if (nestedMessages === null) {
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
return Object.keys(nestedMessages).reduce((messages, key) => {
|
return Object.keys(nestedMessages).reduce((messages, key) => {
|
||||||
const value = nestedMessages[key]
|
const value = nestedMessages[key];
|
||||||
const prefixedKey = prefix ? `${prefix}.${key}` : key
|
const prefixedKey = prefix ? `${prefix}.${key}` : key;
|
||||||
|
|
||||||
if (typeof value === 'string') {
|
if (typeof value === "string") {
|
||||||
Object.assign(messages, { [prefixedKey]: value })
|
Object.assign(messages, { [prefixedKey]: value });
|
||||||
} else {
|
} else {
|
||||||
Object.assign(messages, flattenMessages(value, prefixedKey))
|
Object.assign(messages, flattenMessages(value, prefixedKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
return messages
|
return messages;
|
||||||
}, {})
|
}, {});
|
||||||
})
|
};
|
||||||
|
|
||||||
export default flattenMessages;
|
export default flattenMessages;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue