From 47f550b18dd7d336bd52aafe312aeacd2843e66a Mon Sep 17 00:00:00 2001 From: tdgao Date: Thu, 3 Sep 2026 16:20:00 -0600 Subject: [PATCH] feat: hide validation error when field has been edited --- .../src/components/ValidationMessage.vue | 68 +++++++++++++---- apps/frontend/src/pages/[type]/[project].vue | 74 ++++++++++--------- .../src/pages/[type]/[project]/gallery.vue | 12 ++- .../[type]/[project]/settings/description.vue | 7 +- .../[type]/[project]/settings/disclosures.vue | 2 + .../[type]/[project]/settings/gallery.vue | 14 +++- .../[type]/[project]/settings/general.vue | 21 +++++- .../pages/[type]/[project]/settings/index.vue | 21 +++++- .../[type]/[project]/settings/license.vue | 19 ++++- .../pages/[type]/[project]/settings/links.vue | 62 +++++++++++++--- .../[type]/[project]/settings/server.vue | 23 +++++- .../pages/[type]/[project]/settings/tags.vue | 6 +- 12 files changed, 250 insertions(+), 79 deletions(-) diff --git a/apps/frontend/src/components/ValidationMessage.vue b/apps/frontend/src/components/ValidationMessage.vue index 9df4b72a14..ccfabf1fe3 100644 --- a/apps/frontend/src/components/ValidationMessage.vue +++ b/apps/frontend/src/components/ValidationMessage.vue @@ -28,8 +28,8 @@ diff --git a/apps/frontend/src/pages/[type]/[project].vue b/apps/frontend/src/pages/[type]/[project].vue index 0f895da046..71f4d8b9ef 100644 --- a/apps/frontend/src/pages/[type]/[project].vue +++ b/apps/frontend/src/pages/[type]/[project].vue @@ -842,6 +842,14 @@ const messages = defineMessages({ id: 'project.notification.updated.message', defaultMessage: 'Your project has been updated.', }, + projectReviewSaveFailed: { + id: 'project.notification.review-save-failed.title', + defaultMessage: 'Failed to save project in review', + }, + projectReviewSaveFailedDescription: { + id: 'project.notification.review-save-failed.description', + defaultMessage: 'You cannot save edits to your project which result in failing validation.', + }, reviewEnvironmentSettings: { id: 'project.environment.migration.review-button', defaultMessage: 'Review environment settings', @@ -1377,6 +1385,30 @@ function mergeV3ProjectPatch(old, data) { return merged } +const PROJECT_REVIEW_VALIDATION_ERROR = + 'project must have no required validation nags before or while under review' + +function addProjectMutationErrorNotification(error) { + const description = + error?.v1Error?.description ?? + error?.responseData?.description ?? + error?.data?.description ?? + error?.message + const isProjectReviewValidationError = description === PROJECT_REVIEW_VALIDATION_ERROR + + addNotification({ + title: formatMessage( + isProjectReviewValidationError + ? messages.projectReviewSaveFailed + : commonMessages.errorNotificationTitle, + ), + text: isProjectReviewValidationError + ? formatMessage(messages.projectReviewSaveFailedDescription) + : description, + type: 'error', + }) +} + // Mutation for patching project data const patchProjectMutation = useMutation({ mutationFn: async ({ projectId, data }) => { @@ -1412,11 +1444,7 @@ const patchProjectMutation = useMutation({ if (context?.previousV3) { queryClient.setQueryData(['project', 'v3', context.projectId], context.previousV3) } - addNotification({ - title: formatMessage(commonMessages.errorNotificationTitle), - text: err.data ? err.data.description : err.message, - type: 'error', - }) + addProjectMutationErrorNotification(err) }, onSettled: async () => { @@ -1447,11 +1475,7 @@ const patchStatusMutation = useMutation({ if (context?.previousProject) { queryClient.setQueryData(['project', 'v2', context.projectId], context.previousProject) } - addNotification({ - title: formatMessage(commonMessages.errorNotificationTitle), - text: err.data ? err.data.description : err.message, - type: 'error', - }) + addProjectMutationErrorNotification(err) }, onSettled: async () => { @@ -1491,11 +1515,7 @@ const patchProjectV3Mutation = useMutation({ if (context?.previousV2) { queryClient.setQueryData(['project', 'v2', context.projectId], context.previousV2) } - addNotification({ - title: formatMessage(commonMessages.errorNotificationTitle), - text: err.data ? err.data.description : err.message, - type: 'error', - }) + addProjectMutationErrorNotification(err) }, onSettled: () => { @@ -1519,11 +1539,7 @@ const patchIconMutation = useMutation({ }, onError: (err) => { - addNotification({ - title: formatMessage(commonMessages.errorNotificationTitle), - text: err.data ? err.data.description : err.message, - type: 'error', - }) + addProjectMutationErrorNotification(err) }, onSettled: async () => { @@ -1572,11 +1588,7 @@ const createGalleryItemMutation = useMutation({ if (context?.previousProject) { queryClient.setQueryData(['project', 'v2', context.projectId], context.previousProject) } - addNotification({ - title: formatMessage(commonMessages.errorNotificationTitle), - text: err.data ? err.data.description : err.message, - type: 'error', - }) + addProjectMutationErrorNotification(err) }, onSettled: async () => { @@ -1625,11 +1637,7 @@ const editGalleryItemMutation = useMutation({ if (context?.previousProject) { queryClient.setQueryData(['project', 'v2', context.projectId], context.previousProject) } - addNotification({ - title: formatMessage(commonMessages.errorNotificationTitle), - text: err.data ? err.data.description : err.message, - type: 'error', - }) + addProjectMutationErrorNotification(err) }, onSettled: async () => { @@ -1662,11 +1670,7 @@ const deleteGalleryItemMutation = useMutation({ if (context?.previousProject) { queryClient.setQueryData(['project', 'v2', context.projectId], context.previousProject) } - addNotification({ - title: formatMessage(commonMessages.errorNotificationTitle), - text: err.data ? err.data.description : err.message, - type: 'error', - }) + addProjectMutationErrorNotification(err) }, onSettled: async () => { diff --git a/apps/frontend/src/pages/[type]/[project]/gallery.vue b/apps/frontend/src/pages/[type]/[project]/gallery.vue index 50a5f75983..adb0181e3b 100644 --- a/apps/frontend/src/pages/[type]/[project]/gallery.vue +++ b/apps/frontend/src/pages/[type]/[project]/gallery.vue @@ -44,7 +44,11 @@ :maxlength="64" placeholder="Enter title..." /> - + @@ -54,7 +58,11 @@ :maxlength="255" placeholder="Enter description..." /> - + diff --git a/apps/frontend/src/pages/[type]/[project]/settings/description.vue b/apps/frontend/src/pages/[type]/[project]/settings/description.vue index 59790ace31..147d7c6ded 100644 --- a/apps/frontend/src/pages/[type]/[project]/settings/description.vue +++ b/apps/frontend/src/pages/[type]/[project]/settings/description.vue @@ -20,7 +20,12 @@ :disabled="!hasPermission" :on-image-upload="onUploadHandler" /> - + - + @@ -55,7 +60,12 @@ :maxlength="255" placeholder="Enter description..." /> - + diff --git a/apps/frontend/src/pages/[type]/[project]/settings/general.vue b/apps/frontend/src/pages/[type]/[project]/settings/general.vue index bfa3122c05..8218fe02e7 100644 --- a/apps/frontend/src/pages/[type]/[project]/settings/general.vue +++ b/apps/frontend/src/pages/[type]/[project]/settings/general.vue @@ -179,7 +179,12 @@ const placeholder = computed(() => placeholders[placeholderIndex.value] ?? place
- +
placeholders[placeholderIndex.value] ?? place wrapper-class="flex-grow" />
- +
placeholders[placeholderIndex.value] ?? place :maxlength="120" wrapper-class="w-full" /> - +
diff --git a/apps/frontend/src/pages/[type]/[project]/settings/index.vue b/apps/frontend/src/pages/[type]/[project]/settings/index.vue index 9aed869850..f8cbe637fa 100644 --- a/apps/frontend/src/pages/[type]/[project]/settings/index.vue +++ b/apps/frontend/src/pages/[type]/[project]/settings/index.vue @@ -29,7 +29,12 @@ wrapper-class="w-full max-w-72" :disabled="!hasPermission" /> - +
@@ -69,7 +74,12 @@ :disabled="!hasPermission" resize="vertical" /> - +
@@ -109,7 +119,12 @@
- + diff --git a/apps/frontend/src/pages/[type]/[project]/settings/license.vue b/apps/frontend/src/pages/[type]/[project]/settings/license.vue index d95a1cb05e..ff4c60b4df 100644 --- a/apps/frontend/src/pages/[type]/[project]/settings/license.vue +++ b/apps/frontend/src/pages/[type]/[project]/settings/license.vue @@ -36,7 +36,12 @@ :disabled="!hasPermission" trigger-type="base" /> - + @@ -85,8 +90,16 @@ :disabled="!hasPermission || licenseId === 'LicenseRef-Unknown'" wrapper-class="w-full" /> - - + + diff --git a/apps/frontend/src/pages/[type]/[project]/settings/links.vue b/apps/frontend/src/pages/[type]/[project]/settings/links.vue index d95d234c50..3c7256c6d7 100644 --- a/apps/frontend/src/pages/[type]/[project]/settings/links.vue +++ b/apps/frontend/src/pages/[type]/[project]/settings/links.vue @@ -4,7 +4,12 @@

External links

- +

External links

- +
Donation links diff --git a/apps/frontend/src/pages/[type]/[project]/settings/server.vue b/apps/frontend/src/pages/[type]/[project]/settings/server.vue index 770a30d7a9..b2b4e39eb2 100644 --- a/apps/frontend/src/pages/[type]/[project]/settings/server.vue +++ b/apps/frontend/src/pages/[type]/[project]/settings/server.vue @@ -20,7 +20,12 @@ :placeholder="formatMessage(messages.selectRegionPlaceholder)" :disabled="!hasPermission" /> - + @@ -43,7 +48,14 @@ :placeholder="formatMessage(messages.selectLanguagesPlaceholder)" :disabled="!hasPermission" /> - + @@ -129,7 +141,12 @@ /> - + diff --git a/apps/frontend/src/pages/[type]/[project]/settings/tags.vue b/apps/frontend/src/pages/[type]/[project]/settings/tags.vue index d85efa8937..a9c863405e 100644 --- a/apps/frontend/src/pages/[type]/[project]/settings/tags.vue +++ b/apps/frontend/src/pages/[type]/[project]/settings/tags.vue @@ -409,7 +409,11 @@ const toggleFeatured = (tag: string) => { - +