mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 04:44:37 +03:00
Add disambiguation and links to tagger results (#4180)
Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
This commit is contained in:
@@ -122,7 +122,14 @@ export const PerformerSelect: React.FC<
|
|||||||
|
|
||||||
thisOptionProps = {
|
thisOptionProps = {
|
||||||
...optionProps,
|
...optionProps,
|
||||||
children: object.name,
|
children: (
|
||||||
|
<>
|
||||||
|
{object.name}
|
||||||
|
{object.disambiguation && (
|
||||||
|
<span className="performer-disambiguation">{` (${object.disambiguation})`}</span>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
return <reactSelectComponents.SingleValue {...thisOptionProps} />;
|
return <reactSelectComponents.SingleValue {...thisOptionProps} />;
|
||||||
|
|||||||
@@ -11,6 +11,41 @@ import {
|
|||||||
Performer,
|
Performer,
|
||||||
PerformerSelect,
|
PerformerSelect,
|
||||||
} from "src/components/Performers/PerformerSelect";
|
} from "src/components/Performers/PerformerSelect";
|
||||||
|
import { getStashboxBase } from "src/utils/stashbox";
|
||||||
|
|
||||||
|
interface IPerformerName {
|
||||||
|
performer: GQL.ScrapedPerformer | Performer;
|
||||||
|
className?: string;
|
||||||
|
baseURL: string | undefined;
|
||||||
|
id: string | undefined | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PerformerName: React.FC<IPerformerName> = ({
|
||||||
|
performer,
|
||||||
|
className,
|
||||||
|
baseURL,
|
||||||
|
id,
|
||||||
|
}) => {
|
||||||
|
const name =
|
||||||
|
baseURL && id ? (
|
||||||
|
<a href={`${baseURL}${id}`} target="_blank" rel="noreferrer">
|
||||||
|
{performer.name}
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
performer.name
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className={className}>
|
||||||
|
<span>{name}</span>
|
||||||
|
{performer.disambiguation && (
|
||||||
|
<span className="performer-disambiguation">
|
||||||
|
{` (${performer.disambiguation})`}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
interface IPerformerResultProps {
|
interface IPerformerResultProps {
|
||||||
performer: GQL.ScrapedPerformer;
|
performer: GQL.ScrapedPerformer;
|
||||||
@@ -44,6 +79,11 @@ const PerformerResult: React.FC<IPerformerResultProps> = ({
|
|||||||
|
|
||||||
const [selectedPerformer, setSelectedPerformer] = useState<Performer>();
|
const [selectedPerformer, setSelectedPerformer] = useState<Performer>();
|
||||||
|
|
||||||
|
const stashboxPerformerPrefix = endpoint
|
||||||
|
? `${getStashboxBase(endpoint)}performers/`
|
||||||
|
: undefined;
|
||||||
|
const performerURLPrefix = "/performers/";
|
||||||
|
|
||||||
function selectPerformer(selected: Performer | undefined) {
|
function selectPerformer(selected: Performer | undefined) {
|
||||||
setSelectedPerformer(selected);
|
setSelectedPerformer(selected);
|
||||||
setSelectedID(selected?.id);
|
setSelectedID(selected?.id);
|
||||||
@@ -77,7 +117,12 @@ const PerformerResult: React.FC<IPerformerResultProps> = ({
|
|||||||
<div className="row no-gutters my-2">
|
<div className="row no-gutters my-2">
|
||||||
<div className="entity-name">
|
<div className="entity-name">
|
||||||
<FormattedMessage id="countables.performers" values={{ count: 1 }} />:
|
<FormattedMessage id="countables.performers" values={{ count: 1 }} />:
|
||||||
<b className="ml-2">{performer.name}</b>
|
<PerformerName
|
||||||
|
performer={performer}
|
||||||
|
className="ml-2"
|
||||||
|
id={performer.remote_site_id}
|
||||||
|
baseURL={stashboxPerformerPrefix}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span className="ml-auto">
|
<span className="ml-auto">
|
||||||
<OptionalField
|
<OptionalField
|
||||||
@@ -90,7 +135,12 @@ const PerformerResult: React.FC<IPerformerResultProps> = ({
|
|||||||
<span className="mr-2">
|
<span className="mr-2">
|
||||||
<FormattedMessage id="component_tagger.verb_matched" />:
|
<FormattedMessage id="component_tagger.verb_matched" />:
|
||||||
</span>
|
</span>
|
||||||
<b className="col-3 text-right">{matchedPerformer.name}</b>
|
<PerformerName
|
||||||
|
performer={matchedPerformer}
|
||||||
|
className="ml-3 text-right"
|
||||||
|
id={matchedPerformer.id}
|
||||||
|
baseURL={performerURLPrefix}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</OptionalField>
|
</OptionalField>
|
||||||
</span>
|
</span>
|
||||||
@@ -119,7 +169,12 @@ const PerformerResult: React.FC<IPerformerResultProps> = ({
|
|||||||
<div className="row no-gutters align-items-center mt-2">
|
<div className="row no-gutters align-items-center mt-2">
|
||||||
<div className="entity-name">
|
<div className="entity-name">
|
||||||
<FormattedMessage id="countables.performers" values={{ count: 1 }} />:
|
<FormattedMessage id="countables.performers" values={{ count: 1 }} />:
|
||||||
<b className="ml-2">{performer.name}</b>
|
<PerformerName
|
||||||
|
performer={performer}
|
||||||
|
className="ml-2"
|
||||||
|
id={performer.remote_site_id}
|
||||||
|
baseURL={stashboxPerformerPrefix}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<ButtonGroup>
|
<ButtonGroup>
|
||||||
<Button variant="secondary" onClick={() => onCreate()}>
|
<Button variant="secondary" onClick={() => onCreate()}>
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import PerformerResult from "./PerformerResult";
|
|||||||
import StudioResult from "./StudioResult";
|
import StudioResult from "./StudioResult";
|
||||||
import { useInitialState } from "src/hooks/state";
|
import { useInitialState } from "src/hooks/state";
|
||||||
import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import { getStashboxBase } from "src/utils/stashbox";
|
||||||
|
|
||||||
const getDurationStatus = (
|
const getDurationStatus = (
|
||||||
scene: IScrapedScene,
|
scene: IScrapedScene,
|
||||||
@@ -301,13 +302,14 @@ const StashSearchResult: React.FC<IStashSearchResultProps> = ({
|
|||||||
}
|
}
|
||||||
}, [isActive, loading, stashScene, index, resolveScene, scene]);
|
}, [isActive, loading, stashScene, index, resolveScene, scene]);
|
||||||
|
|
||||||
|
const stashBoxBaseURL = currentSource?.stashboxEndpoint
|
||||||
|
? getStashboxBase(currentSource.stashboxEndpoint)
|
||||||
|
: undefined;
|
||||||
const stashBoxURL = useMemo(() => {
|
const stashBoxURL = useMemo(() => {
|
||||||
if (currentSource?.stashboxEndpoint && scene.remote_site_id) {
|
if (stashBoxBaseURL) {
|
||||||
const endpoint = currentSource.stashboxEndpoint;
|
return `${stashBoxBaseURL}scenes/${scene.remote_site_id}`;
|
||||||
const endpointBase = endpoint.match(/https?:\/\/.*?\//)?.[0];
|
|
||||||
return `${endpointBase}scenes/${scene.remote_site_id}`;
|
|
||||||
}
|
}
|
||||||
}, [currentSource, scene]);
|
}, [scene, stashBoxBaseURL]);
|
||||||
|
|
||||||
const setExcludedField = (name: string, value: boolean) =>
|
const setExcludedField = (name: string, value: boolean) =>
|
||||||
setExcludedFields({
|
setExcludedFields({
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import * as GQL from "src/core/generated-graphql";
|
|||||||
|
|
||||||
import { OptionalField } from "../IncludeButton";
|
import { OptionalField } from "../IncludeButton";
|
||||||
import { faSave } from "@fortawesome/free-solid-svg-icons";
|
import { faSave } from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import { getStashboxBase } from "src/utils/stashbox";
|
||||||
|
|
||||||
interface IStudioResultProps {
|
interface IStudioResultProps {
|
||||||
studio: GQL.ScrapedStudio;
|
studio: GQL.ScrapedStudio;
|
||||||
@@ -38,6 +39,11 @@ const StudioResult: React.FC<IStudioResultProps> = ({
|
|||||||
(stashID) => stashID.endpoint === endpoint && stashID.stash_id
|
(stashID) => stashID.endpoint === endpoint && stashID.stash_id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const stashboxStudioPrefix = endpoint
|
||||||
|
? `${getStashboxBase(endpoint)}studios/`
|
||||||
|
: undefined;
|
||||||
|
const studioURLPrefix = "/studios/";
|
||||||
|
|
||||||
const handleSelect = (studios: SelectObject[]) => {
|
const handleSelect = (studios: SelectObject[]) => {
|
||||||
if (studios.length) {
|
if (studios.length) {
|
||||||
setSelectedID(studios[0].id);
|
setSelectedID(studios[0].id);
|
||||||
@@ -52,12 +58,36 @@ const StudioResult: React.FC<IStudioResultProps> = ({
|
|||||||
|
|
||||||
if (stashLoading) return <div>Loading studio</div>;
|
if (stashLoading) return <div>Loading studio</div>;
|
||||||
|
|
||||||
|
const StudioName = ({
|
||||||
|
name,
|
||||||
|
baseURL,
|
||||||
|
id,
|
||||||
|
}: {
|
||||||
|
name: string;
|
||||||
|
baseURL: string | undefined;
|
||||||
|
id: string | undefined | null;
|
||||||
|
}) => {
|
||||||
|
return baseURL && id ? (
|
||||||
|
<a href={`${baseURL}${id}`} target="_blank" rel="noreferrer">
|
||||||
|
{name}
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<span>name</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
if (matchedStudio && matchedStashID) {
|
if (matchedStudio && matchedStashID) {
|
||||||
return (
|
return (
|
||||||
<div className="row no-gutters my-2">
|
<div className="row no-gutters my-2">
|
||||||
<div className="entity-name">
|
<div className="entity-name">
|
||||||
<FormattedMessage id="countables.studios" values={{ count: 1 }} />:
|
<FormattedMessage id="countables.studios" values={{ count: 1 }} />:
|
||||||
<b className="ml-2">{studio.name}</b>
|
<b className="ml-2">
|
||||||
|
<StudioName
|
||||||
|
name={studio.name}
|
||||||
|
baseURL={stashboxStudioPrefix}
|
||||||
|
id={studio.remote_site_id}
|
||||||
|
/>
|
||||||
|
</b>
|
||||||
</div>
|
</div>
|
||||||
<span className="ml-auto">
|
<span className="ml-auto">
|
||||||
<OptionalField
|
<OptionalField
|
||||||
@@ -70,7 +100,13 @@ const StudioResult: React.FC<IStudioResultProps> = ({
|
|||||||
<span className="mr-2">
|
<span className="mr-2">
|
||||||
<FormattedMessage id="component_tagger.verb_matched" />:
|
<FormattedMessage id="component_tagger.verb_matched" />:
|
||||||
</span>
|
</span>
|
||||||
<b className="col-3 text-right">{matchedStudio.name}</b>
|
<b className="col-3 text-right">
|
||||||
|
<StudioName
|
||||||
|
name={matchedStudio.name}
|
||||||
|
baseURL={studioURLPrefix}
|
||||||
|
id={matchedStudio.id}
|
||||||
|
/>
|
||||||
|
</b>
|
||||||
</div>
|
</div>
|
||||||
</OptionalField>
|
</OptionalField>
|
||||||
</span>
|
</span>
|
||||||
@@ -99,7 +135,13 @@ const StudioResult: React.FC<IStudioResultProps> = ({
|
|||||||
<div className="row no-gutters align-items-center mt-2">
|
<div className="row no-gutters align-items-center mt-2">
|
||||||
<div className="entity-name">
|
<div className="entity-name">
|
||||||
<FormattedMessage id="countables.studios" values={{ count: 1 }} />:
|
<FormattedMessage id="countables.studios" values={{ count: 1 }} />:
|
||||||
<b className="ml-2">{studio.name}</b>
|
<b className="ml-2">
|
||||||
|
<StudioName
|
||||||
|
name={studio.name}
|
||||||
|
baseURL={stashboxStudioPrefix}
|
||||||
|
id={studio.remote_site_id}
|
||||||
|
/>
|
||||||
|
</b>
|
||||||
</div>
|
</div>
|
||||||
<ButtonGroup>
|
<ButtonGroup>
|
||||||
<Button variant="secondary" onClick={() => onCreate()}>
|
<Button variant="secondary" onClick={() => onCreate()}>
|
||||||
|
|||||||
Reference in New Issue
Block a user