- {gallery.studio && (
-
-
-
-
-
- )}
+
@@ -409,11 +423,7 @@ export const GalleryPage: React.FC = ({ gallery, add }) => {
{!!gallery.date && (
-
+
)}
diff --git a/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryAddPanel.tsx b/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryAddPanel.tsx
index 9e859c1c8..e0c115f34 100644
--- a/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryAddPanel.tsx
+++ b/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryAddPanel.tsx
@@ -1,106 +1,113 @@
-import React from "react";
+import React, { useCallback } from "react";
import * as GQL from "src/core/generated-graphql";
import { GalleriesCriterion } from "src/models/list-filter/criteria/galleries";
import { ListFilterModel } from "src/models/list-filter/filter";
-import { ImageList } from "src/components/Images/ImageList";
+import { FilteredImageList } from "src/components/Images/ImageList";
import { showWhenSelected } from "src/components/List/ItemList";
import { mutateAddGalleryImages } from "src/core/StashService";
import { useToast } from "src/hooks/Toast";
import { useIntl } from "react-intl";
import { faPlus } from "@fortawesome/free-solid-svg-icons";
import { galleryTitle } from "src/core/galleries";
+import { IItemListOperation } from "src/components/List/FilteredListToolbar";
+import { PatchComponent } from "src/patch";
interface IGalleryAddProps {
active: boolean;
gallery: GQL.GalleryDataFragment;
+ extraOperations?: IItemListOperation[];
}
-export const GalleryAddPanel: React.FC = ({
- active,
- gallery,
-}) => {
- const Toast = useToast();
- const intl = useIntl();
+export const GalleryAddPanel: React.FC = PatchComponent(
+ "GalleryAddPanel",
+ ({ active, gallery, extraOperations = [] }) => {
+ const Toast = useToast();
+ const intl = useIntl();
- function filterHook(filter: ListFilterModel) {
- const galleryValue = {
- id: gallery.id,
- label: galleryTitle(gallery),
- };
- // if galleries is already present, then we modify it, otherwise add
- let galleryCriterion = filter.criteria.find((c) => {
- return c.criterionOption.type === "galleries";
- }) as GalleriesCriterion | undefined;
+ const filterHook = useCallback(
+ (filter: ListFilterModel) => {
+ const galleryValue = {
+ id: gallery.id,
+ label: galleryTitle(gallery),
+ };
+ // if galleries is already present, then we modify it, otherwise add
+ let galleryCriterion = filter.criteria.find((c) => {
+ return c.criterionOption.type === "galleries";
+ }) as GalleriesCriterion | undefined;
- if (
- galleryCriterion &&
- galleryCriterion.modifier === GQL.CriterionModifier.Excludes
- ) {
- // add the gallery if not present
- if (
- !galleryCriterion.value.find((p) => {
- return p.id === gallery.id;
- })
- ) {
- galleryCriterion.value.push(galleryValue);
- }
-
- galleryCriterion.modifier = GQL.CriterionModifier.Excludes;
- } else {
- // overwrite
- galleryCriterion = new GalleriesCriterion();
- galleryCriterion.modifier = GQL.CriterionModifier.Excludes;
- galleryCriterion.value = [galleryValue];
- filter.criteria.push(galleryCriterion);
- }
-
- return filter;
- }
-
- async function addImages(
- result: GQL.FindImagesQueryResult,
- filter: ListFilterModel,
- selectedIds: Set
- ) {
- try {
- await mutateAddGalleryImages({
- gallery_id: gallery.id!,
- image_ids: Array.from(selectedIds.values()),
- });
- const imageCount = selectedIds.size;
- Toast.success(
- intl.formatMessage(
- { id: "toast.added_entity" },
- {
- count: imageCount,
- singularEntity: intl.formatMessage({ id: "image" }),
- pluralEntity: intl.formatMessage({ id: "images" }),
+ if (
+ galleryCriterion &&
+ galleryCriterion.modifier === GQL.CriterionModifier.Excludes
+ ) {
+ // add the gallery if not present
+ if (
+ !galleryCriterion.value.find((p) => {
+ return p.id === gallery.id;
+ })
+ ) {
+ galleryCriterion.value.push(galleryValue);
}
- )
- );
- } catch (e) {
- Toast.error(e);
+
+ galleryCriterion.modifier = GQL.CriterionModifier.Excludes;
+ } else {
+ // overwrite
+ galleryCriterion = new GalleriesCriterion();
+ galleryCriterion.modifier = GQL.CriterionModifier.Excludes;
+ galleryCriterion.value = [galleryValue];
+ filter.criteria.push(galleryCriterion);
+ }
+
+ return filter;
+ },
+ [gallery]
+ );
+
+ async function addImages(
+ result: GQL.FindImagesQueryResult,
+ filter: ListFilterModel,
+ selectedIds: Set
+ ) {
+ try {
+ await mutateAddGalleryImages({
+ gallery_id: gallery.id!,
+ image_ids: Array.from(selectedIds.values()),
+ });
+ const imageCount = selectedIds.size;
+ Toast.success(
+ intl.formatMessage(
+ { id: "toast.added_entity" },
+ {
+ count: imageCount,
+ singularEntity: intl.formatMessage({ id: "image" }),
+ pluralEntity: intl.formatMessage({ id: "images" }),
+ }
+ )
+ );
+ } catch (e) {
+ Toast.error(e);
+ }
}
+
+ const otherOperations = [
+ ...extraOperations,
+ {
+ text: intl.formatMessage(
+ { id: "actions.add_to_entity" },
+ { entityType: intl.formatMessage({ id: "gallery" }) }
+ ),
+ onClick: addImages,
+ isDisplayed: showWhenSelected,
+ postRefetch: true,
+ icon: faPlus,
+ },
+ ];
+
+ return (
+
+ );
}
-
- const otherOperations = [
- {
- text: intl.formatMessage(
- { id: "actions.add_to_entity" },
- { entityType: intl.formatMessage({ id: "gallery" }) }
- ),
- onClick: addImages,
- isDisplayed: showWhenSelected,
- postRefetch: true,
- icon: faPlus,
- },
- ];
-
- return (
-
- );
-};
+);
diff --git a/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryCreate.tsx b/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryCreate.tsx
index 128e70d38..ebb465868 100644
--- a/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryCreate.tsx
+++ b/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryCreate.tsx
@@ -19,12 +19,14 @@ const GalleryCreate: React.FC = () => {
const [createGallery] = useGalleryCreate();
- async function onSave(input: GQL.GalleryCreateInput) {
+ async function onSave(input: GQL.GalleryCreateInput, andNew?: boolean) {
const result = await createGallery({
variables: { input },
});
if (result.data?.galleryCreate) {
- history.push(`/galleries/${result.data.galleryCreate.id}`);
+ if (!andNew) {
+ history.push(`/galleries/${result.data.galleryCreate.id}`);
+ }
Toast.success(
intl.formatMessage(
{ id: "toast.created_entity" },
diff --git a/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryDetailPanel.tsx b/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryDetailPanel.tsx
index 597a57b15..ead882ec0 100644
--- a/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryDetailPanel.tsx
+++ b/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryDetailPanel.tsx
@@ -6,6 +6,7 @@ import { TagLink } from "src/components/Shared/TagLink";
import { PerformerCard } from "src/components/Performers/PerformerCard";
import { sortPerformers } from "src/core/performers";
import { PhotographerLink } from "src/components/Shared/Link";
+import { CustomFields } from "src/components/Shared/CustomFields";
interface IGalleryDetailProps {
gallery: GQL.GalleryDataFragment;
@@ -108,6 +109,7 @@ export const GalleryDetailPanel: React.FC = ({
{renderDetails()}
{renderTags()}
{renderPerformers()}
+
>
diff --git a/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryEditPanel.tsx b/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryEditPanel.tsx
index b9eea8f5d..14b5d6aad 100644
--- a/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryEditPanel.tsx
+++ b/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryEditPanel.tsx
@@ -1,7 +1,7 @@
import React, { useEffect, useMemo, useState } from "react";
import { FormattedMessage, useIntl } from "react-intl";
import { Prompt } from "react-router-dom";
-import { Button, Form, Col, Row } from "react-bootstrap";
+import { Button, Dropdown, Form, Col, Row, SplitButton } from "react-bootstrap";
import Mousetrap from "mousetrap";
import * as GQL from "src/core/generated-graphql";
import * as yup from "yup";
@@ -31,11 +31,16 @@ import { Studio, StudioSelect } from "src/components/Studios/StudioSelect";
import { Scene, SceneSelect } from "src/components/Scenes/SceneSelect";
import { useTagsEdit } from "src/hooks/tagsEdit";
import { ScraperMenu } from "src/components/Shared/ScraperMenu";
+import {
+ CustomFieldsInput,
+ formatCustomFieldInput,
+} from "src/components/Shared/CustomFields";
+import { cloneDeep } from "@apollo/client/utilities";
interface IProps {
gallery: Partial
;
isVisible: boolean;
- onSubmit: (input: GQL.GalleryCreateInput) => Promise;
+ onSubmit: (input: GQL.GalleryCreateInput, andNew?: boolean) => Promise;
onDelete: () => void;
}
@@ -76,6 +81,7 @@ export const GalleryEditPanel: React.FC = ({
tag_ids: yup.array(yup.string().required()).defined(),
scene_ids: yup.array(yup.string().required()).defined(),
details: yup.string().ensure(),
+ custom_fields: yup.object().required().defined(),
});
const initialValues = {
@@ -89,15 +95,26 @@ export const GalleryEditPanel: React.FC = ({
tag_ids: (gallery?.tags ?? []).map((t) => t.id),
scene_ids: (gallery?.scenes ?? []).map((s) => s.id),
details: gallery?.details ?? "",
+ custom_fields: cloneDeep(gallery?.custom_fields ?? {}),
};
type InputValues = yup.InferType;
+ const [customFieldsError, setCustomFieldsError] = useState();
+
+ function submit(values: InputValues) {
+ const input = {
+ ...schema.cast(values),
+ custom_fields: formatCustomFieldInput(isNew, values.custom_fields),
+ };
+ onSave(input);
+ }
+
const formik = useFormik({
initialValues,
enableReinitialize: true,
validate: yupFormikValidate(schema),
- onSubmit: (values) => onSave(schema.cast(values)),
+ onSubmit: submit,
});
const { tags, updateTagsStateFromScraper, tagsControl } = useTagsEdit(
@@ -162,10 +179,25 @@ export const GalleryEditPanel: React.FC = ({
);
}, [scrapers]);
- async function onSave(input: InputValues) {
+ const cover = useMemo(() => {
+ if (gallery?.paths?.cover) {
+ return (
+
+

+
+ );
+ }
+
+ return ;
+ }, [gallery?.paths?.cover, intl]);
+
+ async function onSave(input: InputValues, andNew?: boolean) {
setIsLoading(true);
try {
- await onSubmit(input);
+ await onSubmit(input, andNew);
formik.resetForm();
} catch (e) {
Toast.error(e);
@@ -173,6 +205,14 @@ export const GalleryEditPanel: React.FC = ({
setIsLoading(false);
}
+ async function onSaveAndNewClick() {
+ const input = {
+ ...schema.cast(formik.values),
+ custom_fields: formatCustomFieldInput(isNew, formik.values.custom_fields),
+ };
+ onSave(input, true);
+ }
+
async function onScrapeClicked(s: GQL.ScraperSourceInput) {
if (!gallery || !gallery.id) return;
@@ -335,6 +375,19 @@ export const GalleryEditPanel: React.FC = ({
xl: 12,
},
};
+ const urlProps = isNew
+ ? splitProps
+ : {
+ labelProps: {
+ column: true,
+ md: 3,
+ lg: 12,
+ },
+ fieldProps: {
+ md: 9,
+ lg: 12,
+ },
+ };
const { renderField, renderInputField, renderDateField, renderURLListField } =
formikUtils(intl, formik, splitProps);
@@ -417,16 +470,35 @@ export const GalleryEditPanel: React.FC = ({
);
diff --git a/ui/v2.5/src/components/Groups/GroupCard.tsx b/ui/v2.5/src/components/Groups/GroupCard.tsx
index f1d6089d0..5bc1b5d7f 100644
--- a/ui/v2.5/src/components/Groups/GroupCard.tsx
+++ b/ui/v2.5/src/components/Groups/GroupCard.tsx
@@ -1,6 +1,7 @@
import React, { useMemo } from "react";
import { Button, ButtonGroup } from "react-bootstrap";
import * as GQL from "src/core/generated-graphql";
+import { PatchComponent } from "src/patch";
import { GridCard } from "../Shared/GridCard/GridCard";
import { HoverPopover } from "../Shared/HoverPopover";
import { Icon } from "../Shared/Icon";
@@ -10,6 +11,7 @@ import { FormattedMessage } from "react-intl";
import { RatingBanner } from "../Shared/RatingBanner";
import { faPlayCircle, faTag } from "@fortawesome/free-solid-svg-icons";
import { RelatedGroupPopoverButton } from "./RelatedGroupPopover";
+import { OCounterButton } from "../Shared/CountButton";
const Description: React.FC<{
sceneNumber?: number;
@@ -35,7 +37,7 @@ const Description: React.FC<{
};
interface IProps {
- group: GQL.GroupDataFragment;
+ group: GQL.ListGroupDataFragment;
cardWidth?: number;
sceneNumber?: number;
selecting?: boolean;
@@ -46,130 +48,140 @@ interface IProps {
onMove?: (srcIds: string[], targetId: string, after: boolean) => void;
}
-export const GroupCard: React.FC = ({
- group,
- sceneNumber,
- cardWidth,
- selecting,
- selected,
- zoomIndex,
- onSelectedChanged,
- fromGroupId,
- onMove,
-}) => {
- const groupDescription = useMemo(() => {
- if (!fromGroupId) {
- return undefined;
- }
+export const GroupCard: React.FC = PatchComponent(
+ "GroupCard",
+ ({
+ group,
+ sceneNumber,
+ cardWidth,
+ selecting,
+ selected,
+ zoomIndex,
+ onSelectedChanged,
+ fromGroupId,
+ onMove,
+ }) => {
+ const groupDescription = useMemo(() => {
+ if (!fromGroupId) {
+ return undefined;
+ }
- const containingGroup = group.containing_groups.find(
- (cg) => cg.group.id === fromGroupId
- );
+ const containingGroup = group.containing_groups.find(
+ (cg) => cg.group.id === fromGroupId
+ );
- return containingGroup?.description ?? undefined;
- }, [fromGroupId, group.containing_groups]);
+ return containingGroup?.description ?? undefined;
+ }, [fromGroupId, group.containing_groups]);
- function maybeRenderScenesPopoverButton() {
- if (group.scenes.length === 0) return;
+ function maybeRenderScenesPopoverButton() {
+ if (group.scenes.length === 0) return;
- const popoverContent = group.scenes.map((scene) => (
-
- ));
+ const popoverContent = group.scenes.map((scene) => (
+
+ ));
- return (
-
-
-
- );
- }
-
- function maybeRenderTagPopoverButton() {
- if (group.tags.length <= 0) return;
-
- const popoverContent = group.tags.map((tag) => (
-
- ));
-
- return (
-
-
-
- );
- }
-
- function maybeRenderPopoverButtonGroup() {
- if (
- sceneNumber ||
- groupDescription ||
- group.scenes.length > 0 ||
- group.tags.length > 0 ||
- group.containing_groups.length > 0 ||
- group.sub_group_count > 0
- ) {
return (
- <>
-
-
-
- {maybeRenderScenesPopoverButton()}
- {maybeRenderTagPopoverButton()}
- {(group.sub_group_count > 0 ||
- group.containing_groups.length > 0) && (
-
- )}
-
- >
+
+
+
);
}
- }
- return (
-
-
-
- >
+ function maybeRenderTagPopoverButton() {
+ if (group.tags.length <= 0) return;
+
+ const popoverContent = group.tags.map((tag) => (
+
+ ));
+
+ return (
+
+
+
+ );
+ }
+
+ function maybeRenderOCounter() {
+ if (!group.o_counter) return;
+
+ return ;
+ }
+
+ function maybeRenderPopoverButtonGroup() {
+ if (
+ sceneNumber ||
+ groupDescription ||
+ group.scenes.length > 0 ||
+ group.tags.length > 0 ||
+ group.containing_groups.length > 0 ||
+ group.sub_group_count > 0
+ ) {
+ return (
+ <>
+
+
+
+ {maybeRenderScenesPopoverButton()}
+ {maybeRenderTagPopoverButton()}
+ {(group.sub_group_count > 0 ||
+ group.containing_groups.length > 0) && (
+
+ )}
+ {maybeRenderOCounter()}
+
+ >
+ );
}
- details={
-
- {group.date}
-
-
- }
- selected={selected}
- selecting={selecting}
- onSelectedChanged={onSelectedChanged}
- popovers={maybeRenderPopoverButtonGroup()}
- />
- );
-};
+ }
+
+ return (
+
+
+
+ >
+ }
+ details={
+
+ {group.date}
+
+
+ }
+ selected={selected}
+ selecting={selecting}
+ onSelectedChanged={onSelectedChanged}
+ popovers={maybeRenderPopoverButtonGroup()}
+ />
+ );
+ }
+);
diff --git a/ui/v2.5/src/components/Groups/GroupCardGrid.tsx b/ui/v2.5/src/components/Groups/GroupCardGrid.tsx
index b73919e64..e3b70c75f 100644
--- a/ui/v2.5/src/components/Groups/GroupCardGrid.tsx
+++ b/ui/v2.5/src/components/Groups/GroupCardGrid.tsx
@@ -5,9 +5,10 @@ import {
useCardWidth,
useContainerDimensions,
} from "../Shared/GridCard/GridCard";
+import { PatchComponent } from "src/patch";
interface IGroupCardGrid {
- groups: GQL.GroupDataFragment[];
+ groups: GQL.ListGroupDataFragment[];
selectedIds: Set;
zoomIndex: number;
onSelectChange: (id: string, selected: boolean, shiftKey: boolean) => void;
@@ -17,34 +18,30 @@ interface IGroupCardGrid {
const zoomWidths = [210, 250, 300, 375];
-export const GroupCardGrid: React.FC = ({
- groups,
- selectedIds,
- zoomIndex,
- onSelectChange,
- fromGroupId,
- onMove,
-}) => {
- const [componentRef, { width: containerWidth }] = useContainerDimensions();
- const cardWidth = useCardWidth(containerWidth, zoomIndex, zoomWidths);
+export const GroupCardGrid: React.FC = PatchComponent(
+ "GroupCardGrid",
+ ({ groups, selectedIds, zoomIndex, onSelectChange, fromGroupId, onMove }) => {
+ const [componentRef, { width: containerWidth }] = useContainerDimensions();
+ const cardWidth = useCardWidth(containerWidth, zoomIndex, zoomWidths);
- return (
-
- {groups.map((p) => (
- 0}
- selected={selectedIds.has(p.id)}
- onSelectedChanged={(selected: boolean, shiftKey: boolean) =>
- onSelectChange(p.id, selected, shiftKey)
- }
- fromGroupId={fromGroupId}
- onMove={onMove}
- />
- ))}
-
- );
-};
+ return (
+
+ {groups.map((p) => (
+ 0}
+ selected={selectedIds.has(p.id)}
+ onSelectedChanged={(selected: boolean, shiftKey: boolean) =>
+ onSelectChange(p.id, selected, shiftKey)
+ }
+ fromGroupId={fromGroupId}
+ onMove={onMove}
+ />
+ ))}
+
+ );
+ }
+);
diff --git a/ui/v2.5/src/components/Groups/GroupDetails/AddGroupsDialog.tsx b/ui/v2.5/src/components/Groups/GroupDetails/AddGroupsDialog.tsx
index b89356810..79c6075c0 100644
--- a/ui/v2.5/src/components/Groups/GroupDetails/AddGroupsDialog.tsx
+++ b/ui/v2.5/src/components/Groups/GroupDetails/AddGroupsDialog.tsx
@@ -114,6 +114,7 @@ export const AddSubGroupsDialog: React.FC = (
onUpdate={(input) => setEntries(input)}
excludeIDs={excludeIDs}
filterHook={filterHook}
+ menuPortalTarget={document.body}
/>
diff --git a/ui/v2.5/src/components/Groups/GroupDetails/Group.tsx b/ui/v2.5/src/components/Groups/GroupDetails/Group.tsx
index bd58a6682..b2b3d8176 100644
--- a/ui/v2.5/src/components/Groups/GroupDetails/Group.tsx
+++ b/ui/v2.5/src/components/Groups/GroupDetails/Group.tsx
@@ -23,7 +23,7 @@ import {
import { GroupEditPanel } from "./GroupEditPanel";
import { faRefresh, faTrashAlt } from "@fortawesome/free-solid-svg-icons";
import { RatingSystem } from "src/components/Shared/Rating/RatingSystem";
-import { ConfigurationContext } from "src/hooks/Config";
+import { useConfigurationContext } from "src/hooks/Config";
import { DetailImage } from "src/components/Shared/DetailImage";
import { useRatingKeybinds } from "src/hooks/keybinds";
import { useLoadStickyHeader } from "src/hooks/detailsPanel";
@@ -43,6 +43,7 @@ import { Button, Tab, Tabs } from "react-bootstrap";
import { GroupSubGroupsPanel } from "./GroupSubGroupsPanel";
import { GroupPerformersPanel } from "./GroupPerformersPanel";
import { Icon } from "src/components/Shared/Icon";
+import { goBackOrReplace } from "src/utils/history";
const validTabs = ["default", "scenes", "performers", "subgroups"] as const;
type TabKey = (typeof validTabs)[number];
@@ -145,7 +146,7 @@ const GroupPage: React.FC = ({ group, tabKey }) => {
const Toast = useToast();
// Configuration settings
- const { configuration } = React.useContext(ConfigurationContext);
+ const { configuration } = useConfigurationContext();
const uiConfig = configuration?.ui;
const enableBackgroundImage = uiConfig?.enableMovieBackgroundImage ?? false;
const compactExpandedDetails = uiConfig?.compactExpandedDetails ?? false;
@@ -276,7 +277,7 @@ const GroupPage: React.FC = ({ group, tabKey }) => {
return;
}
- history.goBack();
+ goBackOrReplace(history, "/groups");
}
function toggleEditing(value?: boolean) {
diff --git a/ui/v2.5/src/components/Groups/GroupDetails/GroupCreate.tsx b/ui/v2.5/src/components/Groups/GroupDetails/GroupCreate.tsx
index 9dd3e22b9..5026d5b6e 100644
--- a/ui/v2.5/src/components/Groups/GroupDetails/GroupCreate.tsx
+++ b/ui/v2.5/src/components/Groups/GroupDetails/GroupCreate.tsx
@@ -25,12 +25,14 @@ const GroupCreate: React.FC = () => {
const [createGroup] = useGroupCreate();
- async function onSave(input: GQL.GroupCreateInput) {
+ async function onSave(input: GQL.GroupCreateInput, andNew?: boolean) {
const result = await createGroup({
variables: { input },
});
if (result.data?.groupCreate?.id) {
- history.push(`/groups/${result.data.groupCreate.id}`);
+ if (!andNew) {
+ history.push(`/groups/${result.data.groupCreate.id}`);
+ }
Toast.success(
intl.formatMessage(
{ id: "toast.created_entity" },
diff --git a/ui/v2.5/src/components/Groups/GroupDetails/GroupDetailsPanel.tsx b/ui/v2.5/src/components/Groups/GroupDetails/GroupDetailsPanel.tsx
index d93b06466..8ae4b16a9 100644
--- a/ui/v2.5/src/components/Groups/GroupDetails/GroupDetailsPanel.tsx
+++ b/ui/v2.5/src/components/Groups/GroupDetails/GroupDetailsPanel.tsx
@@ -6,6 +6,7 @@ import { DetailItem } from "src/components/Shared/DetailItem";
import { Link } from "react-router-dom";
import { DirectorLink } from "src/components/Shared/Link";
import { GroupLink, TagLink } from "src/components/Shared/TagLink";
+import { CustomFields } from "src/components/Shared/CustomFields";
interface IGroupDescription {
group: GQL.SlimGroupDataFragment;
@@ -65,7 +66,7 @@ export const GroupDetailsPanel: React.FC = ({
/>
= ({
fullWidth={fullWidth}
/>
)}
+
);
};
diff --git a/ui/v2.5/src/components/Groups/GroupDetails/GroupEditPanel.tsx b/ui/v2.5/src/components/Groups/GroupDetails/GroupEditPanel.tsx
index 0b94baf27..6401738fa 100644
--- a/ui/v2.5/src/components/Groups/GroupDetails/GroupEditPanel.tsx
+++ b/ui/v2.5/src/components/Groups/GroupDetails/GroupEditPanel.tsx
@@ -28,10 +28,15 @@ import { Studio, StudioSelect } from "src/components/Studios/StudioSelect";
import { useTagsEdit } from "src/hooks/tagsEdit";
import { Group } from "src/components/Groups/GroupSelect";
import { RelatedGroupTable, IRelatedGroupEntry } from "./RelatedGroupTable";
+import {
+ CustomFieldsInput,
+ formatCustomFieldInput,
+} from "src/components/Shared/CustomFields";
+import { cloneDeep } from "@apollo/client/utilities";
interface IGroupEditPanel {
group: Partial