mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 12:54:38 +03:00
Touch up Performer Page (#2200)
* Moves "Edit" and "Autotag" out of performer tabs * Smoothen out fedit submission behavior
This commit is contained in:
committed by
GitHub
parent
be5dc7e545
commit
baf148625c
@@ -1,4 +1,5 @@
|
|||||||
### 🎨 Improvements
|
### 🎨 Improvements
|
||||||
|
* Made Performer page consistent with Studio and Tag pages. ([#2200](https://github.com/stashapp/stash/pull/2200))
|
||||||
* Add gender icons to performers. ([#2179](https://github.com/stashapp/stash/pull/2179))
|
* Add gender icons to performers. ([#2179](https://github.com/stashapp/stash/pull/2179))
|
||||||
* Add button to test credentials when adding/editing stash-box endpoints. ([#2173](https://github.com/stashapp/stash/pull/2173))
|
* Add button to test credentials when adding/editing stash-box endpoints. ([#2173](https://github.com/stashapp/stash/pull/2173))
|
||||||
* Show counts on list tabs in Performer, Studio and Tag pages. ([#2169](https://github.com/stashapp/stash/pull/2169))
|
* Show counts on list tabs in Performer, Studio and Tag pages. ([#2169](https://github.com/stashapp/stash/pull/2169))
|
||||||
|
|||||||
@@ -470,7 +470,7 @@ export const MovieEditPanel: React.FC<IMovieEditPanel> = ({
|
|||||||
</Form>
|
</Form>
|
||||||
|
|
||||||
<DetailsEditNavbar
|
<DetailsEditNavbar
|
||||||
objectName={movie?.name ?? "movie"}
|
objectName={movie?.name ?? intl.formatMessage({ id: "movie" })}
|
||||||
isNew={isNew}
|
isNew={isNew}
|
||||||
isEditing={isEditing}
|
isEditing={isEditing}
|
||||||
onToggleEdit={onCancel}
|
onToggleEdit={onCancel}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const GenderIcon: React.FC<IIconProps> = ({ gender, className }) => {
|
|||||||
: faTransgenderAlt;
|
: faTransgenderAlt;
|
||||||
return (
|
return (
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
title={intl.formatMessage({ id: "gender." + gender })}
|
title={intl.formatMessage({ id: "gender_types." + gender })}
|
||||||
className={className}
|
className={className}
|
||||||
icon={icon}
|
icon={icon}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useMemo, useState } from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
import { Button, Tabs, Tab, Badge } from "react-bootstrap";
|
import { Button, Tabs, Tab, Badge, Col, Row } from "react-bootstrap";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
import { useParams, useHistory } from "react-router-dom";
|
import { useParams, useHistory } from "react-router-dom";
|
||||||
import { Helmet } from "react-helmet";
|
import { Helmet } from "react-helmet";
|
||||||
@@ -10,9 +10,11 @@ import {
|
|||||||
useFindPerformer,
|
useFindPerformer,
|
||||||
usePerformerUpdate,
|
usePerformerUpdate,
|
||||||
usePerformerDestroy,
|
usePerformerDestroy,
|
||||||
|
mutateMetadataAutoTag,
|
||||||
} from "src/core/StashService";
|
} from "src/core/StashService";
|
||||||
import {
|
import {
|
||||||
CountryFlag,
|
CountryFlag,
|
||||||
|
DetailsEditNavbar,
|
||||||
ErrorMessage,
|
ErrorMessage,
|
||||||
Icon,
|
Icon,
|
||||||
LoadingIndicator,
|
LoadingIndicator,
|
||||||
@@ -21,7 +23,6 @@ import { useLightbox, useToast } from "src/hooks";
|
|||||||
import { TextUtils } from "src/utils";
|
import { TextUtils } from "src/utils";
|
||||||
import { RatingStars } from "src/components/Scenes/SceneDetails/RatingStars";
|
import { RatingStars } from "src/components/Scenes/SceneDetails/RatingStars";
|
||||||
import { PerformerDetailsPanel } from "./PerformerDetailsPanel";
|
import { PerformerDetailsPanel } from "./PerformerDetailsPanel";
|
||||||
import { PerformerOperationsPanel } from "./PerformerOperationsPanel";
|
|
||||||
import { PerformerScenesPanel } from "./PerformerScenesPanel";
|
import { PerformerScenesPanel } from "./PerformerScenesPanel";
|
||||||
import { PerformerGalleriesPanel } from "./PerformerGalleriesPanel";
|
import { PerformerGalleriesPanel } from "./PerformerGalleriesPanel";
|
||||||
import { PerformerMoviesPanel } from "./PerformerMoviesPanel";
|
import { PerformerMoviesPanel } from "./PerformerMoviesPanel";
|
||||||
@@ -44,6 +45,7 @@ const PerformerPage: React.FC<IProps> = ({ performer }) => {
|
|||||||
|
|
||||||
const [imagePreview, setImagePreview] = useState<string | null>();
|
const [imagePreview, setImagePreview] = useState<string | null>();
|
||||||
const [imageEncoding, setImageEncoding] = useState<boolean>(false);
|
const [imageEncoding, setImageEncoding] = useState<boolean>(false);
|
||||||
|
const [isEditing, setIsEditing] = useState<boolean>(false);
|
||||||
|
|
||||||
// if undefined then get the existing image
|
// if undefined then get the existing image
|
||||||
// if null then get the default (no) image
|
// if null then get the default (no) image
|
||||||
@@ -68,9 +70,7 @@ const PerformerPage: React.FC<IProps> = ({ performer }) => {
|
|||||||
tab === "scenes" ||
|
tab === "scenes" ||
|
||||||
tab === "galleries" ||
|
tab === "galleries" ||
|
||||||
tab === "images" ||
|
tab === "images" ||
|
||||||
tab === "movies" ||
|
tab === "movies"
|
||||||
tab === "edit" ||
|
|
||||||
tab === "operations"
|
|
||||||
? tab
|
? tab
|
||||||
: "details";
|
: "details";
|
||||||
const setActiveTabKey = (newTab: string | null) => {
|
const setActiveTabKey = (newTab: string | null) => {
|
||||||
@@ -84,14 +84,24 @@ const PerformerPage: React.FC<IProps> = ({ performer }) => {
|
|||||||
|
|
||||||
const onImageEncoding = (isEncoding = false) => setImageEncoding(isEncoding);
|
const onImageEncoding = (isEncoding = false) => setImageEncoding(isEncoding);
|
||||||
|
|
||||||
|
async function onAutoTag() {
|
||||||
|
try {
|
||||||
|
await mutateMetadataAutoTag({ performers: [performer.id] });
|
||||||
|
Toast.success({
|
||||||
|
content: intl.formatMessage({ id: "toast.started_auto_tagging" }),
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
Toast.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// set up hotkeys
|
// set up hotkeys
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
Mousetrap.bind("a", () => setActiveTabKey("details"));
|
Mousetrap.bind("a", () => setActiveTabKey("details"));
|
||||||
Mousetrap.bind("e", () => setActiveTabKey("edit"));
|
Mousetrap.bind("e", () => setIsEditing(!isEditing));
|
||||||
Mousetrap.bind("c", () => setActiveTabKey("scenes"));
|
Mousetrap.bind("c", () => setActiveTabKey("scenes"));
|
||||||
Mousetrap.bind("g", () => setActiveTabKey("galleries"));
|
Mousetrap.bind("g", () => setActiveTabKey("galleries"));
|
||||||
Mousetrap.bind("m", () => setActiveTabKey("movies"));
|
Mousetrap.bind("m", () => setActiveTabKey("movies"));
|
||||||
Mousetrap.bind("o", () => setActiveTabKey("operations"));
|
|
||||||
Mousetrap.bind("f", () => setFavorite(!performer.favorite));
|
Mousetrap.bind("f", () => setFavorite(!performer.favorite));
|
||||||
|
|
||||||
// numeric keypresses get caught by jwplayer, so blur the element
|
// numeric keypresses get caught by jwplayer, so blur the element
|
||||||
@@ -139,6 +149,25 @@ const PerformerPage: React.FC<IProps> = ({ performer }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const renderTabs = () => (
|
const renderTabs = () => (
|
||||||
|
<React.Fragment>
|
||||||
|
<Col>
|
||||||
|
<Row xs={8}>
|
||||||
|
<DetailsEditNavbar
|
||||||
|
objectName={
|
||||||
|
performer?.name ?? intl.formatMessage({ id: "performer" })
|
||||||
|
}
|
||||||
|
onToggleEdit={() => {
|
||||||
|
setIsEditing(!isEditing);
|
||||||
|
}}
|
||||||
|
onDelete={onDelete}
|
||||||
|
onAutoTag={onAutoTag}
|
||||||
|
isNew={false}
|
||||||
|
isEditing={false}
|
||||||
|
onSave={() => {}}
|
||||||
|
onImageChange={() => {}}
|
||||||
|
/>
|
||||||
|
</Row>
|
||||||
|
</Col>
|
||||||
<Tabs
|
<Tabs
|
||||||
activeKey={activeTabKey}
|
activeKey={activeTabKey}
|
||||||
onSelect={setActiveTabKey}
|
onSelect={setActiveTabKey}
|
||||||
@@ -200,24 +229,28 @@ const PerformerPage: React.FC<IProps> = ({ performer }) => {
|
|||||||
>
|
>
|
||||||
<PerformerMoviesPanel performer={performer} />
|
<PerformerMoviesPanel performer={performer} />
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab eventKey="edit" title={intl.formatMessage({ id: "actions.edit" })}>
|
</Tabs>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
|
||||||
|
function renderTabsOrEditPanel() {
|
||||||
|
if (isEditing) {
|
||||||
|
return (
|
||||||
<PerformerEditPanel
|
<PerformerEditPanel
|
||||||
performer={performer}
|
performer={performer}
|
||||||
isVisible={activeTabKey === "edit"}
|
isVisible={isEditing}
|
||||||
isNew={false}
|
isNew={false}
|
||||||
onDelete={onDelete}
|
|
||||||
onImageChange={onImageChange}
|
onImageChange={onImageChange}
|
||||||
onImageEncoding={onImageEncoding}
|
onImageEncoding={onImageEncoding}
|
||||||
|
onCancelEditing={() => {
|
||||||
|
setIsEditing(false);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Tab>
|
|
||||||
<Tab
|
|
||||||
eventKey="operations"
|
|
||||||
title={intl.formatMessage({ id: "operations" })}
|
|
||||||
>
|
|
||||||
<PerformerOperationsPanel performer={performer} />
|
|
||||||
</Tab>
|
|
||||||
</Tabs>
|
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
return renderTabs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function maybeRenderAge() {
|
function maybeRenderAge() {
|
||||||
if (performer?.birthdate) {
|
if (performer?.birthdate) {
|
||||||
@@ -375,7 +408,7 @@ const PerformerPage: React.FC<IProps> = ({ performer }) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="performer-body">
|
<div className="performer-body">
|
||||||
<div className="performer-tabs">{renderTabs()}</div>
|
<div className="performer-tabs">{renderTabsOrEditPanel()}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -96,10 +96,10 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({
|
|||||||
return (
|
return (
|
||||||
<dl className="details-list">
|
<dl className="details-list">
|
||||||
<TextField
|
<TextField
|
||||||
id="gender.gender"
|
id="gender"
|
||||||
value={
|
value={
|
||||||
performer.gender
|
performer.gender
|
||||||
? intl.formatMessage({ id: "gender." + performer.gender })
|
? intl.formatMessage({ id: "gender_types." + performer.gender })
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { Button, Form, Col, Row, Badge, Dropdown } from "react-bootstrap";
|
import { Button, Form, Col, Row, Badge, Dropdown } from "react-bootstrap";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
import Mousetrap from "mousetrap";
|
import Mousetrap from "mousetrap";
|
||||||
import * as GQL from "src/core/generated-graphql";
|
import * as GQL from "src/core/generated-graphql";
|
||||||
import * as yup from "yup";
|
import * as yup from "yup";
|
||||||
@@ -18,7 +18,6 @@ import {
|
|||||||
ImageInput,
|
ImageInput,
|
||||||
LoadingIndicator,
|
LoadingIndicator,
|
||||||
CollapseButton,
|
CollapseButton,
|
||||||
Modal,
|
|
||||||
TagSelect,
|
TagSelect,
|
||||||
URLField,
|
URLField,
|
||||||
} from "src/components/Shared";
|
} from "src/components/Shared";
|
||||||
@@ -46,20 +45,19 @@ interface IPerformerDetails {
|
|||||||
performer: Partial<GQL.PerformerDataFragment>;
|
performer: Partial<GQL.PerformerDataFragment>;
|
||||||
isNew?: boolean;
|
isNew?: boolean;
|
||||||
isVisible: boolean;
|
isVisible: boolean;
|
||||||
onDelete?: () => void;
|
|
||||||
onImageChange?: (image?: string | null) => void;
|
onImageChange?: (image?: string | null) => void;
|
||||||
onImageEncoding?: (loading?: boolean) => void;
|
onImageEncoding?: (loading?: boolean) => void;
|
||||||
|
onCancelEditing?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
||||||
performer,
|
performer,
|
||||||
isNew,
|
isNew,
|
||||||
isVisible,
|
isVisible,
|
||||||
onDelete,
|
|
||||||
onImageChange,
|
onImageChange,
|
||||||
onImageEncoding,
|
onImageEncoding,
|
||||||
|
onCancelEditing,
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
|
||||||
const Toast = useToast();
|
const Toast = useToast();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
@@ -67,7 +65,6 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
const [scraper, setScraper] = useState<GQL.Scraper | IStashBox | undefined>();
|
const [scraper, setScraper] = useState<GQL.Scraper | IStashBox | undefined>();
|
||||||
const [newTags, setNewTags] = useState<GQL.ScrapedTag[]>();
|
const [newTags, setNewTags] = useState<GQL.ScrapedTag[]>();
|
||||||
const [isScraperModalOpen, setIsScraperModalOpen] = useState<boolean>(false);
|
const [isScraperModalOpen, setIsScraperModalOpen] = useState<boolean>(false);
|
||||||
const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState<boolean>(false);
|
|
||||||
|
|
||||||
// Network state
|
// Network state
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
@@ -361,7 +358,17 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
async function onSave(performerInput: InputValues) {
|
async function onSave(performerInput: InputValues) {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
try {
|
||||||
if (!isNew) {
|
if (isNew) {
|
||||||
|
const input = getCreateValues(performerInput);
|
||||||
|
const result = await createPerformer({
|
||||||
|
variables: {
|
||||||
|
input,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (result.data?.performerCreate) {
|
||||||
|
history.push(`/performers/${result.data.performerCreate.id}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
const input = getUpdateValues(performerInput);
|
const input = getUpdateValues(performerInput);
|
||||||
|
|
||||||
await updatePerformer({
|
await updatePerformer({
|
||||||
@@ -372,20 +379,14 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
history.push(`/performers/${performer.id}`);
|
|
||||||
} else {
|
|
||||||
const input = getCreateValues(performerInput);
|
|
||||||
const result = await createPerformer({
|
|
||||||
variables: {
|
|
||||||
input,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (result.data?.performerCreate) {
|
|
||||||
history.push(`/performers/${result.data.performerCreate.id}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Toast.error(e);
|
Toast.error(e);
|
||||||
|
setIsLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!isNew && onCancelEditing) {
|
||||||
|
onCancelEditing();
|
||||||
}
|
}
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
@@ -397,12 +398,6 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
onSave?.(formik.values);
|
onSave?.(formik.values);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!isNew) {
|
|
||||||
Mousetrap.bind("d d", () => {
|
|
||||||
setIsDeleteAlertOpen(true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
Mousetrap.unbind("s s");
|
Mousetrap.unbind("s s");
|
||||||
|
|
||||||
@@ -655,25 +650,17 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
setScraper(undefined);
|
setScraper(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderButtons() {
|
function renderButtons(classNames: string) {
|
||||||
return (
|
return (
|
||||||
<Row>
|
<Row>
|
||||||
<Col className="mt-3" xs={12}>
|
<Col className={classNames} xs={12}>
|
||||||
|
{!isNew && onCancelEditing ? (
|
||||||
<Button
|
<Button
|
||||||
className="mr-2"
|
className="mr-2"
|
||||||
variant="primary"
|
variant="primary"
|
||||||
disabled={!formik.dirty}
|
onClick={() => onCancelEditing()}
|
||||||
onClick={() => formik.submitForm()}
|
|
||||||
>
|
>
|
||||||
<FormattedMessage id="actions.save" />
|
<FormattedMessage id="actions.cancel" />
|
||||||
</Button>
|
|
||||||
{!isNew ? (
|
|
||||||
<Button
|
|
||||||
className="mr-2"
|
|
||||||
variant="danger"
|
|
||||||
onClick={() => setIsDeleteAlertOpen(true)}
|
|
||||||
>
|
|
||||||
<FormattedMessage id="actions.delete" />
|
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : (
|
||||||
""
|
""
|
||||||
@@ -685,12 +672,19 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
onImageURL={onImageChangeURL}
|
onImageURL={onImageChangeURL}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
className="mx-2"
|
className="mr-2"
|
||||||
variant="danger"
|
variant="danger"
|
||||||
onClick={() => formik.setFieldValue("image", null)}
|
onClick={() => formik.setFieldValue("image", null)}
|
||||||
>
|
>
|
||||||
<FormattedMessage id="actions.clear_image" />
|
<FormattedMessage id="actions.clear_image" />
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="success"
|
||||||
|
disabled={!formik.dirty}
|
||||||
|
onClick={() => formik.submitForm()}
|
||||||
|
>
|
||||||
|
<FormattedMessage id="actions.save" />
|
||||||
|
</Button>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
);
|
);
|
||||||
@@ -716,28 +710,6 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
) : undefined;
|
) : undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
function renderDeleteAlert() {
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
show={isDeleteAlertOpen}
|
|
||||||
icon="trash-alt"
|
|
||||||
accept={{
|
|
||||||
text: intl.formatMessage({ id: "actions.delete" }),
|
|
||||||
variant: "danger",
|
|
||||||
onClick: onDelete,
|
|
||||||
}}
|
|
||||||
cancel={{ onClick: () => setIsDeleteAlertOpen(false) }}
|
|
||||||
>
|
|
||||||
<p>
|
|
||||||
<FormattedMessage
|
|
||||||
id="dialogs.delete_confirm"
|
|
||||||
values={{ entityName: performer.name }}
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderTagsField() {
|
function renderTagsField() {
|
||||||
return (
|
return (
|
||||||
<Form.Group controlId="tags" as={Row}>
|
<Form.Group controlId="tags" as={Row}>
|
||||||
@@ -837,7 +809,6 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{renderDeleteAlert()}
|
|
||||||
{renderScrapeModal()}
|
{renderScrapeModal()}
|
||||||
{maybeRenderScrapeDialog()}
|
{maybeRenderScrapeDialog()}
|
||||||
|
|
||||||
@@ -845,6 +816,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
when={formik.dirty}
|
when={formik.dirty}
|
||||||
message="Unsaved changes. Are you sure you want to leave?"
|
message="Unsaved changes. Are you sure you want to leave?"
|
||||||
/>
|
/>
|
||||||
|
{renderButtons("mb-3")}
|
||||||
|
|
||||||
<Form noValidate onSubmit={formik.handleSubmit} id="performer-edit">
|
<Form noValidate onSubmit={formik.handleSubmit} id="performer-edit">
|
||||||
<Form.Group controlId="name" as={Row}>
|
<Form.Group controlId="name" as={Row}>
|
||||||
@@ -880,7 +852,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
|
|
||||||
<Form.Group as={Row}>
|
<Form.Group as={Row}>
|
||||||
<Form.Label column xs={labelXS} xl={labelXL}>
|
<Form.Label column xs={labelXS} xl={labelXL}>
|
||||||
<FormattedMessage id="gender.gender" />
|
<FormattedMessage id="gender" />
|
||||||
</Form.Label>
|
</Form.Label>
|
||||||
<Col xs="auto">
|
<Col xs="auto">
|
||||||
<Form.Control
|
<Form.Control
|
||||||
@@ -970,7 +942,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||||||
|
|
||||||
{renderStashIDs()}
|
{renderStashIDs()}
|
||||||
|
|
||||||
{renderButtons()}
|
{renderButtons("mt-3")}
|
||||||
</Form>
|
</Form>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
import { Button } from "react-bootstrap";
|
|
||||||
import React from "react";
|
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
|
||||||
import * as GQL from "src/core/generated-graphql";
|
|
||||||
import { mutateMetadataAutoTag } from "src/core/StashService";
|
|
||||||
import { useToast } from "src/hooks";
|
|
||||||
|
|
||||||
interface IPerformerOperationsProps {
|
|
||||||
performer: GQL.PerformerDataFragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const PerformerOperationsPanel: React.FC<IPerformerOperationsProps> = ({
|
|
||||||
performer,
|
|
||||||
}) => {
|
|
||||||
const Toast = useToast();
|
|
||||||
const intl = useIntl();
|
|
||||||
|
|
||||||
async function onAutoTag() {
|
|
||||||
try {
|
|
||||||
await mutateMetadataAutoTag({ performers: [performer.id] });
|
|
||||||
Toast.success({
|
|
||||||
content: intl.formatMessage({ id: "toast.started_auto_tagging" }),
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
Toast.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Button onClick={onAutoTag}>
|
|
||||||
<FormattedMessage id="actions.auto_tag" />
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -429,7 +429,7 @@ export const PerformerScrapeDialog: React.FC<IPerformerScrapeDialogProps> = (
|
|||||||
onChange={(value) => setAliases(value)}
|
onChange={(value) => setAliases(value)}
|
||||||
/>
|
/>
|
||||||
{renderScrapedGenderRow(
|
{renderScrapedGenderRow(
|
||||||
intl.formatMessage({ id: "gender.gender" }),
|
intl.formatMessage({ id: "gender" }),
|
||||||
gender,
|
gender,
|
||||||
(value) => setGender(value)
|
(value) => setGender(value)
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -318,7 +318,7 @@ export const StudioEditPanel: React.FC<IStudioEditPanel> = ({
|
|||||||
</Form>
|
</Form>
|
||||||
|
|
||||||
<DetailsEditNavbar
|
<DetailsEditNavbar
|
||||||
objectName={studio?.name ?? "studio"}
|
objectName={studio?.name ?? intl.formatMessage({ id: "studio" })}
|
||||||
isNew={isNew}
|
isNew={isNew}
|
||||||
isEditing
|
isEditing
|
||||||
onToggleEdit={onCancel}
|
onToggleEdit={onCancel}
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ const PerformerModal: React.FC<IPerformerModalProps> = ({
|
|||||||
{renderField(
|
{renderField(
|
||||||
"gender",
|
"gender",
|
||||||
performer.gender
|
performer.gender
|
||||||
? intl.formatMessage({ id: "gender." + performer.gender })
|
? intl.formatMessage({ id: "gender_types." + performer.gender })
|
||||||
: ""
|
: ""
|
||||||
)}
|
)}
|
||||||
{renderField("birthdate", performer.birthdate)}
|
{renderField("birthdate", performer.birthdate)}
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ export const TagEditPanel: React.FC<ITagEditPanel> = ({
|
|||||||
</Form>
|
</Form>
|
||||||
|
|
||||||
<DetailsEditNavbar
|
<DetailsEditNavbar
|
||||||
objectName={tag?.name ?? "tag"}
|
objectName={tag?.name ?? intl.formatMessage({ id: "tag" })}
|
||||||
isNew={isNew}
|
isNew={isNew}
|
||||||
isEditing={isEditing}
|
isEditing={isEditing}
|
||||||
onToggleEdit={onCancel}
|
onToggleEdit={onCancel}
|
||||||
|
|||||||
@@ -691,8 +691,8 @@
|
|||||||
"galleries": "Galleries",
|
"galleries": "Galleries",
|
||||||
"gallery": "Gallery",
|
"gallery": "Gallery",
|
||||||
"gallery_count": "Gallery Count",
|
"gallery_count": "Gallery Count",
|
||||||
"gender": {
|
|
||||||
"gender": "Gender",
|
"gender": "Gender",
|
||||||
|
"gender_types": {
|
||||||
"MALE": "Male",
|
"MALE": "Male",
|
||||||
"FEMALE": "Female",
|
"FEMALE": "Female",
|
||||||
"TRANSGENDER_MALE": "Transgender Male",
|
"TRANSGENDER_MALE": "Transgender Male",
|
||||||
|
|||||||
Reference in New Issue
Block a user