diff --git a/ui/v2.5/src/components/Galleries/GallerySelect.tsx b/ui/v2.5/src/components/Galleries/GallerySelect.tsx index 2adf6823a..b2d0cd09b 100644 --- a/ui/v2.5/src/components/Galleries/GallerySelect.tsx +++ b/ui/v2.5/src/components/Galleries/GallerySelect.tsx @@ -28,6 +28,10 @@ import { Placement } from "react-bootstrap/esm/Overlay"; import { sortByRelevance } from "src/utils/query"; import { galleryTitle } from "src/core/galleries"; import { PatchComponent } from "src/patch"; +import { + Criterion, + CriterionValue, +} from "src/models/list-filter/criteria/criterion"; export type Gallery = Pick & { files: Pick[]; @@ -40,6 +44,8 @@ const _GallerySelect: React.FC< IFilterValueProps & { hoverPlacement?: Placement; excludeIds?: string[]; + } & { + extraCriteria?: Array>; } > = (props) => { const { configuration } = React.useContext(ConfigurationContext); @@ -56,6 +62,11 @@ const _GallerySelect: React.FC< filter.itemsPerPage = maxOptionsShown; filter.sortBy = "title"; filter.sortDirection = GQL.SortDirectionEnum.Asc; + + if (props.extraCriteria) { + filter.criteria = [...props.extraCriteria]; + } + const query = await queryFindGalleriesForSelect(filter); let ret = query.data.findGalleries.galleries.filter((gallery) => { // HACK - we should probably exclude these in the backend query, but diff --git a/ui/v2.5/src/components/Images/ImageDetails/ImageEditPanel.tsx b/ui/v2.5/src/components/Images/ImageDetails/ImageEditPanel.tsx index 91657a872..de93cb7f0 100644 --- a/ui/v2.5/src/components/Images/ImageDetails/ImageEditPanel.tsx +++ b/ui/v2.5/src/components/Images/ImageDetails/ImageEditPanel.tsx @@ -23,6 +23,9 @@ import { import { formikUtils } from "src/utils/form"; import { Tag, TagSelect } from "src/components/Tags/TagSelect"; import { Studio, StudioSelect } from "src/components/Studios/StudioSelect"; +import { galleryTitle } from "src/core/galleries"; +import { Gallery, GallerySelect } from "src/components/Galleries/GallerySelect"; +import { PathCriterion } from "src/models/list-filter/criteria/path"; interface IProps { image: GQL.ImageDataFragment; @@ -31,6 +34,14 @@ interface IProps { onDelete: () => void; } +function getExcludeFilebaseGalleriesFilter() { + const ret = new PathCriterion(); + ret.modifier = GQL.CriterionModifier.IsNull; + return ret; +} + +const excludeFileBasedGalleries = [getExcludeFilebaseGalleriesFilter()]; + export const ImageEditPanel: React.FC = ({ image, isVisible, @@ -45,10 +56,22 @@ export const ImageEditPanel: React.FC = ({ const { configuration } = React.useContext(ConfigurationContext); + const [galleries, setGalleries] = useState([]); const [performers, setPerformers] = useState([]); const [tags, setTags] = useState([]); const [studio, setStudio] = useState(null); + useEffect(() => { + setGalleries( + image.galleries?.map((g) => ({ + id: g.id, + title: galleryTitle(g), + files: g.files, + folder: g.folder, + })) ?? [] + ); + }, [image.galleries]); + const schema = yup.object({ title: yup.string().ensure(), code: yup.string().ensure(), @@ -57,6 +80,7 @@ export const ImageEditPanel: React.FC = ({ details: yup.string().ensure(), photographer: yup.string().ensure(), rating100: yup.number().integer().nullable().defined(), + gallery_ids: yup.array(yup.string().required()).defined(), studio_id: yup.string().required().nullable(), performer_ids: yup.array(yup.string().required()).defined(), tag_ids: yup.array(yup.string().required()).defined(), @@ -70,6 +94,7 @@ export const ImageEditPanel: React.FC = ({ details: image.details ?? "", photographer: image.photographer ?? "", rating100: image.rating100 ?? null, + gallery_ids: (image.galleries ?? []).map((g) => g.id), studio_id: image.studio?.id ?? null, performer_ids: (image.performers ?? []).map((p) => p.id), tag_ids: (image.tags ?? []).map((t) => t.id), @@ -88,6 +113,14 @@ export const ImageEditPanel: React.FC = ({ formik.setFieldValue("rating100", v); } + function onSetGalleries(items: Gallery[]) { + setGalleries(items); + formik.setFieldValue( + "gallery_ids", + items.map((i) => i.id) + ); + } + function onSetPerformers(items: Performer[]) { setPerformers(items); formik.setFieldValue( @@ -189,6 +222,20 @@ export const ImageEditPanel: React.FC = ({ renderURLListField, } = formikUtils(intl, formik, splitProps); + function renderGalleriesField() { + const title = intl.formatMessage({ id: "galleries" }); + const control = ( + onSetGalleries(items)} + isMulti + extraCriteria={excludeFileBasedGalleries} + /> + ); + + return renderField("gallery_ids", title, control); + } + function renderStudioField() { const title = intl.formatMessage({ id: "studio" }); const control = ( @@ -278,6 +325,7 @@ export const ImageEditPanel: React.FC = ({ {renderInputField("photographer")} {renderRatingField("rating100", "rating")} + {renderGalleriesField()} {renderStudioField()} {renderPerformersField()} {renderTagsField()}