From 959f2531fd175c61e3a25c9d7b9094d63409454b Mon Sep 17 00:00:00 2001 From: DingDongSoLong4 <99329275+DingDongSoLong4@users.noreply.github.com> Date: Mon, 20 Nov 2023 03:42:26 +0200 Subject: [PATCH] Form-related fixes, improvements and refactoring (#4283) * Fix another validateDOMNesting error * Fix React.forwardRef error * Fix encoding_image intl message * Return null instead of undefined from RatingSystem * DurationInput tweaks * DateInput tweaks, remove unused utils functions * Refactor and deduplicate edit form rendering * Improve/fix yup validation --- ui/v2.5/package.json | 4 +- .../Galleries/EditGalleriesDialog.tsx | 4 +- .../GalleryDetails/GalleryChapterForm.tsx | 61 +- .../GalleryDetails/GalleryEditPanel.tsx | 315 +++++----- .../components/Galleries/GalleryWallCard.tsx | 2 +- ui/v2.5/src/components/Galleries/styles.scss | 4 - .../components/Images/EditImagesDialog.tsx | 4 +- .../Images/ImageDetails/ImageEditPanel.tsx | 236 +++----- .../List/Filters/DurationFilter.tsx | 4 +- .../components/Movies/EditMoviesDialog.tsx | 4 +- .../components/Movies/MovieDetails/Movie.tsx | 6 +- .../Movies/MovieDetails/MovieCreate.tsx | 2 +- .../Movies/MovieDetails/MovieDetailsPanel.tsx | 3 +- .../Movies/MovieDetails/MovieEditPanel.tsx | 188 ++---- .../Movies/MovieDetails/MovieScrapeDialog.tsx | 6 +- .../Performers/EditPerformersDialog.tsx | 8 +- .../Performers/PerformerDetails/Performer.tsx | 6 +- .../PerformerDetails/PerformerCreate.tsx | 2 +- .../PerformerDetails/PerformerEditPanel.tsx | 549 +++++------------- .../components/Performers/PerformerSelect.tsx | 6 +- .../components/Scenes/EditScenesDialog.tsx | 4 +- .../Scenes/SceneDetails/SceneEditPanel.tsx | 433 ++++++-------- .../Scenes/SceneDetails/SceneMarkerForm.tsx | 185 +++--- .../components/Scenes/SceneMergeDialog.tsx | 2 +- ui/v2.5/src/components/Scenes/styles.scss | 4 - .../SettingsInterfacePanel.tsx | 4 +- ui/v2.5/src/components/Shared/DateInput.tsx | 37 +- .../src/components/Shared/DurationInput.tsx | 40 +- .../components/Shared/Rating/RatingNumber.tsx | 8 +- .../components/Shared/Rating/RatingStars.tsx | 6 +- .../components/Shared/Rating/RatingSystem.tsx | 14 +- .../components/Shared/ReassignFilesDialog.tsx | 2 +- ui/v2.5/src/components/Shared/Select.tsx | 14 +- ui/v2.5/src/components/Shared/StashID.tsx | 2 +- ui/v2.5/src/components/Shared/TagLink.tsx | 20 +- .../Studios/StudioDetails/Studio.tsx | 6 +- .../Studios/StudioDetails/StudioCreate.tsx | 2 +- .../Studios/StudioDetails/StudioEditPanel.tsx | 216 ++----- .../Tagger/scenes/StashSearchResult.tsx | 2 +- .../src/components/Tags/TagDetails/Tag.tsx | 2 +- .../components/Tags/TagDetails/TagCreate.tsx | 2 +- .../Tags/TagDetails/TagEditPanel.tsx | 205 ++----- .../Tags/TagDetails/TagMergeDialog.tsx | 2 +- ui/v2.5/src/core/movies.ts | 6 +- ui/v2.5/src/hooks/Lightbox/Lightbox.tsx | 6 +- ui/v2.5/src/locales/en-GB.json | 5 +- .../models/list-filter/criteria/criterion.ts | 6 +- ui/v2.5/src/utils/duration.ts | 53 -- ui/v2.5/src/utils/editabletext.tsx | 183 ------ ui/v2.5/src/utils/form.tsx | 467 ++++++++++----- ui/v2.5/src/utils/rating.ts | 2 +- ui/v2.5/src/utils/table.tsx | 105 ---- ui/v2.5/src/utils/text.ts | 74 ++- ui/v2.5/src/utils/yup.ts | 82 ++- ui/v2.5/yarn.lock | 21 +- 55 files changed, 1419 insertions(+), 2217 deletions(-) delete mode 100644 ui/v2.5/src/utils/duration.ts delete mode 100644 ui/v2.5/src/utils/editabletext.tsx delete mode 100644 ui/v2.5/src/utils/table.tsx diff --git a/ui/v2.5/package.json b/ui/v2.5/package.json index c6473174a..7542413c5 100644 --- a/ui/v2.5/package.json +++ b/ui/v2.5/package.json @@ -37,7 +37,7 @@ "classnames": "^2.3.2", "flag-icons": "^6.6.6", "flexbin": "^0.2.0", - "formik": "^2.2.9", + "formik": "^2.4.5", "graphql": "^16.8.1", "graphql-tag": "^2.12.6", "graphql-ws": "^5.11.3", @@ -74,7 +74,7 @@ "videojs-seek-buttons": "^3.0.1", "videojs-vr": "^2.0.0", "videojs-vtt.js": "^0.15.4", - "yup": "^1.0.0" + "yup": "^1.3.2" }, "devDependencies": { "@babel/core": "^7.20.12", diff --git a/ui/v2.5/src/components/Galleries/EditGalleriesDialog.tsx b/ui/v2.5/src/components/Galleries/EditGalleriesDialog.tsx index 68fb1f310..d779a3def 100644 --- a/ui/v2.5/src/components/Galleries/EditGalleriesDialog.tsx +++ b/ui/v2.5/src/components/Galleries/EditGalleriesDialog.tsx @@ -7,7 +7,7 @@ import * as GQL from "src/core/generated-graphql"; import { StudioSelect } from "../Shared/Select"; import { ModalComponent } from "../Shared/Modal"; import { useToast } from "src/hooks/Toast"; -import FormUtils from "src/utils/form"; +import * as FormUtils from "src/utils/form"; import { MultiSet } from "../Shared/MultiSet"; import { RatingSystem } from "../Shared/Rating/RatingSystem"; import { @@ -257,7 +257,7 @@ export const EditGalleriesDialog: React.FC = ( setRating(value)} + onSetRating={(value) => setRating(value ?? undefined)} disabled={isUpdating} /> diff --git a/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryChapterForm.tsx b/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryChapterForm.tsx index ef8bfda0a..368fb5214 100644 --- a/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryChapterForm.tsx +++ b/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryChapterForm.tsx @@ -11,6 +11,8 @@ import { } from "src/core/StashService"; import { useToast } from "src/hooks/Toast"; import isEqual from "lodash-es/isEqual"; +import { formikUtils } from "src/utils/form"; +import { yupFormikValidate, yupInputNumber } from "src/utils/yup"; interface IGalleryChapterForm { galleryID: string; @@ -34,11 +36,10 @@ export const GalleryChapterForm: React.FC = ({ const schema = yup.object({ title: yup.string().ensure(), - image_index: yup - .number() + image_index: yupInputNumber() .integer() - .required() .moreThan(0) + .required() .label(intl.formatMessage({ id: "image_index" })), }); @@ -51,9 +52,9 @@ export const GalleryChapterForm: React.FC = ({ const formik = useFormik({ initialValues, - validationSchema: schema, enableReinitialize: true, - onSubmit: (values) => onSave(values), + validate: yupFormikValidate(schema), + onSubmit: (values) => onSave(schema.cast(values)), }); async function onSave(input: InputValues) { @@ -93,43 +94,25 @@ export const GalleryChapterForm: React.FC = ({ } } + const splitProps = { + labelProps: { + column: true, + sm: 3, + }, + fieldProps: { + sm: 9, + }, + }; + const { renderInputField } = formikUtils(intl, formik, splitProps); + return (
-
- - - - - - - - {formik.errors.title} - - - - - - - - - - - {formik.errors.image_index} - - +
+ {renderInputField("title")} + {renderInputField("image_index", "number")}
-
-
+
+
- - {renderScraperMenu()} +
{renderScraperMenu()}
+ + + + {renderInputField("title")} + + {renderURLListField( + "urls", + "validation.urls_must_be_unique", + onScrapeGalleryURL, + urlScrapable + )} + + {renderDateField("date")} + {renderRatingField("rating100", "rating")} + + {renderScenesField()} + {renderStudioField()} + {renderPerformersField()} + {renderTagsField()} -
-
-
- {renderTextField("title", intl.formatMessage({ id: "title" }))} - - - - - - - - formik.setFieldValue("urls", value)} - errors={urlsErrorMsg} - errorIdx={urlsErrorIdx} - onScrapeClick={(url) => onScrapeGalleryURL(url)} - urlScrapable={urlScrapable} - /> - - - - {FormUtils.renderLabel({ - title: intl.formatMessage({ id: "date" }), - })} - - formik.setFieldValue("date", value)} - error={formik.errors.date} - /> - - - - {FormUtils.renderLabel({ - title: intl.formatMessage({ id: "rating" }), - })} - - - formik.setFieldValue("rating100", value ?? null) - } - /> - - - - {FormUtils.renderLabel({ - title: intl.formatMessage({ id: "studio" }), - })} - - - formik.setFieldValue( - "studio_id", - items.length > 0 ? items[0]?.id : null - ) - } - ids={formik.values.studio_id ? [formik.values.studio_id] : []} - /> - - - - - {FormUtils.renderLabel({ - title: intl.formatMessage({ id: "performers" }), - labelProps: { - column: true, - sm: 3, - xl: 12, - }, - })} - - - - - - - {FormUtils.renderLabel({ - title: intl.formatMessage({ id: "tags" }), - labelProps: { - column: true, - sm: 3, - xl: 12, - }, - })} - - - formik.setFieldValue( - "tag_ids", - items.map((item) => item.id) - ) - } - ids={formik.values.tag_ids} - hoverPlacement="right" - /> - - - - - {FormUtils.renderLabel({ - title: intl.formatMessage({ id: "scenes" }), - labelProps: { - column: true, - sm: 3, - xl: 12, - }, - })} - - onSetScenes(items)} - isMulti - /> - - -
-
- - - - - - formik.setFieldValue("details", e.currentTarget.value) - } - value={formik.values.details} - /> - -
-
+ + {renderDetailsField()} + +
); diff --git a/ui/v2.5/src/components/Galleries/GalleryWallCard.tsx b/ui/v2.5/src/components/Galleries/GalleryWallCard.tsx index f79fe02a1..acb26a066 100644 --- a/ui/v2.5/src/components/Galleries/GalleryWallCard.tsx +++ b/ui/v2.5/src/components/Galleries/GalleryWallCard.tsx @@ -50,7 +50,7 @@ const GalleryWallCard: React.FC = ({ gallery }) => { role="button" tabIndex={0} > - +