Define server error messages to display in FE from the server (#12973)
Currently, when a server query or mutation from the front-end fails, the error message defined server-side is displayed in a snackbar in the front-end. These error messages usually contain technical details that don't belong to the user interface, such as "ObjectMetadataCollection not found" or "invalid ENUM value for ...". **BE** In addition to the original error message that is still needed (for the request response, debugging, sentry monitoring etc.), we add a `displayedErrorMessage` that will be used in the snackbars. It's only relevant to add it for the messages that will reach the FE (ie. not in jobs or in rest api for instance) and if it can help the user sort out / fix things (ie. we do add displayedErrorMessage for "Cannot create multiple draft versions for the same workflow" or "Cannot delete [field], please update the label identifier field first", but not "Object metadata does not exist"), even if in practice in the FE users should not be able to perform an action that will not work (ie should not be able to save creation of multiple draft versions of the same workflows). **FE** To ease the usage we replaced enqueueSnackBar with enqueueErrorSnackBar and enqueueSuccessSnackBar with an api that only requires to pass on the error. If no displayedErrorMessage is specified then the default error message is `An error occured.`
This commit is contained in:
@ -10,7 +10,7 @@ exports[`validateMetadataNameOrThrow throws error when string has spaces 1`] = `
|
||||
|
||||
exports[`validateMetadataNameOrThrow throws error when string is a reserved word 1`] = `"The name "role" is not available"`;
|
||||
|
||||
exports[`validateMetadataNameOrThrow throws error when string is above 63 characters 1`] = `"String "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" exceeds 63 characters limit"`;
|
||||
exports[`validateMetadataNameOrThrow throws error when string is above 63 characters 1`] = `"Name is too long: it exceeds the 63 characters limit."`;
|
||||
|
||||
exports[`validateMetadataNameOrThrow throws error when string is empty 1`] = `"Input is too short: """`;
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import camelCase from 'lodash.camelcase';
|
||||
import { slugify } from 'transliteration';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@ -12,6 +13,9 @@ export const computeMetadataNameFromLabel = (label: string): string => {
|
||||
throw new InvalidMetadataException(
|
||||
'Label is required',
|
||||
InvalidMetadataExceptionCode.LABEL_REQUIRED,
|
||||
{
|
||||
userFriendlyMessage: t`Label is required`,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@ -31,6 +35,9 @@ export const computeMetadataNameFromLabel = (label: string): string => {
|
||||
throw new InvalidMetadataException(
|
||||
`Invalid label: "${label}"`,
|
||||
InvalidMetadataExceptionCode.INVALID_LABEL,
|
||||
{
|
||||
userFriendlyMessage: t`Invalid label: "${label}"`,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -1,8 +1,12 @@
|
||||
import { CustomException } from 'src/utils/custom-exception';
|
||||
|
||||
export class InvalidMetadataException extends CustomException {
|
||||
constructor(message: string, code: InvalidMetadataExceptionCode) {
|
||||
super(message, code);
|
||||
constructor(
|
||||
message: string,
|
||||
code: InvalidMetadataExceptionCode,
|
||||
{ userFriendlyMessage }: { userFriendlyMessage?: string } = {},
|
||||
) {
|
||||
super(message, code, userFriendlyMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
|
||||
import { compositeTypeDefinitions } from 'src/engine/metadata-modules/field-metadata/composite-types';
|
||||
import { computeCompositeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
|
||||
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
|
||||
@ -43,6 +45,9 @@ export const validateFieldNameAvailabilityOrThrow = (
|
||||
throw new InvalidMetadataException(
|
||||
`Name "${name}" is not available`,
|
||||
InvalidMetadataExceptionCode.NOT_AVAILABLE,
|
||||
{
|
||||
userFriendlyMessage: t`This name is not available.`,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import camelCase from 'lodash.camelcase';
|
||||
|
||||
import {
|
||||
@ -8,7 +9,7 @@ import {
|
||||
export const validateMetadataNameIsCamelCaseOrThrow = (name: string) => {
|
||||
if (name !== camelCase(name)) {
|
||||
throw new InvalidMetadataException(
|
||||
`${name} should be in camelCase`,
|
||||
t`${name} should be in camelCase`,
|
||||
InvalidMetadataExceptionCode.NOT_CAMEL_CASE,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
|
||||
import {
|
||||
InvalidMetadataException,
|
||||
InvalidMetadataExceptionCode,
|
||||
@ -71,6 +73,9 @@ export const validateMetadataNameIsNotReservedKeywordOrThrow = (
|
||||
throw new InvalidMetadataException(
|
||||
`The name "${name}" is not available`,
|
||||
InvalidMetadataExceptionCode.RESERVED_KEYWORD,
|
||||
{
|
||||
userFriendlyMessage: t`This name is not available.`,
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
|
||||
import {
|
||||
InvalidMetadataException,
|
||||
InvalidMetadataExceptionCode,
|
||||
@ -7,7 +9,7 @@ import { exceedsDatabaseIdentifierMaximumLength } from 'src/engine/metadata-modu
|
||||
export const validateMetadataNameIsNotTooLongOrThrow = (name: string) => {
|
||||
if (exceedsDatabaseIdentifierMaximumLength(name)) {
|
||||
throw new InvalidMetadataException(
|
||||
`String "${name}" exceeds 63 characters limit`,
|
||||
t`Name is too long: it exceeds the 63 characters limit.`,
|
||||
InvalidMetadataExceptionCode.EXCEEDS_MAX_LENGTH,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
|
||||
import {
|
||||
InvalidMetadataException,
|
||||
InvalidMetadataExceptionCode,
|
||||
@ -7,7 +9,7 @@ import { beneathDatabaseIdentifierMinimumLength } from 'src/engine/metadata-modu
|
||||
export const validateMetadataNameIsNotTooShortOrThrow = (name: string) => {
|
||||
if (beneathDatabaseIdentifierMinimumLength(name)) {
|
||||
throw new InvalidMetadataException(
|
||||
`Input is too short: "${name}"`,
|
||||
t`Input is too short: "${name}"`,
|
||||
InvalidMetadataExceptionCode.INPUT_TOO_SHORT,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
|
||||
import {
|
||||
InvalidMetadataException,
|
||||
InvalidMetadataExceptionCode,
|
||||
@ -14,7 +16,7 @@ export const validateMetadataNameStartWithLowercaseLetterAndContainDigitsNorLett
|
||||
)
|
||||
) {
|
||||
throw new InvalidMetadataException(
|
||||
`String "${name}" is not valid: must start with lowercase letter and contain only alphanumeric letters`,
|
||||
t`String "${name}" is not valid: must start with lowercase letter and contain only alphanumeric letters`,
|
||||
InvalidMetadataExceptionCode.INVALID_STRING,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
|
||||
import {
|
||||
ObjectMetadataException,
|
||||
ObjectMetadataExceptionCode,
|
||||
@ -30,6 +32,9 @@ export const validatesNoOtherObjectWithSameNameExistsOrThrows = ({
|
||||
throw new ObjectMetadataException(
|
||||
'Object already exists',
|
||||
ObjectMetadataExceptionCode.OBJECT_ALREADY_EXISTS,
|
||||
{
|
||||
userFriendlyMessage: t`Object already exists`,
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user