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:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user