mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 12:24:38 +03:00
Movie select overhaul (#4563)
* Add ids to findMovies input * Use ids for other find interfaces * Update client side * Fix gallery select function * Replace movie select * Re-add creatable * Overhaul movie table * Remove and deprecated unused code
This commit is contained in:
@@ -13,15 +13,9 @@ import Select, {
|
||||
import CreatableSelect from "react-select/creatable";
|
||||
|
||||
import * as GQL from "src/core/generated-graphql";
|
||||
import {
|
||||
useAllMoviesForFilter,
|
||||
useMarkerStrings,
|
||||
useMovieCreate,
|
||||
} from "src/core/StashService";
|
||||
import { useToast } from "src/hooks/Toast";
|
||||
import { useMarkerStrings } from "src/core/StashService";
|
||||
import { SelectComponents } from "react-select/dist/declarations/src/components";
|
||||
import { ConfigurationContext } from "src/hooks/Config";
|
||||
import { useIntl } from "react-intl";
|
||||
import { objectTitle } from "src/core/files";
|
||||
import { defaultMaxOptionsShown } from "src/core/config";
|
||||
import { useDebounce } from "src/hooks/debounce";
|
||||
@@ -32,6 +26,7 @@ import { faTableColumns } from "@fortawesome/free-solid-svg-icons";
|
||||
import { TagIDSelect } from "../Tags/TagSelect";
|
||||
import { StudioIDSelect } from "../Studios/StudioSelect";
|
||||
import { GalleryIDSelect } from "../Galleries/GallerySelect";
|
||||
import { MovieIDSelect } from "../Movies/MovieSelect";
|
||||
|
||||
export type SelectObject = {
|
||||
id: string;
|
||||
@@ -89,23 +84,6 @@ interface ISelectProps<T extends boolean> {
|
||||
closeMenuOnSelect?: boolean;
|
||||
noOptionsMessage?: string | null;
|
||||
}
|
||||
interface IFilterComponentProps extends IFilterProps {
|
||||
items: SelectObject[];
|
||||
toOption?: (item: SelectObject) => Option;
|
||||
onCreate?: (name: string) => Promise<{ item: SelectObject; message: string }>;
|
||||
}
|
||||
interface IFilterSelectProps<T extends boolean>
|
||||
extends Pick<
|
||||
ISelectProps<T>,
|
||||
| "isLoading"
|
||||
| "isMulti"
|
||||
| "components"
|
||||
| "filterOption"
|
||||
| "isValidNewOption"
|
||||
| "placeholder"
|
||||
| "closeMenuOnSelect"
|
||||
> {}
|
||||
|
||||
type TitledObject = { id: string; title: string };
|
||||
interface ITitledSelect {
|
||||
className?: string;
|
||||
@@ -125,9 +103,6 @@ const getSelectedItems = (selectedItems: OnChangeValue<Option, boolean>) => {
|
||||
}
|
||||
};
|
||||
|
||||
const getSelectedValues = (selectedItems: OnChangeValue<Option, boolean>) =>
|
||||
getSelectedItems(selectedItems).map((item) => item.value);
|
||||
|
||||
const LimitedSelectMenu = <T extends boolean>(
|
||||
props: MenuListProps<Option, T, GroupBase<Option>>
|
||||
) => {
|
||||
@@ -273,67 +248,6 @@ const SelectComponent = <T extends boolean>({
|
||||
);
|
||||
};
|
||||
|
||||
const FilterSelectComponent = <T extends boolean>(
|
||||
props: IFilterComponentProps & ITypeProps & IFilterSelectProps<T>
|
||||
) => {
|
||||
const { items, ids, isMulti, onSelect } = props;
|
||||
const [loading, setLoading] = useState(false);
|
||||
const selectedIds = ids ?? [];
|
||||
const Toast = useToast();
|
||||
|
||||
const options = items.map((i) => {
|
||||
if (props.toOption) {
|
||||
return props.toOption(i);
|
||||
}
|
||||
return {
|
||||
value: i.id,
|
||||
label: i.name ?? i.title ?? "",
|
||||
};
|
||||
});
|
||||
|
||||
const selected = options.filter((option) =>
|
||||
selectedIds.includes(option.value)
|
||||
);
|
||||
const selectedOptions = (
|
||||
isMulti ? selected : selected[0] ?? null
|
||||
) as OnChangeValue<Option, T>;
|
||||
|
||||
const onChange = (selectedItems: OnChangeValue<Option, boolean>) => {
|
||||
const selectedValues = getSelectedValues(selectedItems);
|
||||
onSelect?.(items.filter((item) => selectedValues.includes(item.id)));
|
||||
};
|
||||
|
||||
const onCreate = async (name: string) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const { item: newItem, message } = await props.onCreate!(name);
|
||||
props.onSelect?.([
|
||||
...items.filter((item) => selectedIds.includes(item.id)),
|
||||
newItem,
|
||||
]);
|
||||
setLoading(false);
|
||||
Toast.success(
|
||||
<span>
|
||||
{message}: <b>{name}</b>
|
||||
</span>
|
||||
);
|
||||
} catch (e) {
|
||||
Toast.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<SelectComponent<T>
|
||||
{...props}
|
||||
isLoading={props.isLoading || loading}
|
||||
onChange={onChange}
|
||||
items={options}
|
||||
selectedOptions={selectedOptions}
|
||||
onCreateOption={props.creatable ? onCreate : undefined}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const GallerySelect: React.FC<
|
||||
IFilterProps & { excludeIds?: string[] }
|
||||
> = (props) => {
|
||||
@@ -493,50 +407,7 @@ export const StudioSelect: React.FC<
|
||||
};
|
||||
|
||||
export const MovieSelect: React.FC<IFilterProps> = (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 (
|
||||
<FilterSelectComponent
|
||||
{...props}
|
||||
isMulti={props.isMulti ?? false}
|
||||
type="movies"
|
||||
isLoading={loading}
|
||||
items={items}
|
||||
placeholder={
|
||||
props.noSelectionString ??
|
||||
intl.formatMessage(
|
||||
{ id: "actions.select_entity" },
|
||||
{
|
||||
entityType: intl.formatMessage({
|
||||
id: props.isMulti ? "movies" : "movie",
|
||||
}),
|
||||
}
|
||||
)
|
||||
}
|
||||
creatable={props.creatable ?? defaultCreatable}
|
||||
onCreate={onCreate}
|
||||
/>
|
||||
);
|
||||
return <MovieIDSelect {...props} />;
|
||||
};
|
||||
|
||||
export const TagSelect: React.FC<
|
||||
|
||||
Reference in New Issue
Block a user