diff --git a/graphql/documents/data/studio.graphql b/graphql/documents/data/studio.graphql index 3badb9bf67e..f40b4a620fb 100644 --- a/graphql/documents/data/studio.graphql +++ b/graphql/documents/data/studio.graphql @@ -33,3 +33,16 @@ fragment StudioData on Studio { rating100 aliases } + +fragment SelectStudioData on Studio { + id + name + aliases + details + image_path + + parent_studio { + id + name + } +} diff --git a/graphql/documents/queries/misc.graphql b/graphql/documents/queries/misc.graphql index 03777141d2b..1730585c651 100644 --- a/graphql/documents/queries/misc.graphql +++ b/graphql/documents/queries/misc.graphql @@ -6,14 +6,6 @@ query MarkerStrings($q: String, $sort: String) { } } -query AllStudiosForFilter { - allStudios { - id - name - aliases - } -} - query AllMoviesForFilter { allMovies { id diff --git a/graphql/documents/queries/studio.graphql b/graphql/documents/queries/studio.graphql index 592e0ac2b31..8ed45dc6a51 100644 --- a/graphql/documents/queries/studio.graphql +++ b/graphql/documents/queries/studio.graphql @@ -12,3 +12,16 @@ query FindStudio($id: ID!) { ...StudioData } } + +query FindStudiosForSelect( + $filter: FindFilterType + $studio_filter: StudioFilterType + $ids: [ID!] +) { + findStudios(filter: $filter, studio_filter: $studio_filter, ids: $ids) { + count + studios { + ...SelectStudioData + } + } +} diff --git a/graphql/schema/schema.graphql b/graphql/schema/schema.graphql index 3e7a81a9e99..f052d78ed19 100644 --- a/graphql/schema/schema.graphql +++ b/graphql/schema/schema.graphql @@ -69,6 +69,7 @@ type Query { findStudios( studio_filter: StudioFilterType filter: FindFilterType + ids: [ID!] ): FindStudiosResultType! "Find a movie by ID" @@ -202,11 +203,11 @@ type Query { allSceneMarkers: [SceneMarker!]! allImages: [Image!]! allGalleries: [Gallery!]! - allStudios: [Studio!]! allMovies: [Movie!]! allPerformers: [Performer!]! @deprecated(reason: "Use findPerformers instead") allTags: [Tag!]! @deprecated(reason: "Use findTags instead") + allStudios: [Studio!]! @deprecated(reason: "Use findStudios instead") # Get everything with minimal metadata diff --git a/internal/api/resolver_query_find_studio.go b/internal/api/resolver_query_find_studio.go index 51cac620859..84359295302 100644 --- a/internal/api/resolver_query_find_studio.go +++ b/internal/api/resolver_query_find_studio.go @@ -5,6 +5,7 @@ import ( "strconv" "github.com/stashapp/stash/pkg/models" + "github.com/stashapp/stash/pkg/sliceutil/stringslice" ) func (r *queryResolver) FindStudio(ctx context.Context, id string) (ret *models.Studio, err error) { @@ -24,9 +25,23 @@ func (r *queryResolver) FindStudio(ctx context.Context, id string) (ret *models. return ret, nil } -func (r *queryResolver) FindStudios(ctx context.Context, studioFilter *models.StudioFilterType, filter *models.FindFilterType) (ret *FindStudiosResultType, err error) { +func (r *queryResolver) FindStudios(ctx context.Context, studioFilter *models.StudioFilterType, filter *models.FindFilterType, ids []string) (ret *FindStudiosResultType, err error) { + idInts, err := stringslice.StringSliceToIntSlice(ids) + if err != nil { + return nil, err + } + if err := r.withReadTxn(ctx, func(ctx context.Context) error { - studios, total, err := r.repository.Studio.Query(ctx, studioFilter, filter) + var studios []*models.Studio + var err error + var total int + + if len(idInts) > 0 { + studios, err = r.repository.Studio.FindMany(ctx, idInts) + total = len(studios) + } else { + studios, total, err = r.repository.Studio.Query(ctx, studioFilter, filter) + } if err != nil { return err } diff --git a/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryEditPanel.tsx b/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryEditPanel.tsx index 157e7ab4c94..b7c49176331 100644 --- a/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryEditPanel.tsx +++ b/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryEditPanel.tsx @@ -18,7 +18,7 @@ import { useListGalleryScrapers, mutateReloadScrapers, } from "src/core/StashService"; -import { SceneSelect, StudioSelect } from "src/components/Shared/Select"; +import { SceneSelect } from "src/components/Shared/Select"; import { Icon } from "src/components/Shared/Icon"; import { LoadingIndicator } from "src/components/Shared/LoadingIndicator"; import { useToast } from "src/hooks/Toast"; @@ -41,6 +41,7 @@ import { } from "src/utils/yup"; import { formikUtils } from "src/utils/form"; import { Tag, TagSelect } from "src/components/Tags/TagSelect"; +import { Studio, StudioSelect } from "src/components/Studios/StudioSelect"; interface IProps { gallery: Partial; @@ -66,6 +67,7 @@ export const GalleryEditPanel: React.FC = ({ const [performers, setPerformers] = useState([]); const [tags, setTags] = useState([]); + const [studio, setStudio] = useState(null); const isNew = gallery.id === undefined; const { configuration: stashConfig } = React.useContext(ConfigurationContext); @@ -152,6 +154,11 @@ export const GalleryEditPanel: React.FC = ({ ); } + function onSetStudio(item: Studio | null) { + setStudio(item); + formik.setFieldValue("studio_id", item ? item.id : null); + } + useRatingKeybinds( isVisible, stashConfig?.ui?.ratingSystemOptions?.type, @@ -166,6 +173,10 @@ export const GalleryEditPanel: React.FC = ({ setTags(gallery.tags ?? []); }, [gallery.tags]); + useEffect(() => { + setStudio(gallery.studio ?? null); + }, [gallery.studio]); + useEffect(() => { if (isVisible) { Mousetrap.bind("s s", () => { @@ -252,6 +263,7 @@ export const GalleryEditPanel: React.FC = ({ return ( = ({ } if (galleryData.studio?.stored_id) { - formik.setFieldValue("studio_id", galleryData.studio.stored_id); + onSetStudio({ + id: galleryData.studio.stored_id, + name: galleryData.studio.name ?? "", + aliases: [], + }); } if (galleryData.performers?.length) { @@ -429,13 +445,8 @@ export const GalleryEditPanel: React.FC = ({ const title = intl.formatMessage({ id: "studio" }); const control = ( - formik.setFieldValue( - "studio_id", - items.length > 0 ? items[0]?.id : null - ) - } - ids={formik.values.studio_id ? [formik.values.studio_id] : []} + onSelect={(items) => onSetStudio(items.length > 0 ? items[0] : null)} + values={studio ? [studio] : []} /> ); diff --git a/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryScrapeDialog.tsx b/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryScrapeDialog.tsx index 2c01390b336..01ad1d3071d 100644 --- a/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryScrapeDialog.tsx +++ b/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryScrapeDialog.tsx @@ -25,9 +25,11 @@ import { } from "src/components/Shared/ScrapeDialog/createObjects"; import { uniq } from "lodash-es"; import { Tag } from "src/components/Tags/TagSelect"; +import { Studio } from "src/components/Studios/StudioSelect"; interface IGalleryScrapeDialogProps { gallery: Partial; + galleryStudio: Studio | null; galleryTags: Tag[]; galleryPerformers: Performer[]; scraped: GQL.ScrapedGallery; @@ -37,6 +39,7 @@ interface IGalleryScrapeDialogProps { export const GalleryScrapeDialog: React.FC = ({ gallery, + galleryStudio, galleryTags, galleryPerformers, scraped, @@ -63,8 +66,16 @@ export const GalleryScrapeDialog: React.FC = ({ const [photographer, setPhotographer] = useState>( new ScrapeResult(gallery.photographer, scraped.photographer) ); - const [studio, setStudio] = useState>( - new ScrapeResult(gallery.studio_id, scraped.studio?.stored_id) + const [studio, setStudio] = useState>( + new ScrapeResult( + galleryStudio + ? { + stored_id: galleryStudio.id, + name: galleryStudio.name, + } + : undefined, + scraped.studio + ) ); const [newStudio, setNewStudio] = useState( scraped.studio && !scraped.studio.stored_id ? scraped.studio : undefined @@ -156,12 +167,7 @@ export const GalleryScrapeDialog: React.FC = ({ urls: urls.getNewValue(), date: date.getNewValue(), photographer: photographer.getNewValue(), - studio: newStudioValue - ? { - stored_id: newStudioValue, - name: "", - } - : undefined, + studio: newStudioValue, performers: performers.getNewValue(), tags: tags.getNewValue(), details: details.getNewValue(), diff --git a/ui/v2.5/src/components/Images/ImageDetails/ImageEditPanel.tsx b/ui/v2.5/src/components/Images/ImageDetails/ImageEditPanel.tsx index 96181f257c1..71f80909501 100644 --- a/ui/v2.5/src/components/Images/ImageDetails/ImageEditPanel.tsx +++ b/ui/v2.5/src/components/Images/ImageDetails/ImageEditPanel.tsx @@ -4,7 +4,6 @@ import { FormattedMessage, useIntl } from "react-intl"; import Mousetrap from "mousetrap"; import * as GQL from "src/core/generated-graphql"; import * as yup from "yup"; -import { StudioSelect } from "src/components/Shared/Select"; import { LoadingIndicator } from "src/components/Shared/LoadingIndicator"; import { useToast } from "src/hooks/Toast"; import { useFormik } from "formik"; @@ -23,6 +22,7 @@ import { } from "src/components/Performers/PerformerSelect"; import { formikUtils } from "src/utils/form"; import { Tag, TagSelect } from "src/components/Tags/TagSelect"; +import { Studio, StudioSelect } from "src/components/Studios/StudioSelect"; interface IProps { image: GQL.ImageDataFragment; @@ -47,6 +47,7 @@ export const ImageEditPanel: React.FC = ({ const [performers, setPerformers] = useState([]); const [tags, setTags] = useState([]); + const [studio, setStudio] = useState(null); const schema = yup.object({ title: yup.string().ensure(), @@ -103,6 +104,11 @@ export const ImageEditPanel: React.FC = ({ ); } + function onSetStudio(item: Studio | null) { + setStudio(item); + formik.setFieldValue("studio_id", item ? item.id : null); + } + useRatingKeybinds( true, configuration?.ui?.ratingSystemOptions?.type, @@ -117,6 +123,10 @@ export const ImageEditPanel: React.FC = ({ setTags(image.tags ?? []); }, [image.tags]); + useEffect(() => { + setStudio(image.studio ?? null); + }, [image.studio]); + useEffect(() => { if (isVisible) { Mousetrap.bind("s s", () => { @@ -183,13 +193,8 @@ export const ImageEditPanel: React.FC = ({ const title = intl.formatMessage({ id: "studio" }); const control = ( - formik.setFieldValue( - "studio_id", - items.length > 0 ? items[0]?.id : null - ) - } - ids={formik.values.studio_id ? [formik.values.studio_id] : []} + onSelect={(items) => onSetStudio(items.length > 0 ? items[0] : null)} + values={studio ? [studio] : []} /> ); diff --git a/ui/v2.5/src/components/Movies/MovieDetails/MovieEditPanel.tsx b/ui/v2.5/src/components/Movies/MovieDetails/MovieEditPanel.tsx index b393d29e368..ed8102d85d0 100644 --- a/ui/v2.5/src/components/Movies/MovieDetails/MovieEditPanel.tsx +++ b/ui/v2.5/src/components/Movies/MovieDetails/MovieEditPanel.tsx @@ -8,7 +8,6 @@ import { useListMovieScrapers, } from "src/core/StashService"; import { LoadingIndicator } from "src/components/Shared/LoadingIndicator"; -import { StudioSelect } from "src/components/Shared/Select"; import { DetailsEditNavbar } from "src/components/Shared/DetailsEditNavbar"; import { URLField } from "src/components/Shared/URLField"; import { useToast } from "src/hooks/Toast"; @@ -22,6 +21,7 @@ import isEqual from "lodash-es/isEqual"; import { handleUnsavedChanges } from "src/utils/navigation"; import { formikUtils } from "src/utils/form"; import { yupDateString, yupFormikValidate } from "src/utils/yup"; +import { Studio, StudioSelect } from "src/components/Studios/StudioSelect"; interface IMovieEditPanel { movie: Partial; @@ -55,6 +55,8 @@ export const MovieEditPanel: React.FC = ({ const Scrapers = useListMovieScrapers(); const [scrapedMovie, setScrapedMovie] = useState(); + const [studio, setStudio] = useState(null); + const schema = yup.object({ name: yup.string().required(), aliases: yup.string().ensure(), @@ -88,6 +90,15 @@ export const MovieEditPanel: React.FC = ({ onSubmit: (values) => onSave(schema.cast(values)), }); + function onSetStudio(item: Studio | null) { + setStudio(item); + formik.setFieldValue("studio_id", item ? item.id : null); + } + + useEffect(() => { + setStudio(movie.studio ?? null); + }, [movie.studio]); + // set up hotkeys useEffect(() => { // Mousetrap.bind("u", (e) => { @@ -129,7 +140,11 @@ export const MovieEditPanel: React.FC = ({ } if (state.studio && state.studio.stored_id) { - formik.setFieldValue("studio_id", state.studio.stored_id); + onSetStudio({ + id: state.studio.stored_id, + name: state.studio.name ?? "", + aliases: [], + }); } if (state.director) { @@ -324,13 +339,8 @@ export const MovieEditPanel: React.FC = ({ const title = intl.formatMessage({ id: "studio" }); const control = ( - formik.setFieldValue( - "studio_id", - items.length > 0 ? items[0]?.id : null - ) - } - ids={formik.values.studio_id ? [formik.values.studio_id] : []} + onSelect={(items) => onSetStudio(items.length > 0 ? items[0] : null)} + values={studio ? [studio] : []} /> ); diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx index 9f64d041ccb..295f4cc89c5 100644 --- a/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx +++ b/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx @@ -19,11 +19,7 @@ import { mutateReloadScrapers, queryScrapeSceneQueryFragment, } from "src/core/StashService"; -import { - StudioSelect, - GallerySelect, - MovieSelect, -} from "src/components/Shared/Select"; +import { GallerySelect, MovieSelect } from "src/components/Shared/Select"; import { Icon } from "src/components/Shared/Icon"; import { LoadingIndicator } from "src/components/Shared/LoadingIndicator"; import { ImageInput } from "src/components/Shared/ImageInput"; @@ -52,6 +48,7 @@ import { } from "src/components/Performers/PerformerSelect"; import { formikUtils } from "src/utils/form"; import { Tag, TagSelect } from "src/components/Tags/TagSelect"; +import { Studio, StudioSelect } from "src/components/Studios/StudioSelect"; const SceneScrapeDialog = lazyComponent(() => import("./SceneScrapeDialog")); const SceneQueryModal = lazyComponent(() => import("./SceneQueryModal")); @@ -81,6 +78,7 @@ export const SceneEditPanel: React.FC = ({ ); const [performers, setPerformers] = useState([]); const [tags, setTags] = useState([]); + const [studio, setStudio] = useState(null); const Scrapers = useListSceneScrapers(); const [fragmentScrapers, setFragmentScrapers] = useState([]); @@ -109,6 +107,10 @@ export const SceneEditPanel: React.FC = ({ setTags(scene.tags ?? []); }, [scene.tags]); + useEffect(() => { + setStudio(scene.studio ?? null); + }, [scene.studio]); + const { configuration: stashConfig } = React.useContext(ConfigurationContext); // Network state @@ -215,6 +217,11 @@ export const SceneEditPanel: React.FC = ({ ); } + function onSetStudio(item: Studio | null) { + setStudio(item); + formik.setFieldValue("studio_id", item ? item.id : null); + } + useRatingKeybinds( isVisible, stashConfig?.ui?.ratingSystemOptions?.type, @@ -394,6 +401,7 @@ export const SceneEditPanel: React.FC = ({ return ( = ({ } if (updatedScene.studio && updatedScene.studio.stored_id) { - formik.setFieldValue("studio_id", updatedScene.studio.stored_id); + onSetStudio({ + id: updatedScene.studio.stored_id, + name: updatedScene.studio.name ?? "", + aliases: [], + }); } if (updatedScene.performers && updatedScene.performers.length > 0) { @@ -726,13 +738,8 @@ export const SceneEditPanel: React.FC = ({ const title = intl.formatMessage({ id: "studio" }); const control = ( - formik.setFieldValue( - "studio_id", - items.length > 0 ? items[0]?.id : null - ) - } - ids={formik.values.studio_id ? [formik.values.studio_id] : []} + onSelect={(items) => onSetStudio(items.length > 0 ? items[0] : null)} + values={studio ? [studio] : []} /> ); diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/SceneScrapeDialog.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/SceneScrapeDialog.tsx index 7f3dfdb66f9..c016214d0e4 100644 --- a/ui/v2.5/src/components/Scenes/SceneDetails/SceneScrapeDialog.tsx +++ b/ui/v2.5/src/components/Scenes/SceneDetails/SceneScrapeDialog.tsx @@ -29,9 +29,11 @@ import { useCreateScrapedTag, } from "src/components/Shared/ScrapeDialog/createObjects"; import { Tag } from "src/components/Tags/TagSelect"; +import { Studio } from "src/components/Studios/StudioSelect"; interface ISceneScrapeDialogProps { scene: Partial; + sceneStudio: Studio | null; scenePerformers: Performer[]; sceneTags: Tag[]; scraped: GQL.ScrapedScene; @@ -42,6 +44,7 @@ interface ISceneScrapeDialogProps { export const SceneScrapeDialog: React.FC = ({ scene, + sceneStudio, scenePerformers, sceneTags, scraped, @@ -70,8 +73,16 @@ export const SceneScrapeDialog: React.FC = ({ const [director, setDirector] = useState>( new ScrapeResult(scene.director, scraped.director) ); - const [studio, setStudio] = useState>( - new ScrapeResult(scene.studio_id, scraped.studio?.stored_id) + const [studio, setStudio] = useState>( + new ScrapeResult( + sceneStudio + ? { + stored_id: sceneStudio.id, + name: sceneStudio.name, + } + : undefined, + scraped.studio?.stored_id ? scraped.studio : undefined + ) ); const [newStudio, setNewStudio] = useState( scraped.studio && !scraped.studio.stored_id ? scraped.studio : undefined @@ -235,12 +246,7 @@ export const SceneScrapeDialog: React.FC = ({ urls: urls.getNewValue(), date: date.getNewValue(), director: director.getNewValue(), - studio: newStudioValue - ? { - stored_id: newStudioValue, - name: "", - } - : undefined, + studio: newStudioValue, performers: performers.getNewValue(), movies: movies.getNewValue()?.map((m) => { return { diff --git a/ui/v2.5/src/components/Scenes/SceneMergeDialog.tsx b/ui/v2.5/src/components/Scenes/SceneMergeDialog.tsx index 8873fc4403e..8e629204fc4 100644 --- a/ui/v2.5/src/components/Scenes/SceneMergeDialog.tsx +++ b/ui/v2.5/src/components/Scenes/SceneMergeDialog.tsx @@ -87,8 +87,17 @@ const SceneMergeDetails: React.FC = ({ new ScrapeResult(dest.play_duration) ); - const [studio, setStudio] = useState>( - new ScrapeResult(dest.studio?.id) + function idToStoredID(o: { id: string; name: string }) { + return { + stored_id: o.id, + name: o.name, + }; + } + + const [studio, setStudio] = useState>( + new ScrapeResult( + dest.studio ? idToStoredID(dest.studio) : undefined + ) ); function sortIdList(idList?: string[] | null) { @@ -105,13 +114,6 @@ const SceneMergeDetails: React.FC = ({ return ret; } - function idToStoredID(o: { id: string; name: string }) { - return { - stored_id: o.id, - name: o.name, - }; - } - function uniqIDStoredIDs(objs: T[]) { return objs.filter((o, i) => { return objs.findIndex((oo) => oo.stored_id === o.stored_id) === i; @@ -197,10 +199,18 @@ const SceneMergeDetails: React.FC = ({ setDate( new ScrapeResult(dest.date, sources.find((s) => s.date)?.date, !dest.date) ); + + const foundStudio = sources.find((s) => s.studio)?.studio; + setStudio( - new ScrapeResult( - dest.studio?.id, - sources.find((s) => s.studio)?.studio?.id, + new ScrapeResult( + dest.studio ? idToStoredID(dest.studio) : undefined, + foundStudio + ? { + stored_id: foundStudio.id, + name: foundStudio.name, + } + : undefined, !dest.studio ) ); @@ -581,7 +591,7 @@ const SceneMergeDetails: React.FC = ({ play_count: playCount.getNewValue(), play_duration: playDuration.getNewValue(), gallery_ids: galleries.getNewValue(), - studio_id: studio.getNewValue(), + studio_id: studio.getNewValue()?.stored_id, performer_ids: performers.getNewValue()?.map((p) => p.stored_id!), movies: movies.getNewValue()?.map((m) => { // find the equivalent movie in the original scenes diff --git a/ui/v2.5/src/components/Shared/FilterSelect.tsx b/ui/v2.5/src/components/Shared/FilterSelect.tsx index 82b45661842..e6f47bba47e 100644 --- a/ui/v2.5/src/components/Shared/FilterSelect.tsx +++ b/ui/v2.5/src/components/Shared/FilterSelect.tsx @@ -89,6 +89,7 @@ const SelectComponent = ( ...props, styles, defaultOptions: true, + isClearable: true, value: selectedOptions ?? null, className: cx("react-select", props.className), classNamePrefix: "react-select", diff --git a/ui/v2.5/src/components/Shared/ScrapeDialog/ScrapedObjectsRow.tsx b/ui/v2.5/src/components/Shared/ScrapeDialog/ScrapedObjectsRow.tsx index f3db0b3b33c..1bbc1510ba5 100644 --- a/ui/v2.5/src/components/Shared/ScrapeDialog/ScrapedObjectsRow.tsx +++ b/ui/v2.5/src/components/Shared/ScrapeDialog/ScrapedObjectsRow.tsx @@ -1,6 +1,6 @@ import React, { useMemo } from "react"; import * as GQL from "src/core/generated-graphql"; -import { MovieSelect, StudioSelect } from "src/components/Shared/Select"; +import { MovieSelect } from "src/components/Shared/Select"; import { ScrapeDialogRow, IHasName, @@ -8,11 +8,12 @@ import { import { PerformerSelect } from "src/components/Performers/PerformerSelect"; import { ScrapeResult } from "src/components/Shared/ScrapeDialog/scrapeResult"; import { TagSelect } from "src/components/Tags/TagSelect"; +import { StudioSelect } from "src/components/Studios/StudioSelect"; interface IScrapedStudioRow { title: string; - result: ScrapeResult; - onChange: (value: ScrapeResult) => void; + result: ScrapeResult; + onChange: (value: ScrapeResult) => void; newStudio?: GQL.ScrapedStudio; onCreateNew?: (value: GQL.ScrapedStudio) => void; } @@ -25,25 +26,34 @@ export const ScrapedStudioRow: React.FC = ({ onCreateNew, }) => { function renderScrapedStudio( - scrapeResult: ScrapeResult, + scrapeResult: ScrapeResult, isNew?: boolean, - onChangeFn?: (value: string) => void + onChangeFn?: (value: GQL.ScrapedStudio) => void ) { const resultValue = isNew ? scrapeResult.newValue : scrapeResult.originalValue; const value = resultValue ? [resultValue] : []; + const selectValue = value.map((p) => { + const aliases: string[] = []; + return { + id: p.stored_id ?? "", + name: p.name ?? "", + aliases, + }; + }); + return ( { if (onChangeFn) { - onChangeFn(items[0]?.id); + onChangeFn(items[0]); } }} - ids={value} + values={selectValue} /> ); } diff --git a/ui/v2.5/src/components/Shared/ScrapeDialog/createObjects.ts b/ui/v2.5/src/components/Shared/ScrapeDialog/createObjects.ts index 10ac099af3f..c2bd205ab00 100644 --- a/ui/v2.5/src/components/Shared/ScrapeDialog/createObjects.ts +++ b/ui/v2.5/src/components/Shared/ScrapeDialog/createObjects.ts @@ -41,8 +41,8 @@ function useCreateObject( } interface IUseCreateNewStudioProps { - scrapeResult: ScrapeResult; - setScrapeResult: (scrapeResult: ScrapeResult) => void; + scrapeResult: ScrapeResult; + setScrapeResult: (scrapeResult: ScrapeResult) => void; setNewObject: (newObject: GQL.ScrapedStudio | undefined) => void; } @@ -62,7 +62,12 @@ export function useCreateScrapedStudio(props: IUseCreateNewStudioProps) { }); // set the new studio as the value - setScrapeResult(scrapeResult.cloneWithValue(result.data!.studioCreate!.id)); + setScrapeResult( + scrapeResult.cloneWithValue({ + stored_id: result.data!.studioCreate!.id, + name: toCreate.name, + }) + ); setNewObject(undefined); } diff --git a/ui/v2.5/src/components/Shared/Select.tsx b/ui/v2.5/src/components/Shared/Select.tsx index 2ecf60fd784..03dd528fae1 100644 --- a/ui/v2.5/src/components/Shared/Select.tsx +++ b/ui/v2.5/src/components/Shared/Select.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useMemo, useState } from "react"; +import React, { useMemo, useState } from "react"; import Select, { OnChangeValue, StylesConfig, @@ -15,9 +15,7 @@ import CreatableSelect from "react-select/creatable"; import * as GQL from "src/core/generated-graphql"; import { useAllMoviesForFilter, - useAllStudiosForFilter, useMarkerStrings, - useStudioCreate, useMovieCreate, } from "src/core/StashService"; import { useToast } from "src/hooks/Toast"; @@ -33,6 +31,7 @@ import { PerformerIDSelect } from "../Performers/PerformerSelect"; import { Icon } from "./Icon"; import { faTableColumns } from "@fortawesome/free-solid-svg-icons"; import { TagIDSelect } from "../Tags/TagSelect"; +import { StudioIDSelect } from "../Studios/StudioSelect"; export type SelectObject = { id: string; @@ -534,144 +533,7 @@ export const PerformerSelect: React.FC = (props) => { export const StudioSelect: React.FC< IFilterProps & { excludeIds?: string[] } > = (props) => { - const [studioAliases, setStudioAliases] = useState>( - {} - ); - const [allAliases, setAllAliases] = useState([]); - const { data, loading } = useAllStudiosForFilter(); - const [createStudio] = useStudioCreate(); - const intl = useIntl(); - - const { configuration } = React.useContext(ConfigurationContext); - const defaultCreatable = - !configuration?.interface.disableDropdownCreate.studio ?? true; - - const exclude = useMemo(() => props.excludeIds ?? [], [props.excludeIds]); - const studios = useMemo( - () => - (data?.allStudios ?? []).filter((studio) => !exclude.includes(studio.id)), - [data?.allStudios, exclude] - ); - - useEffect(() => { - // build the studio aliases map - const newAliases: Record = {}; - const newAll: string[] = []; - studios.forEach((s) => { - newAliases[s.id] = s.aliases; - newAll.push(...s.aliases); - }); - setStudioAliases(newAliases); - setAllAliases(newAll); - }, [studios]); - - const StudioOption: React.FC> = ( - optionProps - ) => { - const { inputValue } = optionProps.selectProps; - - let thisOptionProps = optionProps; - if ( - inputValue && - !optionProps.label.toLowerCase().includes(inputValue.toLowerCase()) - ) { - // must be alias - const newLabel = `${optionProps.data.label} (alias)`; - thisOptionProps = { - ...optionProps, - children: newLabel, - }; - } - - return ; - }; - - const filterOption = (option: Option, rawInput: string): boolean => { - if (!rawInput) { - return true; - } - - const input = rawInput.toLowerCase(); - const optionVal = option.label.toLowerCase(); - - if (optionVal.includes(input)) { - return true; - } - - // search for studio aliases - const aliases = studioAliases[option.value]; - // only match on alias if exact - if (aliases && aliases.some((a) => a.toLowerCase() === input)) { - return true; - } - - return false; - }; - - const onCreate = async (name: string) => { - const result = await createStudio({ - variables: { - input: { name }, - }, - }); - return { - item: result.data!.studioCreate!, - message: intl.formatMessage( - { id: "toast.created_entity" }, - { entity: intl.formatMessage({ id: "studio" }).toLocaleLowerCase() } - ), - }; - }; - - const isValidNewOption = ( - inputValue: string, - value: OnChangeValue, - options: OptionsOrGroups> - ) => { - if (!inputValue) { - return false; - } - - if ( - (options as Options