mirror of
https://github.com/nowcommunity/nowdatabase.git
synced 2026-10-12 19:13:52 +03:00
Merge pull request #1153 from nowcommunity/codex/reference-validation-display-labels
[codex] Show reference validation display labels
This commit is contained in:
@@ -10,7 +10,7 @@ import {
|
||||
useDeleteReferenceMutation,
|
||||
useGetReferenceTypesQuery,
|
||||
} from '@/redux/referenceReducer'
|
||||
import { EditDataType, ReferenceDetailsType, ValidationErrors } from '@/shared/types'
|
||||
import { EditDataType, ReferenceDetailsType } from '@/shared/types'
|
||||
import { emptyReference } from '../DetailView/common/defaultValues'
|
||||
import {
|
||||
createReferenceValidatorWithLabels,
|
||||
@@ -23,6 +23,7 @@ import { createReferenceTitle } from './referenceFormatting'
|
||||
import { useReturnNavigation } from '@/hooks/useReturnNavigation'
|
||||
import type { FetchBaseQueryError } from '@reduxjs/toolkit/query'
|
||||
import type { SerializedError } from '@reduxjs/toolkit'
|
||||
import { formatReferenceValidationErrorMessage } from './referenceValidationErrors'
|
||||
|
||||
const REFERENCE_DELETE_CONFLICT_MESSAGE = 'The Reference with associated updates cannot be deleted.'
|
||||
const GENERIC_DELETE_MESSAGE = 'Could not delete item. Error happened.'
|
||||
@@ -101,8 +102,8 @@ export const ReferenceDetails = ({
|
||||
notify('Saved reference successfully.')
|
||||
setTimeout(() => navigate(`/reference/${rid}`), 15)
|
||||
} catch (e) {
|
||||
const error = e as ValidationErrors
|
||||
notify('Following validators failed: ' + error.data.map(e => e.name).join(', '), 'error')
|
||||
const message = formatReferenceValidationErrorMessage(e, editData.ref_type_id, referenceFieldDisplayLabelMap)
|
||||
notify(message, 'error')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import type { EditDataType, ReferenceDetailsType, ValidationErrors } from '@/shared/types'
|
||||
import type { ReferenceDisplayLabelMap } from '@/shared/validators/reference'
|
||||
|
||||
const GENERIC_REFERENCE_SAVE_ERROR = 'Could not edit item. Error happened.'
|
||||
const GROUPED_REQUIRED_PREFIX = 'At least one of the following fields is required:'
|
||||
|
||||
const isValidationErrors = (error: unknown): error is ValidationErrors => {
|
||||
if (typeof error !== 'object' || error === null || !('data' in error)) {
|
||||
return false
|
||||
}
|
||||
|
||||
const possibleError = error as { data?: unknown }
|
||||
return Array.isArray(possibleError.data)
|
||||
}
|
||||
|
||||
const getReferenceFieldDisplayLabel = (
|
||||
fieldName: string,
|
||||
refTypeId: number | null | undefined,
|
||||
displayLabelMap?: ReferenceDisplayLabelMap
|
||||
) => {
|
||||
if (!refTypeId) return fieldName
|
||||
|
||||
const fieldLabels = displayLabelMap?.[refTypeId]
|
||||
return fieldLabels?.[fieldName as keyof EditDataType<ReferenceDetailsType>] ?? fieldName
|
||||
}
|
||||
|
||||
export const formatReferenceValidationErrorMessage = (
|
||||
error: unknown,
|
||||
refTypeId: number | null | undefined,
|
||||
displayLabelMap?: ReferenceDisplayLabelMap
|
||||
) => {
|
||||
if (!isValidationErrors(error) || error.data.length === 0) {
|
||||
return GENERIC_REFERENCE_SAVE_ERROR
|
||||
}
|
||||
|
||||
const messages = error.data.map(validationError => {
|
||||
const errorText = validationError.error.trim()
|
||||
|
||||
if (errorText.startsWith(GROUPED_REQUIRED_PREFIX)) {
|
||||
return errorText
|
||||
}
|
||||
|
||||
const fieldLabel = getReferenceFieldDisplayLabel(validationError.name, refTypeId, displayLabelMap)
|
||||
return errorText.length > 0 ? `${fieldLabel}: ${errorText}` : fieldLabel
|
||||
})
|
||||
|
||||
return `Following validators failed: ${[...new Set(messages)].join(', ')}`
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { describe, expect, it } from '@jest/globals'
|
||||
|
||||
import { formatReferenceValidationErrorMessage } from '@/components/Reference/referenceValidationErrors'
|
||||
|
||||
describe('formatReferenceValidationErrorMessage', () => {
|
||||
it('uses reference display labels for backend validation field names', () => {
|
||||
const message = formatReferenceValidationErrorMessage(
|
||||
{
|
||||
status: '403',
|
||||
data: [
|
||||
{ name: 'title_primary', error: 'This field is required' },
|
||||
{ name: 'gen_notes', error: 'This field is required' },
|
||||
],
|
||||
},
|
||||
4,
|
||||
{
|
||||
4: {
|
||||
title_primary: 'Title',
|
||||
gen_notes: 'Notes',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
expect(message).toBe('Following validators failed: Title: This field is required, Notes: This field is required')
|
||||
})
|
||||
|
||||
it('deduplicates grouped title errors that already contain display labels', () => {
|
||||
const groupedError = 'At least one of the following fields is required: Title, Notes'
|
||||
const message = formatReferenceValidationErrorMessage(
|
||||
{
|
||||
status: '403',
|
||||
data: [
|
||||
{ name: 'title_primary', error: groupedError },
|
||||
{ name: 'gen_notes', error: groupedError },
|
||||
],
|
||||
},
|
||||
4
|
||||
)
|
||||
|
||||
expect(message).toBe(`Following validators failed: ${groupedError}`)
|
||||
})
|
||||
|
||||
it('falls back to a generic save error for unexpected responses', () => {
|
||||
expect(formatReferenceValidationErrorMessage({ status: 500 }, 4)).toBe('Could not edit item. Error happened.')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user