mirror of
https://github.com/stashapp/stash.git
synced 2025-12-16 20:07:05 +03:00
Respect user preference for type-to-create in image/scene multi-select form (#6376)
This commit is contained in:
@@ -319,6 +319,7 @@ input ConfigDisableDropdownCreateInput {
|
||||
tag: Boolean
|
||||
studio: Boolean
|
||||
movie: Boolean
|
||||
gallery: Boolean
|
||||
}
|
||||
|
||||
enum ImageLightboxDisplayMode {
|
||||
@@ -419,6 +420,7 @@ type ConfigDisableDropdownCreate {
|
||||
tag: Boolean!
|
||||
studio: Boolean!
|
||||
movie: Boolean!
|
||||
gallery: Boolean!
|
||||
}
|
||||
|
||||
type ConfigInterfaceResult {
|
||||
|
||||
@@ -521,6 +521,7 @@ func (r *mutationResolver) ConfigureInterface(ctx context.Context, input ConfigI
|
||||
r.setConfigBool(config.DisableDropdownCreateStudio, ddc.Studio)
|
||||
r.setConfigBool(config.DisableDropdownCreateTag, ddc.Tag)
|
||||
r.setConfigBool(config.DisableDropdownCreateMovie, ddc.Movie)
|
||||
r.setConfigBool(config.DisableDropdownCreateGallery, ddc.Gallery)
|
||||
}
|
||||
|
||||
r.setConfigString(config.HandyKey, input.HandyKey)
|
||||
|
||||
@@ -219,6 +219,7 @@ const (
|
||||
DisableDropdownCreateStudio = "disable_dropdown_create.studio"
|
||||
DisableDropdownCreateTag = "disable_dropdown_create.tag"
|
||||
DisableDropdownCreateMovie = "disable_dropdown_create.movie"
|
||||
DisableDropdownCreateGallery = "disable_dropdown_create.gallery"
|
||||
|
||||
HandyKey = "handy_key"
|
||||
FunscriptOffset = "funscript_offset"
|
||||
@@ -1311,6 +1312,7 @@ func (i *Config) GetDisableDropdownCreate() *ConfigDisableDropdownCreate {
|
||||
Studio: i.getBool(DisableDropdownCreateStudio),
|
||||
Tag: i.getBool(DisableDropdownCreateTag),
|
||||
Movie: i.getBool(DisableDropdownCreateMovie),
|
||||
Gallery: i.getBool(DisableDropdownCreateGallery),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -105,4 +105,5 @@ type ConfigDisableDropdownCreate struct {
|
||||
Tag bool `json:"tag"`
|
||||
Studio bool `json:"studio"`
|
||||
Movie bool `json:"movie"`
|
||||
Gallery bool `json:"gallery"`
|
||||
}
|
||||
|
||||
@@ -107,6 +107,7 @@ fragment ConfigInterfaceData on ConfigInterfaceResult {
|
||||
tag
|
||||
studio
|
||||
movie
|
||||
gallery
|
||||
}
|
||||
handyKey
|
||||
funscriptOffset
|
||||
|
||||
@@ -11,6 +11,7 @@ import * as GQL from "src/core/generated-graphql";
|
||||
import {
|
||||
queryFindGalleriesForSelect,
|
||||
queryFindGalleriesByIDForSelect,
|
||||
useGalleryCreate,
|
||||
} from "src/core/StashService";
|
||||
import { useConfigurationContext } from "src/hooks/Config";
|
||||
import { useIntl } from "react-intl";
|
||||
@@ -70,10 +71,14 @@ const gallerySelectSort = PatchFunction(
|
||||
const _GallerySelect: React.FC<
|
||||
IFilterProps & IFilterValueProps<Gallery> & ExtraGalleryProps
|
||||
> = (props) => {
|
||||
const [createGallery] = useGalleryCreate();
|
||||
|
||||
const { configuration } = useConfigurationContext();
|
||||
const intl = useIntl();
|
||||
const maxOptionsShown =
|
||||
configuration?.ui.maxOptionsShown ?? defaultMaxOptionsShown;
|
||||
const defaultCreatable =
|
||||
!configuration?.interface.disableDropdownCreate.gallery;
|
||||
|
||||
const exclude = useMemo(() => props.excludeIds ?? [], [props.excludeIds]);
|
||||
|
||||
@@ -203,6 +208,42 @@ const _GallerySelect: React.FC<
|
||||
return <reactSelectComponents.SingleValue {...thisOptionProps} />;
|
||||
};
|
||||
|
||||
const onCreate = async (name: string) => {
|
||||
const result = await createGallery({
|
||||
variables: { input: { title: name } },
|
||||
});
|
||||
return {
|
||||
value: result.data!.galleryCreate!.id,
|
||||
item: result.data!.galleryCreate!,
|
||||
message: "Created gallery",
|
||||
};
|
||||
};
|
||||
|
||||
const getNamedObject = (id: string, name: string): Gallery => {
|
||||
return {
|
||||
id,
|
||||
title: name,
|
||||
files: [],
|
||||
folder: null,
|
||||
};
|
||||
};
|
||||
|
||||
const isValidNewOption = (inputValue: string, options: Gallery[]) => {
|
||||
if (!inputValue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
options.some((o) => {
|
||||
return galleryTitle(o).toLowerCase() === inputValue.toLowerCase();
|
||||
})
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
return (
|
||||
<FilterSelectComponent<Gallery, boolean>
|
||||
{...props}
|
||||
@@ -214,12 +255,16 @@ const _GallerySelect: React.FC<
|
||||
props.className
|
||||
)}
|
||||
loadOptions={loadGalleries}
|
||||
getNamedObject={getNamedObject}
|
||||
isValidNewOption={isValidNewOption}
|
||||
components={{
|
||||
Option: GalleryOption,
|
||||
MultiValueLabel: GalleryMultiValueLabel,
|
||||
SingleValue: GalleryValueLabel,
|
||||
}}
|
||||
isMulti={props.isMulti ?? false}
|
||||
creatable={props.creatable ?? defaultCreatable}
|
||||
onCreate={onCreate}
|
||||
placeholder={
|
||||
props.noSelectionString ??
|
||||
intl.formatMessage(
|
||||
|
||||
@@ -735,6 +735,19 @@ export const SettingsInterfacePanel: React.FC = PatchComponent(
|
||||
})
|
||||
}
|
||||
/>
|
||||
<BooleanSetting
|
||||
id="disableDropdownCreate_gallery"
|
||||
headingID="gallery"
|
||||
checked={iface.disableDropdownCreate?.gallery ?? undefined}
|
||||
onChange={(v) =>
|
||||
saveInterface({
|
||||
disableDropdownCreate: {
|
||||
...iface.disableDropdownCreate,
|
||||
gallery: v,
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<NumberSetting
|
||||
id="max_options_shown"
|
||||
|
||||
@@ -8,6 +8,10 @@ import {
|
||||
GalleryIDSelect,
|
||||
excludeFileBasedGalleries,
|
||||
} from "../Galleries/GallerySelect";
|
||||
import { PerformerIDSelect } from "../Performers/PerformerSelect";
|
||||
import { StudioIDSelect } from "../Studios/StudioSelect";
|
||||
import { TagIDSelect } from "../Tags/TagSelect";
|
||||
import { GroupIDSelect } from "../Groups/GroupSelect";
|
||||
|
||||
interface IMultiSetProps {
|
||||
type: "performers" | "studios" | "tags" | "groups" | "galleries";
|
||||
@@ -27,32 +31,77 @@ const Select: React.FC<IMultiSetProps> = (props) => {
|
||||
props.onUpdate(items.map((i) => i.id));
|
||||
}
|
||||
|
||||
if (type === "galleries") {
|
||||
return (
|
||||
<GalleryIDSelect
|
||||
isDisabled={disabled}
|
||||
isMulti
|
||||
isClearable={false}
|
||||
onSelect={onUpdate}
|
||||
ids={props.ids ?? []}
|
||||
// exclude file-based galleries when setting galleries
|
||||
extraCriteria={excludeFileBasedGalleries}
|
||||
menuPortalTarget={props.menuPortalTarget}
|
||||
/>
|
||||
);
|
||||
switch (type) {
|
||||
case "performers":
|
||||
return (
|
||||
<PerformerIDSelect
|
||||
isDisabled={disabled}
|
||||
isMulti
|
||||
isClearable={false}
|
||||
onSelect={onUpdate}
|
||||
ids={props.ids ?? []}
|
||||
menuPortalTarget={props.menuPortalTarget}
|
||||
/>
|
||||
);
|
||||
case "studios":
|
||||
return (
|
||||
<StudioIDSelect
|
||||
isDisabled={disabled}
|
||||
isMulti
|
||||
isClearable={false}
|
||||
onSelect={onUpdate}
|
||||
ids={props.ids ?? []}
|
||||
menuPortalTarget={props.menuPortalTarget}
|
||||
/>
|
||||
);
|
||||
case "tags":
|
||||
return (
|
||||
<TagIDSelect
|
||||
isDisabled={disabled}
|
||||
isMulti
|
||||
isClearable={false}
|
||||
onSelect={onUpdate}
|
||||
ids={props.ids ?? []}
|
||||
menuPortalTarget={props.menuPortalTarget}
|
||||
/>
|
||||
);
|
||||
case "groups":
|
||||
return (
|
||||
<GroupIDSelect
|
||||
isDisabled={disabled}
|
||||
isMulti
|
||||
isClearable={false}
|
||||
onSelect={onUpdate}
|
||||
ids={props.ids ?? []}
|
||||
menuPortalTarget={props.menuPortalTarget}
|
||||
/>
|
||||
);
|
||||
case "galleries":
|
||||
return (
|
||||
<GalleryIDSelect
|
||||
isDisabled={disabled}
|
||||
isMulti
|
||||
isClearable={false}
|
||||
onSelect={onUpdate}
|
||||
ids={props.ids ?? []}
|
||||
// exclude file-based galleries when setting galleries
|
||||
extraCriteria={excludeFileBasedGalleries}
|
||||
menuPortalTarget={props.menuPortalTarget}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<FilterSelect
|
||||
type={type}
|
||||
isDisabled={disabled}
|
||||
isMulti
|
||||
isClearable={false}
|
||||
onSelect={onUpdate}
|
||||
ids={props.ids ?? []}
|
||||
menuPortalTarget={props.menuPortalTarget}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<FilterSelect
|
||||
type={type}
|
||||
isDisabled={disabled}
|
||||
isMulti
|
||||
isClearable={false}
|
||||
onSelect={onUpdate}
|
||||
ids={props.ids ?? []}
|
||||
menuPortalTarget={props.menuPortalTarget}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
function getModeText(intl: IntlShape, mode: GQL.BulkUpdateIdMode) {
|
||||
|
||||
@@ -385,7 +385,7 @@ export const FilterSelect: React.FC<IFilterProps & ITypeProps> = (props) => {
|
||||
case "groups":
|
||||
return <GroupSelect {...props} creatable={false} />;
|
||||
case "galleries":
|
||||
return <GallerySelect {...props} />;
|
||||
return <GallerySelect {...props} creatable={false} />;
|
||||
default:
|
||||
return <TagSelect {...props} creatable={false} />;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user