feat: autolabel fields when label is omitted (#42)

* feat: autolabel fields when omitted

* feat: handle autolabel in graphql mutation build

* feat: autolabel blocks

* test: add required slug field to blocks

* feat: handle graphql names when label is false

* feat: adds relationship field to test searchable input

* feat: handle block cell type labeling pluralization

* docs: remove all explicit labeling, no longer needed

* fix: falsey column labels, allows false array labels

* fix: client tests

* fix: auto-labels globals

* docs: globals auto-labeling and hooks clarification

* fix; proper object type naming

Co-authored-by: James <james@trbl.design>
This commit is contained in:
Elliot DeNolf
2021-04-16 22:37:08 -04:00
committed by GitHub
parent 21b2bd4b67
commit b383eb65c6
49 changed files with 277 additions and 150 deletions

View File

@@ -1,5 +1,6 @@
import sanitizeFields from './sanitize';
import { MissingFieldType, InvalidFieldRelationship } from '../../errors';
import { Block } from './types';
describe('sanitizeFields', () => {
it('should throw on missing type field', () => {
@@ -11,6 +12,39 @@ describe('sanitizeFields', () => {
sanitizeFields(fields, []);
}).toThrow(MissingFieldType);
});
it('should populate label if missing', () => {
const fields = [{
name: 'someCollection',
type: 'text',
}];
const sanitizedField = sanitizeFields(fields, [])[0];
expect(sanitizedField.name).toStrictEqual('someCollection');
expect(sanitizedField.label).toStrictEqual('Some Collection');
expect(sanitizedField.type).toStrictEqual('text');
});
it('should allow auto-label override', () => {
const fields = [{
name: 'someCollection',
type: 'text',
label: 'Do not label',
}];
const sanitizedField = sanitizeFields(fields, [])[0];
expect(sanitizedField.name).toStrictEqual('someCollection');
expect(sanitizedField.label).toStrictEqual('Do not label');
expect(sanitizedField.type).toStrictEqual('text');
});
it('should allow label opt-out', () => {
const fields = [{
name: 'someCollection',
type: 'text',
label: false,
}];
const sanitizedField = sanitizeFields(fields, [])[0];
expect(sanitizedField.name).toStrictEqual('someCollection');
expect(sanitizedField.label).toStrictEqual(false);
expect(sanitizedField.type).toStrictEqual('text');
});
describe('relationships', () => {
it('should not throw on valid relationship', () => {
@@ -41,6 +75,15 @@ describe('sanitizeFields', () => {
it('should not throw on valid relationship inside blocks', () => {
const validRelationships = ['some-collection'];
const relationshipBlock: Block = {
slug: 'relationshipBlock',
fields: [{
type: 'relationship',
label: 'my-relationship',
name: 'My Relationship',
relationTo: 'some-collection',
}],
};
const fields = [{
name: 'layout',
label: 'Layout Blocks',
@@ -48,14 +91,7 @@ describe('sanitizeFields', () => {
singular: 'Block',
},
type: 'blocks',
blocks: [{
fields: [{
type: 'relationship',
label: 'my-relationship',
name: 'My Relationship',
relationTo: 'some-collection',
}],
}],
blocks: [relationshipBlock],
}];
expect(() => {
sanitizeFields(fields, validRelationships);
@@ -90,6 +126,15 @@ describe('sanitizeFields', () => {
it('should throw on invalid relationship inside blocks', () => {
const validRelationships = ['some-collection'];
const relationshipBlock: Block = {
slug: 'relationshipBlock',
fields: [{
type: 'relationship',
label: 'my-relationship',
name: 'My Relationship',
relationTo: 'not-valid',
}],
};
const fields = [{
name: 'layout',
label: 'Layout Blocks',
@@ -97,14 +142,7 @@ describe('sanitizeFields', () => {
singular: 'Block',
},
type: 'blocks',
blocks: [{
fields: [{
type: 'relationship',
label: 'my-relationship',
name: 'My Relationship',
relationTo: 'not-valid',
}],
}],
blocks: [relationshipBlock],
}];
expect(() => {
sanitizeFields(fields, validRelationships);

View File

@@ -1,7 +1,8 @@
import { formatLabels, toWords } from '../../utilities/formatLabels';
import { MissingFieldType, InvalidFieldRelationship } from '../../errors';
import validations from '../validations';
const sanitizeFields = (fields, validRelationships) => {
const sanitizeFields = (fields, validRelationships: string[]) => {
if (!fields) return [];
return fields.map((unsanitizedField) => {
@@ -9,15 +10,24 @@ const sanitizeFields = (fields, validRelationships) => {
if (!field.type) throw new MissingFieldType(field);
// Auto-label
if (field.name && typeof field.label !== 'string' && field.label !== false) {
field.label = toWords(field.name);
}
if (field.type === 'relationship') {
const relationships = Array.isArray(field.relationTo) ? field.relationTo : [field.relationTo];
relationships.forEach((relationship) => {
relationships.forEach((relationship: string) => {
if (!validRelationships.includes(relationship)) {
throw new InvalidFieldRelationship(field, relationship);
}
});
}
if (field.type === 'blocks') {
field.labels = field.labels || formatLabels(field.name);
}
if (typeof field.validate === 'undefined') {
const defaultValidate = validations[field.type];
if (defaultValidate) {
@@ -36,6 +46,7 @@ const sanitizeFields = (fields, validRelationships) => {
if (field.blocks) {
field.blocks = field.blocks.map((block) => {
const unsanitizedBlock = { ...block };
unsanitizedBlock.labels = !unsanitizedBlock.labels ? formatLabels(unsanitizedBlock.slug) : unsanitizedBlock.labels;
unsanitizedBlock.fields = sanitizeFields(block.fields, validRelationships);
return unsanitizedBlock;
});

View File

@@ -21,7 +21,10 @@ export const baseAdminFields = joi.object().keys({
});
export const baseField = joi.object().keys({
label: joi.string(),
label: joi.alternatives().try(
joi.string(),
joi.valid(false),
),
required: joi.boolean().default(false),
saveToJWT: joi.boolean().default(false),
unique: joi.boolean().default(false),

View File

@@ -51,7 +51,7 @@ export type Option = OptionObject | string
export interface FieldBase {
name?: string;
label?: string;
label?: string | false;
required?: boolean;
unique?: boolean;
index?: boolean;
@@ -209,7 +209,7 @@ export type RadioField = FieldBase & {
export type Block = {
slug: string,
labels: Labels
labels?: Labels
fields: Field[],
imageURL?: string
imageAltText?: string