diff --git a/graphql/documents/data/config.graphql b/graphql/documents/data/config.graphql index 048bb4815..3892cdac7 100644 --- a/graphql/documents/data/config.graphql +++ b/graphql/documents/data/config.graphql @@ -90,6 +90,7 @@ fragment ConfigInterfaceData on ConfigInterfaceResult { performer tag studio + movie } handyKey funscriptOffset diff --git a/graphql/schema/types/config.graphql b/graphql/schema/types/config.graphql index 08fa4e217..3bd341de9 100644 --- a/graphql/schema/types/config.graphql +++ b/graphql/schema/types/config.graphql @@ -269,6 +269,7 @@ input ConfigDisableDropdownCreateInput { performer: Boolean tag: Boolean studio: Boolean + movie: Boolean } enum ImageLightboxDisplayMode { @@ -366,6 +367,7 @@ type ConfigDisableDropdownCreate { performer: Boolean! tag: Boolean! studio: Boolean! + movie: Boolean! } type ConfigInterfaceResult { diff --git a/internal/api/resolver_mutation_configure.go b/internal/api/resolver_mutation_configure.go index 177b44427..f12b3aa0c 100644 --- a/internal/api/resolver_mutation_configure.go +++ b/internal/api/resolver_mutation_configure.go @@ -469,6 +469,7 @@ func (r *mutationResolver) ConfigureInterface(ctx context.Context, input ConfigI setBool(config.DisableDropdownCreatePerformer, ddc.Performer) setBool(config.DisableDropdownCreateStudio, ddc.Studio) setBool(config.DisableDropdownCreateTag, ddc.Tag) + setBool(config.DisableDropdownCreateMovie, ddc.Movie) } if input.HandyKey != nil { diff --git a/internal/manager/config/config.go b/internal/manager/config/config.go index 3a339a136..76d37d2f6 100644 --- a/internal/manager/config/config.go +++ b/internal/manager/config/config.go @@ -189,6 +189,7 @@ const ( DisableDropdownCreatePerformer = "disable_dropdown_create.performer" DisableDropdownCreateStudio = "disable_dropdown_create.studio" DisableDropdownCreateTag = "disable_dropdown_create.tag" + DisableDropdownCreateMovie = "disable_dropdown_create.movie" HandyKey = "handy_key" FunscriptOffset = "funscript_offset" @@ -1096,6 +1097,7 @@ func (i *Instance) GetDisableDropdownCreate() *ConfigDisableDropdownCreate { Performer: i.getBool(DisableDropdownCreatePerformer), Studio: i.getBool(DisableDropdownCreateStudio), Tag: i.getBool(DisableDropdownCreateTag), + Movie: i.getBool(DisableDropdownCreateMovie), } } diff --git a/internal/manager/config/config_concurrency_test.go b/internal/manager/config/config_concurrency_test.go index 0ede5f055..e96983527 100644 --- a/internal/manager/config/config_concurrency_test.go +++ b/internal/manager/config/config_concurrency_test.go @@ -112,6 +112,7 @@ func TestConcurrentConfigAccess(t *testing.T) { i.Set(DisableDropdownCreatePerformer, i.GetDisableDropdownCreate().Performer) i.Set(DisableDropdownCreateStudio, i.GetDisableDropdownCreate().Studio) i.Set(DisableDropdownCreateTag, i.GetDisableDropdownCreate().Tag) + i.Set(DisableDropdownCreateMovie, i.GetDisableDropdownCreate().Movie) i.Set(AutostartVideoOnPlaySelected, i.GetAutostartVideoOnPlaySelected()) i.Set(ContinuePlaylistDefault, i.GetContinuePlaylistDefault()) i.Set(PythonPath, i.GetPythonPath()) diff --git a/internal/manager/config/ui.go b/internal/manager/config/ui.go index a2744a741..699091154 100644 --- a/internal/manager/config/ui.go +++ b/internal/manager/config/ui.go @@ -103,4 +103,5 @@ type ConfigDisableDropdownCreate struct { Performer bool `json:"performer"` Tag bool `json:"tag"` Studio bool `json:"studio"` + Movie bool `json:"movie"` } diff --git a/ui/v2.5/src/components/Settings/SettingsInterfacePanel/SettingsInterfacePanel.tsx b/ui/v2.5/src/components/Settings/SettingsInterfacePanel/SettingsInterfacePanel.tsx index 2332538b1..df20ecf0f 100644 --- a/ui/v2.5/src/components/Settings/SettingsInterfacePanel/SettingsInterfacePanel.tsx +++ b/ui/v2.5/src/components/Settings/SettingsInterfacePanel/SettingsInterfacePanel.tsx @@ -549,6 +549,19 @@ export const SettingsInterfacePanel: React.FC = () => { }) } /> + + saveInterface({ + disableDropdownCreate: { + ...iface.disableDropdownCreate, + movie: v, + }, + }) + } + /> = (props) => { }); return { item: result.data!.performerCreate!, - message: "Created performer", + message: intl.formatMessage( + { id: "toast.created_entity" }, + { entity: intl.formatMessage({ id: "performer" }).toLocaleLowerCase() } + ), }; }; @@ -760,7 +764,13 @@ export const StudioSelect: React.FC< input: { name }, }, }); - return { item: result.data!.studioCreate!, message: "Created studio" }; + return { + item: result.data!.studioCreate!, + message: intl.formatMessage( + { id: "toast.created_entity" }, + { entity: intl.formatMessage({ id: "studio" }).toLocaleLowerCase() } + ), + }; }; const isValidNewOption = ( @@ -812,9 +822,27 @@ export const StudioSelect: React.FC< export const MovieSelect: React.FC = (props) => { const { data, loading } = useAllMoviesForFilter(); + const [createMovie] = useMovieCreate(); const items = data?.allMovies ?? []; const intl = useIntl(); + const { configuration } = React.useContext(ConfigurationContext); + const defaultCreatable = + !configuration?.interface.disableDropdownCreate.movie ?? true; + + const onCreate = async (name: string) => { + const result = await createMovie({ + variables: { input: { name } }, + }); + return { + item: result.data!.movieCreate!, + message: intl.formatMessage( + { id: "toast.created_entity" }, + { entity: intl.formatMessage({ id: "movie" }).toLocaleLowerCase() } + ), + }; + }; + return ( = (props) => { { entityType: intl.formatMessage({ id: "movie" }) } ) } + creatable={props.creatable ?? defaultCreatable} + onCreate={onCreate} /> ); }; @@ -927,7 +957,13 @@ export const TagSelect: React.FC< }, }, }); - return { item: result.data!.tagCreate!, message: "Created tag" }; + return { + item: result.data!.tagCreate!, + message: intl.formatMessage( + { id: "toast.created_entity" }, + { entity: intl.formatMessage({ id: "tag" }).toLocaleLowerCase() } + ), + }; }; const isValidNewOption = (