From 3058eb561710f0e23afe4873e497f8ff9f4e236e Mon Sep 17 00:00:00 2001 From: Jarrod Flesch <30633324+JarrodMFlesch@users.noreply.github.com> Date: Mon, 30 Jan 2023 14:17:40 -0500 Subject: [PATCH] fix: corrects type for required named tab fields (#1939) * fix: corrects type for required named tab fields * chore: tabs and groups are always required * chore: adjusts tab and group type to omit required since a group/named-tab will always exist --- src/fields/config/types.ts | 8 ++++---- src/graphql/schema/isFieldNullable.ts | 2 +- src/graphql/schema/withNullableType.ts | 2 +- src/graphql/schema/withOperators.ts | 2 +- src/utilities/entityToJSONSchema.ts | 8 +++----- src/utilities/groupOrTabHasRequiredSubfield.ts | 2 +- 6 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/fields/config/types.ts b/src/fields/config/types.ts index 177f92f040..689a7241f8 100644 --- a/src/fields/config/types.ts +++ b/src/fields/config/types.ts @@ -174,7 +174,7 @@ export type DateField = FieldBase & { } } -export type GroupField = FieldBase & { +export type GroupField = Omit & { type: 'group'; fields: Field[]; admin?: Admin & { @@ -201,14 +201,14 @@ export type CollapsibleField = Omit & { export type TabsAdmin = Omit; -type TabBase = { +type TabBase = Omit & { fields: Field[] description?: Description } -export type NamedTab = TabBase & FieldBase +export type NamedTab = TabBase -export type UnnamedTab = TabBase & Omit & { +export type UnnamedTab = Omit & { label: Record | string localized?: never } diff --git a/src/graphql/schema/isFieldNullable.ts b/src/graphql/schema/isFieldNullable.ts index c9915490d0..6602712d01 100644 --- a/src/graphql/schema/isFieldNullable.ts +++ b/src/graphql/schema/isFieldNullable.ts @@ -3,7 +3,7 @@ import { FieldAffectingData, fieldAffectsData } from '../../fields/config/types' const isFieldNullable = (field: FieldAffectingData, force: boolean): boolean => { const hasReadAccessControl = field.access && field.access.read; const condition = field.admin && field.admin.condition; - return !(force && fieldAffectsData(field) && field.required && !field.localized && !condition && !hasReadAccessControl); + return !(force && fieldAffectsData(field) && 'required' in field && field.required && !field.localized && !condition && !hasReadAccessControl); }; export default isFieldNullable; diff --git a/src/graphql/schema/withNullableType.ts b/src/graphql/schema/withNullableType.ts index b1551cb324..4c0259f034 100644 --- a/src/graphql/schema/withNullableType.ts +++ b/src/graphql/schema/withNullableType.ts @@ -5,7 +5,7 @@ const withNullableType = (field: FieldAffectingData, type: GraphQLType, forceNul const hasReadAccessControl = field.access && field.access.read; const condition = field.admin && field.admin.condition; - if (!forceNullable && field.required && !field.localized && !condition && !hasReadAccessControl) { + if (!forceNullable && 'required' in field && field.required && !field.localized && !condition && !hasReadAccessControl) { return new GraphQLNonNull(type); } diff --git a/src/graphql/schema/withOperators.ts b/src/graphql/schema/withOperators.ts index e6a73d4a56..d088c1bd1a 100644 --- a/src/graphql/schema/withOperators.ts +++ b/src/graphql/schema/withOperators.ts @@ -6,7 +6,7 @@ const withOperators = (field: FieldAffectingData, type: GraphQLType, parentName: const name = `${combineParentName(parentName, field.name)}_operator`; const listOperators = ['in', 'not_in', 'all']; - if (!field.required) operators.push('exists'); + if (!('required' in field) || !field.required) operators.push('exists'); return new GraphQLInputObjectType({ name, diff --git a/src/utilities/entityToJSONSchema.ts b/src/utilities/entityToJSONSchema.ts index 7c43f29fe9..467d533a47 100644 --- a/src/utilities/entityToJSONSchema.ts +++ b/src/utilities/entityToJSONSchema.ts @@ -5,14 +5,13 @@ import { fieldAffectsData, Field, Option, FieldAffectingData, tabHasName } from import { SanitizedCollectionConfig } from '../collections/config/types'; import { SanitizedGlobalConfig } from '../globals/config/types'; import deepCopyObject from './deepCopyObject'; -import { groupOrTabHasRequiredSubfield } from './groupOrTabHasRequiredSubfield'; import { toWords } from './formatLabels'; import { SanitizedConfig } from '../config/types'; const nonOptionalFieldTypes = ['group', 'array', 'blocks']; const propertyIsOptional = (field: Field) => { - return fieldAffectsData(field) && (field.required === true || nonOptionalFieldTypes.includes(field.type)); + return fieldAffectsData(field) && (('required' in field && field.required === true) || nonOptionalFieldTypes.includes(field.type)); }; function getCollectionIDType(collections: SanitizedCollectionConfig[], slug: string): 'string' | 'number' { @@ -310,8 +309,7 @@ function generateFieldTypes(config: SanitizedConfig, fields: Field[]): { case 'tabs': { field.tabs.forEach((tab) => { if (tabHasName(tab)) { - const hasRequiredSubfields = groupOrTabHasRequiredSubfield(tab); - if (hasRequiredSubfields) requiredTopLevelProps.push(tab.name); + requiredTopLevelProps.push(tab.name); topLevelProps.push([ tab.name, @@ -378,7 +376,7 @@ export function entityToJSONSchema(config: SanitizedConfig, incomingEntity: Sani const idField: FieldAffectingData = { type: 'text', name: 'id', required: true }; const customIdField = entity.fields.find((field) => fieldAffectsData(field) && field.name === 'id') as FieldAffectingData; - if (customIdField) { + if (customIdField && customIdField.type !== 'group' && customIdField.type !== 'tab') { customIdField.required = true; } else { entity.fields.unshift(idField); diff --git a/src/utilities/groupOrTabHasRequiredSubfield.ts b/src/utilities/groupOrTabHasRequiredSubfield.ts index 773a63fab6..b186511760 100644 --- a/src/utilities/groupOrTabHasRequiredSubfield.ts +++ b/src/utilities/groupOrTabHasRequiredSubfield.ts @@ -3,7 +3,7 @@ import { Field, fieldAffectsData, Tab } from '../fields/config/types'; export const groupOrTabHasRequiredSubfield = (entity: Field | Tab): boolean => { if ('type' in entity && entity.type === 'group') { return entity.fields.some((subField) => { - return (fieldAffectsData(subField) && subField.required) || groupOrTabHasRequiredSubfield(subField); + return (fieldAffectsData(subField) && 'required' in subField && subField.required) || groupOrTabHasRequiredSubfield(subField); }); }