Update prettier to v2.0.1 and enable for SCSS (#420)

This commit is contained in:
InfiniteTF
2020-04-03 01:29:33 +02:00
committed by GitHub
parent ad7bfb8dbf
commit 66cb7f4928
98 changed files with 1365 additions and 1299 deletions

View File

@@ -21,6 +21,16 @@
"warn", "warn",
{ "prefixWithI": "always" } { "prefixWithI": "always" }
], ],
"import/extensions": [
"error",
"ignorePackages",
{
"js": "never",
"jsx": "never",
"ts": "never",
"tsx": "never"
}
],
"import/named": "off", "import/named": "off",
"import/namespace": "off", "import/namespace": "off",
"import/default": "off", "import/default": "off",

View File

@@ -2,6 +2,7 @@
"plugins": [ "plugins": [
"stylelint-order" "stylelint-order"
], ],
"extends": "stylelint-config-prettier",
"rules": { "rules": {
"indentation": 2, "indentation": 2,
"at-rule-empty-line-before": [ "always", { "at-rule-empty-line-before": [ "always", {
@@ -33,7 +34,6 @@
"declaration-block-semicolon-space-before": "never", "declaration-block-semicolon-space-before": "never",
"declaration-block-single-line-max-declarations": 1, "declaration-block-single-line-max-declarations": 1,
"declaration-block-trailing-semicolon": "always", "declaration-block-trailing-semicolon": "always",
"declaration-colon-newline-after": "always-multi-line",
"declaration-colon-space-after": "always-single-line", "declaration-colon-space-after": "always-single-line",
"declaration-colon-space-before": "never", "declaration-colon-space-before": "never",
"declaration-no-important": true, "declaration-no-important": true,
@@ -61,7 +61,6 @@
"no-descending-specificity": null, "no-descending-specificity": null,
"no-invalid-double-slash-comments": true, "no-invalid-double-slash-comments": true,
"no-missing-end-of-source-newline": true, "no-missing-end-of-source-newline": true,
"number-leading-zero": "never",
"number-max-precision": 2, "number-max-precision": 2,
"number-no-trailing-zeros": true, "number-no-trailing-zeros": true,
"order/order": [ "order/order": [
@@ -87,7 +86,6 @@
"string-quotes": "double", "string-quotes": "double",
"time-min-milliseconds": 100, "time-min-milliseconds": 100,
"unit-blacklist": ["em"], "unit-blacklist": ["em"],
"value-list-comma-newline-after": "always-multi-line",
"value-list-comma-space-after": "always-single-line", "value-list-comma-space-after": "always-single-line",
"value-list-comma-space-before": "never", "value-list-comma-space-before": "never",
"value-no-vendor-prefix": true "value-no-vendor-prefix": true

View File

@@ -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/**/!(generated-graphql).{js,jsx,ts,tsx}\"", "format": "prettier --write \"src/**/!(generated-graphql).{js,jsx,ts,tsx,scss}\"",
"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'"
}, },
@@ -80,7 +80,7 @@
"@typescript-eslint/parser": "^2.16.0", "@typescript-eslint/parser": "^2.16.0",
"eslint": "^6.7.2", "eslint": "^6.7.2",
"eslint-config-airbnb-typescript": "^6.3.1", "eslint-config-airbnb-typescript": "^6.3.1",
"eslint-config-prettier": "^6.9.0", "eslint-config-prettier": "^6.10.1",
"eslint-plugin-import": "^2.20.0", "eslint-plugin-import": "^2.20.0",
"eslint-plugin-jsx-a11y": "^6.2.3", "eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-react": "^7.18.0", "eslint-plugin-react": "^7.18.0",
@@ -88,9 +88,10 @@
"extract-react-intl-messages": "^2.3.5", "extract-react-intl-messages": "^2.3.5",
"node-sass": "4.13.1", "node-sass": "4.13.1",
"postcss-safe-parser": "^4.0.1", "postcss-safe-parser": "^4.0.1",
"prettier": "1.19.1", "prettier": "2.0.2",
"react-scripts": "^3.3.1", "react-scripts": "^3.3.1",
"stylelint": "^13.0.0", "stylelint": "^13.0.0",
"stylelint-config-prettier": "^8.0.1",
"stylelint-order": "^4.0.0", "stylelint-order": "^4.0.0",
"typescript": "^3.7.5" "typescript": "^3.7.5"
} }

View File

@@ -25,7 +25,7 @@ export class ErrorBoundary extends React.Component<
public componentDidCatch(error: Error, errorInfo: ErrorInfo) { public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
this.setState({ this.setState({
error, error,
errorInfo errorInfo,
}); });
} }

View File

@@ -8,7 +8,7 @@ import { DisplayMode } from "src/models/list-filter/types";
export const GalleryList: React.FC = () => { export const GalleryList: React.FC = () => {
const listData = useGalleriesList({ const listData = useGalleriesList({
renderContent renderContent,
}); });
function renderContent( function renderContent(
@@ -31,7 +31,7 @@ export const GalleryList: React.FC = () => {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{result.data.findGalleries.galleries.map(gallery => ( {result.data.findGalleries.galleries.map((gallery) => (
<tr key={gallery.id}> <tr key={gallery.id}>
<td> <td>
<Link to={`/galleries/${gallery.id}`}> <Link to={`/galleries/${gallery.id}`}>
@@ -41,9 +41,7 @@ export const GalleryList: React.FC = () => {
className="w-100 w-sm-auto" className="w-100 w-sm-auto"
src={`${gallery.files[0].path}?thumb=true`} src={`${gallery.files[0].path}?thumb=true`}
/> />
) : ( ) : undefined}
undefined
)}
</Link> </Link>
</td> </td>
<td className="d-none d-sm-block"> <td className="d-none d-sm-block">

View File

@@ -29,14 +29,14 @@ export const GalleryViewer: FunctionComponent<IProps> = ({ gallery }) => {
setCurrentImage(currentImage + 1); setCurrentImage(currentImage + 1);
} }
const photos = gallery.files.map(file => ({ const photos = gallery.files.map((file) => ({
src: file.path ?? "", src: file.path ?? "",
caption: file.name ?? "" caption: file.name ?? "",
})); }));
const thumbs = gallery.files.map(file => ({ const thumbs = gallery.files.map((file) => ({
src: `${file.path}?thumb=true` || "", src: `${file.path}?thumb=true` || "",
width: 1, width: 1,
height: 1 height: 1,
})); }));
return ( return (

View File

@@ -7,7 +7,7 @@ import {
Criterion, Criterion,
CriterionType, CriterionType,
DurationCriterion, DurationCriterion,
CriterionValue CriterionValue,
} from "src/models/list-filter/criteria/criterion"; } from "src/models/list-filter/criteria/criterion";
import { NoneCriterion } from "src/models/list-filter/criteria/none"; import { NoneCriterion } from "src/models/list-filter/criteria/none";
import { makeCriteria } from "src/models/list-filter/criteria/utils"; import { makeCriteria } from "src/models/list-filter/criteria/utils";
@@ -118,7 +118,7 @@ export const AddFilter: React.FC<IAddFilterProps> = (
onChange={onChangedModifierSelect} onChange={onChangedModifierSelect}
value={criterion.modifier} value={criterion.modifier}
> >
{criterion.modifierOptions.map(c => ( {criterion.modifierOptions.map((c) => (
<option key={c.value} value={c.value}> <option key={c.value} value={c.value}>
{c.label} {c.label}
</option> </option>
@@ -149,15 +149,15 @@ export const AddFilter: React.FC<IAddFilterProps> = (
<FilterSelect <FilterSelect
type={criterion.type} type={criterion.type}
isMulti isMulti
onSelect={items => { onSelect={(items) => {
const newCriterion = _.cloneDeep(criterion); const newCriterion = _.cloneDeep(criterion);
newCriterion.value = items.map(i => ({ newCriterion.value = items.map((i) => ({
id: i.id, id: i.id,
label: i.name! label: i.name!,
})); }));
setCriterion(newCriterion); setCriterion(newCriterion);
}} }}
ids={criterion.value.map(labeled => labeled.id)} ids={criterion.value.map((labeled) => labeled.id)}
/> />
); );
} }
@@ -169,7 +169,7 @@ export const AddFilter: React.FC<IAddFilterProps> = (
onChange={onChangedSingleSelect} onChange={onChangedSingleSelect}
value={criterion.value.toString()} value={criterion.value.toString()}
> >
{criterion.options.map(c => ( {criterion.options.map((c) => (
<option key={c.toString()} value={c.toString()}> <option key={c.toString()} value={c.toString()}>
{c} {c}
</option> </option>
@@ -215,7 +215,7 @@ export const AddFilter: React.FC<IAddFilterProps> = (
onChange={onChangedCriteriaType} onChange={onChangedCriteriaType}
value={criterion.type} value={criterion.type}
> >
{props.filter.criterionOptions.map(c => ( {props.filter.criterionOptions.map((c) => (
<option key={c.value} value={c.value}> <option key={c.value} value={c.value}>
{c.label} {c.label}
</option> </option>

View File

@@ -9,7 +9,7 @@ import {
Form, Form,
OverlayTrigger, OverlayTrigger,
Tooltip, Tooltip,
SafeAnchor SafeAnchor,
} from "react-bootstrap"; } from "react-bootstrap";
import { Icon } from "src/components/Shared"; import { Icon } from "src/components/Shared";
@@ -106,7 +106,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
} }
function renderSortByOptions() { function renderSortByOptions() {
return props.filter.sortByOptions.map(option => ( return props.filter.sortByOptions.map((option) => (
<Dropdown.Item <Dropdown.Item
onClick={onChangeSortBy} onClick={onChangeSortBy}
key={option} key={option}
@@ -138,7 +138,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
return "Wall"; return "Wall";
} }
} }
return props.filter.displayModeOptions.map(option => ( return props.filter.displayModeOptions.map((option) => (
<OverlayTrigger <OverlayTrigger
key={option} key={option}
overlay={ overlay={
@@ -157,7 +157,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
} }
function renderFilterTags() { function renderFilterTags() {
return props.filter.criteria.map(criterion => ( return props.filter.criteria.map((criterion) => (
<Badge <Badge
className="tag-item" className="tag-item"
variant="secondary" variant="secondary"
@@ -219,7 +219,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
const options = [renderSelectAll(), renderSelectNone()]; const options = [renderSelectAll(), renderSelectNone()];
if (props.otherOperations) { if (props.otherOperations) {
props.otherOperations.forEach(o => { props.otherOperations.forEach((o) => {
options.push( options.push(
<Dropdown.Item <Dropdown.Item
key={o.text} key={o.text}
@@ -285,7 +285,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
value={props.filter.itemsPerPage.toString()} value={props.filter.itemsPerPage.toString()}
className="btn-secondary filter-item col-1 d-none d-sm-inline" className="btn-secondary filter-item col-1 d-none d-sm-inline"
> >
{PAGE_SIZE_OPTIONS.map(s => ( {PAGE_SIZE_OPTIONS.map((s) => (
<option value={s} key={s}> <option value={s} key={s}>
{s} {s}
</option> </option>

View File

@@ -12,7 +12,7 @@ export const Pagination: React.FC<IPaginationProps> = ({
itemsPerPage, itemsPerPage,
currentPage, currentPage,
totalItems, totalItems,
onChangePage onChangePage,
}) => { }) => {
const totalPages = Math.ceil(totalItems / itemsPerPage); const totalPages = Math.ceil(totalItems / itemsPerPage);
@@ -34,7 +34,7 @@ export const Pagination: React.FC<IPaginationProps> = ({
} }
const pages = [...Array(endPage + 1 - startPage).keys()].map( const pages = [...Array(endPage + 1 - startPage).keys()].map(
i => startPage + i (i) => startPage + i
); );
const calculatePageClass = (buttonPage: number) => { const calculatePageClass = (buttonPage: number) => {

View File

@@ -17,38 +17,38 @@ const menuItems: IMenuItem[] = [
{ {
icon: "play-circle", icon: "play-circle",
messageID: "scenes", messageID: "scenes",
href: "/scenes" href: "/scenes",
}, },
{ {
href: "/movies", href: "/movies",
icon: "film", icon: "film",
messageID: "movies" messageID: "movies",
}, },
{ {
href: "/scenes/markers", href: "/scenes/markers",
icon: "map-marker-alt", icon: "map-marker-alt",
messageID: "markers" messageID: "markers",
}, },
{ {
href: "/galleries", href: "/galleries",
icon: "image", icon: "image",
messageID: "galleries" messageID: "galleries",
}, },
{ {
href: "/performers", href: "/performers",
icon: "user", icon: "user",
messageID: "performers" messageID: "performers",
}, },
{ {
href: "/studios", href: "/studios",
icon: "video", icon: "video",
messageID: "studios" messageID: "studios",
}, },
{ {
href: "/tags", href: "/tags",
icon: "tag", icon: "tag",
messageID: "tags" messageID: "tags",
} },
]; ];
export const MainNavbar: React.FC = () => { export const MainNavbar: React.FC = () => {
@@ -127,7 +127,7 @@ export const MainNavbar: React.FC = () => {
<Navbar.Toggle className="order-0" /> <Navbar.Toggle className="order-0" />
<Navbar.Collapse className="order-3 order-md-1"> <Navbar.Collapse className="order-3 order-md-1">
<Nav className="mr-md-auto"> <Nav className="mr-md-auto">
{menuItems.map(i => ( {menuItems.map((i) => (
<Nav.Link eventKey={i.href} as="div" key={i.href}> <Nav.Link eventKey={i.href} as="div" key={i.href}>
<LinkContainer <LinkContainer
activeClassName="active" activeClassName="active"

View File

@@ -7,7 +7,7 @@ import cx from "classnames";
import { import {
DetailsEditNavbar, DetailsEditNavbar,
LoadingIndicator, LoadingIndicator,
Modal Modal,
} from "src/components/Shared"; } from "src/components/Shared";
import { useToast } from "src/hooks"; import { useToast } from "src/hooks";
import { Table, Form } from "react-bootstrap"; import { Table, Form } from "react-bootstrap";
@@ -117,7 +117,7 @@ export const Movie: React.FC = () => {
synopsis, synopsis,
url, url,
front_image: frontImage, front_image: frontImage,
back_image: backImage back_image: backImage,
}; };
if (!isNew) { if (!isNew) {
@@ -183,7 +183,7 @@ export const Movie: React.FC = () => {
<div className="row"> <div className="row">
<div <div
className={cx("movie-details", "col", { className={cx("movie-details", "col", {
"col ml-sm-5": !isNew "col ml-sm-5": !isNew,
})} })}
> >
{isNew && <h2>Add Movie</h2>} {isNew && <h2>Add Movie</h2>}
@@ -198,38 +198,38 @@ export const Movie: React.FC = () => {
title: "Name", title: "Name",
value: movie.name ?? "", value: movie.name ?? "",
isEditing: !!isEditing, isEditing: !!isEditing,
onChange: setName onChange: setName,
})} })}
{TableUtils.renderInputGroup({ {TableUtils.renderInputGroup({
title: "Aliases", title: "Aliases",
value: aliases, value: aliases,
isEditing, isEditing,
onChange: setAliases onChange: setAliases,
})} })}
{TableUtils.renderInputGroup({ {TableUtils.renderInputGroup({
title: "Duration", title: "Duration",
value: duration, value: duration,
isEditing, isEditing,
onChange: setDuration onChange: setDuration,
})} })}
{TableUtils.renderInputGroup({ {TableUtils.renderInputGroup({
title: "Date (YYYY-MM-DD)", title: "Date (YYYY-MM-DD)",
value: date, value: date,
isEditing, isEditing,
onChange: setDate onChange: setDate,
})} })}
{TableUtils.renderInputGroup({ {TableUtils.renderInputGroup({
title: "Director", title: "Director",
value: director, value: director,
isEditing, isEditing,
onChange: setDirector onChange: setDirector,
})} })}
{TableUtils.renderHtmlSelect({ {TableUtils.renderHtmlSelect({
title: "Rating", title: "Rating",
value: rating, value: rating,
isEditing, isEditing,
onChange: (value: string) => setRating(value), onChange: (value: string) => setRating(value),
selectOptions: ["", "1", "2", "3", "4", "5"] selectOptions: ["", "1", "2", "3", "4", "5"],
})} })}
</tbody> </tbody>
</Table> </Table>

View File

@@ -12,7 +12,7 @@ export const MovieScenesPanel: React.FC<IMovieScenesPanel> = ({ movie }) => {
function filterHook(filter: ListFilterModel) { function filterHook(filter: ListFilterModel) {
const movieValue = { id: movie.id!, label: movie.name! }; const movieValue = { id: movie.id!, label: movie.name! };
// if movie is already present, then we modify it, otherwise add // if movie is already present, then we modify it, otherwise add
let movieCriterion = filter.criteria.find(c => { let movieCriterion = filter.criteria.find((c) => {
return c.type === "movies"; return c.type === "movies";
}) as MoviesCriterion; }) as MoviesCriterion;
@@ -23,7 +23,7 @@ export const MovieScenesPanel: React.FC<IMovieScenesPanel> = ({ movie }) => {
) { ) {
// add the movie if not present // add the movie if not present
if ( if (
!movieCriterion.value.find(p => { !movieCriterion.value.find((p) => {
return p.id === movie.id; return p.id === movie.id;
}) })
) { ) {

View File

@@ -7,7 +7,7 @@ import { MovieCard } from "./MovieCard";
export const MovieList: React.FC = () => { export const MovieList: React.FC = () => {
const listData = useMoviesList({ const listData = useMoviesList({
renderContent renderContent,
}); });
function renderContent( function renderContent(
@@ -20,7 +20,7 @@ export const MovieList: React.FC = () => {
if (filter.displayMode === DisplayMode.Grid) { if (filter.displayMode === DisplayMode.Grid) {
return ( return (
<div className="row justify-content-center"> <div className="row justify-content-center">
{result.data.findMovies.movies.map(p => ( {result.data.findMovies.movies.map((p) => (
<MovieCard key={p.id} movie={p} /> <MovieCard key={p.id} movie={p} />
))} ))}
</div> </div>

View File

@@ -11,7 +11,7 @@ interface IPerformerCardProps {
export const PerformerCard: React.FC<IPerformerCardProps> = ({ export const PerformerCard: React.FC<IPerformerCardProps> = ({
performer, performer,
ageFromDate ageFromDate,
}) => { }) => {
const age = TextUtils.age(performer.birthdate, ageFromDate); const age = TextUtils.age(performer.birthdate, ageFromDate);
const ageString = `${age} years old${ageFromDate ? " in this scene." : "."}`; const ageString = `${age} years old${ageFromDate ? " in this scene." : "."}`;

View File

@@ -62,13 +62,13 @@ export const Performer: React.FC = () => {
try { try {
if (!isNew) { if (!isNew) {
const result = await updatePerformer({ const result = await updatePerformer({
variables: performerInput as GQL.PerformerUpdateInput variables: performerInput as GQL.PerformerUpdateInput,
}); });
if (result.data?.performerUpdate) if (result.data?.performerUpdate)
setPerformer(result.data?.performerUpdate); setPerformer(result.data?.performerUpdate);
} else { } else {
const result = await createPerformer({ const result = await createPerformer({
variables: performerInput as GQL.PerformerCreateInput variables: performerInput as GQL.PerformerCreateInput,
}); });
if (result.data?.performerCreate) { if (result.data?.performerCreate) {
setPerformer(result.data.performerCreate); setPerformer(result.data.performerCreate);

View File

@@ -9,7 +9,7 @@ import {
Modal, Modal,
ImageInput, ImageInput,
ScrapePerformerSuggest, ScrapePerformerSuggest,
LoadingIndicator LoadingIndicator,
} from "src/components/Shared"; } from "src/components/Shared";
import { ImageUtils, TableUtils } from "src/utils"; import { ImageUtils, TableUtils } from "src/utils";
import { useToast } from "src/hooks"; import { useToast } from "src/hooks";
@@ -33,7 +33,7 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({
isEditing, isEditing,
onSave, onSave,
onDelete, onDelete,
onImageChange onImageChange,
}) => { }) => {
const Toast = useToast(); const Toast = useToast();
@@ -93,7 +93,11 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({
setUrl(state.url ?? undefined); setUrl(state.url ?? undefined);
setTwitter(state.twitter ?? undefined); setTwitter(state.twitter ?? undefined);
setInstagram(state.instagram ?? undefined); setInstagram(state.instagram ?? undefined);
setGender(StashService.genderToString((state as GQL.PerformerDataFragment).gender ?? undefined)); setGender(
StashService.genderToString(
(state as GQL.PerformerDataFragment).gender ?? undefined
)
);
} }
function updatePerformerEditStateFromScraper( function updatePerformerEditStateFromScraper(
@@ -128,7 +132,9 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({
useEffect(() => { useEffect(() => {
const newQueryableScrapers = ( const newQueryableScrapers = (
Scrapers?.data?.listPerformerScrapers ?? [] Scrapers?.data?.listPerformerScrapers ?? []
).filter(s => s.performer?.supported_scrapes.includes(GQL.ScrapeType.Name)); ).filter((s) =>
s.performer?.supported_scrapes.includes(GQL.ScrapeType.Name)
);
setQueryableScrapers(newQueryableScrapers); setQueryableScrapers(newQueryableScrapers);
}, [Scrapers]); }, [Scrapers]);
@@ -156,7 +162,7 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({
twitter, twitter,
instagram, instagram,
image, image,
gender: StashService.stringToGender(gender) gender: StashService.stringToGender(gender),
}; };
if (!isNew) { if (!isNew) {
@@ -226,7 +232,7 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({
value: ethnicity, value: ethnicity,
isEditing: !!isEditing, isEditing: !!isEditing,
placeholder: "Ethnicity", placeholder: "Ethnicity",
onChange: setEthnicity onChange: setEthnicity,
}); });
} }
@@ -240,7 +246,7 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({
<Popover.Content> <Popover.Content>
<div> <div>
{queryableScrapers {queryableScrapers
? queryableScrapers.map(s => ( ? queryableScrapers.map((s) => (
<div key={s.name}> <div key={s.name}>
<Button <Button
key={s.name} key={s.name}
@@ -278,7 +284,7 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({
scraperId={ scraperId={
isDisplayingScraperDialog ? isDisplayingScraperDialog.id : "" isDisplayingScraperDialog ? isDisplayingScraperDialog.id : ""
} }
onSelectPerformer={query => setScrapePerformerDetails(query)} onSelectPerformer={(query) => setScrapePerformerDetails(query)}
/> />
</div> </div>
</Modal> </Modal>
@@ -288,8 +294,8 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({
function urlScrapable(scrapedUrl: string) { function urlScrapable(scrapedUrl: string) {
return ( return (
!!scrapedUrl && !!scrapedUrl &&
(Scrapers?.data?.listPerformerScrapers ?? []).some(s => (Scrapers?.data?.listPerformerScrapers ?? []).some((s) =>
(s?.performer?.urls ?? []).some(u => scrapedUrl.includes(u)) (s?.performer?.urls ?? []).some((u) => scrapedUrl.includes(u))
) )
); );
} }
@@ -383,7 +389,7 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({
value: name, value: name,
isEditing: !!isEditing, isEditing: !!isEditing,
placeholder: "Name", placeholder: "Name",
onChange: setName onChange: setName,
}); });
} }
} }
@@ -395,7 +401,7 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({
value: aliases, value: aliases,
isEditing: !!isEditing, isEditing: !!isEditing,
placeholder: "Aliases", placeholder: "Aliases",
onChange: setAliases onChange: setAliases,
}); });
} }
} }
@@ -424,69 +430,69 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({
title: "Birthdate", title: "Birthdate",
value: birthdate, value: birthdate,
isEditing: !!isEditing, isEditing: !!isEditing,
onChange: setBirthdate onChange: setBirthdate,
})} })}
{renderEthnicity()} {renderEthnicity()}
{TableUtils.renderInputGroup({ {TableUtils.renderInputGroup({
title: "Eye Color", title: "Eye Color",
value: eyeColor, value: eyeColor,
isEditing: !!isEditing, isEditing: !!isEditing,
onChange: setEyeColor onChange: setEyeColor,
})} })}
{TableUtils.renderInputGroup({ {TableUtils.renderInputGroup({
title: "Country", title: "Country",
value: country, value: country,
isEditing: !!isEditing, isEditing: !!isEditing,
onChange: setCountry onChange: setCountry,
})} })}
{TableUtils.renderInputGroup({ {TableUtils.renderInputGroup({
title: "Height (cm)", title: "Height (cm)",
value: height, value: height,
isEditing: !!isEditing, isEditing: !!isEditing,
onChange: setHeight onChange: setHeight,
})} })}
{TableUtils.renderInputGroup({ {TableUtils.renderInputGroup({
title: "Measurements", title: "Measurements",
value: measurements, value: measurements,
isEditing: !!isEditing, isEditing: !!isEditing,
onChange: setMeasurements onChange: setMeasurements,
})} })}
{TableUtils.renderInputGroup({ {TableUtils.renderInputGroup({
title: "Fake Tits", title: "Fake Tits",
value: fakeTits, value: fakeTits,
isEditing: !!isEditing, isEditing: !!isEditing,
onChange: setFakeTits onChange: setFakeTits,
})} })}
{TableUtils.renderInputGroup({ {TableUtils.renderInputGroup({
title: "Career Length", title: "Career Length",
value: careerLength, value: careerLength,
isEditing: !!isEditing, isEditing: !!isEditing,
onChange: setCareerLength onChange: setCareerLength,
})} })}
{TableUtils.renderInputGroup({ {TableUtils.renderInputGroup({
title: "Tattoos", title: "Tattoos",
value: tattoos, value: tattoos,
isEditing: !!isEditing, isEditing: !!isEditing,
onChange: setTattoos onChange: setTattoos,
})} })}
{TableUtils.renderInputGroup({ {TableUtils.renderInputGroup({
title: "Piercings", title: "Piercings",
value: piercings, value: piercings,
isEditing: !!isEditing, isEditing: !!isEditing,
onChange: setPiercings onChange: setPiercings,
})} })}
{renderURLField()} {renderURLField()}
{TableUtils.renderInputGroup({ {TableUtils.renderInputGroup({
title: "Twitter", title: "Twitter",
value: twitter, value: twitter,
isEditing: !!isEditing, isEditing: !!isEditing,
onChange: setTwitter onChange: setTwitter,
})} })}
{TableUtils.renderInputGroup({ {TableUtils.renderInputGroup({
title: "Instagram", title: "Instagram",
value: instagram, value: instagram,
isEditing: !!isEditing, isEditing: !!isEditing,
onChange: setInstagram onChange: setInstagram,
})} })}
</tbody> </tbody>
</Table> </Table>

View File

@@ -9,7 +9,7 @@ interface IPerformerOperationsProps {
} }
export const PerformerOperationsPanel: React.FC<IPerformerOperationsProps> = ({ export const PerformerOperationsPanel: React.FC<IPerformerOperationsProps> = ({
performer performer,
}) => { }) => {
const Toast = useToast(); const Toast = useToast();

View File

@@ -9,12 +9,12 @@ interface IPerformerDetailsProps {
} }
export const PerformerScenesPanel: React.FC<IPerformerDetailsProps> = ({ export const PerformerScenesPanel: React.FC<IPerformerDetailsProps> = ({
performer performer,
}) => { }) => {
function filterHook(filter: ListFilterModel) { function filterHook(filter: ListFilterModel) {
const performerValue = { id: performer.id!, label: performer.name! }; const performerValue = { id: performer.id!, label: performer.name! };
// if performers is already present, then we modify it, otherwise add // 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"; return c.type === "performers";
}) as PerformersCriterion; }) as PerformersCriterion;
@@ -25,7 +25,7 @@ export const PerformerScenesPanel: React.FC<IPerformerDetailsProps> = ({
) { ) {
// add the performer if not present // add the performer if not present
if ( if (
!performerCriterion.value.find(p => { !performerCriterion.value.find((p) => {
return p.id === performer.id; return p.id === performer.id;
}) })
) { ) {

View File

@@ -14,13 +14,13 @@ export const PerformerList: React.FC = () => {
const otherOperations = [ const otherOperations = [
{ {
text: "Open Random", text: "Open Random",
onClick: getRandom onClick: getRandom,
} },
]; ];
const listData = usePerformersList({ const listData = usePerformersList({
otherOperations, otherOperations,
renderContent renderContent,
}); });
async function getRandom( async function getRandom(
@@ -56,7 +56,7 @@ export const PerformerList: React.FC = () => {
if (filter.displayMode === DisplayMode.Grid) { if (filter.displayMode === DisplayMode.Grid) {
return ( return (
<div className="row justify-content-center"> <div className="row justify-content-center">
{result.data.findPerformers.performers.map(p => ( {result.data.findPerformers.performers.map((p) => (
<PerformerCard key={p.id} performer={p} /> <PerformerCard key={p.id} performer={p} />
))} ))}
</div> </div>

View File

@@ -2,7 +2,7 @@
.scrape-url-button { .scrape-url-button {
color: $text-color; color: $text-color;
float: right; float: right;
margin-right: .5rem; margin-right: 0.5rem;
} }
} }
@@ -29,7 +29,7 @@
margin-left: 10px; margin-left: 10px;
.not-favorite { .not-favorite {
color: rgba(191, 204, 214, .5); color: rgba(191, 204, 214, 0.5);
} }
.favorite { .favorite {

View File

@@ -52,7 +52,7 @@ export class ParserField {
ParserField.DDMMYYYY, ParserField.DDMMYYYY,
ParserField.DDMMYY, ParserField.DDMMYY,
ParserField.MMDDYYYY, ParserField.MMDDYYYY,
ParserField.MMDDYY ParserField.MMDDYY,
]; ];
static fullDateFields = [ static fullDateFields = [
@@ -61,6 +61,6 @@ export class ParserField {
ParserField.DDMMYYYY, ParserField.DDMMYYYY,
ParserField.DDMMYY, ParserField.DDMMYY,
ParserField.MMDDYYYY, ParserField.MMDDYYYY,
ParserField.MMDDYY ParserField.MMDDYY,
]; ];
} }

View File

@@ -4,7 +4,7 @@ import {
Dropdown, Dropdown,
DropdownButton, DropdownButton,
Form, Form,
InputGroup InputGroup,
} from "react-bootstrap"; } from "react-bootstrap";
import { ParserField } from "./ParserField"; import { ParserField } from "./ParserField";
import { ShowFields } from "./ShowFields"; import { ShowFields } from "./ShowFields";
@@ -15,43 +15,43 @@ const builtInRecipes = [
ignoreWords: [], ignoreWords: [],
whitespaceCharacters: "", whitespaceCharacters: "",
capitalizeTitle: false, capitalizeTitle: false,
description: "Filename" description: "Filename",
}, },
{ {
pattern: "{title}.{ext}", pattern: "{title}.{ext}",
ignoreWords: [], ignoreWords: [],
whitespaceCharacters: "", whitespaceCharacters: "",
capitalizeTitle: false, capitalizeTitle: false,
description: "Without extension" description: "Without extension",
}, },
{ {
pattern: "{}.{yy}.{mm}.{dd}.{title}.XXX.{}.{ext}", pattern: "{}.{yy}.{mm}.{dd}.{title}.XXX.{}.{ext}",
ignoreWords: [], ignoreWords: [],
whitespaceCharacters: ".", whitespaceCharacters: ".",
capitalizeTitle: true, capitalizeTitle: true,
description: "" description: "",
}, },
{ {
pattern: "{}.{yy}.{mm}.{dd}.{title}.{ext}", pattern: "{}.{yy}.{mm}.{dd}.{title}.{ext}",
ignoreWords: [], ignoreWords: [],
whitespaceCharacters: ".", whitespaceCharacters: ".",
capitalizeTitle: true, capitalizeTitle: true,
description: "" description: "",
}, },
{ {
pattern: "{title}.XXX.{}.{ext}", pattern: "{title}.XXX.{}.{ext}",
ignoreWords: [], ignoreWords: [],
whitespaceCharacters: ".", whitespaceCharacters: ".",
capitalizeTitle: true, capitalizeTitle: true,
description: "" description: "",
}, },
{ {
pattern: "{}.{yy}.{mm}.{dd}.{title}.{i}.{ext}", pattern: "{}.{yy}.{mm}.{dd}.{title}.{i}.{ext}",
ignoreWords: ["cz", "fr"], ignoreWords: ["cz", "fr"],
whitespaceCharacters: ".", whitespaceCharacters: ".",
capitalizeTitle: true, capitalizeTitle: true,
description: "Foreign language" description: "Foreign language",
} },
]; ];
export interface IParserInput { export interface IParserInput {
@@ -102,7 +102,7 @@ export const ParserInput: React.FC<IParserInputProps> = (
capitalizeTitle, capitalizeTitle,
page: 1, page: 1,
pageSize: props.input.pageSize, pageSize: props.input.pageSize,
findClicked: props.input.findClicked findClicked: props.input.findClicked,
}); });
} }
@@ -139,7 +139,7 @@ export const ParserInput: React.FC<IParserInputProps> = (
/> />
<InputGroup.Append> <InputGroup.Append>
<DropdownButton id="parser-field-select" title="Add Field"> <DropdownButton id="parser-field-select" title="Add Field">
{validFields.map(item => ( {validFields.map((item) => (
<Dropdown.Item <Dropdown.Item
key={item.field} key={item.field}
onSelect={() => addParserField(item)} onSelect={() => addParserField(item)}
@@ -207,7 +207,7 @@ export const ParserInput: React.FC<IParserInputProps> = (
id="recipe-select" id="recipe-select"
title="Select Parser Recipe" title="Select Parser Recipe"
> >
{builtInRecipes.map(item => ( {builtInRecipes.map((item) => (
<Dropdown.Item <Dropdown.Item
key={item.pattern} key={item.pattern}
onSelect={() => setParserRecipe(item)} onSelect={() => setParserRecipe(item)}
@@ -222,7 +222,7 @@ export const ParserInput: React.FC<IParserInputProps> = (
<Form.Group> <Form.Group>
<ShowFields <ShowFields
fields={props.showFields} fields={props.showFields}
onShowFieldsChanged={fields => props.setShowFields(fields)} onShowFieldsChanged={(fields) => props.setShowFields(fields)}
/> />
</Form.Group> </Form.Group>
@@ -239,7 +239,7 @@ export const ParserInput: React.FC<IParserInputProps> = (
defaultValue={props.input.pageSize} defaultValue={props.input.pageSize}
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}> <option key={val} value={val}>
{val} {val}
</option> </option>

View File

@@ -19,7 +19,7 @@ const initialParserInput = {
capitalizeTitle: true, capitalizeTitle: true,
page: 1, page: 1,
pageSize: 20, pageSize: 20,
findClicked: false findClicked: false,
}; };
const initialShowFieldsState = new Map<string, boolean>([ const initialShowFieldsState = new Map<string, boolean>([
@@ -27,7 +27,7 @@ const initialShowFieldsState = new Map<string, boolean>([
["Date", true], ["Date", true],
["Performers", true], ["Performers", true],
["Tags", true], ["Tags", true],
["Studio", true] ["Studio", true],
]); ]);
export const SceneFilenameParser: React.FC = () => { export const SceneFilenameParser: React.FC = () => {
@@ -60,7 +60,7 @@ export const SceneFilenameParser: React.FC = () => {
const dateSet = const dateSet =
pattern.includes("{date}") || pattern.includes("{date}") ||
pattern.includes("{dd}") || // don't worry about other partial date fields since this should be implied pattern.includes("{dd}") || // don't worry about other partial date fields since this should be implied
ParserField.fullDateFields.some(f => { ParserField.fullDateFields.some((f) => {
return pattern.includes(`{${f.field}}`); return pattern.includes(`{${f.field}}`);
}); });
const performerSet = pattern.includes("{performer}"); const performerSet = pattern.includes("{performer}");
@@ -72,7 +72,7 @@ export const SceneFilenameParser: React.FC = () => {
["Date", dateSet], ["Date", dateSet],
["Performers", performerSet], ["Performers", performerSet],
["Tags", tagSet], ["Tags", tagSet],
["Studio", studioSet] ["Studio", studioSet],
]); ]);
setShowFields(newShowFields); setShowFields(newShowFields);
@@ -84,10 +84,10 @@ export const SceneFilenameParser: React.FC = () => {
) => { ) => {
if (results) { if (results) {
const result = results const result = results
.map(r => { .map((r) => {
return new SceneParserResult(r); return new SceneParserResult(r);
}) })
.filter(r => !!r) as SceneParserResult[]; .filter((r) => !!r) as SceneParserResult[];
setParserResult(result); setParserResult(result);
determineFieldsToHide(); determineFieldsToHide();
@@ -106,24 +106,24 @@ export const SceneFilenameParser: React.FC = () => {
page: parserInput.page, page: parserInput.page,
per_page: parserInput.pageSize, per_page: parserInput.pageSize,
sort: "path", sort: "path",
direction: GQL.SortDirectionEnum.Asc direction: GQL.SortDirectionEnum.Asc,
}; };
const parserInputData = { const parserInputData = {
ignoreWords: parserInput.ignoreWords, ignoreWords: parserInput.ignoreWords,
whitespaceCharacters: parserInput.whitespaceCharacters, whitespaceCharacters: parserInput.whitespaceCharacters,
capitalizeTitle: parserInput.capitalizeTitle capitalizeTitle: parserInput.capitalizeTitle,
}; };
StashService.queryParseSceneFilenames(parserFilter, parserInputData) StashService.queryParseSceneFilenames(parserFilter, parserInputData)
.then(response => { .then((response) => {
const result = response.data.parseSceneFilenames; const result = response.data.parseSceneFilenames;
if (result) { if (result) {
parseResults(result.results); parseResults(result.results);
setTotalItems(result.count); setTotalItems(result.count);
} }
}) })
.catch(err => Toast.error(err)) .catch((err) => Toast.error(err))
.finally(() => setIsLoading(false)); .finally(() => setIsLoading(false));
} }
}, [parserInput, parseResults, Toast]); }, [parserInput, parseResults, Toast]);
@@ -152,8 +152,8 @@ export const SceneFilenameParser: React.FC = () => {
function getScenesUpdateData() { function getScenesUpdateData() {
return parserResult return parserResult
.filter(result => result.isChanged()) .filter((result) => result.isChanged())
.map(result => result.toSceneUpdateInput()); .map((result) => result.toSceneUpdateInput());
} }
async function onApply() { async function onApply() {
@@ -170,19 +170,19 @@ export const SceneFilenameParser: React.FC = () => {
} }
useEffect(() => { useEffect(() => {
const newAllTitleSet = !parserResult.some(r => { const newAllTitleSet = !parserResult.some((r) => {
return !r.title.isSet; return !r.title.isSet;
}); });
const newAllDateSet = !parserResult.some(r => { const newAllDateSet = !parserResult.some((r) => {
return !r.date.isSet; return !r.date.isSet;
}); });
const newAllPerformerSet = !parserResult.some(r => { const newAllPerformerSet = !parserResult.some((r) => {
return !r.performers.isSet; return !r.performers.isSet;
}); });
const newAllTagSet = !parserResult.some(r => { const newAllTagSet = !parserResult.some((r) => {
return !r.tags.isSet; return !r.tags.isSet;
}); });
const newAllStudioSet = !parserResult.some(r => { const newAllStudioSet = !parserResult.some((r) => {
return !r.studio.isSet; return !r.studio.isSet;
}); });
@@ -196,7 +196,7 @@ export const SceneFilenameParser: React.FC = () => {
function onSelectAllTitleSet(selected: boolean) { function onSelectAllTitleSet(selected: boolean) {
const newResult = [...parserResult]; const newResult = [...parserResult];
newResult.forEach(r => { newResult.forEach((r) => {
r.title.isSet = selected; r.title.isSet = selected;
}); });
@@ -207,7 +207,7 @@ export const SceneFilenameParser: React.FC = () => {
function onSelectAllDateSet(selected: boolean) { function onSelectAllDateSet(selected: boolean) {
const newResult = [...parserResult]; const newResult = [...parserResult];
newResult.forEach(r => { newResult.forEach((r) => {
r.date.isSet = selected; r.date.isSet = selected;
}); });
@@ -218,7 +218,7 @@ export const SceneFilenameParser: React.FC = () => {
function onSelectAllPerformerSet(selected: boolean) { function onSelectAllPerformerSet(selected: boolean) {
const newResult = [...parserResult]; const newResult = [...parserResult];
newResult.forEach(r => { newResult.forEach((r) => {
r.performers.isSet = selected; r.performers.isSet = selected;
}); });
@@ -229,7 +229,7 @@ export const SceneFilenameParser: React.FC = () => {
function onSelectAllTagSet(selected: boolean) { function onSelectAllTagSet(selected: boolean) {
const newResult = [...parserResult]; const newResult = [...parserResult];
newResult.forEach(r => { newResult.forEach((r) => {
r.tags.isSet = selected; r.tags.isSet = selected;
}); });
@@ -240,7 +240,7 @@ export const SceneFilenameParser: React.FC = () => {
function onSelectAllStudioSet(selected: boolean) { function onSelectAllStudioSet(selected: boolean) {
const newResult = [...parserResult]; const newResult = [...parserResult];
newResult.forEach(r => { newResult.forEach((r) => {
r.studio.isSet = selected; r.studio.isSet = selected;
}); });
@@ -305,11 +305,11 @@ export const SceneFilenameParser: React.FC = () => {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{parserResult.map(scene => ( {parserResult.map((scene) => (
<SceneParserRow <SceneParserRow
scene={scene} scene={scene}
key={scene.id} key={scene.id}
onChange={changedScene => onChange(scene, changedScene)} onChange={(changedScene) => onChange(scene, changedScene)}
showFields={showFields} showFields={showFields}
/> />
))} ))}
@@ -320,7 +320,7 @@ export const SceneFilenameParser: React.FC = () => {
currentPage={parserInput.page} currentPage={parserInput.page}
itemsPerPage={parserInput.pageSize} itemsPerPage={parserInput.pageSize}
totalItems={totalItems} totalItems={totalItems}
onChangePage={page => onPageChanged(page)} onChangePage={(page) => onPageChanged(page)}
/> />
<Button variant="primary" onClick={onApply}> <Button variant="primary" onClick={onApply}>
Apply Apply
@@ -334,7 +334,7 @@ export const SceneFilenameParser: React.FC = () => {
<h4>Scene Filename Parser</h4> <h4>Scene Filename Parser</h4>
<ParserInput <ParserInput
input={parserInput} input={parserInput}
onFind={input => onFindClicked(input)} onFind={(input) => onFindClicked(input)}
onPageSizeChanged={onPageSizeChanged} onPageSizeChanged={onPageSizeChanged}
showFields={showFields} showFields={showFields}
setShowFields={setShowFields} setShowFields={setShowFields}

View File

@@ -3,12 +3,12 @@ import _ from "lodash";
import { Form } from "react-bootstrap"; import { Form } from "react-bootstrap";
import { import {
ParseSceneFilenamesQuery, ParseSceneFilenamesQuery,
SlimSceneDataFragment SlimSceneDataFragment,
} from "src/core/generated-graphql"; } from "src/core/generated-graphql";
import { import {
PerformerSelect, PerformerSelect,
TagSelect, TagSelect,
StudioSelect StudioSelect,
} from "src/components/Shared"; } from "src/components/Shared";
import { TextUtils } from "src/utils"; import { TextUtils } from "src/utils";
@@ -51,8 +51,8 @@ export class SceneParserResult {
this.filename = TextUtils.fileNameFromPath(this.scene.path); this.filename = TextUtils.fileNameFromPath(this.scene.path);
this.title.setOriginalValue(this.scene.title ?? undefined); this.title.setOriginalValue(this.scene.title ?? undefined);
this.date.setOriginalValue(this.scene.date ?? undefined); this.date.setOriginalValue(this.scene.date ?? undefined);
this.performers.setOriginalValue(this.scene.performers.map(p => p.id)); this.performers.setOriginalValue(this.scene.performers.map((p) => p.id));
this.tags.setOriginalValue(this.scene.tags.map(t => t.id)); this.tags.setOriginalValue(this.scene.tags.map((t) => t.id));
this.studio.setOriginalValue(this.scene.studio?.id); this.studio.setOriginalValue(this.scene.studio?.id);
this.title.setValue(result.title ?? undefined); this.title.setValue(result.title ?? undefined);
@@ -82,10 +82,10 @@ export class SceneParserResult {
studio_id: this.studio.isSet ? this.studio.value : this.scene.studio?.id, studio_id: this.studio.isSet ? this.studio.value : this.scene.studio?.id,
performer_ids: this.performers.isSet performer_ids: this.performers.isSet
? this.performers.value ? this.performers.value
: this.scene.performers.map(performer => performer.id), : this.scene.performers.map((performer) => performer.id),
tag_ids: this.tags.isSet tag_ids: this.tags.isSet
? this.tags.value ? this.tags.value
: this.scene.tags.map(tag => tag.id) : this.scene.tags.map((tag) => tag.id),
}; };
} }
} }
@@ -165,8 +165,8 @@ function SceneParserPerformerField(props: ISceneParserFieldProps<string[]>) {
<PerformerSelect isDisabled isMulti ids={originalPerformers} /> <PerformerSelect isDisabled isMulti ids={originalPerformers} />
<PerformerSelect <PerformerSelect
isMulti isMulti
onSelect={items => { onSelect={(items) => {
maybeValueChanged(items.map(i => i.id)); maybeValueChanged(items.map((i) => i.id));
}} }}
ids={newPerformers} ids={newPerformers}
/> />
@@ -201,8 +201,8 @@ function SceneParserTagField(props: ISceneParserFieldProps<string[]>) {
<TagSelect isDisabled isMulti ids={originalTags} /> <TagSelect isDisabled isMulti ids={originalTags} />
<TagSelect <TagSelect
isMulti isMulti
onSelect={items => { onSelect={(items) => {
maybeValueChanged(items.map(i => i.id)); maybeValueChanged(items.map((i) => i.id));
}} }}
ids={newTags} ids={newTags}
/> />
@@ -238,7 +238,7 @@ function SceneParserStudioField(props: ISceneParserFieldProps<string>) {
<Form.Group className={props.className}> <Form.Group className={props.className}>
<StudioSelect isDisabled ids={originalStudio} /> <StudioSelect isDisabled ids={originalStudio} />
<StudioSelect <StudioSelect
onSelect={items => { onSelect={(items) => {
maybeValueChanged(items[0].id); maybeValueChanged(items[0].id);
}} }}
ids={newStudio} ids={newStudio}
@@ -304,10 +304,10 @@ export const SceneParserRow = (props: ISceneParserRowProps) => {
fieldName="Title" fieldName="Title"
className="parser-field-title" className="parser-field-title"
parserResult={props.scene.title} parserResult={props.scene.title}
onSetChanged={isSet => onSetChanged={(isSet) =>
onTitleChanged(isSet, props.scene.title.value ?? "") onTitleChanged(isSet, props.scene.title.value ?? "")
} }
onValueChanged={value => onValueChanged={(value) =>
onTitleChanged(props.scene.title.isSet, value) onTitleChanged(props.scene.title.isSet, value)
} }
/> />
@@ -318,10 +318,12 @@ export const SceneParserRow = (props: ISceneParserRowProps) => {
fieldName="Date" fieldName="Date"
className="parser-field-date" className="parser-field-date"
parserResult={props.scene.date} parserResult={props.scene.date}
onSetChanged={isSet => onSetChanged={(isSet) =>
onDateChanged(isSet, props.scene.date.value ?? "") onDateChanged(isSet, props.scene.date.value ?? "")
} }
onValueChanged={value => onDateChanged(props.scene.date.isSet, value)} onValueChanged={(value) =>
onDateChanged(props.scene.date.isSet, value)
}
/> />
)} )}
{props.showFields.get("Performers") && ( {props.showFields.get("Performers") && (
@@ -331,10 +333,10 @@ export const SceneParserRow = (props: ISceneParserRowProps) => {
className="parser-field-performers" className="parser-field-performers"
parserResult={props.scene.performers} parserResult={props.scene.performers}
originalParserResult={props.scene.performers} originalParserResult={props.scene.performers}
onSetChanged={set => onSetChanged={(set) =>
onPerformerIdsChanged(set, props.scene.performers.value ?? []) onPerformerIdsChanged(set, props.scene.performers.value ?? [])
} }
onValueChanged={value => onValueChanged={(value) =>
onPerformerIdsChanged(props.scene.performers.isSet, value) onPerformerIdsChanged(props.scene.performers.isSet, value)
} }
/> />
@@ -346,10 +348,10 @@ export const SceneParserRow = (props: ISceneParserRowProps) => {
className="parser-field-tags" className="parser-field-tags"
parserResult={props.scene.tags} parserResult={props.scene.tags}
originalParserResult={props.scene.tags} originalParserResult={props.scene.tags}
onSetChanged={isSet => onSetChanged={(isSet) =>
onTagIdsChanged(isSet, props.scene.tags.value ?? []) onTagIdsChanged(isSet, props.scene.tags.value ?? [])
} }
onValueChanged={value => onValueChanged={(value) =>
onTagIdsChanged(props.scene.tags.isSet, value) onTagIdsChanged(props.scene.tags.isSet, value)
} }
/> />
@@ -361,10 +363,10 @@ export const SceneParserRow = (props: ISceneParserRowProps) => {
className="parser-field-studio" className="parser-field-studio"
parserResult={props.scene.studio} parserResult={props.scene.studio}
originalParserResult={props.scene.studio} originalParserResult={props.scene.studio}
onSetChanged={set => onSetChanged={(set) =>
onStudioIdChanged(set, props.scene.studio.value ?? "") onStudioIdChanged(set, props.scene.studio.value ?? "")
} }
onValueChanged={value => onValueChanged={(value) =>
onStudioIdChanged(props.scene.studio.isSet, value) onStudioIdChanged(props.scene.studio.isSet, value)
} }
/> />

View File

@@ -35,11 +35,11 @@
} }
.form-control + .form-control { .form-control + .form-control {
margin-top: .5rem; margin-top: 0.5rem;
} }
.badge-items { .badge-items {
background-color: #e9ecef; background-color: #e9ecef;
margin-bottom: .25rem; margin-bottom: 0.25rem;
} }
} }

View File

@@ -25,7 +25,7 @@ const KeyMap = {
NUM0: "0", NUM0: "0",
NUM1: "1", NUM1: "1",
NUM2: "2", NUM2: "2",
SPACE: " " SPACE: " ",
}; };
export class ScenePlayerImpl extends React.Component< export class ScenePlayerImpl extends React.Component<
@@ -49,7 +49,7 @@ export class ScenePlayerImpl extends React.Component<
}, },
SPACE: () => { SPACE: () => {
this.onPause(); this.onPause();
} },
}; };
constructor(props: IScenePlayerProps) { constructor(props: IScenePlayerProps) {
@@ -63,15 +63,15 @@ export class ScenePlayerImpl extends React.Component<
this.state = { this.state = {
scrubberPosition: 0, scrubberPosition: 0,
config: this.makeJWPlayerConfig(props.scene) config: this.makeJWPlayerConfig(props.scene),
}; };
} }
public UNSAFE_componentWillReceiveProps(props: IScenePlayerProps) { public UNSAFE_componentWillReceiveProps(props: IScenePlayerProps) {
if (props.scene !== this.props.scene) { if (props.scene !== this.props.scene) {
this.setState(state => ({ this.setState((state) => ({
...state, ...state,
config: this.makeJWPlayerConfig(this.props.scene) config: this.makeJWPlayerConfig(this.props.scene),
})); }));
} }
} }
@@ -177,17 +177,17 @@ export class ScenePlayerImpl extends React.Component<
tracks: [ tracks: [
{ {
file: scene.paths.vtt, file: scene.paths.vtt,
kind: "thumbnails" kind: "thumbnails",
}, },
{ {
file: scene.paths.chapters_vtt, file: scene.paths.chapters_vtt,
kind: "chapters" kind: "chapters",
} },
], ],
aspectratio: "16:9", aspectratio: "16:9",
width: "100%", width: "100%",
floating: { floating: {
dismissible: true dismissible: true,
}, },
cast: {}, cast: {},
primary: "html5", primary: "html5",
@@ -199,7 +199,7 @@ export class ScenePlayerImpl extends React.Component<
playbackRates: [0.75, 1, 1.5, 2, 3, 4], playbackRates: [0.75, 1, 1.5, 2, 3, 4],
getDurationHook, getDurationHook,
seekHook, seekHook,
getCurrentTimeHook getCurrentTimeHook,
}; };
return ret; return ret;

View File

@@ -5,7 +5,7 @@ import React, {
useEffect, useEffect,
useRef, useRef,
useState, useState,
useCallback useCallback,
} from "react"; } from "react";
import { Button } from "react-bootstrap"; import { Button } from "react-bootstrap";
import axios from "axios"; import axios from "axios";
@@ -45,10 +45,7 @@ async function fetchSpriteInfo(vttPath: string) {
const line = lines.shift(); const line = lines.shift();
if (line !== undefined) { if (line !== undefined) {
if (line.includes("#") && line.includes("=") && line.includes(",")) { if (line.includes("#") && line.includes("=") && line.includes(",")) {
const size = line const size = line.split("#")[1].split("=")[1].split(",");
.split("#")[1]
.split("=")[1]
.split(",");
item.x = Number(size[0]); item.x = Number(size[0]);
item.y = Number(size[1]); item.y = Number(size[1]);
item.w = Number(size[2]); item.w = Number(size[2]);
@@ -120,13 +117,14 @@ export const ScenePlayerScrubber: React.FC<IScenePlayerScrubberProps> = (
if (!scrubberSliderEl.current) { if (!scrubberSliderEl.current) {
return; return;
} }
scrubberSliderEl.current.style.transform = `translateX(${scrubberSliderEl scrubberSliderEl.current.style.transform = `translateX(${
.current.clientWidth / 2}px)`; scrubberSliderEl.current.clientWidth / 2
}px)`;
}, [scrubberSliderEl]); }, [scrubberSliderEl]);
useEffect(() => { useEffect(() => {
if (!props.scene.paths.vtt) return; if (!props.scene.paths.vtt) return;
fetchSpriteInfo(props.scene.paths.vtt).then(sprites => { fetchSpriteInfo(props.scene.paths.vtt).then((sprites) => {
if (sprites) setSpriteItems(sprites); if (sprites) setSpriteItems(sprites);
}); });
}, [props.scene]); }, [props.scene]);
@@ -297,13 +295,13 @@ export const ScenePlayerScrubber: React.FC<IScenePlayerScrubberProps> = (
tag!.clientWidth / 2; tag!.clientWidth / 2;
return { return {
left: `${left}px`, left: `${left}px`,
height: 20 height: 20,
}; };
} }
return props.scene.scene_markers.map((marker, index) => { return props.scene.scene_markers.map((marker, index) => {
const dataAttrs = { const dataAttrs = {
"data-marker-id": index "data-marker-id": index,
}; };
return ( return (
<div <div
@@ -332,13 +330,13 @@ export const ScenePlayerScrubber: React.FC<IScenePlayerScrubberProps> = (
margin: "0px auto", margin: "0px auto",
backgroundPosition: `${-sprite.x}px ${-sprite.y}px`, backgroundPosition: `${-sprite.x}px ${-sprite.y}px`,
backgroundImage: `url(${path})`, backgroundImage: `url(${path})`,
left: `${left}px` left: `${left}px`,
}; };
} }
return spriteItems.map((spriteItem, index) => { return spriteItems.map((spriteItem, index) => {
const dataAttrs = { const dataAttrs = {
"data-sprite-item-id": index "data-sprite-item-id": index,
}; };
return ( return (
<div <div

View File

@@ -34,7 +34,7 @@
cursor: grab; cursor: grab;
display: inline-block; display: inline-block;
height: 120px; height: 120px;
margin: 0 .5%; margin: 0 0.5%;
overflow: hidden; overflow: hidden;
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
position: relative; position: relative;

View File

@@ -20,7 +20,7 @@ export const SceneCard: React.FC<ISceneCardProps> = (
) => { ) => {
const [previewPath, setPreviewPath] = useState<string>(); const [previewPath, setPreviewPath] = useState<string>();
const videoHoverHook = VideoHoverHook.useVideoHover({ const videoHoverHook = VideoHoverHook.useVideoHover({
resetOnMouseLeave: false resetOnMouseLeave: false,
}); });
const config = StashService.useConfiguration(); const config = StashService.useConfiguration();
@@ -83,7 +83,7 @@ export const SceneCard: React.FC<ISceneCardProps> = (
function maybeRenderTagPopoverButton() { function maybeRenderTagPopoverButton() {
if (props.scene.tags.length <= 0) return; if (props.scene.tags.length <= 0) return;
const popoverContent = props.scene.tags.map(tag => ( const popoverContent = props.scene.tags.map((tag) => (
<TagLink key={tag.id} tag={tag} /> <TagLink key={tag.id} tag={tag} />
)); ));
@@ -100,7 +100,7 @@ export const SceneCard: React.FC<ISceneCardProps> = (
function maybeRenderPerformerPopoverButton() { function maybeRenderPerformerPopoverButton() {
if (props.scene.performers.length <= 0) return; if (props.scene.performers.length <= 0) return;
const popoverContent = props.scene.performers.map(performer => ( const popoverContent = props.scene.performers.map((performer) => (
<div className="performer-tag-container row" key="performer"> <div className="performer-tag-container row" key="performer">
<Link <Link
to={`/performers/${performer.id}`} to={`/performers/${performer.id}`}
@@ -129,7 +129,7 @@ export const SceneCard: React.FC<ISceneCardProps> = (
function maybeRenderMoviePopoverButton() { function maybeRenderMoviePopoverButton() {
if (props.scene.movies.length <= 0) return; if (props.scene.movies.length <= 0) return;
const popoverContent = props.scene.movies.map(sceneMovie => ( const popoverContent = props.scene.movies.map((sceneMovie) => (
<div className="movie-tag-container row" key="movie"> <div className="movie-tag-container row" key="movie">
<Link <Link
to={`/movies/${sceneMovie.movie.id}`} to={`/movies/${sceneMovie.movie.id}`}
@@ -162,7 +162,7 @@ export const SceneCard: React.FC<ISceneCardProps> = (
function maybeRenderSceneMarkerPopoverButton() { function maybeRenderSceneMarkerPopoverButton() {
if (props.scene.scene_markers.length <= 0) return; if (props.scene.scene_markers.length <= 0) return;
const popoverContent = props.scene.scene_markers.map(marker => { const popoverContent = props.scene.scene_markers.map((marker) => {
const markerPopover = { ...marker, scene: { id: props.scene.id } }; const markerPopover = { ...marker, scene: { id: props.scene.id } };
return <TagLink key={marker.id} marker={markerPopover} />; return <TagLink key={marker.id} marker={markerPopover} />;
}); });

View File

@@ -12,13 +12,13 @@ interface IPrimaryTags {
export const PrimaryTags: React.FC<IPrimaryTags> = ({ export const PrimaryTags: React.FC<IPrimaryTags> = ({
sceneMarkers, sceneMarkers,
onClickMarker, onClickMarker,
onEdit onEdit,
}) => { }) => {
if (!sceneMarkers?.length) return <div />; if (!sceneMarkers?.length) return <div />;
const primaries: Record<string, GQL.Tag> = {}; const primaries: Record<string, GQL.Tag> = {};
const primaryTags: Record<string, GQL.SceneMarkerDataFragment[]> = {}; const primaryTags: Record<string, GQL.SceneMarkerDataFragment[]> = {};
sceneMarkers.forEach(m => { sceneMarkers.forEach((m) => {
if (primaryTags[m.primary_tag.id]) primaryTags[m.primary_tag.id].push(m); if (primaryTags[m.primary_tag.id]) primaryTags[m.primary_tag.id].push(m);
else { else {
primaryTags[m.primary_tag.id] = [m]; primaryTags[m.primary_tag.id] = [m];
@@ -26,9 +26,9 @@ export const PrimaryTags: React.FC<IPrimaryTags> = ({
} }
}); });
const primaryCards = Object.keys(primaryTags).map(id => { const primaryCards = Object.keys(primaryTags).map((id) => {
const markers = primaryTags[id].map(marker => { const markers = primaryTags[id].map((marker) => {
const tags = marker.tags.map(tag => ( const tags = marker.tags.map((tag) => (
<Badge key={tag.id} variant="secondary" className="tag-item"> <Badge key={tag.id} variant="secondary" className="tag-item">
{tag.name} {tag.name}
</Badge> </Badge>

View File

@@ -149,7 +149,7 @@ export const Scene: React.FC = () => {
<Tab eventKey="scene-edit-panel" title="Edit"> <Tab eventKey="scene-edit-panel" title="Edit">
<SceneEditPanel <SceneEditPanel
scene={scene} scene={scene}
onUpdate={newScene => setScene(newScene)} onUpdate={(newScene) => setScene(newScene)}
onDelete={() => history.push("/scenes")} onDelete={() => history.push("/scenes")}
/> />
</Tab> </Tab>

View File

@@ -8,7 +8,7 @@ interface ISceneDetailProps {
scene: GQL.SceneDataFragment; scene: GQL.SceneDataFragment;
} }
export const SceneDetailPanel: React.FC<ISceneDetailProps> = props => { export const SceneDetailPanel: React.FC<ISceneDetailProps> = (props) => {
function renderDetails() { function renderDetails() {
if (!props.scene.details || props.scene.details === "") return; if (!props.scene.details || props.scene.details === "") return;
return ( return (
@@ -21,7 +21,7 @@ export const SceneDetailPanel: React.FC<ISceneDetailProps> = props => {
function renderTags() { function renderTags() {
if (props.scene.tags.length === 0) return; if (props.scene.tags.length === 0) return;
const tags = props.scene.tags.map(tag => ( const tags = props.scene.tags.map((tag) => (
<TagLink key={tag.id} tag={tag} /> <TagLink key={tag.id} tag={tag} />
)); ));
return ( return (

View File

@@ -12,7 +12,7 @@ import {
Modal, Modal,
Icon, Icon,
LoadingIndicator, LoadingIndicator,
ImageInput ImageInput,
} from "src/components/Shared"; } from "src/components/Shared";
import { useToast } from "src/hooks"; import { useToast } from "src/hooks";
import { ImageUtils, TableUtils } from "src/utils"; import { ImageUtils, TableUtils } from "src/utils";
@@ -60,7 +60,9 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
useEffect(() => { useEffect(() => {
const newQueryableScrapers = ( const newQueryableScrapers = (
Scrapers?.data?.listSceneScrapers ?? [] Scrapers?.data?.listSceneScrapers ?? []
).filter(s => s.scene?.supported_scrapes.includes(GQL.ScrapeType.Fragment)); ).filter((s) =>
s.scene?.supported_scrapes.includes(GQL.ScrapeType.Fragment)
);
setQueryableScrapers(newQueryableScrapers); setQueryableScrapers(newQueryableScrapers);
}, [Scrapers]); }, [Scrapers]);
@@ -69,7 +71,7 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
let changed = false; let changed = false;
const newMap: MovieSceneIndexMap = new Map(); const newMap: MovieSceneIndexMap = new Map();
if (movieIds) { if (movieIds) {
movieIds.forEach(id => { movieIds.forEach((id) => {
if (!movieSceneIndexes.has(id)) { if (!movieSceneIndexes.has(id)) {
changed = true; changed = true;
newMap.set(id, undefined); newMap.set(id, undefined);
@@ -94,14 +96,14 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
}, [movieIds, movieSceneIndexes]); }, [movieIds, movieSceneIndexes]);
function updateSceneEditState(state: Partial<GQL.SceneDataFragment>) { function updateSceneEditState(state: Partial<GQL.SceneDataFragment>) {
const perfIds = state.performers?.map(performer => performer.id); const perfIds = state.performers?.map((performer) => performer.id);
const tIds = state.tags ? state.tags.map(tag => tag.id) : undefined; const tIds = state.tags ? state.tags.map((tag) => tag.id) : undefined;
const moviIds = state.movies const moviIds = state.movies
? state.movies.map(sceneMovie => sceneMovie.movie.id) ? state.movies.map((sceneMovie) => sceneMovie.movie.id)
: undefined; : undefined;
const movieSceneIdx: MovieSceneIndexMap = new Map(); const movieSceneIdx: MovieSceneIndexMap = new Map();
if (state.movies) { if (state.movies) {
state.movies.forEach(m => { state.movies.forEach((m) => {
movieSceneIdx.set(m.movie.id, m.scene_index ?? undefined); movieSceneIdx.set(m.movie.id, m.scene_index ?? undefined);
}); });
} }
@@ -140,7 +142,7 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
performer_ids: performerIds, performer_ids: performerIds,
movies: makeMovieInputs(), movies: makeMovieInputs(),
tag_ids: tagIds, tag_ids: tagIds,
cover_image: coverImage cover_image: coverImage,
}; };
} }
@@ -149,14 +151,14 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
return undefined; return undefined;
} }
let ret = movieIds.map(id => { let ret = movieIds.map((id) => {
const r: GQL.SceneMovieInput = { const r: GQL.SceneMovieInput = {
movie_id: id movie_id: id,
}; };
return r; return r;
}); });
ret = ret.map(r => { ret = ret.map((r) => {
return { scene_index: movieSceneIndexes.get(r.movie_id), ...r }; return { scene_index: movieSceneIndexes.get(r.movie_id), ...r };
}); });
@@ -181,7 +183,7 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
return { return {
id: props.scene.id, id: props.scene.id,
delete_file: deleteFile, delete_file: deleteFile,
delete_generated: deleteGenerated delete_generated: deleteGenerated,
}; };
} }
@@ -202,7 +204,7 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
return ( return (
<SceneMovieTable <SceneMovieTable
movieSceneIndexes={movieSceneIndexes} movieSceneIndexes={movieSceneIndexes}
onUpdate={items => { onUpdate={(items) => {
setMovieSceneIndexes(items); setMovieSceneIndexes(items);
}} }}
/> />
@@ -272,7 +274,7 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
return ( return (
<DropdownButton id="scene-scrape" title="Scrape with..."> <DropdownButton id="scene-scrape" title="Scrape with...">
{queryableScrapers.map(s => ( {queryableScrapers.map((s) => (
<Dropdown.Item key={s.name} onClick={() => onScrapeClicked(s)}> <Dropdown.Item key={s.name} onClick={() => onScrapeClicked(s)}>
{s.name} {s.name}
</Dropdown.Item> </Dropdown.Item>
@@ -282,8 +284,8 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
} }
function urlScrapable(scrapedUrl: string): boolean { function urlScrapable(scrapedUrl: string): boolean {
return (Scrapers?.data?.listSceneScrapers ?? []).some(s => return (Scrapers?.data?.listSceneScrapers ?? []).some((s) =>
(s?.scene?.urls ?? []).some(u => scrapedUrl.includes(u)) (s?.scene?.urls ?? []).some((u) => scrapedUrl.includes(u))
); );
} }
@@ -313,12 +315,12 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
scene.performers && scene.performers &&
scene.performers.length > 0 scene.performers.length > 0
) { ) {
const idPerfs = scene.performers.filter(p => { const idPerfs = scene.performers.filter((p) => {
return p.id !== undefined && p.id !== null; return p.id !== undefined && p.id !== null;
}); });
if (idPerfs.length > 0) { if (idPerfs.length > 0) {
const newIds = idPerfs.map(p => p.id); const newIds = idPerfs.map((p) => p.id);
setPerformerIds(newIds as string[]); setPerformerIds(newIds as string[]);
} }
} }
@@ -328,23 +330,23 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
scene.movies && scene.movies &&
scene.movies.length > 0 scene.movies.length > 0
) { ) {
const idMovis = scene.movies.filter(p => { const idMovis = scene.movies.filter((p) => {
return p.id !== undefined && p.id !== null; return p.id !== undefined && p.id !== null;
}); });
if (idMovis.length > 0) { if (idMovis.length > 0) {
const newIds = idMovis.map(p => p.id); const newIds = idMovis.map((p) => p.id);
setMovieIds(newIds as string[]); setMovieIds(newIds as string[]);
} }
} }
if (!tagIds?.length && scene?.tags?.length) { if (!tagIds?.length && scene?.tags?.length) {
const idTags = scene.tags.filter(p => { const idTags = scene.tags.filter((p) => {
return p.id !== undefined && p.id !== null; return p.id !== undefined && p.id !== null;
}); });
if (idTags.length > 0) { if (idTags.length > 0) {
const newIds = idTags.map(p => p.id); const newIds = idTags.map((p) => p.id);
setTagIds(newIds as string[]); setTagIds(newIds as string[]);
} }
} }
@@ -396,7 +398,7 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
title: "Title", title: "Title",
value: title, value: title,
onChange: setTitle, onChange: setTitle,
isEditing: true isEditing: true,
})} })}
<tr> <tr>
<td>URL</td> <td>URL</td>
@@ -417,7 +419,7 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
value: date, value: date,
isEditing: true, isEditing: true,
onChange: setDate, onChange: setDate,
placeholder: "YYYY-MM-DD" placeholder: "YYYY-MM-DD",
})} })}
{TableUtils.renderHtmlSelect({ {TableUtils.renderHtmlSelect({
title: "Rating", title: "Rating",
@@ -425,7 +427,7 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
isEditing: true, isEditing: true,
onChange: (value: string) => onChange: (value: string) =>
setRating(Number.parseInt(value, 10)), setRating(Number.parseInt(value, 10)),
selectOptions: ["", 1, 2, 3, 4, 5] selectOptions: ["", 1, 2, 3, 4, 5],
})} })}
<tr> <tr>
<td>Gallery</td> <td>Gallery</td>
@@ -433,7 +435,7 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
<SceneGallerySelect <SceneGallerySelect
sceneId={props.scene.id} sceneId={props.scene.id}
initialId={galleryId} initialId={galleryId}
onSelect={item => setGalleryId(item ? item.id : undefined)} onSelect={(item) => setGalleryId(item ? item.id : undefined)}
/> />
</td> </td>
</tr> </tr>
@@ -441,7 +443,7 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
<td>Studio</td> <td>Studio</td>
<td> <td>
<StudioSelect <StudioSelect
onSelect={items => onSelect={(items) =>
setStudioId(items.length > 0 ? items[0]?.id : undefined) setStudioId(items.length > 0 ? items[0]?.id : undefined)
} }
ids={studioId ? [studioId] : []} ids={studioId ? [studioId] : []}
@@ -453,8 +455,8 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
<td> <td>
<PerformerSelect <PerformerSelect
isMulti isMulti
onSelect={items => onSelect={(items) =>
setPerformerIds(items.map(item => item.id)) setPerformerIds(items.map((item) => item.id))
} }
ids={performerIds} ids={performerIds}
/> />
@@ -465,7 +467,9 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
<td> <td>
<MovieSelect <MovieSelect
isMulti isMulti
onSelect={items => setMovieIds(items.map(item => item.id))} onSelect={(items) =>
setMovieIds(items.map((item) => item.id))
}
ids={movieIds} ids={movieIds}
/> />
{renderTableMovies()} {renderTableMovies()}
@@ -476,7 +480,7 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
<td> <td>
<TagSelect <TagSelect
isMulti isMulti
onSelect={items => setTagIds(items.map(item => item.id))} onSelect={(items) => setTagIds(items.map((item) => item.id))}
ids={tagIds} ids={tagIds}
/> />
</td> </td>

View File

@@ -20,7 +20,7 @@ export const SceneFileInfoPanel: React.FC<ISceneFileInfoPanelProps> = (
function renderPath() { function renderPath() {
const { const {
scene: { path } scene: { path },
} = props; } = props;
return ( return (
<div className="row"> <div className="row">

View File

@@ -6,7 +6,7 @@ import { StashService } from "src/core/StashService";
import { import {
DurationInput, DurationInput,
TagSelect, TagSelect,
MarkerTitleSuggest MarkerTitleSuggest,
} from "src/components/Shared"; } from "src/components/Shared";
import { useToast } from "src/hooks"; import { useToast } from "src/hooks";
import { JWUtils } from "src/utils"; import { JWUtils } from "src/utils";
@@ -27,7 +27,7 @@ interface ISceneMarkerForm {
export const SceneMarkerForm: React.FC<ISceneMarkerForm> = ({ export const SceneMarkerForm: React.FC<ISceneMarkerForm> = ({
sceneID, sceneID,
editingMarker, editingMarker,
onClose onClose,
}) => { }) => {
const [sceneMarkerCreate] = StashService.useSceneMarkerCreate(); const [sceneMarkerCreate] = StashService.useSceneMarkerCreate();
const [sceneMarkerUpdate] = StashService.useSceneMarkerUpdate(); const [sceneMarkerUpdate] = StashService.useSceneMarkerUpdate();
@@ -40,18 +40,18 @@ export const SceneMarkerForm: React.FC<ISceneMarkerForm> = ({
seconds: parseFloat(values.seconds), seconds: parseFloat(values.seconds),
scene_id: sceneID, scene_id: sceneID,
primary_tag_id: values.primaryTagId, primary_tag_id: values.primaryTagId,
tag_ids: values.tagIds tag_ids: values.tagIds,
}; };
if (!editingMarker) { if (!editingMarker) {
sceneMarkerCreate({ variables }) sceneMarkerCreate({ variables })
.then(onClose) .then(onClose)
.catch(err => Toast.error(err)); .catch((err) => Toast.error(err));
} else { } else {
const updateVariables = variables as GQL.SceneMarkerUpdateInput; const updateVariables = variables as GQL.SceneMarkerUpdateInput;
updateVariables.id = editingMarker!.id; updateVariables.id = editingMarker!.id;
sceneMarkerUpdate({ variables: updateVariables }) sceneMarkerUpdate({ variables: updateVariables })
.then(onClose) .then(onClose)
.catch(err => Toast.error(err)); .catch((err) => Toast.error(err));
} }
}; };
@@ -60,7 +60,7 @@ export const SceneMarkerForm: React.FC<ISceneMarkerForm> = ({
sceneMarkerDestroy({ variables: { id: editingMarker.id } }) sceneMarkerDestroy({ variables: { id: editingMarker.id } })
.then(onClose) .then(onClose)
.catch(err => Toast.error(err)); .catch((err) => Toast.error(err));
}; };
const renderTitleField = (fieldProps: FieldProps<string>) => ( const renderTitleField = (fieldProps: FieldProps<string>) => (
<div className="col-10"> <div className="col-10">
@@ -76,7 +76,7 @@ export const SceneMarkerForm: React.FC<ISceneMarkerForm> = ({
const renderSecondsField = (fieldProps: FieldProps<string>) => ( const renderSecondsField = (fieldProps: FieldProps<string>) => (
<div className="col-3"> <div className="col-3">
<DurationInput <DurationInput
onValueChange={s => fieldProps.form.setFieldValue("seconds", s)} onValueChange={(s) => fieldProps.form.setFieldValue("seconds", s)}
onReset={() => onReset={() =>
fieldProps.form.setFieldValue( fieldProps.form.setFieldValue(
"seconds", "seconds",
@@ -90,7 +90,7 @@ export const SceneMarkerForm: React.FC<ISceneMarkerForm> = ({
const renderPrimaryTagField = (fieldProps: FieldProps<string>) => ( const renderPrimaryTagField = (fieldProps: FieldProps<string>) => (
<TagSelect <TagSelect
onSelect={tags => onSelect={(tags) =>
fieldProps.form.setFieldValue("primaryTagId", tags[0]?.id) fieldProps.form.setFieldValue("primaryTagId", tags[0]?.id)
} }
ids={fieldProps.field.value ? [fieldProps.field.value] : []} ids={fieldProps.field.value ? [fieldProps.field.value] : []}
@@ -101,10 +101,10 @@ export const SceneMarkerForm: React.FC<ISceneMarkerForm> = ({
const renderTagsField = (fieldProps: FieldProps<string[]>) => ( const renderTagsField = (fieldProps: FieldProps<string[]>) => (
<TagSelect <TagSelect
isMulti isMulti
onSelect={tags => onSelect={(tags) =>
fieldProps.form.setFieldValue( fieldProps.form.setFieldValue(
"tagIds", "tagIds",
tags.map(tag => tag.id) tags.map((tag) => tag.id)
) )
} }
ids={fieldProps.field.value} ids={fieldProps.field.value}
@@ -119,7 +119,7 @@ export const SceneMarkerForm: React.FC<ISceneMarkerForm> = ({
Math.round(JWUtils.getPlayer()?.getPosition() ?? 0) Math.round(JWUtils.getPlayer()?.getPosition() ?? 0)
).toString(), ).toString(),
primaryTagId: editingMarker?.primary_tag.id ?? "", primaryTagId: editingMarker?.primary_tag.id ?? "",
tagIds: editingMarker?.tags.map(tag => tag.id) ?? [] tagIds: editingMarker?.tags.map((tag) => tag.id) ?? [],
}; };
return ( return (

View File

@@ -54,7 +54,7 @@ export const SceneMarkersPanel: React.FC<ISceneMarkersPanelProps> = (
<div className="row"> <div className="row">
<WallPanel <WallPanel
sceneMarkers={props.scene.scene_markers} sceneMarkers={props.scene.scene_markers}
clickHandler={marker => { clickHandler={(marker) => {
window.scrollTo(0, 0); window.scrollTo(0, 0);
onClickMarker(marker as GQL.SceneMarkerDataFragment); onClickMarker(marker as GQL.SceneMarkerDataFragment);
}} }}

View File

@@ -9,7 +9,7 @@ interface ISceneMoviePanelProps {
export const SceneMoviePanel: FunctionComponent<ISceneMoviePanelProps> = ( export const SceneMoviePanel: FunctionComponent<ISceneMoviePanelProps> = (
props: ISceneMoviePanelProps props: ISceneMoviePanelProps
) => { ) => {
const cards = props.scene.movies.map(sceneMovie => ( const cards = props.scene.movies.map((sceneMovie) => (
<MovieCard <MovieCard
key={sceneMovie.movie.id} key={sceneMovie.movie.id}
movie={sceneMovie.movie} movie={sceneMovie.movie}

View File

@@ -22,11 +22,11 @@ export const SceneMovieTable: React.FunctionComponent<IProps> = (
if (!!props.movieSceneIndexes && !!items) { if (!!props.movieSceneIndexes && !!items) {
props.movieSceneIndexes.forEach((index, movieId) => { props.movieSceneIndexes.forEach((index, movieId) => {
itemsFilter = itemsFilter.concat(items.filter(x => x.id === movieId)); itemsFilter = itemsFilter.concat(items.filter((x) => x.id === movieId));
}); });
} }
const storeIdx = itemsFilter.map(movie => { const storeIdx = itemsFilter.map((movie) => {
return props.movieSceneIndexes.get(movie.id); return props.movieSceneIndexes.get(movie.id);
}); });
@@ -54,7 +54,7 @@ export const SceneMovieTable: React.FunctionComponent<IProps> = (
} }
> >
{["", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"].map( {["", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"].map(
opt => ( (opt) => (
<option value={opt} key={opt}> <option value={opt} key={opt}>
{opt} {opt}
</option> </option>

View File

@@ -19,8 +19,8 @@ export const SceneOperationsPanel: FunctionComponent<IOperationsPanelProps> = (
await generateScreenshot({ await generateScreenshot({
variables: { variables: {
id: props.scene.id, id: props.scene.id,
at at,
} },
}); });
Toast.success({ content: "Generating screenshot" }); Toast.success({ content: "Generating screenshot" });
} }

View File

@@ -9,7 +9,7 @@ interface IScenePerformerPanelProps {
export const ScenePerformerPanel: FunctionComponent<IScenePerformerPanelProps> = ( export const ScenePerformerPanel: FunctionComponent<IScenePerformerPanelProps> = (
props: IScenePerformerPanelProps props: IScenePerformerPanelProps
) => { ) => {
const cards = props.scene.performers.map(performer => ( const cards = props.scene.performers.map((performer) => (
<PerformerCard <PerformerCard
key={performer.id} key={performer.id}
performer={performer} performer={performer}

View File

@@ -3,7 +3,7 @@ import _ from "lodash";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { import {
FindScenesQueryResult, FindScenesQueryResult,
SlimSceneDataFragment SlimSceneDataFragment,
} from "src/core/generated-graphql"; } from "src/core/generated-graphql";
import { StashService } from "src/core/StashService"; import { StashService } from "src/core/StashService";
import { useScenesList } from "src/hooks"; import { useScenesList } from "src/hooks";
@@ -21,14 +21,14 @@ interface ISceneList {
export const SceneList: React.FC<ISceneList> = ({ export const SceneList: React.FC<ISceneList> = ({
subComponent, subComponent,
filterHook filterHook,
}) => { }) => {
const history = useHistory(); const history = useHistory();
const otherOperations = [ const otherOperations = [
{ {
text: "Play Random", text: "Play Random",
onClick: playRandom onClick: playRandom,
} },
]; ];
const listData = useScenesList({ const listData = useScenesList({
@@ -37,7 +37,7 @@ export const SceneList: React.FC<ISceneList> = ({
renderContent, renderContent,
renderSelectedOptions, renderSelectedOptions,
subComponent, subComponent,
filterHook filterHook,
}); });
async function playRandom( async function playRandom(
@@ -78,8 +78,8 @@ export const SceneList: React.FC<ISceneList> = ({
const { scenes } = result.data.findScenes; const { scenes } = result.data.findScenes;
const selectedScenes: SlimSceneDataFragment[] = []; const selectedScenes: SlimSceneDataFragment[] = [];
selectedIds.forEach(id => { selectedIds.forEach((id) => {
const scene = scenes.find(s => s.id === id); const scene = scenes.find((s) => s.id === id);
if (scene) { if (scene) {
selectedScenes.push(scene); selectedScenes.push(scene);
@@ -126,7 +126,7 @@ export const SceneList: React.FC<ISceneList> = ({
if (filter.displayMode === DisplayMode.Grid) { if (filter.displayMode === DisplayMode.Grid) {
return ( return (
<div className="row justify-content-center"> <div className="row justify-content-center">
{result.data.findScenes.scenes.map(scene => {result.data.findScenes.scenes.map((scene) =>
renderSceneCard(scene, selectedIds, zoomIndex) renderSceneCard(scene, selectedIds, zoomIndex)
)} )}
</div> </div>

View File

@@ -13,24 +13,22 @@ 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)}>
<h6>{performer.name}</h6> <h6>{performer.name}</h6>
</Link> </Link>
)); ));
const renderMovies = (movies: Partial<GQL.SceneMovie>[]) => { const renderMovies = (movies: Partial<GQL.SceneMovie>[]) => {
return movies.map(sceneMovie => return movies.map((sceneMovie) =>
!sceneMovie.movie ? ( !sceneMovie.movie ? undefined : (
undefined
) : (
<Link to={NavUtils.makeMovieScenesUrl(sceneMovie.movie)}> <Link to={NavUtils.makeMovieScenesUrl(sceneMovie.movie)}>
<h6>{sceneMovie.movie.name}</h6> <h6>{sceneMovie.movie.name}</h6>
</Link> </Link>

View File

@@ -14,13 +14,13 @@ export const SceneMarkerList: React.FC = () => {
const otherOperations = [ const otherOperations = [
{ {
text: "Play Random", text: "Play Random",
onClick: playRandom onClick: playRandom,
} },
]; ];
const listData = useSceneMarkersList({ const listData = useSceneMarkersList({
otherOperations, otherOperations,
renderContent renderContent,
}); });
async function playRandom( async function playRandom(

View File

@@ -3,10 +3,7 @@ import { Button, Form } from "react-bootstrap";
import _ from "lodash"; import _ from "lodash";
import { StashService } from "src/core/StashService"; import { StashService } from "src/core/StashService";
import * as GQL from "src/core/generated-graphql"; import * as GQL from "src/core/generated-graphql";
import { import { StudioSelect, LoadingIndicator } from "src/components/Shared";
StudioSelect,
LoadingIndicator
} from "src/components/Shared";
import { useToast } from "src/hooks"; import { useToast } from "src/hooks";
import MultiSet from "../Shared/MultiSet"; import MultiSet from "../Shared/MultiSet";
@@ -21,9 +18,13 @@ export const SceneSelectedOptions: React.FC<IListOperationProps> = (
const Toast = useToast(); const Toast = useToast();
const [rating, setRating] = useState<string>(""); const [rating, setRating] = useState<string>("");
const [studioId, setStudioId] = useState<string>(); const [studioId, setStudioId] = useState<string>();
const [performerMode, setPerformerMode] = React.useState<GQL.BulkUpdateIdMode>(GQL.BulkUpdateIdMode.Add); const [performerMode, setPerformerMode] = React.useState<
GQL.BulkUpdateIdMode
>(GQL.BulkUpdateIdMode.Add);
const [performerIds, setPerformerIds] = useState<string[]>(); const [performerIds, setPerformerIds] = useState<string[]>();
const [tagMode, setTagMode] = React.useState<GQL.BulkUpdateIdMode>(GQL.BulkUpdateIdMode.Add); const [tagMode, setTagMode] = React.useState<GQL.BulkUpdateIdMode>(
GQL.BulkUpdateIdMode.Add
);
const [tagIds, setTagIds] = useState<string[]>(); const [tagIds, setTagIds] = useState<string[]>();
const [updateScenes] = StashService.useBulkSceneUpdate(getSceneInput()); const [updateScenes] = StashService.useBulkSceneUpdate(getSceneInput());
@@ -31,10 +32,13 @@ export const SceneSelectedOptions: React.FC<IListOperationProps> = (
// Network state // Network state
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
function makeBulkUpdateIds(ids: string[], mode: GQL.BulkUpdateIdMode) : GQL.BulkUpdateIds { function makeBulkUpdateIds(
ids: string[],
mode: GQL.BulkUpdateIdMode
): GQL.BulkUpdateIds {
return { return {
mode, mode,
ids ids,
}; };
} }
@@ -46,9 +50,9 @@ export const SceneSelectedOptions: React.FC<IListOperationProps> = (
const aggregateTagIds = getTagIds(props.selected); const aggregateTagIds = getTagIds(props.selected);
const sceneInput: GQL.BulkSceneUpdateInput = { const sceneInput: GQL.BulkSceneUpdateInput = {
ids: props.selected.map(scene => { ids: props.selected.map((scene) => {
return scene.id; return scene.id;
}) }),
}; };
// if rating is undefined // if rating is undefined
@@ -78,19 +82,31 @@ export const SceneSelectedOptions: React.FC<IListOperationProps> = (
} }
// if performerIds are empty // if performerIds are empty
if (performerMode === GQL.BulkUpdateIdMode.Set && (!performerIds || performerIds.length === 0)) { if (
performerMode === GQL.BulkUpdateIdMode.Set &&
(!performerIds || performerIds.length === 0)
) {
// and all scenes have the same ids, // and all scenes have the same ids,
if (aggregatePerformerIds.length > 0) { if (aggregatePerformerIds.length > 0) {
// then unset the performerIds, otherwise ignore // then unset the performerIds, otherwise ignore
sceneInput.performer_ids = makeBulkUpdateIds(performerIds || [], performerMode); sceneInput.performer_ids = makeBulkUpdateIds(
performerIds || [],
performerMode
);
} }
} else { } else {
// if performerIds non-empty, then we are setting them // if performerIds non-empty, then we are setting them
sceneInput.performer_ids = makeBulkUpdateIds(performerIds || [], performerMode); sceneInput.performer_ids = makeBulkUpdateIds(
performerIds || [],
performerMode
);
} }
// if tagIds non-empty, then we are setting them // if tagIds non-empty, then we are setting them
if (tagMode === GQL.BulkUpdateIdMode.Set && (!tagIds || tagIds.length === 0)) { if (
tagMode === GQL.BulkUpdateIdMode.Set &&
(!tagIds || tagIds.length === 0)
) {
// and all scenes have the same ids, // and all scenes have the same ids,
if (aggregateTagIds.length > 0) { if (aggregateTagIds.length > 0) {
// then unset the tagIds, otherwise ignore // then unset the tagIds, otherwise ignore
@@ -157,11 +173,11 @@ export const SceneSelectedOptions: React.FC<IListOperationProps> = (
state.forEach((scene: GQL.SlimSceneDataFragment) => { state.forEach((scene: GQL.SlimSceneDataFragment) => {
if (first) { if (first) {
ret = scene.performers ? scene.performers.map(p => p.id).sort() : []; ret = scene.performers ? scene.performers.map((p) => p.id).sort() : [];
first = false; first = false;
} else { } else {
const perfIds = scene.performers const perfIds = scene.performers
? scene.performers.map(p => p.id).sort() ? scene.performers.map((p) => p.id).sort()
: []; : [];
if (!_.isEqual(ret, perfIds)) { if (!_.isEqual(ret, perfIds)) {
@@ -179,10 +195,10 @@ export const SceneSelectedOptions: React.FC<IListOperationProps> = (
state.forEach((scene: GQL.SlimSceneDataFragment) => { state.forEach((scene: GQL.SlimSceneDataFragment) => {
if (first) { if (first) {
ret = scene.tags ? scene.tags.map(t => t.id).sort() : []; ret = scene.tags ? scene.tags.map((t) => t.id).sort() : [];
first = false; first = false;
} else { } else {
const tIds = scene.tags ? scene.tags.map(t => t.id).sort() : []; const tIds = scene.tags ? scene.tags.map((t) => t.id).sort() : [];
if (!_.isEqual(ret, tIds)) { if (!_.isEqual(ret, tIds)) {
ret = []; ret = [];
@@ -204,8 +220,10 @@ export const SceneSelectedOptions: React.FC<IListOperationProps> = (
state.forEach((scene: GQL.SlimSceneDataFragment) => { state.forEach((scene: GQL.SlimSceneDataFragment) => {
const sceneRating = scene.rating?.toString() ?? ""; const sceneRating = scene.rating?.toString() ?? "";
const sceneStudioID = scene?.studio?.id; const sceneStudioID = scene?.studio?.id;
const scenePerformerIDs = (scene.performers ?? []).map(p => p.id).sort(); const scenePerformerIDs = (scene.performers ?? [])
const sceneTagIDs = (scene.tags ?? []).map(p => p.id).sort(); .map((p) => p.id)
.sort();
const sceneTagIDs = (scene.tags ?? []).map((p) => p.id).sort();
if (first) { if (first) {
updateRating = sceneRating; updateRating = sceneRating;
@@ -248,15 +266,19 @@ export const SceneSelectedOptions: React.FC<IListOperationProps> = (
) { ) {
let mode = GQL.BulkUpdateIdMode.Add; let mode = GQL.BulkUpdateIdMode.Add;
switch (type) { switch (type) {
case "performers": mode = performerMode; break; case "performers":
case "tags": mode = tagMode; break; mode = performerMode;
break;
case "tags":
mode = tagMode;
break;
} }
return ( return (
<MultiSet <MultiSet
type={type} type={type}
onUpdate={items => { onUpdate={(items) => {
const itemIDs = items.map(i => i.id); const itemIDs = items.map((i) => i.id);
switch (type) { switch (type) {
case "performers": case "performers":
setPerformerIds(itemIDs); setPerformerIds(itemIDs);
@@ -266,10 +288,14 @@ export const SceneSelectedOptions: React.FC<IListOperationProps> = (
break; break;
} }
}} }}
onSetMode={(mode) => { onSetMode={(newMode) => {
switch (type) { switch (type) {
case "performers": setPerformerMode(mode); break; case "performers":
case "tags": setTagMode(mode); break; setPerformerMode(newMode);
break;
case "tags":
setTagMode(newMode);
break;
} }
}} }}
ids={ids ?? []} ids={ids ?? []}
@@ -296,7 +322,7 @@ export const SceneSelectedOptions: React.FC<IListOperationProps> = (
setRating(event.currentTarget.value) setRating(event.currentTarget.value)
} }
> >
{["", "1", "2", "3", "4", "5"].map(opt => ( {["", "1", "2", "3", "4", "5"].map((opt) => (
<option key={opt} value={opt}> <option key={opt} value={opt}>
{opt} {opt}
</option> </option>
@@ -307,7 +333,7 @@ export const SceneSelectedOptions: React.FC<IListOperationProps> = (
<Form.Group controlId="studio" className="operation-item"> <Form.Group controlId="studio" className="operation-item">
<Form.Label>Studio</Form.Label> <Form.Label>Studio</Form.Label>
<StudioSelect <StudioSelect
onSelect={items => setStudioId(items[0]?.id)} onSelect={(items) => setStudioId(items[0]?.id)}
ids={studioId ? [studioId] : []} ids={studioId ? [studioId] : []}
/> />
</Form.Group> </Form.Group>

View File

@@ -15,7 +15,7 @@
.card-section { .card-section {
margin-bottom: 0; margin-bottom: 0;
padding: .5rem 1rem 0 1rem; padding: 0.5rem 1rem 0 1rem;
&-title { &-title {
overflow: hidden; overflow: hidden;
@@ -25,12 +25,12 @@
} }
.scene-card-check { .scene-card-check {
left: .5rem; left: 0.5rem;
margin-top: -12px; margin-top: -12px;
opacity: .5; opacity: 0.5;
padding-left: 15px; padding-left: 15px;
position: absolute; position: absolute;
top: .7rem; top: 0.7rem;
width: 1.2rem; width: 1.2rem;
z-index: 1; z-index: 1;
} }
@@ -95,7 +95,7 @@
.file-info-panel { .file-info-panel {
div { div {
margin-bottom: .5rem; margin-bottom: 0.5rem;
} }
} }
@@ -113,7 +113,7 @@
} }
.studio-card { .studio-card {
padding: .5rem; padding: 0.5rem;
&-header { &-header {
height: 150px; height: 150px;
@@ -138,9 +138,9 @@
color: $text-color; color: $text-color;
display: block; display: block;
font-weight: 400; font-weight: 400;
letter-spacing: -.03rem; letter-spacing: -0.03rem;
position: absolute; position: absolute;
right: .7rem; right: 0.7rem;
text-shadow: 0 0 3px #000; text-shadow: 0 0 3px #000;
} }
@@ -149,10 +149,10 @@
font-weight: 900; font-weight: 900;
height: 10%; height: 10%;
max-width: 40%; max-width: 40%;
opacity: .75; opacity: 0.75;
position: absolute; position: absolute;
right: .7rem; right: 0.7rem;
top: .7rem; top: 0.7rem;
z-index: 9; z-index: 9;
.image-thumbnail { .image-thumbnail {
@@ -164,7 +164,7 @@
a { a {
color: $text-color; color: $text-color;
display: inline-block; display: inline-block;
letter-spacing: -.03rem; letter-spacing: -0.03rem;
text-align: right; text-align: right;
text-decoration: none; text-decoration: none;
text-shadow: 0 0 3px #000; text-shadow: 0 0 3px #000;
@@ -173,7 +173,7 @@
.overlay-resolution { .overlay-resolution {
font-weight: 900; font-weight: 900;
margin-right: .3rem; margin-right: 0.3rem;
text-transform: uppercase; text-transform: uppercase;
} }
@@ -190,7 +190,7 @@
.scene-specs-overlay, .scene-specs-overlay,
.rating-banner, .rating-banner,
.scene-studio-overlay { .scene-studio-overlay {
transition: opacity .5s; transition: opacity 0.5s;
} }
&:hover { &:hover {
@@ -198,12 +198,12 @@
.rating-banner, .rating-banner,
.scene-studio-overlay { .scene-studio-overlay {
opacity: 0; opacity: 0;
transition: opacity .5s; transition: opacity 0.5s;
} }
.scene-studio-overlay:hover { .scene-studio-overlay:hover {
opacity: .75; opacity: 0.75;
transition: opacity .5s; transition: opacity 0.5s;
} }
} }
} }

View File

@@ -10,7 +10,7 @@ export const SettingsAboutPanel: React.FC = () => {
error: errorLatest, error: errorLatest,
loading: loadingLatest, loading: loadingLatest,
refetch, refetch,
networkStatus networkStatus,
} = StashService.useLatestVersion(); } = StashService.useLatestVersion();
function maybeRenderTag() { function maybeRenderTag() {

View File

@@ -48,7 +48,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
logLevel, logLevel,
logAccess, logAccess,
excludes, excludes,
scraperUserAgent scraperUserAgent,
}); });
useEffect(() => { useEffect(() => {
@@ -116,7 +116,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
GQL.StreamingResolutionEnum.StandardHd, GQL.StreamingResolutionEnum.StandardHd,
GQL.StreamingResolutionEnum.FullHd, GQL.StreamingResolutionEnum.FullHd,
GQL.StreamingResolutionEnum.FourK, GQL.StreamingResolutionEnum.FourK,
GQL.StreamingResolutionEnum.Original GQL.StreamingResolutionEnum.Original,
].map(resolutionToString); ].map(resolutionToString);
function resolutionToString(r: GQL.StreamingResolutionEnum | undefined) { function resolutionToString(r: GQL.StreamingResolutionEnum | undefined) {
@@ -258,7 +258,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
} }
value={resolutionToString(maxTranscodeSize)} value={resolutionToString(maxTranscodeSize)}
> >
{transcodeQualities.map(q => ( {transcodeQualities.map((q) => (
<option key={q} value={q}> <option key={q} value={q}>
{q} {q}
</option> </option>
@@ -280,7 +280,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
} }
value={resolutionToString(maxStreamingTranscodeSize)} value={resolutionToString(maxStreamingTranscodeSize)}
> >
{transcodeQualities.map(q => ( {transcodeQualities.map((q) => (
<option key={q} value={q}> <option key={q} value={q}>
{q} {q}
</option> </option>
@@ -382,7 +382,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
} }
value={logLevel} value={logLevel}
> >
{["Debug", "Info", "Warning", "Error"].map(o => ( {["Debug", "Info", "Warning", "Error"].map((o) => (
<option key={o} value={o}> <option key={o} value={o}>
{o} {o}
</option> </option>

View File

@@ -24,7 +24,7 @@ export const SettingsInterfacePanel: React.FC = () => {
showStudioAsText, showStudioAsText,
css, css,
cssEnabled, cssEnabled,
language language,
}); });
useEffect(() => { useEffect(() => {
@@ -119,7 +119,7 @@ export const SettingsInterfacePanel: React.FC = () => {
<DurationInput <DurationInput
className="row col col-4" className="row col col-4"
numericValue={maximumLoopDuration} numericValue={maximumLoopDuration}
onValueChange={duration => setMaximumLoopDuration(duration)} onValueChange={(duration) => setMaximumLoopDuration(duration)}
/> />
<Form.Text className="text-muted"> <Form.Text className="text-muted">
Maximum scene duration where scene player will loop the video - 0 to Maximum scene duration where scene player will loop the video - 0 to

View File

@@ -73,8 +73,8 @@ export const SettingsLogsPanel: React.FC = () => {
const { data: existingData } = StashService.useLogs(); const { data: existingData } = StashService.useLogs();
const [logLevel, setLogLevel] = useState<string>("Info"); const [logLevel, setLogLevel] = useState<string>("Info");
const oldData = (existingData?.logs ?? []).map(e => new LogEntry(e)); const oldData = (existingData?.logs ?? []).map((e) => new LogEntry(e));
const newData = (data?.loggingSubscribe ?? []).map(e => new LogEntry(e)); const newData = (data?.loggingSubscribe ?? []).map((e) => new LogEntry(e));
const filteredLogEntries = [...newData.reverse(), ...oldData] const filteredLogEntries = [...newData.reverse(), ...oldData]
.filter(filterByLogLevel) .filter(filterByLogLevel)
@@ -104,9 +104,9 @@ export const SettingsLogsPanel: React.FC = () => {
className="col-6 col-sm-2 input-control" className="col-6 col-sm-2 input-control"
as="select" as="select"
defaultValue={logLevel} defaultValue={logLevel}
onChange={event => setLogLevel(event.currentTarget.value)} onChange={(event) => setLogLevel(event.currentTarget.value)}
> >
{logLevels.map(level => ( {logLevels.map((level) => (
<option key={level} value={level}> <option key={level} value={level}>
{level} {level}
</option> </option>
@@ -115,7 +115,7 @@ export const SettingsLogsPanel: React.FC = () => {
</Form.Row> </Form.Row>
<div className="logs"> <div className="logs">
{maybeRenderError} {maybeRenderError}
{filteredLogEntries.map(logEntry => ( {filteredLogEntries.map((logEntry) => (
<LogElement logEntry={logEntry} key={logEntry.id} /> <LogElement logEntry={logEntry} key={logEntry.id} />
))} ))}
</div> </div>

View File

@@ -16,7 +16,7 @@ export const GenerateButton: React.FC = () => {
sprites, sprites,
previews, previews,
markers, markers,
transcodes transcodes,
}); });
Toast.success({ content: "Started generating" }); Toast.success({ content: "Started generating" });
} catch (e) { } catch (e) {

View File

@@ -128,7 +128,7 @@ export const SettingsTasksPanel: React.FC = () => {
return { return {
performers: autoTagPerformers ? wildcard : [], performers: autoTagPerformers ? wildcard : [],
studios: autoTagStudios ? wildcard : [], studios: autoTagStudios ? wildcard : [],
tags: autoTagTags ? wildcard : [] tags: autoTagTags ? wildcard : [],
}; };
} }

View File

@@ -1,5 +1,6 @@
.logs { .logs {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
font-size: smaller; font-size: smaller;
max-height: 100vh; max-height: 100vh;
overflow-x: hidden; overflow-x: hidden;

View File

@@ -32,7 +32,7 @@ export const FolderSelect: React.FC<IProps> = (props: IProps) => {
function onRemoveDirectory(directory: string) { function onRemoveDirectory(directory: string) {
const newSelectedDirectories = selectedDirectories.filter( const newSelectedDirectories = selectedDirectories.filter(
dir => dir !== directory (dir) => dir !== directory
); );
setSelectedDirectories(newSelectedDirectories); setSelectedDirectories(newSelectedDirectories);
props.onDirectoriesChanged(newSelectedDirectories); props.onDirectoriesChanged(newSelectedDirectories);
@@ -66,7 +66,7 @@ export const FolderSelect: React.FC<IProps> = (props: IProps) => {
</InputGroup.Append> </InputGroup.Append>
</InputGroup> </InputGroup>
<ul className="folder-list"> <ul className="folder-list">
{selectableDirectories.map(path => { {selectableDirectories.map((path) => {
return ( return (
<li key={path} className="folder-item"> <li key={path} className="folder-item">
<Button <Button
@@ -96,7 +96,7 @@ export const FolderSelect: React.FC<IProps> = (props: IProps) => {
{error ? <h1>{error.message}</h1> : ""} {error ? <h1>{error.message}</h1> : ""}
{renderDialog()} {renderDialog()}
<Form.Group> <Form.Group>
{selectedDirectories.map(path => { {selectedDirectories.map((path) => {
return ( return (
<div key={path}> <div key={path}>
{path}{" "} {path}{" "}

View File

@@ -19,7 +19,7 @@ export const HoverPopover: React.FC<IHoverPopover> = ({
className, className,
placement = "top", placement = "top",
onOpen, onOpen,
onClose onClose,
}) => { }) => {
const [show, setShow] = useState(false); const [show, setShow] = useState(false);
const triggerRef = useRef<HTMLDivElement>(null); const triggerRef = useRef<HTMLDivElement>(null);

View File

@@ -12,7 +12,7 @@ export const ImageInput: React.FC<IImageInput> = ({
isEditing, isEditing,
text, text,
onImageChange, onImageChange,
acceptSVG = false acceptSVG = false,
}) => { }) => {
if (!isEditing) return <div />; if (!isEditing) return <div />;

View File

@@ -12,7 +12,7 @@ const CLASSNAME_MESSAGE = `${CLASSNAME}-message`;
const LoadingIndicator: React.FC<ILoadingProps> = ({ const LoadingIndicator: React.FC<ILoadingProps> = ({
message, message,
inline = false inline = false,
}) => ( }) => (
<div className={cx(CLASSNAME, { inline })}> <div className={cx(CLASSNAME, { inline })}>
<Spinner animation="border" role="status"> <Spinner animation="border" role="status">

View File

@@ -25,7 +25,7 @@ const ModalComponent: React.FC<IModal> = ({
header, header,
cancel, cancel,
accept, accept,
onHide onHide,
}) => ( }) => (
<Modal keyboard={false} onHide={onHide} show={show}> <Modal keyboard={false} onHide={onHide} show={show}>
<Modal.Header> <Modal.Header>

View File

@@ -1,9 +1,9 @@
import * as React from "react"; import * as React from "react";
import * as GQL from "src/core/generated-graphql"; import * as GQL from "src/core/generated-graphql";
import { FilterSelect } from "./Select";
import { Button, InputGroup } from "react-bootstrap"; import { Button, InputGroup } from "react-bootstrap";
import { Icon } from "src/components/Shared"; import { Icon } from "src/components/Shared";
import { FilterSelect } from "./Select";
type ValidTypes = type ValidTypes =
| GQL.SlimPerformerDataFragment | GQL.SlimPerformerDataFragment
@@ -18,13 +18,15 @@ interface IMultiSetProps {
onSetMode: (mode: GQL.BulkUpdateIdMode) => void; onSetMode: (mode: GQL.BulkUpdateIdMode) => void;
} }
const MultiSet: React.FunctionComponent<IMultiSetProps> = (props: IMultiSetProps) => { const MultiSet: React.FunctionComponent<IMultiSetProps> = (
props: IMultiSetProps
) => {
function onUpdate(items: ValidTypes[]) { function onUpdate(items: ValidTypes[]) {
props.onUpdate(items); props.onUpdate(items);
} }
function getModeIcon() { function getModeIcon() {
switch(props.mode) { switch (props.mode) {
case GQL.BulkUpdateIdMode.Set: case GQL.BulkUpdateIdMode.Set:
return "pencil-alt"; return "pencil-alt";
case GQL.BulkUpdateIdMode.Add: case GQL.BulkUpdateIdMode.Add:
@@ -35,7 +37,7 @@ const MultiSet: React.FunctionComponent<IMultiSetProps> = (props: IMultiSetProps
} }
function getModeText() { function getModeText() {
switch(props.mode) { switch (props.mode) {
case GQL.BulkUpdateIdMode.Set: case GQL.BulkUpdateIdMode.Set:
return "Set"; return "Set";
case GQL.BulkUpdateIdMode.Add: case GQL.BulkUpdateIdMode.Add:
@@ -46,7 +48,7 @@ const MultiSet: React.FunctionComponent<IMultiSetProps> = (props: IMultiSetProps
} }
function nextMode() { function nextMode() {
switch(props.mode) { switch (props.mode) {
case GQL.BulkUpdateIdMode.Set: case GQL.BulkUpdateIdMode.Set:
return GQL.BulkUpdateIdMode.Add; return GQL.BulkUpdateIdMode.Add;
case GQL.BulkUpdateIdMode.Add: case GQL.BulkUpdateIdMode.Add:

View File

@@ -57,11 +57,11 @@ interface ISceneGallerySelect {
const getSelectedValues = (selectedItems: ValueType<Option>) => const getSelectedValues = (selectedItems: ValueType<Option>) =>
selectedItems selectedItems
? (Array.isArray(selectedItems) ? selectedItems : [selectedItems]).map( ? (Array.isArray(selectedItems) ? selectedItems : [selectedItems]).map(
item => item.value (item) => item.value
) )
: []; : [];
export const SceneGallerySelect: React.FC<ISceneGallerySelect> = props => { export const SceneGallerySelect: React.FC<ISceneGallerySelect> = (props) => {
const { data, loading } = StashService.useValidGalleriesForScene( const { data, loading } = StashService.useValidGalleriesForScene(
props.sceneId props.sceneId
); );
@@ -69,17 +69,17 @@ export const SceneGallerySelect: React.FC<ISceneGallerySelect> = props => {
const items = (galleries.length > 0 const items = (galleries.length > 0
? [{ path: "None", id: "0" }, ...galleries] ? [{ path: "None", id: "0" }, ...galleries]
: [] : []
).map(g => ({ label: g.path, value: g.id })); ).map((g) => ({ label: g.path, value: g.id }));
const onChange = (selectedItems: ValueType<Option>) => { const onChange = (selectedItems: ValueType<Option>) => {
const selectedItem = getSelectedValues(selectedItems)[0]; const selectedItem = getSelectedValues(selectedItems)[0];
props.onSelect( props.onSelect(
selectedItem ? galleries.find(g => g.id === selectedItem) : undefined selectedItem ? galleries.find((g) => g.id === selectedItem) : undefined
); );
}; };
const selectedOptions: Option[] = props.initialId const selectedOptions: Option[] = props.initialId
? items.filter(item => props.initialId?.indexOf(item.value) !== -1) ? items.filter((item) => props.initialId?.indexOf(item.value) !== -1)
: []; : [];
return ( return (
@@ -98,7 +98,9 @@ interface IScrapePerformerSuggestProps {
onSelectPerformer: (performer: GQL.ScrapedPerformerDataFragment) => void; onSelectPerformer: (performer: GQL.ScrapedPerformerDataFragment) => void;
placeholder?: string; placeholder?: string;
} }
export const ScrapePerformerSuggest: React.FC<IScrapePerformerSuggestProps> = props => { export const ScrapePerformerSuggest: React.FC<IScrapePerformerSuggestProps> = (
props
) => {
const [query, setQuery] = React.useState<string>(""); const [query, setQuery] = React.useState<string>("");
const { data, loading } = StashService.useScrapePerformerList( const { data, loading } = StashService.useScrapePerformerList(
props.scraperId, props.scraperId,
@@ -106,9 +108,9 @@ export const ScrapePerformerSuggest: React.FC<IScrapePerformerSuggestProps> = pr
); );
const performers = data?.scrapePerformerList ?? []; const performers = data?.scrapePerformerList ?? [];
const items = performers.map(item => ({ const items = performers.map((item) => ({
label: item.name ?? "", label: item.name ?? "",
value: item.name ?? "" value: item.name ?? "",
})); }));
const onInputChange = useCallback( const onInputChange = useCallback(
@@ -119,7 +121,7 @@ export const ScrapePerformerSuggest: React.FC<IScrapePerformerSuggestProps> = pr
); );
const onChange = (selectedItems: ValueType<Option>) => { const onChange = (selectedItems: ValueType<Option>) => {
const name = getSelectedValues(selectedItems)[0]; const name = getSelectedValues(selectedItems)[0];
const performer = performers.find(p => p.name === name); const performer = performers.find((p) => p.name === name);
if (performer) props.onSelectPerformer(performer); if (performer) props.onSelectPerformer(performer);
}; };
@@ -141,16 +143,16 @@ interface IMarkerSuggestProps {
initialMarkerTitle?: string; initialMarkerTitle?: string;
onChange: (title: string) => void; onChange: (title: string) => void;
} }
export const MarkerTitleSuggest: React.FC<IMarkerSuggestProps> = props => { export const MarkerTitleSuggest: React.FC<IMarkerSuggestProps> = (props) => {
const { data, loading } = StashService.useMarkerStrings(); const { data, loading } = StashService.useMarkerStrings();
const suggestions = data?.markerStrings ?? []; const suggestions = data?.markerStrings ?? [];
const onChange = (selectedItems: ValueType<Option>) => const onChange = (selectedItems: ValueType<Option>) =>
props.onChange(getSelectedValues(selectedItems)[0]); props.onChange(getSelectedValues(selectedItems)[0]);
const items = suggestions.map(item => ({ const items = suggestions.map((item) => ({
label: item?.title ?? "", label: item?.title ?? "",
value: item?.title ?? "" value: item?.title ?? "",
})); }));
const initialIds = props.initialMarkerTitle ? [props.initialMarkerTitle] : []; const initialIds = props.initialMarkerTitle ? [props.initialMarkerTitle] : [];
return ( return (
@@ -167,7 +169,7 @@ export const MarkerTitleSuggest: React.FC<IMarkerSuggestProps> = props => {
/> />
); );
}; };
export const FilterSelect: React.FC<IFilterProps & ITypeProps> = props => export const FilterSelect: React.FC<IFilterProps & ITypeProps> = (props) =>
props.type === "performers" ? ( props.type === "performers" ? (
<PerformerSelect {...(props as IFilterProps)} /> <PerformerSelect {...(props as IFilterProps)} />
) : props.type === "studios" ? ( ) : props.type === "studios" ? (
@@ -178,23 +180,23 @@ export const FilterSelect: React.FC<IFilterProps & ITypeProps> = props =>
<TagSelect {...(props as IFilterProps)} /> <TagSelect {...(props as IFilterProps)} />
); );
export const PerformerSelect: React.FC<IFilterProps> = props => { export const PerformerSelect: React.FC<IFilterProps> = (props) => {
const { data, loading } = StashService.useAllPerformersForFilter(); const { data, loading } = StashService.useAllPerformersForFilter();
const normalizedData = data?.allPerformers ?? []; const normalizedData = data?.allPerformers ?? [];
const items: Option[] = normalizedData.map(item => ({ const items: Option[] = normalizedData.map((item) => ({
value: item.id, value: item.id,
label: item.name ?? "" label: item.name ?? "",
})); }));
const placeholder = props.noSelectionString ?? "Select performer..."; const placeholder = props.noSelectionString ?? "Select performer...";
const selectedOptions: Option[] = props.ids const selectedOptions: Option[] = props.ids
? items.filter(item => props.ids?.indexOf(item.value) !== -1) ? items.filter((item) => props.ids?.indexOf(item.value) !== -1)
: []; : [];
const onChange = (selectedItems: ValueType<Option>) => { const onChange = (selectedItems: ValueType<Option>) => {
const selectedIds = getSelectedValues(selectedItems); const selectedIds = getSelectedValues(selectedItems);
props.onSelect?.( props.onSelect?.(
normalizedData.filter(item => selectedIds.indexOf(item.id) !== -1) normalizedData.filter((item) => selectedIds.indexOf(item.id) !== -1)
); );
}; };
@@ -211,7 +213,7 @@ export const PerformerSelect: React.FC<IFilterProps> = props => {
); );
}; };
export const StudioSelect: React.FC<IFilterProps> = props => { export const StudioSelect: React.FC<IFilterProps> = (props) => {
const { data, loading } = StashService.useAllStudiosForFilter(); const { data, loading } = StashService.useAllStudiosForFilter();
const normalizedData = data?.allStudios ?? []; const normalizedData = data?.allStudios ?? [];
@@ -219,20 +221,20 @@ export const StudioSelect: React.FC<IFilterProps> = props => {
const items = (normalizedData.length > 0 const items = (normalizedData.length > 0
? [{ name: "None", id: "0" }, ...normalizedData] ? [{ name: "None", id: "0" }, ...normalizedData]
: [] : []
).map(item => ({ ).map((item) => ({
value: item.id, value: item.id,
label: item.name label: item.name,
})); }));
const placeholder = props.noSelectionString ?? "Select studio..."; const placeholder = props.noSelectionString ?? "Select studio...";
const selectedOptions: Option[] = props.ids const selectedOptions: Option[] = props.ids
? items.filter(item => props.ids?.indexOf(item.value) !== -1) ? items.filter((item) => props.ids?.indexOf(item.value) !== -1)
: []; : [];
const onChange = (selectedItems: ValueType<Option>) => { const onChange = (selectedItems: ValueType<Option>) => {
const selectedIds = getSelectedValues(selectedItems); const selectedIds = getSelectedValues(selectedItems);
props.onSelect?.( props.onSelect?.(
normalizedData.filter(item => selectedIds.indexOf(item.id) !== -1) normalizedData.filter((item) => selectedIds.indexOf(item.id) !== -1)
); );
}; };
@@ -249,7 +251,7 @@ export const StudioSelect: React.FC<IFilterProps> = props => {
); );
}; };
export const MovieSelect: React.FC<IFilterProps> = props => { export const MovieSelect: React.FC<IFilterProps> = (props) => {
const { data, loading } = StashService.useAllMoviesForFilter(); const { data, loading } = StashService.useAllMoviesForFilter();
const normalizedData = data?.allMovies ?? []; const normalizedData = data?.allMovies ?? [];
@@ -257,20 +259,20 @@ export const MovieSelect: React.FC<IFilterProps> = props => {
const items = (normalizedData.length > 0 const items = (normalizedData.length > 0
? [{ name: "None", id: "0" }, ...normalizedData] ? [{ name: "None", id: "0" }, ...normalizedData]
: [] : []
).map(item => ({ ).map((item) => ({
value: item.id, value: item.id,
label: item.name label: item.name,
})); }));
const placeholder = props.noSelectionString ?? "Select movie..."; const placeholder = props.noSelectionString ?? "Select movie...";
const selectedOptions: Option[] = props.ids const selectedOptions: Option[] = props.ids
? items.filter(item => props.ids?.indexOf(item.value) !== -1) ? items.filter((item) => props.ids?.indexOf(item.value) !== -1)
: []; : [];
const onChange = (selectedItems: ValueType<Option>) => { const onChange = (selectedItems: ValueType<Option>) => {
const selectedIds = getSelectedValues(selectedItems); const selectedIds = getSelectedValues(selectedItems);
props.onSelect?.( props.onSelect?.(
normalizedData.filter(item => selectedIds.indexOf(item.id) !== -1) normalizedData.filter((item) => selectedIds.indexOf(item.id) !== -1)
); );
}; };
@@ -287,7 +289,7 @@ export const MovieSelect: React.FC<IFilterProps> = props => {
); );
}; };
export const TagSelect: React.FC<IFilterProps> = props => { export const TagSelect: React.FC<IFilterProps> = (props) => {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [selectedIds, setSelectedIds] = useState<string[]>(props.ids ?? []); const [selectedIds, setSelectedIds] = useState<string[]>(props.ids ?? []);
const { data, loading: dataLoading } = StashService.useAllTagsForFilter(); const { data, loading: dataLoading } = StashService.useAllTagsForFilter();
@@ -299,25 +301,25 @@ export const TagSelect: React.FC<IFilterProps> = props => {
const tags = data?.allTags ?? []; const tags = data?.allTags ?? [];
const selected = tags const selected = tags
.filter(tag => selectedTags.indexOf(tag.id) !== -1) .filter((tag) => selectedTags.indexOf(tag.id) !== -1)
.map(tag => ({ value: tag.id, label: tag.name })); .map((tag) => ({ value: tag.id, label: tag.name }));
const items: Option[] = tags.map(item => ({ const items: Option[] = tags.map((item) => ({
value: item.id, value: item.id,
label: item.name label: item.name,
})); }));
const onCreate = async (tagName: string) => { const onCreate = async (tagName: string) => {
try { try {
setLoading(true); setLoading(true);
const result = await createTag({ const result = await createTag({
variables: { name: tagName } variables: { name: tagName },
}); });
if (result?.data?.tagCreate) { if (result?.data?.tagCreate) {
setSelectedIds([...selectedIds, result.data.tagCreate.id]); setSelectedIds([...selectedIds, result.data.tagCreate.id]);
props.onSelect?.( props.onSelect?.(
[...tags, result.data.tagCreate].filter( [...tags, result.data.tagCreate].filter(
item => selectedIds.indexOf(item.id) !== -1 (item) => selectedIds.indexOf(item.id) !== -1
) )
); );
setLoading(false); setLoading(false);
@@ -327,7 +329,7 @@ export const TagSelect: React.FC<IFilterProps> = props => {
<span> <span>
Created tag: <b>{tagName}</b> Created tag: <b>{tagName}</b>
</span> </span>
) ),
}); });
} }
} catch (e) { } catch (e) {
@@ -339,7 +341,7 @@ export const TagSelect: React.FC<IFilterProps> = props => {
const selectedValues = getSelectedValues(selectedItems); const selectedValues = getSelectedValues(selectedItems);
setSelectedIds(selectedValues); setSelectedIds(selectedValues);
props.onSelect?.( props.onSelect?.(
tags.filter(item => selectedValues.indexOf(item.id) !== -1) tags.filter((item) => selectedValues.indexOf(item.id) !== -1)
); );
}; };
@@ -374,35 +376,35 @@ const SelectComponent: React.FC<ISelectProps & ITypeProps> = ({
onInputChange, onInputChange,
placeholder, placeholder,
showDropdown = true, showDropdown = true,
groupHeader groupHeader,
}) => { }) => {
const defaultValue = const defaultValue =
items.filter(item => initialIds?.indexOf(item.value) !== -1) ?? null; items.filter((item) => initialIds?.indexOf(item.value) !== -1) ?? null;
const options = groupHeader const options = groupHeader
? [ ? [
{ {
label: groupHeader, label: groupHeader,
options: items options: items,
} },
] ]
: items; : items;
const styles = { const styles = {
option: (base: CSSProperties) => ({ option: (base: CSSProperties) => ({
...base, ...base,
color: "#000" color: "#000",
}), }),
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
container: (base: CSSProperties, state: any) => ({ container: (base: CSSProperties, state: any) => ({
...base, ...base,
zIndex: state.isFocused ? 10 : base.zIndex zIndex: state.isFocused ? 10 : base.zIndex,
}), }),
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
multiValueRemove: (base: CSSProperties, state: any) => ({ multiValueRemove: (base: CSSProperties, state: any) => ({
...base, ...base,
color: state.isFocused ? base.color : "#333333" color: state.isFocused ? base.color : "#333333",
}) }),
}; };
const props = { const props = {
@@ -423,8 +425,8 @@ const SelectComponent: React.FC<ISelectProps & ITypeProps> = ({
components: { components: {
IndicatorSeparator: () => null, IndicatorSeparator: () => null,
...((!showDropdown || isDisabled) && { DropdownIndicator: () => null }), ...((!showDropdown || isDisabled) && { DropdownIndicator: () => null }),
...(isDisabled && { MultiValueRemove: () => null }) ...(isDisabled && { MultiValueRemove: () => null }),
} },
}; };
return creatable ? ( return creatable ? (

View File

@@ -5,7 +5,7 @@ import {
PerformerDataFragment, PerformerDataFragment,
SceneMarkerDataFragment, SceneMarkerDataFragment,
TagDataFragment, TagDataFragment,
MovieDataFragment MovieDataFragment,
} from "src/core/generated-graphql"; } from "src/core/generated-graphql";
import { NavUtils, TextUtils } from "src/utils"; import { NavUtils, TextUtils } from "src/utils";

View File

@@ -5,7 +5,7 @@ export {
FilterSelect, FilterSelect,
PerformerSelect, PerformerSelect,
StudioSelect, StudioSelect,
TagSelect TagSelect,
} from "./Select"; } from "./Select";
export { default as Icon } from "./Icon"; export { default as Icon } from "./Icon";

View File

@@ -25,7 +25,7 @@
justify-content: left; justify-content: left;
.btn { .btn {
margin-right: .5rem; margin-right: 0.5rem;
} }
.delete, .delete,
@@ -58,7 +58,7 @@
} }
.folder-list { .folder-list {
margin-top: .5rem 0 0 0; margin-top: 0.5rem 0 0 0;
max-height: 30vw; max-height: 30vw;
overflow-x: auto; overflow-x: auto;
} }
@@ -69,9 +69,9 @@
} }
} }
.multi-set > div.input-group-prepend + div { .multi-set > div.input-group-prepend + div {
position: relative;
flex: 1 1; flex: 1 1;
min-width: 0;
margin-bottom: 0; margin-bottom: 0;
min-width: 0;
position: relative;
} }

View File

@@ -11,7 +11,7 @@ import { ImageUtils, TableUtils } from "src/utils";
import { import {
DetailsEditNavbar, DetailsEditNavbar,
Modal, Modal,
LoadingIndicator LoadingIndicator,
} from "src/components/Shared"; } from "src/components/Shared";
import { useToast } from "src/hooks"; import { useToast } from "src/hooks";
import { StudioScenesPanel } from "./StudioScenesPanel"; import { StudioScenesPanel } from "./StudioScenesPanel";
@@ -83,7 +83,7 @@ export const Studio: React.FC = () => {
const input: Partial<GQL.StudioCreateInput | GQL.StudioUpdateInput> = { const input: Partial<GQL.StudioCreateInput | GQL.StudioUpdateInput> = {
name, name,
url, url,
image image,
}; };
if (!isNew) { if (!isNew) {
@@ -155,7 +155,7 @@ export const Studio: React.FC = () => {
<div <div
className={cx("studio-details", { className={cx("studio-details", {
"col ml-sm-5": !isNew, "col ml-sm-5": !isNew,
"col-8": isNew "col-8": isNew,
})} })}
> >
{isNew && <h2>Add Studio</h2>} {isNew && <h2>Add Studio</h2>}
@@ -166,13 +166,13 @@ export const Studio: React.FC = () => {
title: "Name", title: "Name",
value: studio.name ?? "", value: studio.name ?? "",
isEditing: !!isEditing, isEditing: !!isEditing,
onChange: setName onChange: setName,
})} })}
{TableUtils.renderInputGroup({ {TableUtils.renderInputGroup({
title: "URL", title: "URL",
value: url, value: url,
isEditing: !!isEditing, isEditing: !!isEditing,
onChange: setUrl onChange: setUrl,
})} })}
</tbody> </tbody>
</Table> </Table>

View File

@@ -12,7 +12,7 @@ export const StudioScenesPanel: React.FC<IStudioScenesPanel> = ({ studio }) => {
function filterHook(filter: ListFilterModel) { function filterHook(filter: ListFilterModel) {
const studioValue = { id: studio.id!, label: studio.name! }; const studioValue = { id: studio.id!, label: studio.name! };
// if studio is already present, then we modify it, otherwise add // if studio is already present, then we modify it, otherwise add
let studioCriterion = filter.criteria.find(c => { let studioCriterion = filter.criteria.find((c) => {
return c.type === "studios"; return c.type === "studios";
}) as StudiosCriterion; }) as StudiosCriterion;
@@ -23,7 +23,7 @@ export const StudioScenesPanel: React.FC<IStudioScenesPanel> = ({ studio }) => {
) { ) {
// add the studio if not present // add the studio if not present
if ( if (
!studioCriterion.value.find(p => { !studioCriterion.value.find((p) => {
return p.id === studio.id; return p.id === studio.id;
}) })
) { ) {

View File

@@ -7,7 +7,7 @@ import { StudioCard } from "./StudioCard";
export const StudioList: React.FC = () => { export const StudioList: React.FC = () => {
const listData = useStudiosList({ const listData = useStudiosList({
renderContent renderContent,
}); });
function renderContent( function renderContent(
@@ -19,7 +19,7 @@ export const StudioList: React.FC = () => {
if (filter.displayMode === DisplayMode.Grid) { if (filter.displayMode === DisplayMode.Grid) {
return ( return (
<div className="row px-xl-5 justify-content-center"> <div className="row px-xl-5 justify-content-center">
{result.data.findStudios.studios.map(studio => ( {result.data.findStudios.studios.map((studio) => (
<StudioCard key={studio.id} studio={studio} /> <StudioCard key={studio.id} studio={studio} />
))} ))}
</div> </div>

View File

@@ -96,7 +96,7 @@ export const TagList: React.FC = () => {
if (!data?.allTags) return <LoadingIndicator />; if (!data?.allTags) return <LoadingIndicator />;
if (error) return <div>{error.message}</div>; if (error) return <div>{error.message}</div>;
const tagElements = data.allTags.map(tag => { const tagElements = data.allTags.map((tag) => {
return ( return (
<div key={tag.id} className="tag-list-row row"> <div key={tag.id} className="tag-list-row row">
<Button variant="link" onClick={() => setEditingTag(tag)}> <Button variant="link" onClick={() => setEditingTag(tag)}>
@@ -154,7 +154,7 @@ export const TagList: React.FC = () => {
accept={{ accept={{
onClick: onEdit, onClick: onEdit,
variant: "danger", variant: "danger",
text: editingTag?.id ? "Update" : "Create" text: editingTag?.id ? "Update" : "Create",
}} }}
> >
<Form.Group controlId="tag-name"> <Form.Group controlId="tag-name">

View File

@@ -1,10 +1,10 @@
.tag-list { .tag-list {
&-row { &-row {
margin: .5rem 0; margin: 0.5rem 0;
} }
&-button { &-button {
margin: 0 .5rem; margin: 0 0.5rem;
width: 8rem; width: 8rem;
} }
@@ -14,7 +14,7 @@
&-count { &-count {
display: inline-block; display: inline-block;
margin: 0 .5rem; margin: 0 0.5rem;
min-width: 6rem; min-width: 6rem;
} }
} }

View File

@@ -24,7 +24,7 @@ export const WallItem: React.FC<IWallItemProps> = (props: IWallItemProps) => {
const [tags, setTags] = useState<JSX.Element[]>([]); const [tags, setTags] = useState<JSX.Element[]>([]);
const config = StashService.useConfiguration(); const config = StashService.useConfiguration();
const videoHoverHook = VideoHoverHook.useVideoHover({ const videoHoverHook = VideoHoverHook.useVideoHover({
resetOnMouseLeave: true resetOnMouseLeave: true,
}); });
const showTextContainer = const showTextContainer =
config.data?.configuration.interface.wallShowTitle ?? true; config.data?.configuration.interface.wallShowTitle ?? true;
@@ -86,7 +86,7 @@ export const WallItem: React.FC<IWallItemProps> = (props: IWallItemProps) => {
props.sceneMarker.seconds props.sceneMarker.seconds
)}` )}`
); );
const thisTags = props.sceneMarker.tags.map(tag => ( const thisTags = props.sceneMarker.tags.map((tag) => (
<span key={tag.id} className="wall-tag"> <span key={tag.id} className="wall-tag">
{tag.name} {tag.name}
</span> </span>

View File

@@ -1,23 +1,23 @@
.wall-overlay { .wall-overlay {
background-color: rgba(0, 0, 0, .8); background-color: rgba(0, 0, 0, 0.8);
bottom: 0; bottom: 0;
left: 0; left: 0;
pointer-events: none; pointer-events: none;
position: fixed; position: fixed;
right: 0; right: 0;
top: 0; top: 0;
transition: transform .5s ease-in-out; transition: transform 0.5s ease-in-out;
z-index: 1; z-index: 1;
} }
.visible { .visible {
opacity: 1; opacity: 1;
transition: opacity .5s ease-in-out; transition: opacity 0.5s ease-in-out;
} }
.hidden { .hidden {
opacity: 0; opacity: 0;
transition: opacity .5s ease-in-out; transition: opacity 0.5s ease-in-out;
} }
.visible-unanimated { .visible-unanimated {
@@ -52,7 +52,7 @@
justify-content: center; justify-content: center;
max-height: 253px; max-height: 253px;
position: relative; position: relative;
transition: transform .5s; transition: transform 0.5s;
width: 100%; width: 100%;
} }
@@ -64,7 +64,10 @@
} }
.scene-wall-item-text-container { .scene-wall-item-text-container {
background: linear-gradient(rgba(255, 255, 255, .25), rgba(255, 255, 255, .65)); background: linear-gradient(
rgba(255, 255, 255, 0.25),
rgba(255, 255, 255, 0.65)
);
bottom: 0; bottom: 0;
color: #444; color: #444;
font-weight: 700; font-weight: 700;

View File

@@ -41,14 +41,14 @@ export class StashService {
const wsUrl = `${wsPlatformUrl.toString().slice(0, -1)}/graphql`; const wsUrl = `${wsPlatformUrl.toString().slice(0, -1)}/graphql`;
const httpLink = new HttpLink({ const httpLink = new HttpLink({
uri: url uri: url,
}); });
const wsLink = new WebSocketLink({ const wsLink = new WebSocketLink({
uri: wsUrl, uri: wsUrl,
options: { options: {
reconnect: true reconnect: true,
} },
}); });
const link = split( const link = split(
@@ -66,7 +66,7 @@ export class StashService {
StashService.cache = new InMemoryCache(); StashService.cache = new InMemoryCache();
StashService.client = new ApolloClient({ StashService.client = new ApolloClient({
link, link,
cache: StashService.cache cache: StashService.cache,
}); });
return StashService.client; return StashService.client;
@@ -77,14 +77,14 @@ export class StashService {
if (StashService.cache) { if (StashService.cache) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const cache = StashService.cache as any; const cache = StashService.cache as any;
const keyMatchers = queries.map(query => { const keyMatchers = queries.map((query) => {
return new RegExp(`^${query}`); return new RegExp(`^${query}`);
}); });
const rootQuery = cache.data.data.ROOT_QUERY; const rootQuery = cache.data.data.ROOT_QUERY;
Object.keys(rootQuery).forEach(key => { Object.keys(rootQuery).forEach((key) => {
if ( if (
keyMatchers.some(matcher => { keyMatchers.some((matcher) => {
return !!key.match(matcher); return !!key.match(matcher);
}) })
) { ) {
@@ -97,8 +97,8 @@ export class StashService {
public static useFindGalleries(filter: ListFilterModel) { public static useFindGalleries(filter: ListFilterModel) {
return GQL.useFindGalleriesQuery({ return GQL.useFindGalleriesQuery({
variables: { variables: {
filter: filter.makeFindFilter() filter: filter.makeFindFilter(),
} },
}); });
} }
@@ -116,8 +116,8 @@ export class StashService {
return GQL.useFindScenesQuery({ return GQL.useFindScenesQuery({
variables: { variables: {
filter: filter.makeFindFilter(), filter: filter.makeFindFilter(),
scene_filter: sceneFilter scene_filter: sceneFilter,
} },
}); });
} }
@@ -129,8 +129,8 @@ export class StashService {
query: GQL.FindScenesDocument, query: GQL.FindScenesDocument,
variables: { variables: {
filter: filter.makeFindFilter(), filter: filter.makeFindFilter(),
scene_filter: sceneFilter scene_filter: sceneFilter,
} },
}); });
} }
@@ -148,8 +148,8 @@ export class StashService {
return GQL.useFindSceneMarkersQuery({ return GQL.useFindSceneMarkersQuery({
variables: { variables: {
filter: filter.makeFindFilter(), filter: filter.makeFindFilter(),
scene_marker_filter: sceneMarkerFilter scene_marker_filter: sceneMarkerFilter,
} },
}); });
} }
@@ -161,24 +161,24 @@ export class StashService {
query: GQL.FindSceneMarkersDocument, query: GQL.FindSceneMarkersDocument,
variables: { variables: {
filter: filter.makeFindFilter(), filter: filter.makeFindFilter(),
scene_marker_filter: sceneMarkerFilter scene_marker_filter: sceneMarkerFilter,
} },
}); });
} }
public static useFindStudios(filter: ListFilterModel) { public static useFindStudios(filter: ListFilterModel) {
return GQL.useFindStudiosQuery({ return GQL.useFindStudiosQuery({
variables: { variables: {
filter: filter.makeFindFilter() filter: filter.makeFindFilter(),
} },
}); });
} }
public static useFindMovies(filter: ListFilterModel) { public static useFindMovies(filter: ListFilterModel) {
return GQL.useFindMoviesQuery({ return GQL.useFindMoviesQuery({
variables: { variables: {
filter: filter.makeFindFilter() filter: filter.makeFindFilter(),
} },
}); });
} }
@@ -196,8 +196,8 @@ export class StashService {
return GQL.useFindPerformersQuery({ return GQL.useFindPerformersQuery({
variables: { variables: {
filter: filter.makeFindFilter(), filter: filter.makeFindFilter(),
performer_filter: performerFilter performer_filter: performerFilter,
} },
}); });
} }
@@ -209,8 +209,8 @@ export class StashService {
query: GQL.FindPerformersDocument, query: GQL.FindPerformersDocument,
variables: { variables: {
filter: filter.makeFindFilter(), filter: filter.makeFindFilter(),
performer_filter: performerFilter performer_filter: performerFilter,
} },
}); });
} }
@@ -238,7 +238,7 @@ export class StashService {
"findSceneMarkers", "findSceneMarkers",
"findScenes", "findScenes",
"markerStrings", "markerStrings",
"sceneMarkerTags" "sceneMarkerTags",
]; ];
public static useSceneMarkerCreate() { public static useSceneMarkerCreate() {
@@ -257,7 +257,7 @@ export class StashService {
public static useScrapePerformerList(scraperId: string, q: string) { public static useScrapePerformerList(scraperId: string, q: string) {
return GQL.useScrapePerformerListQuery({ return GQL.useScrapePerformerListQuery({
variables: { scraper_id: scraperId, query: q }, variables: { scraper_id: scraperId, query: q },
skip: q === "" skip: q === "",
}); });
} }
public static useScrapePerformer( public static useScrapePerformer(
@@ -265,7 +265,7 @@ export class StashService {
scrapedPerformer: GQL.ScrapedPerformerInput scrapedPerformer: GQL.ScrapedPerformerInput
) { ) {
return GQL.useScrapePerformerQuery({ return GQL.useScrapePerformerQuery({
variables: { scraper_id: scraperId, scraped_performer: scrapedPerformer } variables: { scraper_id: scraperId, scraped_performer: scrapedPerformer },
}); });
} }
@@ -296,7 +296,7 @@ export class StashService {
} }
public static useValidGalleriesForScene(sceneId: string) { public static useValidGalleriesForScene(sceneId: string) {
return GQL.useValidGalleriesForSceneQuery({ return GQL.useValidGalleriesForSceneQuery({
variables: { scene_id: sceneId } variables: { scene_id: sceneId },
}); });
} }
public static useStats() { public static useStats() {
@@ -308,7 +308,7 @@ export class StashService {
public static useLatestVersion() { public static useLatestVersion() {
return GQL.useLatestVersionQuery({ return GQL.useLatestVersionQuery({
notifyOnNetworkStatusChange: true, notifyOnNetworkStatusChange: true,
errorPolicy: "ignore" errorPolicy: "ignore",
}); });
} }
@@ -323,7 +323,7 @@ export class StashService {
"findPerformers", "findPerformers",
"findScenes", "findScenes",
"findSceneMarkers", "findSceneMarkers",
"allPerformers" "allPerformers",
]; ];
public static usePerformerCreate() { public static usePerformerCreate() {
@@ -331,7 +331,7 @@ export class StashService {
update: () => update: () =>
StashService.invalidateQueries( StashService.invalidateQueries(
StashService.performerMutationImpactedQueries StashService.performerMutationImpactedQueries
) ),
}); });
} }
public static usePerformerUpdate() { public static usePerformerUpdate() {
@@ -339,7 +339,7 @@ export class StashService {
update: () => update: () =>
StashService.invalidateQueries( StashService.invalidateQueries(
StashService.performerMutationImpactedQueries StashService.performerMutationImpactedQueries
) ),
}); });
} }
public static usePerformerDestroy() { public static usePerformerDestroy() {
@@ -347,7 +347,7 @@ export class StashService {
update: () => update: () =>
StashService.invalidateQueries( StashService.invalidateQueries(
StashService.performerMutationImpactedQueries StashService.performerMutationImpactedQueries
) ),
}); });
} }
@@ -357,7 +357,7 @@ export class StashService {
"findSceneMarkers", "findSceneMarkers",
"findStudios", "findStudios",
"findMovies", "findMovies",
"allTags" "allTags",
// TODO - add "findTags" when it is implemented // TODO - add "findTags" when it is implemented
]; ];
@@ -368,7 +368,7 @@ export class StashService {
StashService.invalidateQueries( StashService.invalidateQueries(
StashService.sceneMutationImpactedQueries StashService.sceneMutationImpactedQueries
), ),
refetchQueries: ["AllTagsForFilter"] refetchQueries: ["AllTagsForFilter"],
}); });
} }
@@ -379,7 +379,7 @@ export class StashService {
"findSceneMarkers", "findSceneMarkers",
"findStudios", "findStudios",
"findMovies", "findMovies",
"allTags" "allTags",
]; ];
public static useBulkSceneUpdate(input: GQL.BulkSceneUpdateInput) { public static useBulkSceneUpdate(input: GQL.BulkSceneUpdateInput) {
@@ -388,7 +388,7 @@ export class StashService {
update: () => update: () =>
StashService.invalidateQueries( StashService.invalidateQueries(
StashService.sceneBulkMutationImpactedQueries StashService.sceneBulkMutationImpactedQueries
) ),
}); });
} }
@@ -398,19 +398,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 },
}); });
} }
@@ -420,20 +420,20 @@ export class StashService {
update: () => update: () =>
StashService.invalidateQueries( StashService.invalidateQueries(
StashService.sceneMutationImpactedQueries StashService.sceneMutationImpactedQueries
) ),
}); });
} }
public static useSceneGenerateScreenshot() { public static useSceneGenerateScreenshot() {
return GQL.useSceneGenerateScreenshotMutation({ return GQL.useSceneGenerateScreenshotMutation({
update: () => StashService.invalidateQueries(["findScenes"]) update: () => StashService.invalidateQueries(["findScenes"]),
}); });
} }
private static studioMutationImpactedQueries = [ private static studioMutationImpactedQueries = [
"findStudios", "findStudios",
"findScenes", "findScenes",
"allStudios" "allStudios",
]; ];
public static useStudioCreate(input: GQL.StudioCreateInput) { public static useStudioCreate(input: GQL.StudioCreateInput) {
@@ -442,7 +442,7 @@ export class StashService {
update: () => update: () =>
StashService.invalidateQueries( StashService.invalidateQueries(
StashService.studioMutationImpactedQueries StashService.studioMutationImpactedQueries
) ),
}); });
} }
@@ -452,7 +452,7 @@ export class StashService {
update: () => update: () =>
StashService.invalidateQueries( StashService.invalidateQueries(
StashService.studioMutationImpactedQueries StashService.studioMutationImpactedQueries
) ),
}); });
} }
@@ -462,14 +462,14 @@ export class StashService {
update: () => update: () =>
StashService.invalidateQueries( StashService.invalidateQueries(
StashService.studioMutationImpactedQueries StashService.studioMutationImpactedQueries
) ),
}); });
} }
private static movieMutationImpactedQueries = [ private static movieMutationImpactedQueries = [
"findMovies", "findMovies",
"findScenes", "findScenes",
"allMovies" "allMovies",
]; ];
public static useMovieCreate(input: GQL.MovieCreateInput) { public static useMovieCreate(input: GQL.MovieCreateInput) {
@@ -478,7 +478,7 @@ export class StashService {
update: () => update: () =>
StashService.invalidateQueries( StashService.invalidateQueries(
StashService.movieMutationImpactedQueries StashService.movieMutationImpactedQueries
) ),
}); });
} }
@@ -488,7 +488,7 @@ export class StashService {
update: () => update: () =>
StashService.invalidateQueries( StashService.invalidateQueries(
StashService.movieMutationImpactedQueries StashService.movieMutationImpactedQueries
) ),
}); });
} }
@@ -498,7 +498,7 @@ export class StashService {
update: () => update: () =>
StashService.invalidateQueries( StashService.invalidateQueries(
StashService.movieMutationImpactedQueries StashService.movieMutationImpactedQueries
) ),
}); });
} }
@@ -506,20 +506,20 @@ export class StashService {
"findScenes", "findScenes",
"findSceneMarkers", "findSceneMarkers",
"sceneMarkerTags", "sceneMarkerTags",
"allTags" "allTags",
]; ];
public static useTagCreate(input: GQL.TagCreateInput) { public static useTagCreate(input: GQL.TagCreateInput) {
return GQL.useTagCreateMutation({ return GQL.useTagCreateMutation({
variables: input, variables: input,
refetchQueries: ["AllTags", "AllTagsForFilter"] refetchQueries: ["AllTags", "AllTagsForFilter"],
// update: () => StashService.invalidateQueries(StashService.tagMutationImpactedQueries) // update: () => StashService.invalidateQueries(StashService.tagMutationImpactedQueries)
}); });
} }
public static useTagUpdate(input: GQL.TagUpdateInput) { public static useTagUpdate(input: GQL.TagUpdateInput) {
return GQL.useTagUpdateMutation({ return GQL.useTagUpdateMutation({
variables: input, variables: input,
refetchQueries: ["AllTags", "AllTagsForFilter"] refetchQueries: ["AllTags", "AllTagsForFilter"],
}); });
} }
public static useTagDestroy(input: GQL.TagDestroyInput) { public static useTagDestroy(input: GQL.TagDestroyInput) {
@@ -527,21 +527,21 @@ export class StashService {
variables: input, variables: input,
refetchQueries: ["AllTags", "AllTagsForFilter"], refetchQueries: ["AllTags", "AllTagsForFilter"],
update: () => update: () =>
StashService.invalidateQueries(StashService.tagMutationImpactedQueries) StashService.invalidateQueries(StashService.tagMutationImpactedQueries),
}); });
} }
public static useConfigureGeneral(input: GQL.ConfigGeneralInput) { public static useConfigureGeneral(input: GQL.ConfigGeneralInput) {
return GQL.useConfigureGeneralMutation({ return GQL.useConfigureGeneralMutation({
variables: { input }, variables: { input },
refetchQueries: ["Configuration"] refetchQueries: ["Configuration"],
}); });
} }
public static useConfigureInterface(input: GQL.ConfigInterfaceInput) { public static useConfigureInterface(input: GQL.ConfigInterfaceInput) {
return GQL.useConfigureInterfaceMutation({ return GQL.useConfigureInterfaceMutation({
variables: { input }, variables: { input },
refetchQueries: ["Configuration"] refetchQueries: ["Configuration"],
}); });
} }
@@ -555,19 +555,19 @@ export class StashService {
public static useLogs() { public static useLogs() {
return GQL.useLogsQuery({ return GQL.useLogsQuery({
fetchPolicy: "no-cache" fetchPolicy: "no-cache",
}); });
} }
public static useJobStatus() { public static useJobStatus() {
return GQL.useJobStatusQuery({ return GQL.useJobStatusQuery({
fetchPolicy: "no-cache" fetchPolicy: "no-cache",
}); });
} }
public static mutateStopJob() { public static mutateStopJob() {
return StashService.client.mutate<GQL.StopJobMutation>({ return StashService.client.mutate<GQL.StopJobMutation>({
mutation: GQL.StopJobDocument mutation: GQL.StopJobDocument,
}); });
} }
@@ -575,8 +575,8 @@ export class StashService {
return StashService.client.query<GQL.ScrapeFreeonesQuery>({ return StashService.client.query<GQL.ScrapeFreeonesQuery>({
query: GQL.ScrapeFreeonesDocument, query: GQL.ScrapeFreeonesDocument,
variables: { variables: {
performer_name: performerName performer_name: performerName,
} },
}); });
} }
@@ -588,8 +588,8 @@ export class StashService {
query: GQL.ScrapePerformerDocument, query: GQL.ScrapePerformerDocument,
variables: { variables: {
scraper_id: scraperId, scraper_id: scraperId,
scraped_performer: scrapedPerformer scraped_performer: scrapedPerformer,
} },
}); });
} }
@@ -597,8 +597,8 @@ export class StashService {
return StashService.client.query<GQL.ScrapePerformerUrlQuery>({ return StashService.client.query<GQL.ScrapePerformerUrlQuery>({
query: GQL.ScrapePerformerUrlDocument, query: GQL.ScrapePerformerUrlDocument,
variables: { variables: {
url url,
} },
}); });
} }
@@ -606,8 +606,8 @@ export class StashService {
return StashService.client.query<GQL.ScrapeSceneUrlQuery>({ return StashService.client.query<GQL.ScrapeSceneUrlQuery>({
query: GQL.ScrapeSceneUrlDocument, query: GQL.ScrapeSceneUrlDocument,
variables: { variables: {
url url,
} },
}); });
} }
@@ -619,54 +619,54 @@ export class StashService {
query: GQL.ScrapeSceneDocument, query: GQL.ScrapeSceneDocument,
variables: { variables: {
scraper_id: scraperId, scraper_id: scraperId,
scene scene,
} },
}); });
} }
public static mutateMetadataScan(input: GQL.ScanMetadataInput) { public static mutateMetadataScan(input: GQL.ScanMetadataInput) {
return StashService.client.mutate<GQL.MetadataScanMutation>({ return StashService.client.mutate<GQL.MetadataScanMutation>({
mutation: GQL.MetadataScanDocument, mutation: GQL.MetadataScanDocument,
variables: { input } variables: { input },
}); });
} }
public static mutateMetadataAutoTag(input: GQL.AutoTagMetadataInput) { public static mutateMetadataAutoTag(input: GQL.AutoTagMetadataInput) {
return StashService.client.mutate<GQL.MetadataAutoTagMutation>({ return StashService.client.mutate<GQL.MetadataAutoTagMutation>({
mutation: GQL.MetadataAutoTagDocument, mutation: GQL.MetadataAutoTagDocument,
variables: { input } variables: { input },
}); });
} }
public static mutateMetadataGenerate(input: GQL.GenerateMetadataInput) { public static mutateMetadataGenerate(input: GQL.GenerateMetadataInput) {
return StashService.client.mutate<GQL.MetadataGenerateMutation>({ return StashService.client.mutate<GQL.MetadataGenerateMutation>({
mutation: GQL.MetadataGenerateDocument, mutation: GQL.MetadataGenerateDocument,
variables: { input } variables: { input },
}); });
} }
public static mutateMetadataClean() { public static mutateMetadataClean() {
return StashService.client.mutate<GQL.MetadataCleanMutation>({ return StashService.client.mutate<GQL.MetadataCleanMutation>({
mutation: GQL.MetadataCleanDocument mutation: GQL.MetadataCleanDocument,
}); });
} }
public static mutateMetadataExport() { public static mutateMetadataExport() {
return StashService.client.mutate<GQL.MetadataExportMutation>({ return StashService.client.mutate<GQL.MetadataExportMutation>({
mutation: GQL.MetadataExportDocument mutation: GQL.MetadataExportDocument,
}); });
} }
public static mutateMetadataImport() { public static mutateMetadataImport() {
return StashService.client.mutate<GQL.MetadataImportMutation>({ return StashService.client.mutate<GQL.MetadataImportMutation>({
mutation: GQL.MetadataImportDocument mutation: GQL.MetadataImportDocument,
}); });
} }
public static querySceneByPathRegex(filter: GQL.FindFilterType) { public static querySceneByPathRegex(filter: GQL.FindFilterType) {
return StashService.client.query<GQL.FindScenesByPathRegexQuery>({ return StashService.client.query<GQL.FindScenesByPathRegexQuery>({
query: GQL.FindScenesByPathRegexDocument, query: GQL.FindScenesByPathRegexDocument,
variables: { filter } variables: { filter },
}); });
} }
@@ -677,26 +677,28 @@ export class StashService {
return StashService.client.query<GQL.ParseSceneFilenamesQuery>({ return StashService.client.query<GQL.ParseSceneFilenamesQuery>({
query: GQL.ParseSceneFilenamesDocument, query: GQL.ParseSceneFilenamesDocument,
variables: { filter, config }, variables: { filter, config },
fetchPolicy: "network-only" fetchPolicy: "network-only",
}); });
} }
private static stringGenderMap = new Map<string, GQL.GenderEnum>( private static stringGenderMap = new Map<string, GQL.GenderEnum>([
[["Male", GQL.GenderEnum.Male], ["Male", GQL.GenderEnum.Male],
["Female", GQL.GenderEnum.Female], ["Female", GQL.GenderEnum.Female],
["Transgender Male", GQL.GenderEnum.TransgenderMale], ["Transgender Male", GQL.GenderEnum.TransgenderMale],
["Transgender Female", GQL.GenderEnum.TransgenderFemale], ["Transgender Female", GQL.GenderEnum.TransgenderFemale],
["Intersex", GQL.GenderEnum.Intersex]] ["Intersex", GQL.GenderEnum.Intersex],
); ]);
public static genderToString(value?: GQL.GenderEnum) { public static genderToString(value?: GQL.GenderEnum) {
if (!value) { if (!value) {
return undefined; return undefined;
} }
const foundEntry = Array.from(StashService.stringGenderMap.entries()).find((e) => { const foundEntry = Array.from(StashService.stringGenderMap.entries()).find(
return e[1] === value; (e) => {
}); return e[1] === value;
}
);
if (foundEntry) { if (foundEntry) {
return foundEntry[0]; return foundEntry[0];

View File

@@ -16,11 +16,11 @@ import {
FindStudiosQueryResult, FindStudiosQueryResult,
FindPerformersQueryResult, FindPerformersQueryResult,
FindMoviesQueryResult, FindMoviesQueryResult,
MovieDataFragment MovieDataFragment,
} from "src/core/generated-graphql"; } from "src/core/generated-graphql";
import { import {
useInterfaceLocalForage, useInterfaceLocalForage,
IInterfaceConfig IInterfaceConfig,
} from "src/hooks/LocalForage"; } 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";
@@ -100,14 +100,14 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
const updateInterfaceConfig = useCallback( const updateInterfaceConfig = useCallback(
(updatedFilter: ListFilterModel) => { (updatedFilter: ListFilterModel) => {
setInterfaceState(config => { setInterfaceState((config) => {
const data = { ...config } as IInterfaceConfig; const data = { ...config } as IInterfaceConfig;
data.queries = { data.queries = {
[options.filterMode]: { [options.filterMode]: {
filter: updatedFilter.makeQueryParameters(), filter: updatedFilter.makeQueryParameters(),
itemsPerPage: updatedFilter.itemsPerPage, itemsPerPage: updatedFilter.itemsPerPage,
currentPage: updatedFilter.currentPage currentPage: updatedFilter.currentPage,
} },
}; };
return data; return data;
}); });
@@ -133,7 +133,7 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
sortdir: storedFilter.sortdir, sortdir: storedFilter.sortdir,
disp: storedFilter.disp, disp: storedFilter.disp,
perPage: storedFilter.perPage, perPage: storedFilter.perPage,
...queryFilter ...queryFilter,
} }
: storedFilter; : storedFilter;
@@ -161,7 +161,7 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
options.subComponent, options.subComponent,
options.filterMode, options.filterMode,
forageInitialised, forageInitialised,
updateInterfaceConfig updateInterfaceConfig,
]); ]);
function getFilter() { function getFilter() {
@@ -221,7 +221,7 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
const newFilter = _.cloneDeep(filter); const newFilter = _.cloneDeep(filter);
// Find if we are editing an existing criteria, then modify that. Or create a new one. // Find if we are editing an existing criteria, then modify that. Or create a new one.
const existingIndex = newFilter.criteria.findIndex(c => { const existingIndex = newFilter.criteria.findIndex((c) => {
// If we modified an existing criterion, then look for the old id. // If we modified an existing criterion, then look for the old id.
const id = oldId || criterion.getId(); const id = oldId || criterion.getId();
return c.getId() === id; return c.getId() === id;
@@ -234,7 +234,7 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
// Remove duplicate modifiers // Remove duplicate modifiers
newFilter.criteria = newFilter.criteria.filter((obj, pos, arr) => { newFilter.criteria = newFilter.criteria.filter((obj, pos, arr) => {
return arr.map(mapObj => mapObj.getId()).indexOf(obj.getId()) === pos; return arr.map((mapObj) => mapObj.getId()).indexOf(obj.getId()) === pos;
}); });
newFilter.currentPage = 1; newFilter.currentPage = 1;
@@ -244,7 +244,7 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
function onRemoveCriterion(removedCriterion: Criterion) { function onRemoveCriterion(removedCriterion: Criterion) {
const newFilter = _.cloneDeep(filter); const newFilter = _.cloneDeep(filter);
newFilter.criteria = newFilter.criteria.filter( newFilter.criteria = newFilter.criteria.filter(
criterion => criterion.getId() !== removedCriterion.getId() (criterion) => criterion.getId() !== removedCriterion.getId()
); );
newFilter.currentPage = 1; newFilter.currentPage = 1;
updateQueryParams(newFilter); updateQueryParams(newFilter);
@@ -281,7 +281,7 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
const subset = items.slice(start, end + 1); const subset = items.slice(start, end + 1);
const newSelectedIds: Set<string> = new Set(); const newSelectedIds: Set<string> = new Set();
subset.forEach(item => { subset.forEach((item) => {
newSelectedIds.add(item.id); newSelectedIds.add(item.id);
}); });
@@ -293,12 +293,12 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
let thisIndex = -1; let thisIndex = -1;
if (lastClickedId) { if (lastClickedId) {
startIndex = items.findIndex(item => { startIndex = items.findIndex((item) => {
return item.id === lastClickedId; return item.id === lastClickedId;
}); });
} }
thisIndex = items.findIndex(item => { thisIndex = items.findIndex((item) => {
return item.id === id; return item.id === id;
}); });
@@ -315,7 +315,7 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
function onSelectAll() { function onSelectAll() {
const newSelectedIds: Set<string> = new Set(); const newSelectedIds: Set<string> = new Set();
items.forEach(item => { items.forEach((item) => {
newSelectedIds.add(item.id); newSelectedIds.add(item.id);
}); });
@@ -334,12 +334,12 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
} }
const otherOperations = options.otherOperations const otherOperations = options.otherOperations
? options.otherOperations.map(o => { ? options.otherOperations.map((o) => {
return { return {
text: o.text, text: o.text,
onClick: () => { onClick: () => {
o.onClick(result, filter, selectedIds); o.onClick(result, filter, selectedIds);
} },
}; };
}) })
: undefined; : undefined;
@@ -401,7 +401,7 @@ export const useScenesList = (props: IListHookOptions<FindScenesQueryResult>) =>
getData: (result: FindScenesQueryResult) => getData: (result: FindScenesQueryResult) =>
result?.data?.findScenes?.scenes ?? [], result?.data?.findScenes?.scenes ?? [],
getCount: (result: FindScenesQueryResult) => getCount: (result: FindScenesQueryResult) =>
result?.data?.findScenes?.count ?? 0 result?.data?.findScenes?.count ?? 0,
}); });
export const useSceneMarkersList = ( export const useSceneMarkersList = (
@@ -414,7 +414,7 @@ export const useSceneMarkersList = (
getData: (result: FindSceneMarkersQueryResult) => getData: (result: FindSceneMarkersQueryResult) =>
result?.data?.findSceneMarkers?.scene_markers ?? [], result?.data?.findSceneMarkers?.scene_markers ?? [],
getCount: (result: FindSceneMarkersQueryResult) => getCount: (result: FindSceneMarkersQueryResult) =>
result?.data?.findSceneMarkers?.count ?? 0 result?.data?.findSceneMarkers?.count ?? 0,
}); });
export const useGalleriesList = ( export const useGalleriesList = (
@@ -427,7 +427,7 @@ export const useGalleriesList = (
getData: (result: FindGalleriesQueryResult) => getData: (result: FindGalleriesQueryResult) =>
result?.data?.findGalleries?.galleries ?? [], result?.data?.findGalleries?.galleries ?? [],
getCount: (result: FindGalleriesQueryResult) => getCount: (result: FindGalleriesQueryResult) =>
result?.data?.findGalleries?.count ?? 0 result?.data?.findGalleries?.count ?? 0,
}); });
export const useStudiosList = ( export const useStudiosList = (
@@ -440,7 +440,7 @@ export const useStudiosList = (
getData: (result: FindStudiosQueryResult) => getData: (result: FindStudiosQueryResult) =>
result?.data?.findStudios?.studios ?? [], result?.data?.findStudios?.studios ?? [],
getCount: (result: FindStudiosQueryResult) => getCount: (result: FindStudiosQueryResult) =>
result?.data?.findStudios?.count ?? 0 result?.data?.findStudios?.count ?? 0,
}); });
export const usePerformersList = ( export const usePerformersList = (
@@ -453,7 +453,7 @@ export const usePerformersList = (
getData: (result: FindPerformersQueryResult) => getData: (result: FindPerformersQueryResult) =>
result?.data?.findPerformers?.performers ?? [], result?.data?.findPerformers?.performers ?? [],
getCount: (result: FindPerformersQueryResult) => getCount: (result: FindPerformersQueryResult) =>
result?.data?.findPerformers?.count ?? 0 result?.data?.findPerformers?.count ?? 0,
}); });
export const useMoviesList = (props: IListHookOptions<FindMoviesQueryResult>) => export const useMoviesList = (props: IListHookOptions<FindMoviesQueryResult>) =>
@@ -464,5 +464,5 @@ export const useMoviesList = (props: IListHookOptions<FindMoviesQueryResult>) =>
getData: (result: FindMoviesQueryResult) => getData: (result: FindMoviesQueryResult) =>
result?.data?.findMovies?.movies ?? [], result?.data?.findMovies?.movies ?? [],
getCount: (result: FindMoviesQueryResult) => getCount: (result: FindMoviesQueryResult) =>
result?.data?.findMovies?.count ?? 0 result?.data?.findMovies?.count ?? 0,
}); });

View File

@@ -18,9 +18,9 @@ export const ToastProvider: React.FC = ({ children }) => {
const [toasts, setToasts] = useState<IActiveToast[]>([]); const [toasts, setToasts] = useState<IActiveToast[]>([]);
const removeToast = (id: number) => const removeToast = (id: number) =>
setToasts(toasts.filter(item => item.id !== id)); setToasts(toasts.filter((item) => item.id !== id));
const toastItems = toasts.map(toast => ( const toastItems = toasts.map((toast) => (
<Toast <Toast
autohide autohide
key={toast.id} key={toast.id}
@@ -55,9 +55,9 @@ function createHookObject(toastFunc: (toast: IToast) => void) {
toastFunc({ toastFunc({
variant: "danger", variant: "danger",
header: "Error", header: "Error",
content: error.message ?? error.toString() content: error.message ?? error.toString(),
}); });
} },
}; };
} }

View File

@@ -64,7 +64,7 @@ export class VideoHoverHook {
return; return;
} }
if (videoTag.paused && !data.isPlaying.current) { if (videoTag.paused && !data.isPlaying.current) {
videoTag.play().catch(error => { videoTag.play().catch((error) => {
console.log(error.message); console.log(error.message);
}); });
} }

View File

@@ -6,5 +6,5 @@ export {
useSceneMarkersList, useSceneMarkersList,
useGalleriesList, useGalleriesList,
useStudiosList, useStudiosList,
usePerformersList usePerformersList,
} from "./ListHook"; } from "./ListHook";

View File

@@ -32,18 +32,23 @@ a {
code, code,
.code { .code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
} }
.input-control, .input-control,
.text-input { .text-input {
border: 0; border: 0;
box-shadow: 0 0 0 0 rgba(19, 124, 189, 0), 0 0 0 0 rgba(19, 124, 189, 0), 0 0 0 0 rgba(19, 124, 189, 0), inset 0 0 0 1px rgba(16, 22, 26, .3), inset 0 1px 1px rgba(16, 22, 26, .4); box-shadow: 0 0 0 0 rgba(19, 124, 189, 0), 0 0 0 0 rgba(19, 124, 189, 0),
0 0 0 0 rgba(19, 124, 189, 0), inset 0 0 0 1px rgba(16, 22, 26, 0.3),
inset 0 1px 1px rgba(16, 22, 26, 0.4);
color: $text-color; color: $text-color;
&:focus { &:focus {
border: 0; border: 0;
box-shadow: 0 0 0 1px $primary, 0 0 0 1px $primary, 0 0 0 3px rgba(19, 124, 189, .3), inset 0 0 0 1px rgba(16, 22, 26, .3), inset 0 1px 1px rgba(16, 22, 26, .4); box-shadow: 0 0 0 1px $primary, 0 0 0 1px $primary,
0 0 0 3px rgba(19, 124, 189, 0.3), inset 0 0 0 1px rgba(16, 22, 26, 0.3),
inset 0 1px 1px rgba(16, 22, 26, 0.4);
color: $text-color; color: $text-color;
} }
} }
@@ -207,7 +212,7 @@ div.react-select__menu {
} }
.react-select__option--is-focused { .react-select__option--is-focused {
background-color: rgba(167, 182, 194, .3); background-color: rgba(167, 182, 194, 0.3);
} }
} }
} }
@@ -251,8 +256,8 @@ div.react-select__menu {
color: $dark-text; color: $dark-text;
font-size: 12px; font-size: 12px;
line-height: 1rem; line-height: 1rem;
margin-left: .5rem; margin-left: 0.5rem;
opacity: .5; opacity: 0.5;
padding: 0; padding: 0;
position: relative; position: relative;
@@ -308,7 +313,7 @@ div.react-select__menu {
.rating-banner { .rating-banner {
color: #fff; color: #fff;
display: block; display: block;
font-size: .86rem; font-size: 0.86rem;
font-weight: 400; font-weight: 400;
left: -46px; left: -46px;
letter-spacing: 1px; letter-spacing: 1px;
@@ -324,7 +329,8 @@ div.react-select__menu {
.card { .card {
background-color: #30404d; background-color: #30404d;
border-radius: 3px; border-radius: 3px;
box-shadow: 0 0 0 1px rgba(16, 22, 26, .4), 0 0 0 rgba(16, 22, 26, 0), 0 0 0 rgba(16, 22, 26, 0); box-shadow: 0 0 0 1px rgba(16, 22, 26, 0.4), 0 0 0 rgba(16, 22, 26, 0),
0 0 0 rgba(16, 22, 26, 0);
padding: 20px; padding: 20px;
} }
@@ -368,12 +374,13 @@ div.react-select__menu {
overflow: hidden; overflow: hidden;
position: relative; position: relative;
input[type=file], /* FF, IE7+, chrome (except button) */ input[type="file"], /* FF, IE7+, chrome (except button) */
input[type=file]::-webkit-file-upload-button { /* chromes and blink button */ input[type="file"]::-webkit-file-upload-button {
/* chromes and blink button */
cursor: pointer; cursor: pointer;
} }
[type=file] { [type="file"] {
display: block; display: block;
filter: alpha(opacity=0); filter: alpha(opacity=0);
font-size: 999px; font-size: 999px;
@@ -388,7 +395,7 @@ div.react-select__menu {
} }
.fa-icon { .fa-icon {
margin: 0 .4rem; margin: 0 0.4rem;
} }
.btn .fa-icon { .btn .fa-icon {
@@ -406,7 +413,7 @@ div.react-select__menu {
} }
.top-nav { .top-nav {
padding: .25rem 1rem; padding: 0.25rem 1rem;
.nav-link { .nav-link {
padding: 0; padding: 0;
@@ -439,7 +446,7 @@ div.react-select__menu {
.stats { .stats {
&-element { &-element {
flex-grow: 1; flex-grow: 1;
margin: auto .5rem; margin: auto 0.5rem;
} }
.title { .title {

View File

@@ -3,5 +3,5 @@ import de from "./de.json";
export default { export default {
en, en,
de de,
}; };

View File

@@ -129,7 +129,7 @@ export abstract class Criterion {
public getLabelValue(): string { public getLabelValue(): string {
if (typeof this.value === "string") return this.value; if (typeof this.value === "string") return this.value;
if (typeof this.value === "number") return this.value.toString(); if (typeof this.value === "number") return this.value.toString();
return this.value.map(v => v.label).join(", "); return this.value.map((v) => v.label).join(", ");
} }
public getLabel(): string { public getLabel(): string {
@@ -221,7 +221,7 @@ export class StringCriterion extends Criterion {
Criterion.getModifierOption(CriterionModifier.Equals), Criterion.getModifierOption(CriterionModifier.Equals),
Criterion.getModifierOption(CriterionModifier.NotEquals), Criterion.getModifierOption(CriterionModifier.NotEquals),
Criterion.getModifierOption(CriterionModifier.IsNull), Criterion.getModifierOption(CriterionModifier.IsNull),
Criterion.getModifierOption(CriterionModifier.NotNull) Criterion.getModifierOption(CriterionModifier.NotNull),
]; ];
public options: string[] | undefined; public options: string[] | undefined;
public value: string = ""; public value: string = "";
@@ -255,7 +255,7 @@ export class NumberCriterion extends Criterion {
Criterion.getModifierOption(CriterionModifier.GreaterThan), Criterion.getModifierOption(CriterionModifier.GreaterThan),
Criterion.getModifierOption(CriterionModifier.LessThan), Criterion.getModifierOption(CriterionModifier.LessThan),
Criterion.getModifierOption(CriterionModifier.IsNull), Criterion.getModifierOption(CriterionModifier.IsNull),
Criterion.getModifierOption(CriterionModifier.NotNull) Criterion.getModifierOption(CriterionModifier.NotNull),
]; ];
public options: number[] | undefined; public options: number[] | undefined;
public value: number = 0; public value: number = 0;
@@ -287,7 +287,7 @@ export class DurationCriterion extends Criterion {
Criterion.getModifierOption(CriterionModifier.Equals), Criterion.getModifierOption(CriterionModifier.Equals),
Criterion.getModifierOption(CriterionModifier.NotEquals), Criterion.getModifierOption(CriterionModifier.NotEquals),
Criterion.getModifierOption(CriterionModifier.GreaterThan), Criterion.getModifierOption(CriterionModifier.GreaterThan),
Criterion.getModifierOption(CriterionModifier.LessThan) Criterion.getModifierOption(CriterionModifier.LessThan),
]; ];
public options: number[] | undefined; public options: number[] | undefined;
public value: number = 0; public value: number = 0;

View File

@@ -1,10 +1,6 @@
import { CriterionModifier } from "src/core/generated-graphql"; import { CriterionModifier } from "src/core/generated-graphql";
import { StashService } from "src/core/StashService"; import { StashService } from "src/core/StashService";
import { import { Criterion, CriterionType, ICriterionOption } from "./criterion";
Criterion,
CriterionType,
ICriterionOption,
} from "./criterion";
export class GenderCriterion extends Criterion { export class GenderCriterion extends Criterion {
public type: CriterionType = "gender"; public type: CriterionType = "gender";

View File

@@ -13,7 +13,7 @@ export class IsMissingCriterion extends Criterion {
"gallery", "gallery",
"studio", "studio",
"movie", "movie",
"performers" "performers",
]; ];
public value: string = ""; public value: string = "";
} }

View File

@@ -14,13 +14,13 @@ export class MoviesCriterion extends Criterion {
public modifier = CriterionModifier.Includes; public modifier = CriterionModifier.Includes;
public modifierOptions = [ public modifierOptions = [
Criterion.getModifierOption(CriterionModifier.Includes), Criterion.getModifierOption(CriterionModifier.Includes),
Criterion.getModifierOption(CriterionModifier.Excludes) Criterion.getModifierOption(CriterionModifier.Excludes),
]; ];
public options: IOptionType[] = []; public options: IOptionType[] = [];
public value: ILabeledId[] = []; public value: ILabeledId[] = [];
public encodeValue() { public encodeValue() {
return this.value.map(o => { return this.value.map((o) => {
return encodeILabeledId(o); return encodeILabeledId(o);
}); });
} }

View File

@@ -9,13 +9,13 @@ export class PerformersCriterion extends Criterion {
public modifierOptions = [ public modifierOptions = [
Criterion.getModifierOption(CriterionModifier.IncludesAll), Criterion.getModifierOption(CriterionModifier.IncludesAll),
Criterion.getModifierOption(CriterionModifier.Includes), Criterion.getModifierOption(CriterionModifier.Includes),
Criterion.getModifierOption(CriterionModifier.Excludes) Criterion.getModifierOption(CriterionModifier.Excludes),
]; ];
public options: IOptionType[] = []; public options: IOptionType[] = [];
public value: ILabeledId[] = []; public value: ILabeledId[] = [];
public encodeValue() { public encodeValue() {
return this.value.map(o => { return this.value.map((o) => {
return encodeILabeledId(o); return encodeILabeledId(o);
}); });
} }

View File

@@ -11,7 +11,7 @@ export class RatingCriterion extends Criterion {
Criterion.getModifierOption(CriterionModifier.GreaterThan), Criterion.getModifierOption(CriterionModifier.GreaterThan),
Criterion.getModifierOption(CriterionModifier.LessThan), Criterion.getModifierOption(CriterionModifier.LessThan),
Criterion.getModifierOption(CriterionModifier.IsNull), Criterion.getModifierOption(CriterionModifier.IsNull),
Criterion.getModifierOption(CriterionModifier.NotNull) Criterion.getModifierOption(CriterionModifier.NotNull),
]; ];
public options: number[] = [1, 2, 3, 4, 5]; public options: number[] = [1, 2, 3, 4, 5];
public value: number = 0; public value: number = 0;

View File

@@ -8,13 +8,13 @@ export class StudiosCriterion extends Criterion {
public modifier = CriterionModifier.Includes; public modifier = CriterionModifier.Includes;
public modifierOptions = [ public modifierOptions = [
Criterion.getModifierOption(CriterionModifier.Includes), Criterion.getModifierOption(CriterionModifier.Includes),
Criterion.getModifierOption(CriterionModifier.Excludes) Criterion.getModifierOption(CriterionModifier.Excludes),
]; ];
public options: IOptionType[] = []; public options: IOptionType[] = [];
public value: ILabeledId[] = []; public value: ILabeledId[] = [];
public encodeValue() { public encodeValue() {
return this.value.map(o => { return this.value.map((o) => {
return encodeILabeledId(o); return encodeILabeledId(o);
}); });
} }

View File

@@ -9,7 +9,7 @@ export class TagsCriterion extends Criterion {
public modifierOptions = [ public modifierOptions = [
Criterion.getModifierOption(GQL.CriterionModifier.IncludesAll), Criterion.getModifierOption(GQL.CriterionModifier.IncludesAll),
Criterion.getModifierOption(GQL.CriterionModifier.Includes), Criterion.getModifierOption(GQL.CriterionModifier.Includes),
Criterion.getModifierOption(GQL.CriterionModifier.Excludes) Criterion.getModifierOption(GQL.CriterionModifier.Excludes),
]; ];
public options: IOptionType[] = []; public options: IOptionType[] = [];
public value: ILabeledId[] = []; public value: ILabeledId[] = [];
@@ -24,7 +24,7 @@ export class TagsCriterion extends Criterion {
} }
public encodeValue() { public encodeValue() {
return this.value.map(o => { return this.value.map((o) => {
return encodeILabeledId(o); return encodeILabeledId(o);
}); });
} }

View File

@@ -5,7 +5,7 @@ import {
CriterionType, CriterionType,
StringCriterion, StringCriterion,
NumberCriterion, NumberCriterion,
DurationCriterion DurationCriterion,
} from "./criterion"; } from "./criterion";
import { FavoriteCriterion } from "./favorite"; import { FavoriteCriterion } from "./favorite";
import { HasMarkersCriterion } from "./has-markers"; import { HasMarkersCriterion } from "./has-markers";
@@ -57,7 +57,7 @@ export function makeCriteria(type: CriterionType = "none") {
Criterion.getModifierOption(CriterionModifier.Equals), Criterion.getModifierOption(CriterionModifier.Equals),
Criterion.getModifierOption(CriterionModifier.NotEquals), Criterion.getModifierOption(CriterionModifier.NotEquals),
Criterion.getModifierOption(CriterionModifier.GreaterThan), Criterion.getModifierOption(CriterionModifier.GreaterThan),
Criterion.getModifierOption(CriterionModifier.LessThan) Criterion.getModifierOption(CriterionModifier.LessThan),
]; ];
return ret; return ret;
} }

View File

@@ -5,8 +5,9 @@ import {
ResolutionEnum, ResolutionEnum,
SceneFilterType, SceneFilterType,
SceneMarkerFilterType, SceneMarkerFilterType,
SortDirectionEnum SortDirectionEnum,
} from "src/core/generated-graphql"; } from "src/core/generated-graphql";
import { StashService } from "src/core/StashService";
import { import {
Criterion, Criterion,
ICriterionOption, ICriterionOption,
@@ -14,40 +15,39 @@ import {
CriterionOption, CriterionOption,
NumberCriterion, NumberCriterion,
StringCriterion, StringCriterion,
DurationCriterion DurationCriterion,
} from "./criteria/criterion"; } from "./criteria/criterion";
import { import {
FavoriteCriterion, FavoriteCriterion,
FavoriteCriterionOption FavoriteCriterionOption,
} from "./criteria/favorite"; } from "./criteria/favorite";
import { import {
HasMarkersCriterion, HasMarkersCriterion,
HasMarkersCriterionOption HasMarkersCriterionOption,
} from "./criteria/has-markers"; } from "./criteria/has-markers";
import { import {
IsMissingCriterion, IsMissingCriterion,
IsMissingCriterionOption IsMissingCriterionOption,
} from "./criteria/is-missing"; } from "./criteria/is-missing";
import { NoneCriterionOption } from "./criteria/none"; import { NoneCriterionOption } from "./criteria/none";
import { import {
PerformersCriterion, PerformersCriterion,
PerformersCriterionOption PerformersCriterionOption,
} from "./criteria/performers"; } from "./criteria/performers";
import { RatingCriterion, RatingCriterionOption } from "./criteria/rating"; import { RatingCriterion, RatingCriterionOption } from "./criteria/rating";
import { import {
ResolutionCriterion, ResolutionCriterion,
ResolutionCriterionOption ResolutionCriterionOption,
} from "./criteria/resolution"; } from "./criteria/resolution";
import { StudiosCriterion, StudiosCriterionOption } from "./criteria/studios"; import { StudiosCriterion, StudiosCriterionOption } from "./criteria/studios";
import { import {
SceneTagsCriterionOption, SceneTagsCriterionOption,
TagsCriterion, TagsCriterion,
TagsCriterionOption TagsCriterionOption,
} from "./criteria/tags"; } from "./criteria/tags";
import { makeCriteria } from "./criteria/utils"; import { makeCriteria } from "./criteria/utils";
import { DisplayMode, FilterMode } from "./types"; import { DisplayMode, FilterMode } from "./types";
import { GenderCriterionOption, GenderCriterion } from "./criteria/gender"; import { GenderCriterionOption, GenderCriterion } from "./criteria/gender";
import { StashService } from "src/core/StashService";
import { MoviesCriterionOption, MoviesCriterion } from "./criteria/movies"; import { MoviesCriterionOption, MoviesCriterion } from "./criteria/movies";
interface IQueryParameters { interface IQueryParameters {
@@ -64,7 +64,7 @@ const DEFAULT_PARAMS = {
sortDirection: SortDirectionEnum.Asc, sortDirection: SortDirectionEnum.Asc,
displayMode: DisplayMode.Grid, displayMode: DisplayMode.Grid,
currentPage: 1, currentPage: 1,
itemsPerPage: 40 itemsPerPage: 40,
}; };
// TODO: handle customCriteria // TODO: handle customCriteria
@@ -101,12 +101,12 @@ export class ListFilterModel {
"duration", "duration",
"framerate", "framerate",
"bitrate", "bitrate",
"random" "random",
]; ];
this.displayModeOptions = [ this.displayModeOptions = [
DisplayMode.Grid, DisplayMode.Grid,
DisplayMode.List, DisplayMode.List,
DisplayMode.Wall DisplayMode.Wall,
]; ];
this.criterionOptions = [ this.criterionOptions = [
new NoneCriterionOption(), new NoneCriterionOption(),
@@ -119,7 +119,7 @@ export class ListFilterModel {
new TagsCriterionOption(), new TagsCriterionOption(),
new PerformersCriterionOption(), new PerformersCriterionOption(),
new StudiosCriterionOption(), new StudiosCriterionOption(),
new MoviesCriterionOption() new MoviesCriterionOption(),
]; ];
break; break;
case FilterMode.Performers: { case FilterMode.Performers: {
@@ -138,7 +138,7 @@ export class ListFilterModel {
"career_length", "career_length",
"tattoos", "tattoos",
"piercings", "piercings",
"aliases" "aliases",
]; ];
this.criterionOptions = [ this.criterionOptions = [
@@ -148,7 +148,7 @@ export class ListFilterModel {
]; ];
this.criterionOptions = this.criterionOptions.concat( this.criterionOptions = this.criterionOptions.concat(
numberCriteria.concat(stringCriteria).map(c => { numberCriteria.concat(stringCriteria).map((c) => {
return ListFilterModel.createCriterionOption(c); return ListFilterModel.createCriterionOption(c);
}) })
); );
@@ -179,14 +179,14 @@ export class ListFilterModel {
"seconds", "seconds",
"scene_id", "scene_id",
"random", "random",
"scenes_updated_at" "scenes_updated_at",
]; ];
this.displayModeOptions = [DisplayMode.Wall]; this.displayModeOptions = [DisplayMode.Wall];
this.criterionOptions = [ this.criterionOptions = [
new NoneCriterionOption(), new NoneCriterionOption(),
new TagsCriterionOption(), new TagsCriterionOption(),
new SceneTagsCriterionOption(), new SceneTagsCriterionOption(),
new PerformersCriterionOption() new PerformersCriterionOption(),
]; ];
break; break;
default: default:
@@ -244,7 +244,7 @@ export class ListFilterModel {
jsonParameters = [params.c]; jsonParameters = [params.c];
} }
jsonParameters.forEach(jsonString => { jsonParameters.forEach((jsonString) => {
const encodedCriterion = JSON.parse(jsonString); const encodedCriterion = JSON.parse(jsonString);
const criterion = makeCriteria(encodedCriterion.type); const criterion = makeCriteria(encodedCriterion.type);
// it's possible that we have unsupported criteria. Just skip if so. // it's possible that we have unsupported criteria. Just skip if so.
@@ -281,7 +281,7 @@ export class ListFilterModel {
public makeQueryParameters(): string { public makeQueryParameters(): string {
const encodedCriteria: string[] = []; const encodedCriteria: string[] = [];
this.criteria.forEach(criterion => { this.criteria.forEach((criterion) => {
const encodedCriterion: Partial<Criterion> = { const encodedCriterion: Partial<Criterion> = {
type: criterion.type, type: criterion.type,
// #394 - the presence of a # symbol results in the query URL being // #394 - the presence of a # symbol results in the query URL being
@@ -289,7 +289,7 @@ export class ListFilterModel {
// call below, but this results in a URL that gets pretty long and ugly. // call below, but this results in a URL that gets pretty long and ugly.
// Instead, we'll encode the criteria values. // Instead, we'll encode the criteria values.
value: criterion.encodeValue(), value: criterion.encodeValue(),
modifier: criterion.modifier modifier: criterion.modifier,
}; };
const jsonCriterion = JSON.stringify(encodedCriterion); const jsonCriterion = JSON.stringify(encodedCriterion);
encodedCriteria.push(jsonCriterion); encodedCriteria.push(jsonCriterion);
@@ -312,7 +312,7 @@ export class ListFilterModel {
this.currentPage !== DEFAULT_PARAMS.currentPage this.currentPage !== DEFAULT_PARAMS.currentPage
? this.currentPage ? this.currentPage
: undefined, : undefined,
c: encodedCriteria c: encodedCriteria,
}; };
return queryString.stringify(result, { encode: false }); return queryString.stringify(result, { encode: false });
} }
@@ -325,19 +325,19 @@ export class ListFilterModel {
page: this.currentPage, page: this.currentPage,
per_page: this.itemsPerPage, per_page: this.itemsPerPage,
sort: this.getSortBy(), sort: this.getSortBy(),
direction: this.sortDirection direction: this.sortDirection,
}; };
} }
public makeSceneFilter(): SceneFilterType { public makeSceneFilter(): SceneFilterType {
const result: SceneFilterType = {}; const result: SceneFilterType = {};
this.criteria.forEach(criterion => { this.criteria.forEach((criterion) => {
switch (criterion.type) { switch (criterion.type) {
case "rating": { case "rating": {
const ratingCrit = criterion as RatingCriterion; const ratingCrit = criterion as RatingCriterion;
result.rating = { result.rating = {
value: ratingCrit.value, value: ratingCrit.value,
modifier: ratingCrit.modifier modifier: ratingCrit.modifier,
}; };
break; break;
} }
@@ -345,7 +345,7 @@ export class ListFilterModel {
const oCounterCrit = criterion as NumberCriterion; const oCounterCrit = criterion as NumberCriterion;
result.o_counter = { result.o_counter = {
value: oCounterCrit.value, value: oCounterCrit.value,
modifier: oCounterCrit.modifier modifier: oCounterCrit.modifier,
}; };
break; break;
} }
@@ -374,7 +374,7 @@ export class ListFilterModel {
const durationCrit = criterion as DurationCriterion; const durationCrit = criterion as DurationCriterion;
result.duration = { result.duration = {
value: durationCrit.value, value: durationCrit.value,
modifier: durationCrit.modifier modifier: durationCrit.modifier,
}; };
break; break;
} }
@@ -387,32 +387,32 @@ export class ListFilterModel {
case "tags": { case "tags": {
const tagsCrit = criterion as TagsCriterion; const tagsCrit = criterion as TagsCriterion;
result.tags = { result.tags = {
value: tagsCrit.value.map(tag => tag.id), value: tagsCrit.value.map((tag) => tag.id),
modifier: tagsCrit.modifier modifier: tagsCrit.modifier,
}; };
break; break;
} }
case "performers": { case "performers": {
const perfCrit = criterion as PerformersCriterion; const perfCrit = criterion as PerformersCriterion;
result.performers = { result.performers = {
value: perfCrit.value.map(perf => perf.id), value: perfCrit.value.map((perf) => perf.id),
modifier: perfCrit.modifier modifier: perfCrit.modifier,
}; };
break; break;
} }
case "studios": { case "studios": {
const studCrit = criterion as StudiosCriterion; const studCrit = criterion as StudiosCriterion;
result.studios = { result.studios = {
value: studCrit.value.map(studio => studio.id), value: studCrit.value.map((studio) => studio.id),
modifier: studCrit.modifier modifier: studCrit.modifier,
}; };
break; break;
} }
case "movies": { case "movies": {
const movCrit = criterion as MoviesCriterion; const movCrit = criterion as MoviesCriterion;
result.movies = { result.movies = {
value: movCrit.value.map(movie => movie.id), value: movCrit.value.map((movie) => movie.id),
modifier: movCrit.modifier modifier: movCrit.modifier,
}; };
break; break;
} }
@@ -424,7 +424,7 @@ export class ListFilterModel {
public makePerformerFilter(): PerformerFilterType { public makePerformerFilter(): PerformerFilterType {
const result: PerformerFilterType = {}; const result: PerformerFilterType = {};
this.criteria.forEach(criterion => { this.criteria.forEach((criterion) => {
switch (criterion.type) { switch (criterion.type) {
case "favorite": case "favorite":
result.filter_favorites = result.filter_favorites =
@@ -434,7 +434,7 @@ export class ListFilterModel {
const byCrit = criterion as NumberCriterion; const byCrit = criterion as NumberCriterion;
result.birth_year = { result.birth_year = {
value: byCrit.value, value: byCrit.value,
modifier: byCrit.modifier modifier: byCrit.modifier,
}; };
break; break;
} }
@@ -447,7 +447,7 @@ export class ListFilterModel {
const ethCrit = criterion as StringCriterion; const ethCrit = criterion as StringCriterion;
result.ethnicity = { result.ethnicity = {
value: ethCrit.value, value: ethCrit.value,
modifier: ethCrit.modifier modifier: ethCrit.modifier,
}; };
break; break;
} }
@@ -455,7 +455,7 @@ export class ListFilterModel {
const cntryCrit = criterion as StringCriterion; const cntryCrit = criterion as StringCriterion;
result.country = { result.country = {
value: cntryCrit.value, value: cntryCrit.value,
modifier: cntryCrit.modifier modifier: cntryCrit.modifier,
}; };
break; break;
} }
@@ -473,7 +473,7 @@ export class ListFilterModel {
const mCrit = criterion as StringCriterion; const mCrit = criterion as StringCriterion;
result.measurements = { result.measurements = {
value: mCrit.value, value: mCrit.value,
modifier: mCrit.modifier modifier: mCrit.modifier,
}; };
break; break;
} }
@@ -486,7 +486,7 @@ export class ListFilterModel {
const clCrit = criterion as StringCriterion; const clCrit = criterion as StringCriterion;
result.career_length = { result.career_length = {
value: clCrit.value, value: clCrit.value,
modifier: clCrit.modifier modifier: clCrit.modifier,
}; };
break; break;
} }
@@ -507,7 +507,10 @@ export class ListFilterModel {
} }
case "gender": { case "gender": {
const gCrit = criterion as GenderCriterion; const gCrit = criterion as GenderCriterion;
result.gender = { value: StashService.stringToGender(gCrit.value), modifier: gCrit.modifier }; result.gender = {
value: StashService.stringToGender(gCrit.value),
modifier: gCrit.modifier,
};
break; break;
} }
// no default // no default
@@ -518,29 +521,29 @@ export class ListFilterModel {
public makeSceneMarkerFilter(): SceneMarkerFilterType { public makeSceneMarkerFilter(): SceneMarkerFilterType {
const result: SceneMarkerFilterType = {}; const result: SceneMarkerFilterType = {};
this.criteria.forEach(criterion => { this.criteria.forEach((criterion) => {
switch (criterion.type) { switch (criterion.type) {
case "tags": { case "tags": {
const tagsCrit = criterion as TagsCriterion; const tagsCrit = criterion as TagsCriterion;
result.tags = { result.tags = {
value: tagsCrit.value.map(tag => tag.id), value: tagsCrit.value.map((tag) => tag.id),
modifier: tagsCrit.modifier modifier: tagsCrit.modifier,
}; };
break; break;
} }
case "sceneTags": { case "sceneTags": {
const sceneTagsCrit = criterion as TagsCriterion; const sceneTagsCrit = criterion as TagsCriterion;
result.scene_tags = { result.scene_tags = {
value: sceneTagsCrit.value.map(tag => tag.id), value: sceneTagsCrit.value.map((tag) => tag.id),
modifier: sceneTagsCrit.modifier modifier: sceneTagsCrit.modifier,
}; };
break; break;
} }
case "performers": { case "performers": {
const performersCrit = criterion as PerformersCriterion; const performersCrit = criterion as PerformersCriterion;
result.performers = { result.performers = {
value: performersCrit.value.map(performer => performer.id), value: performersCrit.value.map((performer) => performer.id),
modifier: performersCrit.modifier modifier: performersCrit.modifier,
}; };
break; break;
} }

View File

@@ -3,7 +3,7 @@
export enum DisplayMode { export enum DisplayMode {
Grid, Grid,
List, List,
Wall Wall,
} }
export enum FilterMode { export enum FilterMode {
@@ -12,7 +12,7 @@ export enum FilterMode {
Studios, Studios,
Galleries, Galleries,
SceneMarkers, SceneMarkers,
Movies Movies,
} }
export interface ILabeledId { export interface ILabeledId {

View File

@@ -30,7 +30,7 @@ interface IConfig {
function registerValidSW(swUrl: string, config?: IConfig) { function registerValidSW(swUrl: string, config?: IConfig) {
navigator.serviceWorker navigator.serviceWorker
.register(swUrl) .register(swUrl)
.then(registration => { .then((registration) => {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
registration.onupdatefound = () => { registration.onupdatefound = () => {
const installingWorker = registration.installing; const installingWorker = registration.installing;
@@ -67,7 +67,7 @@ function registerValidSW(swUrl: string, config?: IConfig) {
}; };
}; };
}) })
.catch(error => { .catch((error) => {
console.error("Error during service worker registration:", error); console.error("Error during service worker registration:", error);
}); });
} }
@@ -75,7 +75,7 @@ function registerValidSW(swUrl: string, config?: IConfig) {
function checkValidServiceWorker(swUrl: string, config?: IConfig) { function checkValidServiceWorker(swUrl: string, config?: IConfig) {
// Check if the service worker can be found. If it can't reload the page. // Check if the service worker can be found. If it can't reload the page.
fetch(swUrl) fetch(swUrl)
.then(response => { .then((response) => {
// Ensure service worker exists, and that we really are getting a JS file. // Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get("content-type"); const contentType = response.headers.get("content-type");
if ( if (
@@ -83,7 +83,7 @@ function checkValidServiceWorker(swUrl: string, config?: IConfig) {
(contentType != null && contentType.indexOf("javascript") === -1) (contentType != null && contentType.indexOf("javascript") === -1)
) { ) {
// No service worker found. Probably a different app. Reload the page. // No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => { navigator.serviceWorker.ready.then((registration) => {
registration.unregister().then(() => { registration.unregister().then(() => {
window.location.reload(); window.location.reload();
}); });
@@ -139,7 +139,7 @@ export function register(config?: IConfig) {
export function unregister() { export function unregister() {
if ("serviceWorker" in navigator) { if ("serviceWorker" in navigator) {
navigator.serviceWorker.ready.then(registration => { navigator.serviceWorker.ready.then((registration) => {
registration.unregister(); registration.unregister();
}); });
} }

View File

@@ -1,4 +1,4 @@
input[type=range] { input[type="range"] {
-webkit-appearance: none; -webkit-appearance: none;
background-color: transparent; background-color: transparent;
border-color: transparent; border-color: transparent;
@@ -14,7 +14,7 @@ input[type=range] {
} }
&::-webkit-slider-runnable-track { &::-webkit-slider-runnable-track {
animate: .2s; animate: 0.2s;
background: #137cbd; background: #137cbd;
border: 0 solid #000101; border: 0 solid #000101;
border-radius: 25px; border-radius: 25px;
@@ -41,7 +41,7 @@ input[type=range] {
} }
&::-moz-range-track { &::-moz-range-track {
animate: .2s; animate: 0.2s;
background: #137cbd; background: #137cbd;
border: 0 solid #000101; border: 0 solid #000101;
border-radius: 25px; border-radius: 25px;
@@ -62,7 +62,7 @@ input[type=range] {
} }
&::-ms-track { &::-ms-track {
animate: .2s; animate: 0.2s;
background: transparent; background: transparent;
border-color: transparent; border-color: transparent;
color: transparent; color: transparent;

View File

@@ -11,7 +11,7 @@
textarea::selection, textarea::selection,
input::selection { input::selection {
background-color: rgba(100, 100, 100, .4); background-color: rgba(100, 100, 100, 0.4);
color: $dark-text; color: $dark-text;
} }
@@ -24,21 +24,21 @@ body ::-webkit-scrollbar {
} }
body ::-webkit-scrollbar-track { body ::-webkit-scrollbar-track {
background: rgba(0, 0, 0, .1); background: rgba(0, 0, 0, 0.1);
border-radius: 0; border-radius: 0;
} }
body ::-webkit-scrollbar-thumb { body ::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, .25); background: rgba(0, 0, 0, 0.25);
border-radius: 5px; border-radius: 5px;
cursor: pointer; cursor: pointer;
transition: color .2s ease; transition: color 0.2s ease;
} }
body ::-webkit-scrollbar-thumb:window-inactive { body ::-webkit-scrollbar-thumb:window-inactive {
background: rgba(0, 0, 0, .15); background: rgba(0, 0, 0, 0.15);
} }
body ::-webkit-scrollbar-thumb:hover { body ::-webkit-scrollbar-thumb:hover {
background: rgba(128, 135, 139, .8); background: rgba(128, 135, 139, 0.8);
} }

View File

@@ -1,4 +1,3 @@
/* Blueprint dark theme */ /* Blueprint dark theme */
$secondary: #394b59; $secondary: #394b59;
@@ -13,7 +12,7 @@ $theme-colors: (
success: $success, success: $success,
warning: $warning, warning: $warning,
danger: $danger, danger: $danger,
dark: #394b59 dark: #394b59,
); );
$body-bg: #202b33; $body-bg: #202b33;
@@ -25,7 +24,7 @@ $pre-color: $text-color;
$navbar-dark-color: rgb(245, 248, 250); $navbar-dark-color: rgb(245, 248, 250);
$popover-bg: $secondary; $popover-bg: $secondary;
$dark-text: #182026; $dark-text: #182026;
$textfield-bg: rgba(16, 22, 26, .3); $textfield-bg: rgba(16, 22, 26, 0.3);
@import "node_modules/bootstrap/scss/bootstrap"; @import "node_modules/bootstrap/scss/bootstrap";
@@ -37,7 +36,7 @@ $dark-gray5: #394b59;
.btn.active:not(.disabled), .btn.active:not(.disabled),
.btn.active.minimal:not(.disabled) { .btn.active.minimal:not(.disabled) {
background-color: rgba(138, 155, 168, .3); background-color: rgba(138, 155, 168, 0.3);
color: $text-color; color: $text-color;
} }
@@ -49,12 +48,12 @@ button.minimal {
transition: none; transition: none;
&:hover { &:hover {
background: rgba(138, 155, 168, .15); background: rgba(138, 155, 168, 0.15);
color: $text-color; color: $text-color;
} }
&:active { &:active {
background: rgba(138, 155, 168, .3); background: rgba(138, 155, 168, 0.3);
color: $text-color; color: $text-color;
} }
} }
@@ -74,7 +73,7 @@ hr {
.nav-tabs { .nav-tabs {
border: none; border: none;
margin: auto; margin: auto;
margin-bottom: .5rem; margin-bottom: 0.5rem;
.nav-link { .nav-link {
border: none; border: none;
@@ -102,7 +101,7 @@ hr {
} }
.table-striped tr:nth-child(odd) td { .table-striped tr:nth-child(odd) td {
background: rgba(92, 112, 128, .15); background: rgba(92, 112, 128, 0.15);
} }
.table { .table {
@@ -120,7 +119,7 @@ hr {
td { td {
border: none; border: none;
border-color: #414c53; border-color: #414c53;
padding: .25rem .75rem; padding: 0.25rem 0.75rem;
&:first-child { &:first-child {
padding-left: 0; padding-left: 0;

View File

@@ -47,5 +47,5 @@ const stringToSeconds = (v: string) => {
export default { export default {
secondsToString, secondsToString,
stringToSeconds stringToSeconds,
}; };

View File

@@ -36,6 +36,6 @@ const usePasteImage = (onLoadEnd: (this: FileReader) => void) => {
const Image = { const Image = {
onImageChange, onImageChange,
usePasteImage usePasteImage,
}; };
export default Image; export default Image;

View File

@@ -4,5 +4,5 @@ const getPlayer = () => (window as any).jwplayer(playerID);
export default { export default {
playerID, playerID,
getPlayer getPlayer,
}; };

View File

@@ -13,7 +13,7 @@ const makePerformerScenesUrl = (
const filter = new ListFilterModel(FilterMode.Scenes); const filter = new ListFilterModel(FilterMode.Scenes);
const criterion = new PerformersCriterion(); const criterion = new PerformersCriterion();
criterion.value = [ criterion.value = [
{ id: performer.id, label: performer.name || `Performer ${performer.id}` } { id: performer.id, label: performer.name || `Performer ${performer.id}` },
]; ];
filter.criteria.push(criterion); filter.criteria.push(criterion);
return `/scenes?${filter.makeQueryParameters()}`; return `/scenes?${filter.makeQueryParameters()}`;
@@ -24,7 +24,7 @@ const makeStudioScenesUrl = (studio: Partial<GQL.StudioDataFragment>) => {
const filter = new ListFilterModel(FilterMode.Scenes); const filter = new ListFilterModel(FilterMode.Scenes);
const criterion = new StudiosCriterion(); const criterion = new StudiosCriterion();
criterion.value = [ criterion.value = [
{ id: studio.id, label: studio.name || `Studio ${studio.id}` } { id: studio.id, label: studio.name || `Studio ${studio.id}` },
]; ];
filter.criteria.push(criterion); filter.criteria.push(criterion);
return `/scenes?${filter.makeQueryParameters()}`; return `/scenes?${filter.makeQueryParameters()}`;
@@ -35,7 +35,7 @@ const makeMovieScenesUrl = (movie: Partial<GQL.MovieDataFragment>) => {
const filter = new ListFilterModel(FilterMode.Scenes); const filter = new ListFilterModel(FilterMode.Scenes);
const criterion = new MoviesCriterion(); const criterion = new MoviesCriterion();
criterion.value = [ criterion.value = [
{ id: movie.id, label: movie.name || `Movie ${movie.id}` } { id: movie.id, label: movie.name || `Movie ${movie.id}` },
]; ];
filter.criteria.push(criterion); filter.criteria.push(criterion);
return `/scenes?${filter.makeQueryParameters()}`; return `/scenes?${filter.makeQueryParameters()}`;
@@ -72,5 +72,5 @@ export default {
makeTagSceneMarkersUrl, makeTagSceneMarkersUrl,
makeTagScenesUrl, makeTagScenesUrl,
makeSceneMarkerUrl, makeSceneMarkerUrl,
makeMovieScenesUrl makeMovieScenesUrl,
}; };

View File

@@ -97,7 +97,7 @@ const renderHtmlSelect = (options: {
options.onChange(event.currentTarget.value) options.onChange(event.currentTarget.value)
} }
> >
{options.selectOptions.map(opt => ( {options.selectOptions.map((opt) => (
<option value={opt} key={opt}> <option value={opt} key={opt}>
{opt} {opt}
</option> </option>
@@ -119,7 +119,7 @@ const renderFilterSelect = (options: {
<td> <td>
<FilterSelect <FilterSelect
type={options.type} type={options.type}
onSelect={items => options.onChange(items[0]?.id)} onSelect={(items) => options.onChange(items[0]?.id)}
initialIds={options.initialId ? [options.initialId] : []} initialIds={options.initialId ? [options.initialId] : []}
/> />
</td> </td>
@@ -139,7 +139,7 @@ const renderMultiSelect = (options: {
<FilterSelect <FilterSelect
type={options.type} type={options.type}
isMulti isMulti
onSelect={items => options.onChange(items.map(i => i.id))} onSelect={(items) => options.onChange(items.map((i) => i.id))}
initialIds={options.initialIds ?? []} initialIds={options.initialIds ?? []}
/> />
</td> </td>
@@ -152,6 +152,6 @@ const Table = {
renderInputGroup, renderInputGroup,
renderHtmlSelect, renderHtmlSelect,
renderFilterSelect, renderFilterSelect,
renderMultiSelect renderMultiSelect,
}; };
export default Table; export default Table;

View File

@@ -90,7 +90,7 @@ const TextUtils = {
fileNameFromPath, fileNameFromPath,
age: getAge, age: getAge,
bitRate, bitRate,
resolution resolution,
}; };
export default TextUtils; export default TextUtils;

View File

@@ -5438,10 +5438,10 @@ eslint-config-airbnb@^18.0.1:
object.assign "^4.1.0" object.assign "^4.1.0"
object.entries "^1.1.0" object.entries "^1.1.0"
eslint-config-prettier@^6.9.0: eslint-config-prettier@^6.10.1:
version "6.9.0" version "6.10.1"
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.9.0.tgz#430d24822e82f7deb1e22a435bfa3999fae4ad64" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.10.1.tgz#129ef9ec575d5ddc0e269667bf09defcd898642a"
integrity sha512-k4E14HBtcLv0uqThaI6I/n1LEqROp8XaPu6SO9Z32u5NlGRC07Enu1Bh2KEFw4FNHbekH8yzbIU9kUGxbiGmCA== integrity sha512-svTy6zh1ecQojvpbJSgH3aei/Rt7C6i090l5f2WQ4aB05lYHeZIR1qL4wZyyILTbtmnbHP5Yn8MrsOJMGa8RkQ==
dependencies: dependencies:
get-stdin "^6.0.0" get-stdin "^6.0.0"
@@ -11027,6 +11027,11 @@ prettier@1.19.1:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
prettier@2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.2.tgz#1ba8f3eb92231e769b7fcd7cb73ae1b6b74ade08"
integrity sha512-5xJQIPT8BraI7ZnaDwSbu5zLrB6vvi8hVV58yHQ+QK64qrY40dULy0HSRlQ2/2IdzeBpjhDkqdcFBnFeDEMVdg==
pretty-bytes@^5.1.0: pretty-bytes@^5.1.0:
version "5.3.0" version "5.3.0"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.3.0.tgz#f2849e27db79fb4d6cfe24764fc4134f165989f2" resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.3.0.tgz#f2849e27db79fb4d6cfe24764fc4134f165989f2"
@@ -13145,6 +13150,11 @@ stylehacks@^4.0.0:
postcss "^7.0.0" postcss "^7.0.0"
postcss-selector-parser "^3.0.0" postcss-selector-parser "^3.0.0"
stylelint-config-prettier@^8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/stylelint-config-prettier/-/stylelint-config-prettier-8.0.1.tgz#ec7cdd7faabaff52ebfa56c28fed3d995ebb8cab"
integrity sha512-RcjNW7MUaNVqONhJH4+rtlAE3ow/9SsAM0YWV0Lgu3dbTKdWTa/pQXRdFWgoHWpzUKn+9oBKR5x8JdH+20wmgw==
stylelint-order@^4.0.0: stylelint-order@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/stylelint-order/-/stylelint-order-4.0.0.tgz#2a945c2198caac3ff44687d7c8582c81d044b556" resolved "https://registry.yarnpkg.com/stylelint-order/-/stylelint-order-4.0.0.tgz#2a945c2198caac3ff44687d7c8582c81d044b556"