chore: move to monorepo structure
This commit is contained in:
@@ -1,6 +0,0 @@
|
||||
import React from 'react';
|
||||
import { RowLabelComponent } from '../../../../src/admin/components/forms/RowLabel/types';
|
||||
|
||||
export const ArrayRowLabel: RowLabelComponent = ({ data }) => {
|
||||
return <div style={{ textTransform: 'uppercase', color: 'coral' }}>{data.title || 'Untitled'}</div>;
|
||||
};
|
||||
@@ -1,44 +0,0 @@
|
||||
@mixin btn-reset {
|
||||
border: 0;
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
padding: 0;
|
||||
color: currentColor;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#field-customBlocks {
|
||||
margin-bottom: var(--base);
|
||||
|
||||
.blocks-field__drawer-toggler {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.custom-blocks-field-management {
|
||||
&__blocks-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: calc(var(--base) * 2);
|
||||
}
|
||||
|
||||
&__block-button {
|
||||
@include btn-reset;
|
||||
|
||||
border: 1px solid var(--theme-border-color);
|
||||
width: 100%;
|
||||
padding: 25px 10px;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--theme-elevation-400);
|
||||
}
|
||||
}
|
||||
|
||||
&__replace-block-button {
|
||||
margin-top: calc(var(--base) * 1.5);
|
||||
color: var(--theme-bg);
|
||||
background: var(--theme-text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { useForm } from '../../../../../../src/admin/components/forms/Form/context';
|
||||
import useField from '../../../../../../src/admin/components/forms/useField';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
const baseClass = 'custom-blocks-field-management';
|
||||
|
||||
export const AddCustomBlocks: React.FC = () => {
|
||||
const { addFieldRow, replaceFieldRow } = useForm();
|
||||
const { value } = useField({ path: 'customBlocks' });
|
||||
|
||||
const nextIndex = typeof value === 'number' ? value + 1 : 0;
|
||||
|
||||
return (
|
||||
<div className={baseClass}>
|
||||
<div className={`${baseClass}__blocks-grid`}>
|
||||
<button
|
||||
className={`${baseClass}__block-button`}
|
||||
type="button"
|
||||
onClick={() => addFieldRow({ path: 'customBlocks', data: { block1Title: 'Block 1: Prefilled Title', blockType: 'block-1' }, rowIndex: nextIndex })}
|
||||
>
|
||||
Add Block 1
|
||||
</button>
|
||||
|
||||
<button
|
||||
className={`${baseClass}__block-button`}
|
||||
type="button"
|
||||
onClick={() => addFieldRow({ path: 'customBlocks', data: { block2Title: 'Block 2: Prefilled Title', blockType: 'block-2' }, rowIndex: nextIndex })}
|
||||
>
|
||||
Add Block 2
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button
|
||||
className={`${baseClass}__block-button ${baseClass}__replace-block-button`}
|
||||
type="button"
|
||||
onClick={() => replaceFieldRow({ path: 'customBlocks', data: { block1Title: 'REPLACED BLOCK', blockType: 'block-1' }, rowIndex: nextIndex - 1 })}
|
||||
>
|
||||
Replace Block
|
||||
{' '}
|
||||
{nextIndex - 1}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,186 +0,0 @@
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
import { ArrayRowLabel } from './LabelComponent';
|
||||
import { AddCustomBlocks } from './components/AddCustomBlocks';
|
||||
|
||||
export const arrayDefaultValue = [
|
||||
{ text: 'row one' },
|
||||
{ text: 'row two' },
|
||||
];
|
||||
|
||||
export const arrayFieldsSlug = 'array-fields';
|
||||
|
||||
const ArrayFields: CollectionConfig = {
|
||||
slug: arrayFieldsSlug,
|
||||
admin: {
|
||||
enableRichTextLink: false,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'items',
|
||||
type: 'array',
|
||||
required: true,
|
||||
defaultValue: arrayDefaultValue,
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'collapsedArray',
|
||||
type: 'array',
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
admin: {
|
||||
initCollapsed: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'localized',
|
||||
type: 'array',
|
||||
required: true,
|
||||
localized: true,
|
||||
defaultValue: arrayDefaultValue,
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'array',
|
||||
name: 'readOnly',
|
||||
admin: {
|
||||
readOnly: true,
|
||||
},
|
||||
defaultValue: [
|
||||
{
|
||||
text: 'defaultValue',
|
||||
},
|
||||
{
|
||||
text: 'defaultValue2',
|
||||
},
|
||||
],
|
||||
fields: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'array',
|
||||
name: 'potentiallyEmptyArray',
|
||||
fields: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'array',
|
||||
name: 'rowLabelAsFunction',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
admin: {
|
||||
description: 'Row labels rendered from a function.',
|
||||
components: {
|
||||
RowLabel: ({ data }) => data.title,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'array',
|
||||
name: 'rowLabelAsComponent',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
admin: {
|
||||
description: 'Row labels rendered as react components.',
|
||||
components: {
|
||||
RowLabel: ArrayRowLabel,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'customBlocks',
|
||||
type: 'blocks',
|
||||
blocks: [
|
||||
{
|
||||
slug: 'block-1',
|
||||
fields: [
|
||||
{
|
||||
name: 'block1Title',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'block-2',
|
||||
fields: [
|
||||
{
|
||||
name: 'block2Title',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'ui',
|
||||
name: 'ui',
|
||||
admin: {
|
||||
components: {
|
||||
Field: AddCustomBlocks,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const arrayDoc = {
|
||||
items: [
|
||||
{
|
||||
text: 'first row',
|
||||
},
|
||||
{
|
||||
text: 'second row',
|
||||
},
|
||||
{
|
||||
text: 'third row',
|
||||
},
|
||||
{
|
||||
text: 'fourth row',
|
||||
},
|
||||
{
|
||||
text: 'fifth row',
|
||||
},
|
||||
{
|
||||
text: 'sixth row',
|
||||
},
|
||||
],
|
||||
collapsedArray: [
|
||||
{
|
||||
text: 'initialize collapsed',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default ArrayFields;
|
||||
@@ -1,250 +0,0 @@
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
import { Field } from '../../../../src/fields/config/types';
|
||||
|
||||
export const blocksFieldSeedData = [
|
||||
{
|
||||
blockName: 'First block',
|
||||
blockType: 'text',
|
||||
text: 'first block',
|
||||
richText: [{
|
||||
children: [{ text: '' }],
|
||||
}],
|
||||
},
|
||||
{
|
||||
blockName: 'Second block',
|
||||
blockType: 'number',
|
||||
number: 342,
|
||||
},
|
||||
{
|
||||
blockName: 'Sub-block demonstration',
|
||||
blockType: 'subBlocks',
|
||||
subBlocks: [
|
||||
{
|
||||
blockName: 'First sub block',
|
||||
blockType: 'number',
|
||||
number: 123,
|
||||
},
|
||||
{
|
||||
blockName: 'Second sub block',
|
||||
blockType: 'text',
|
||||
text: 'second sub block',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
blockName: 'I18n Block',
|
||||
blockType: 'i18n-text',
|
||||
text: 'first block',
|
||||
},
|
||||
] as const;
|
||||
|
||||
export const blocksField: Field = {
|
||||
name: 'blocks',
|
||||
type: 'blocks',
|
||||
required: true,
|
||||
blocks: [
|
||||
{
|
||||
slug: 'text',
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'richText',
|
||||
type: 'richText',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'number',
|
||||
fields: [
|
||||
{
|
||||
name: 'number',
|
||||
type: 'number',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'subBlocks',
|
||||
fields: [
|
||||
{
|
||||
type: 'collapsible',
|
||||
label: 'Collapsible within Block',
|
||||
fields: [
|
||||
{
|
||||
name: 'subBlocks',
|
||||
type: 'blocks',
|
||||
blocks: [
|
||||
{
|
||||
slug: 'text',
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'number',
|
||||
fields: [
|
||||
{
|
||||
name: 'number',
|
||||
type: 'number',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'tabs',
|
||||
fields: [
|
||||
{
|
||||
type: 'tabs',
|
||||
tabs: [
|
||||
{
|
||||
label: 'Tab with Collapsible',
|
||||
fields: [
|
||||
{
|
||||
type: 'collapsible',
|
||||
label: 'Collapsible within Block',
|
||||
fields: [
|
||||
{
|
||||
// collapsible
|
||||
name: 'textInCollapsible',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'row',
|
||||
fields: [
|
||||
{
|
||||
// collapsible
|
||||
name: 'textInRow',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
defaultValue: blocksFieldSeedData,
|
||||
};
|
||||
|
||||
const BlockFields: CollectionConfig = {
|
||||
slug: 'block-fields',
|
||||
fields: [
|
||||
blocksField,
|
||||
{
|
||||
...blocksField,
|
||||
name: 'collapsedByDefaultBlocks',
|
||||
localized: true,
|
||||
admin: {
|
||||
initCollapsed: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
...blocksField,
|
||||
name: 'localizedBlocks',
|
||||
localized: true,
|
||||
},
|
||||
{
|
||||
type: 'blocks',
|
||||
name: 'i18nBlocks',
|
||||
label: {
|
||||
en: 'Block en',
|
||||
es: 'Block es',
|
||||
},
|
||||
labels: {
|
||||
singular: {
|
||||
en: 'Block en',
|
||||
es: 'Block es',
|
||||
},
|
||||
plural: {
|
||||
en: 'Blocks en',
|
||||
es: 'Blocks es',
|
||||
},
|
||||
},
|
||||
blocks: [
|
||||
{
|
||||
slug: 'text',
|
||||
graphQL: {
|
||||
singularName: 'I18nText',
|
||||
},
|
||||
labels: {
|
||||
singular: {
|
||||
en: 'Text en',
|
||||
es: 'Text es',
|
||||
},
|
||||
plural: {
|
||||
en: 'Texts en',
|
||||
es: 'Texts es',
|
||||
},
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'blocks',
|
||||
name: 'blocksWithSimilarConfigs',
|
||||
blocks: [{
|
||||
slug: 'block-1',
|
||||
fields: [
|
||||
{
|
||||
type: 'array',
|
||||
name: 'items',
|
||||
fields: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'title',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'block-2',
|
||||
fields: [
|
||||
{
|
||||
type: 'array',
|
||||
name: 'items',
|
||||
fields: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'title2',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const blocksDoc = {
|
||||
blocks: blocksFieldSeedData,
|
||||
localizedBlocks: blocksFieldSeedData,
|
||||
};
|
||||
|
||||
export default BlockFields;
|
||||
@@ -1,126 +0,0 @@
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
import { CodeField } from '../../payload-types';
|
||||
|
||||
const Code: CollectionConfig = {
|
||||
slug: 'code-fields',
|
||||
fields: [
|
||||
{
|
||||
name: 'javascript',
|
||||
type: 'code',
|
||||
admin: {
|
||||
language: 'javascript',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'typescript',
|
||||
type: 'code',
|
||||
admin: {
|
||||
language: 'typescript',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'json',
|
||||
type: 'code',
|
||||
admin: {
|
||||
language: 'json',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'html',
|
||||
type: 'code',
|
||||
admin: {
|
||||
language: 'html',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'css',
|
||||
type: 'code',
|
||||
admin: {
|
||||
language: 'css',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const codeDoc: Partial<CodeField> = {
|
||||
javascript: "console.log('Hello');",
|
||||
typescript: `class Greeter {
|
||||
greeting: string;
|
||||
|
||||
constructor(message: string) {
|
||||
this.greeting = message;
|
||||
}
|
||||
|
||||
greet() {
|
||||
return "Hello, " + this.greeting;
|
||||
}
|
||||
}
|
||||
|
||||
let greeter = new Greeter("world");`,
|
||||
|
||||
html: `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
|
||||
<script>
|
||||
// Just a lil’ script to show off that inline JS gets highlighted
|
||||
window.console && console.log('foo');
|
||||
</script>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="assets/favicon.png" />
|
||||
<title>Prism</title>
|
||||
<link rel="stylesheet" href="assets/style.css" />
|
||||
<link rel="stylesheet" href="themes/prism.css" data-noprefix />
|
||||
<script src="assets/vendor/prefixfree.min.js"></script>
|
||||
|
||||
<script>var _gaq = [['_setAccount', 'UA-11111111-1'], ['_trackPageview']];</script>
|
||||
<script src="https://www.google-analytics.com/ga.js" async></script>
|
||||
</head>
|
||||
<body>`,
|
||||
|
||||
css: `@import url(https://fonts.googleapis.com/css?family=Questrial);
|
||||
@import url(https://fonts.googleapis.com/css?family=Arvo);
|
||||
|
||||
@font-face {
|
||||
src: url(https://lea.verou.me/logo.otf);
|
||||
font-family: 'LeaVerou';
|
||||
}
|
||||
|
||||
/*
|
||||
Shared styles
|
||||
*/
|
||||
|
||||
section h1,
|
||||
#features li strong,
|
||||
header h2,
|
||||
footer p {
|
||||
font: 100% Rockwell, Arvo, serif;
|
||||
}
|
||||
|
||||
/*
|
||||
Styles
|
||||
*/
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
font: 100%/1.5 Questrial, sans-serif;
|
||||
tab-size: 4;
|
||||
hyphens: auto;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
section h1 {
|
||||
font-size: 250%;
|
||||
}`,
|
||||
|
||||
json: JSON.stringify({ property: 'value', arr: ['val1', 'val2', 'val3'] }, null, 2),
|
||||
};
|
||||
|
||||
export default Code;
|
||||
@@ -1,6 +0,0 @@
|
||||
import React from 'react';
|
||||
import { RowLabelComponent } from '../../../../src/admin/components/forms/RowLabel/types';
|
||||
|
||||
export const CollapsibleLabelComponent: RowLabelComponent = ({ data }) => {
|
||||
return <div style={{ textTransform: 'uppercase', color: 'hotpink' }}>{data.innerCollapsible || 'Untitled'}</div>;
|
||||
};
|
||||
@@ -1,151 +0,0 @@
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
import { CollapsibleLabelComponent } from './LabelComponent';
|
||||
|
||||
export const collapsibleFieldsSlug = 'collapsible-fields';
|
||||
|
||||
const CollapsibleFields: CollectionConfig = {
|
||||
slug: collapsibleFieldsSlug,
|
||||
versions: true,
|
||||
fields: [
|
||||
{
|
||||
label: 'Collapsible Field',
|
||||
type: 'collapsible',
|
||||
admin: {
|
||||
description: 'This is a collapsible field.',
|
||||
initCollapsed: false,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'group',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
name: 'textWithinGroup',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'subGroup',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
name: 'textWithinSubGroup',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Collapsible Field - Collapsed by Default',
|
||||
type: 'collapsible',
|
||||
admin: {
|
||||
description: 'This is a collapsible field.',
|
||||
initCollapsed: true,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'someText',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
// TODO: change group name, to not be a duplicate of the above collapsible
|
||||
name: 'group',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
name: 'textWithinGroup',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'subGroup',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
name: 'textWithinSubGroup',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: ({ data }) => data.functionTitleField || 'Custom Collapsible Label',
|
||||
type: 'collapsible',
|
||||
admin: {
|
||||
description: 'Collapsible label rendered from a function.',
|
||||
initCollapsed: true,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'functionTitleField',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: ({ data }) => data?.componentTitleField || 'Untitled',
|
||||
type: 'collapsible',
|
||||
admin: {
|
||||
description: 'Collapsible label rendered as a react component.',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'componentTitleField',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
type: 'collapsible',
|
||||
label: ({ data }) => data?.nestedTitle || 'Nested Collapsible',
|
||||
fields: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'nestedTitle',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'arrayWithCollapsibles',
|
||||
type: 'array',
|
||||
fields: [
|
||||
{
|
||||
label: CollapsibleLabelComponent,
|
||||
type: 'collapsible',
|
||||
fields: [
|
||||
{
|
||||
name: 'innerCollapsible',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const collapsibleDoc = {
|
||||
text: 'Seeded collapsible doc',
|
||||
group: {
|
||||
textWithinGroup: 'some text within a group',
|
||||
subGroup: {
|
||||
textWithinSubGroup: 'hello, get out',
|
||||
},
|
||||
},
|
||||
arrayWithCollapsibles: [
|
||||
{
|
||||
innerCollapsible: '',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default CollapsibleFields;
|
||||
@@ -1,105 +0,0 @@
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
|
||||
const ConditionalLogic: CollectionConfig = {
|
||||
slug: 'conditional-logic',
|
||||
admin: {
|
||||
useAsTitle: 'text',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'toggleField',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
name: 'fieldToToggle',
|
||||
type: 'text',
|
||||
required: true,
|
||||
admin: {
|
||||
condition: ({ toggleField }) => Boolean(toggleField),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'userConditional',
|
||||
type: 'text',
|
||||
admin: {
|
||||
condition: (_data, _siblingData, { user }) => {
|
||||
return Boolean(user?.canViewConditionalField);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'parentGroup',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
name: 'enableParentGroupFields',
|
||||
type: 'checkbox',
|
||||
defaultValue: false,
|
||||
},
|
||||
{
|
||||
name: 'siblingField',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'Ensures we can rely on nested fields within `data`.',
|
||||
condition: ({ parentGroup }) => Boolean(parentGroup?.enableParentGroupFields),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'reliesOnParentGroup',
|
||||
type: 'text',
|
||||
admin: {
|
||||
description: 'Ensures we can rely on nested fields within `siblingsData`.',
|
||||
condition: (_, { parentGroup }) => Boolean(parentGroup?.enableParentGroupFields),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'groupSelection',
|
||||
type: 'select',
|
||||
options: [
|
||||
'group1',
|
||||
'group2',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'group1',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
name: 'group1Field',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
admin: {
|
||||
condition: ({ groupSelection }) => groupSelection === 'group1',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'group2',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
name: 'group2Field',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
admin: {
|
||||
condition: ({ groupSelection }) => groupSelection === 'group2',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const conditionalLogicDoc = {
|
||||
text: 'Seeded conditional logic document',
|
||||
toggleField: true,
|
||||
fieldToToggle: 'spiderman',
|
||||
};
|
||||
|
||||
export default ConditionalLogic;
|
||||
@@ -1,74 +0,0 @@
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
|
||||
export const defaultText = 'default-text';
|
||||
|
||||
const DateFields: CollectionConfig = {
|
||||
slug: 'date-fields',
|
||||
admin: {
|
||||
useAsTitle: 'default',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'default',
|
||||
type: 'date',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'timeOnly',
|
||||
type: 'date',
|
||||
admin: {
|
||||
date: {
|
||||
pickerAppearance: 'timeOnly',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'timeOnlyWithCustomFormat',
|
||||
type: 'date',
|
||||
admin: {
|
||||
date: {
|
||||
pickerAppearance: 'timeOnly',
|
||||
displayFormat: 'd MMM yyy',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'dayOnly',
|
||||
type: 'date',
|
||||
admin: {
|
||||
date: {
|
||||
pickerAppearance: 'dayOnly',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'dayAndTime',
|
||||
type: 'date',
|
||||
admin: {
|
||||
date: {
|
||||
pickerAppearance: 'dayAndTime',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'monthOnly',
|
||||
type: 'date',
|
||||
admin: {
|
||||
date: {
|
||||
pickerAppearance: 'monthOnly',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const dateDoc = {
|
||||
default: '2022-08-12T10:00:00.000+00:00',
|
||||
timeOnly: '2022-08-12T10:00:00.157+00:00',
|
||||
timeOnlyWithCustomFormat: '2022-08-12T10:00:00.157+00:00',
|
||||
dayOnly: '2022-08-11T22:00:00.000+00:00',
|
||||
dayAndTime: '2022-08-12T10:00:00.052+00:00',
|
||||
monthOnly: '2022-07-31T22:00:00.000+00:00',
|
||||
};
|
||||
|
||||
export default DateFields;
|
||||
@@ -1,183 +0,0 @@
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
|
||||
export const groupDefaultValue = 'set from parent';
|
||||
export const groupDefaultChild = 'child takes priority';
|
||||
export const groupFieldsSlug = 'group-fields';
|
||||
|
||||
const GroupFields: CollectionConfig = {
|
||||
slug: groupFieldsSlug,
|
||||
versions: true,
|
||||
fields: [
|
||||
{
|
||||
label: 'Group Field',
|
||||
name: 'group',
|
||||
type: 'group',
|
||||
defaultValue: {
|
||||
defaultParent: groupDefaultValue,
|
||||
},
|
||||
admin: {
|
||||
description: 'This is a group.',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
required: true,
|
||||
defaultValue: groupDefaultValue,
|
||||
},
|
||||
{
|
||||
name: 'defaultParent',
|
||||
type: 'text',
|
||||
defaultValue: groupDefaultChild,
|
||||
},
|
||||
{
|
||||
name: 'defaultChild',
|
||||
type: 'text',
|
||||
defaultValue: groupDefaultChild,
|
||||
},
|
||||
{
|
||||
name: 'subGroup',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
name: 'textWithinGroup',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'arrayWithinGroup',
|
||||
type: 'array',
|
||||
fields: [
|
||||
{
|
||||
name: 'textWithinArray',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'potentiallyEmptyGroup',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'row',
|
||||
fields: [
|
||||
{
|
||||
name: 'groupInRow',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
name: 'field',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'secondField',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'thirdField',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'secondGroupInRow',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
name: 'field',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'nestedGroup',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
name: 'nestedField',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
type: 'tabs',
|
||||
tabs: [
|
||||
{
|
||||
name: 'groups',
|
||||
label: 'Groups in tabs',
|
||||
fields: [
|
||||
{
|
||||
type: 'row',
|
||||
fields: [
|
||||
{
|
||||
name: 'groupInRow',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
name: 'field',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'secondField',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'thirdField',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'secondGroupInRow',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
name: 'field',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'nestedGroup',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
name: 'nestedField',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const groupDoc = {
|
||||
group: {
|
||||
text: 'some text within a group',
|
||||
subGroup: {
|
||||
textWithinGroup: 'please',
|
||||
arrayWithinGroup: [{
|
||||
textWithinArray: 'text in a group and array',
|
||||
}],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default GroupFields;
|
||||
@@ -1,95 +0,0 @@
|
||||
import type { BeforeDuplicate, CollectionConfig } from '../../../../src/collections/config/types';
|
||||
import { IndexedField } from '../../payload-types';
|
||||
|
||||
const beforeDuplicate: BeforeDuplicate<IndexedField> = ({ data }) => {
|
||||
return {
|
||||
...data,
|
||||
uniqueText: data.uniqueText ? `${data.uniqueText}-copy` : '',
|
||||
group: {
|
||||
...data.group || {},
|
||||
localizedUnique: data.group?.localizedUnique ? `${data.group?.localizedUnique}-copy` : '',
|
||||
},
|
||||
collapsibleTextUnique: data.collapsibleTextUnique ? `${data.collapsibleTextUnique}-copy` : '',
|
||||
collapsibleLocalizedUnique: data.collapsibleLocalizedUnique ? `${data.collapsibleLocalizedUnique}-copy` : '',
|
||||
partOne: data.partOne ? `${data.partOne}-copy` : '',
|
||||
partTwo: data.partTwo ? `${data.partTwo}-copy` : '',
|
||||
};
|
||||
};
|
||||
|
||||
const IndexedFields: CollectionConfig = {
|
||||
slug: 'indexed-fields',
|
||||
// used to assert that versions also get indexes
|
||||
versions: true,
|
||||
admin: {
|
||||
hooks: {
|
||||
beforeDuplicate,
|
||||
},
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
required: true,
|
||||
index: true,
|
||||
},
|
||||
{
|
||||
name: 'uniqueText',
|
||||
type: 'text',
|
||||
unique: true,
|
||||
},
|
||||
{
|
||||
name: 'point',
|
||||
type: 'point',
|
||||
},
|
||||
{
|
||||
type: 'group',
|
||||
name: 'group',
|
||||
fields: [
|
||||
{
|
||||
name: 'localizedUnique',
|
||||
type: 'text',
|
||||
unique: true,
|
||||
localized: true,
|
||||
},
|
||||
{
|
||||
name: 'point',
|
||||
type: 'point',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'collapsible',
|
||||
label: 'Collapsible',
|
||||
fields: [
|
||||
{
|
||||
name: 'collapsibleLocalizedUnique',
|
||||
type: 'text',
|
||||
unique: true,
|
||||
localized: true,
|
||||
},
|
||||
{
|
||||
name: 'collapsibleTextUnique',
|
||||
type: 'text',
|
||||
label: 'collapsibleTextUnique',
|
||||
unique: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'partOne',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'partTwo',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
indexes: [
|
||||
{
|
||||
fields: { partOne: 1, partTwo: 1 },
|
||||
options: { unique: true, name: 'compound-index', sparse: true },
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default IndexedFields;
|
||||
@@ -1,38 +0,0 @@
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
|
||||
|
||||
type JSONField = {
|
||||
id: string;
|
||||
json?: any;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
const JSON: CollectionConfig = {
|
||||
slug: 'json-fields',
|
||||
versions: {
|
||||
maxPerDoc: 1,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'json',
|
||||
type: 'json',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const jsonDoc: Partial<JSONField> = {
|
||||
json: {
|
||||
property: 'value',
|
||||
arr: [
|
||||
'val1',
|
||||
'val2',
|
||||
'val3',
|
||||
],
|
||||
nested: {
|
||||
value: 'nested value',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default JSON;
|
||||
@@ -1,90 +0,0 @@
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
|
||||
export const defaultNumber = 5;
|
||||
|
||||
const NumberFields: CollectionConfig = {
|
||||
slug: 'number-fields',
|
||||
admin: {
|
||||
useAsTitle: 'number',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'number',
|
||||
type: 'number',
|
||||
},
|
||||
{
|
||||
name: 'min',
|
||||
type: 'number',
|
||||
min: 10,
|
||||
},
|
||||
{
|
||||
name: 'max',
|
||||
type: 'number',
|
||||
max: 10,
|
||||
},
|
||||
{
|
||||
name: 'positiveNumber',
|
||||
type: 'number',
|
||||
min: 0,
|
||||
},
|
||||
{
|
||||
name: 'negativeNumber',
|
||||
type: 'number',
|
||||
max: 0,
|
||||
},
|
||||
{
|
||||
name: 'decimalMin',
|
||||
type: 'number',
|
||||
min: 0.5,
|
||||
},
|
||||
{
|
||||
name: 'decimalMax',
|
||||
type: 'number',
|
||||
max: 0.5,
|
||||
},
|
||||
{
|
||||
name: 'defaultNumber',
|
||||
type: 'number',
|
||||
defaultValue: defaultNumber,
|
||||
},
|
||||
{
|
||||
name: 'hasMany',
|
||||
type: 'number',
|
||||
hasMany: true,
|
||||
min: 5,
|
||||
max: 100,
|
||||
},
|
||||
{
|
||||
name: 'validatesHasMany',
|
||||
type: 'number',
|
||||
hasMany: true,
|
||||
validate: (value: number[]) => {
|
||||
if (value && !Array.isArray(value)) {
|
||||
return 'value should be an array';
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'localizedHasMany',
|
||||
type: 'number',
|
||||
hasMany: true,
|
||||
localized: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const numberDoc = {
|
||||
number: 5,
|
||||
min: 15,
|
||||
max: 5,
|
||||
positiveNumber: 5,
|
||||
negativeNumber: -5,
|
||||
decimalMin: 1.25,
|
||||
decimalMax: 0.25,
|
||||
hasMany: [5, 10, 15],
|
||||
validatesHasMany: [5],
|
||||
localizedHasMany: [10],
|
||||
};
|
||||
|
||||
export default NumberFields;
|
||||
@@ -1,44 +0,0 @@
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
|
||||
export const pointFieldsSlug = 'point-fields';
|
||||
|
||||
const PointFields: CollectionConfig = {
|
||||
slug: pointFieldsSlug,
|
||||
admin: {
|
||||
useAsTitle: 'point',
|
||||
},
|
||||
versions: true,
|
||||
fields: [
|
||||
{
|
||||
name: 'point',
|
||||
type: 'point',
|
||||
label: 'Location',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'localized',
|
||||
type: 'point',
|
||||
label: 'Localized Point',
|
||||
unique: true,
|
||||
localized: true,
|
||||
},
|
||||
{
|
||||
type: 'group',
|
||||
name: 'group',
|
||||
fields: [
|
||||
{
|
||||
name: 'point',
|
||||
type: 'point',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const pointDoc = {
|
||||
point: [7, -7],
|
||||
localized: [15, -12],
|
||||
group: { point: [1, 9] },
|
||||
};
|
||||
|
||||
export default PointFields;
|
||||
@@ -1,34 +0,0 @@
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
|
||||
const RadioFields: CollectionConfig = {
|
||||
slug: 'radio-fields',
|
||||
fields: [
|
||||
{
|
||||
name: 'radio',
|
||||
label: {
|
||||
en: 'Radio en', es: 'Radio es',
|
||||
},
|
||||
type: 'radio',
|
||||
options: [
|
||||
{
|
||||
label: { en: 'Value One', es: 'Value Uno' },
|
||||
value: 'one',
|
||||
},
|
||||
{
|
||||
label: 'Value Two',
|
||||
value: 'two',
|
||||
},
|
||||
{
|
||||
label: 'Value Three',
|
||||
value: 'three',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const radiosDoc = {
|
||||
radio: 'one',
|
||||
};
|
||||
|
||||
export default RadioFields;
|
||||
@@ -1,65 +0,0 @@
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
|
||||
export const relationshipFieldsSlug = 'relationship-fields';
|
||||
|
||||
const RelationshipFields: CollectionConfig = {
|
||||
slug: relationshipFieldsSlug,
|
||||
fields: [
|
||||
{
|
||||
name: 'relationship',
|
||||
type: 'relationship',
|
||||
relationTo: ['text-fields', 'array-fields'],
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'relationToSelf',
|
||||
type: 'relationship',
|
||||
relationTo: relationshipFieldsSlug,
|
||||
},
|
||||
{
|
||||
name: 'relationToSelfSelectOnly',
|
||||
type: 'relationship',
|
||||
relationTo: relationshipFieldsSlug,
|
||||
admin: {
|
||||
allowCreate: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'relationWithDynamicDefault',
|
||||
type: 'relationship',
|
||||
relationTo: 'users',
|
||||
defaultValue: ({ user }) => user.id,
|
||||
},
|
||||
{
|
||||
name: 'relationHasManyWithDynamicDefault',
|
||||
type: 'relationship',
|
||||
relationTo: ['users'],
|
||||
defaultValue: ({ user }) => ({
|
||||
relationTo: 'users',
|
||||
value: user.id,
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: 'relationshipWithMin',
|
||||
type: 'relationship',
|
||||
relationTo: 'text-fields',
|
||||
hasMany: true,
|
||||
minRows: 2,
|
||||
},
|
||||
{
|
||||
name: 'relationshipWithMax',
|
||||
type: 'relationship',
|
||||
relationTo: 'text-fields',
|
||||
hasMany: true,
|
||||
maxRows: 2,
|
||||
},
|
||||
{
|
||||
name: 'relationshipHasMany',
|
||||
type: 'relationship',
|
||||
relationTo: 'text-fields',
|
||||
hasMany: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default RelationshipFields;
|
||||
@@ -1,497 +0,0 @@
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
import { loremIpsum } from './loremIpsum';
|
||||
|
||||
const RichTextFields: CollectionConfig = {
|
||||
slug: 'rich-text-fields',
|
||||
admin: {
|
||||
useAsTitle: 'title',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'selectHasMany',
|
||||
hasMany: true,
|
||||
type: 'select',
|
||||
admin: {
|
||||
description: 'This select field is rendered here to ensure its options dropdown renders above the rich text toolbar.',
|
||||
},
|
||||
options: [
|
||||
{
|
||||
label: 'Value One',
|
||||
value: 'one',
|
||||
},
|
||||
{
|
||||
label: 'Value Two',
|
||||
value: 'two',
|
||||
},
|
||||
{
|
||||
label: 'Value Three',
|
||||
value: 'three',
|
||||
},
|
||||
{
|
||||
label: 'Value Four',
|
||||
value: 'four',
|
||||
},
|
||||
{
|
||||
label: 'Value Five',
|
||||
value: 'five',
|
||||
},
|
||||
{
|
||||
label: 'Value Six',
|
||||
value: 'six',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'richText',
|
||||
type: 'richText',
|
||||
required: true,
|
||||
admin: {
|
||||
elements: [
|
||||
'h1',
|
||||
'h2',
|
||||
'h3',
|
||||
'h4',
|
||||
'h5',
|
||||
'h6',
|
||||
'ul',
|
||||
'ol',
|
||||
'textAlign',
|
||||
'indent',
|
||||
'link',
|
||||
'relationship',
|
||||
'upload',
|
||||
],
|
||||
link: {
|
||||
fields: [
|
||||
{
|
||||
name: 'rel',
|
||||
label: 'Rel Attribute',
|
||||
type: 'select',
|
||||
hasMany: true,
|
||||
options: [
|
||||
'noopener', 'noreferrer', 'nofollow',
|
||||
],
|
||||
admin: {
|
||||
description: 'The rel attribute defines the relationship between a linked resource and the current document. This is a custom link field.',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
upload: {
|
||||
collections: {
|
||||
uploads: {
|
||||
fields: [
|
||||
{
|
||||
name: 'caption',
|
||||
type: 'richText',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'richTextCustomFields',
|
||||
type: 'richText',
|
||||
admin: {
|
||||
elements: [
|
||||
'h1',
|
||||
'h2',
|
||||
'h3',
|
||||
'h4',
|
||||
'h5',
|
||||
'h6',
|
||||
'ul',
|
||||
'ol',
|
||||
'indent',
|
||||
'link',
|
||||
'relationship',
|
||||
'upload',
|
||||
],
|
||||
link: {
|
||||
fields: ({ defaultFields }) => {
|
||||
return [
|
||||
...defaultFields,
|
||||
{
|
||||
label: 'Custom',
|
||||
name: 'customLinkField',
|
||||
type: 'text',
|
||||
},
|
||||
];
|
||||
},
|
||||
},
|
||||
upload: {
|
||||
collections: {
|
||||
uploads: {
|
||||
fields: [
|
||||
{
|
||||
name: 'caption',
|
||||
type: 'richText',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'richTextReadOnly',
|
||||
type: 'richText',
|
||||
admin: {
|
||||
readOnly: true,
|
||||
elements: [
|
||||
'h1',
|
||||
'h2',
|
||||
'h3',
|
||||
'h4',
|
||||
'h5',
|
||||
'h6',
|
||||
'ul',
|
||||
'ol',
|
||||
'indent',
|
||||
'link',
|
||||
'relationship',
|
||||
'upload',
|
||||
],
|
||||
link: {
|
||||
fields: [
|
||||
{
|
||||
name: 'rel',
|
||||
label: 'Rel Attribute',
|
||||
type: 'select',
|
||||
hasMany: true,
|
||||
options: [
|
||||
'noopener', 'noreferrer', 'nofollow',
|
||||
],
|
||||
admin: {
|
||||
description: 'The rel attribute defines the relationship between a linked resource and the current document. This is a custom link field.',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
upload: {
|
||||
collections: {
|
||||
uploads: {
|
||||
fields: [
|
||||
{
|
||||
name: 'caption',
|
||||
type: 'richText',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'blocks',
|
||||
type: 'blocks',
|
||||
blocks: [
|
||||
{
|
||||
slug: 'textBlock',
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'richTextBlock',
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'richText',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
function generateRichText() {
|
||||
return [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: "Hello, I'm a rich text field.",
|
||||
},
|
||||
],
|
||||
type: 'h1',
|
||||
textAlign: 'center',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'I can do all kinds of fun stuff like ',
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
url: 'https://payloadcms.com',
|
||||
newTab: true,
|
||||
children: [
|
||||
{
|
||||
text: 'render links',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: ', ',
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
linkType: 'internal',
|
||||
doc: {
|
||||
value: '{{ARRAY_DOC_ID}}',
|
||||
relationTo: 'array-fields',
|
||||
},
|
||||
fields: {},
|
||||
children: [
|
||||
{
|
||||
text: 'link to relationships',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: ', and store nested relationship fields:',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: '',
|
||||
},
|
||||
],
|
||||
type: 'relationship',
|
||||
value: {
|
||||
id: '',
|
||||
},
|
||||
relationTo: 'text-fields',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'You can build your own elements, too.',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'ul',
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: "It's built with SlateJS",
|
||||
},
|
||||
],
|
||||
type: 'li',
|
||||
},
|
||||
{
|
||||
type: 'li',
|
||||
children: [
|
||||
{
|
||||
text: 'It stores content as JSON so you can use it wherever you need',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'li',
|
||||
children: [
|
||||
{
|
||||
text: "It's got a great editing experience for non-technical users",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'And a whole lot more.',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: '',
|
||||
},
|
||||
],
|
||||
type: 'upload',
|
||||
value: {
|
||||
id: '',
|
||||
},
|
||||
relationTo: 'uploads',
|
||||
fields: {
|
||||
caption: [
|
||||
...[...Array(4)].map(() => {
|
||||
return {
|
||||
children: [
|
||||
{
|
||||
text: loremIpsum,
|
||||
},
|
||||
],
|
||||
};
|
||||
}),
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
...[...Array(2)].map(() => {
|
||||
return {
|
||||
children: [
|
||||
{
|
||||
text: loremIpsum,
|
||||
},
|
||||
],
|
||||
};
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
export const richTextBulletsDoc = {
|
||||
title: 'Bullets and Indentation',
|
||||
richText: [
|
||||
{
|
||||
type: 'ul',
|
||||
children: [
|
||||
{
|
||||
type: 'li',
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'I am semantically connected to my sub-bullets',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'ul',
|
||||
children: [
|
||||
{
|
||||
type: 'li',
|
||||
children: [
|
||||
{
|
||||
text: 'I am sub-bullets that are semantically connected to the parent bullet',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'Normal bullet',
|
||||
},
|
||||
],
|
||||
type: 'li',
|
||||
},
|
||||
{
|
||||
type: 'li',
|
||||
children: [
|
||||
{
|
||||
type: 'ul',
|
||||
children: [
|
||||
{
|
||||
type: 'li',
|
||||
children: [
|
||||
{
|
||||
text: 'I am the old style of sub-bullet',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'li',
|
||||
children: [
|
||||
{
|
||||
text: 'Another normal bullet',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'li',
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'This text precedes a nested list',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'ul',
|
||||
children: [
|
||||
{
|
||||
type: 'li',
|
||||
children: [
|
||||
{
|
||||
text: 'I am a sub-bullet',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'li',
|
||||
children: [
|
||||
{
|
||||
text: 'And I am another sub-bullet',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const richTextBlocks = [
|
||||
{
|
||||
blockType: 'textBlock',
|
||||
text: 'Regular text',
|
||||
},
|
||||
{
|
||||
blockType: 'richTextBlock',
|
||||
text: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'Rich text',
|
||||
},
|
||||
],
|
||||
type: 'h1',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
export const richTextDoc = {
|
||||
title: 'Rich Text',
|
||||
selectHasMany: ['one', 'five'],
|
||||
richText: generateRichText(),
|
||||
richTextReadOnly: generateRichText(),
|
||||
richTextCustomFields: generateRichText(),
|
||||
blocks: richTextBlocks,
|
||||
};
|
||||
|
||||
export default RichTextFields;
|
||||
@@ -1 +0,0 @@
|
||||
export const loremIpsum = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam hendrerit nisi sed sollicitudin pellentesque. Nunc posuere purus rhoncus pulvinar aliquam. Ut aliquet tristique nisl vitae volutpat. Nulla aliquet porttitor venenatis. Donec a dui et dui fringilla consectetur id nec massa. Aliquam erat volutpat. Sed ut dui ut lacus dictum fermentum vel tincidunt neque. Sed sed lacinia lectus. Duis sit amet sodales felis. Duis nunc eros, mattis at dui ac, convallis semper risus. In adipiscing ultrices tellus, in suscipit massa vehicula eu.'
|
||||
@@ -1,32 +0,0 @@
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
|
||||
export const rowFieldsSlug = 'row-fields';
|
||||
|
||||
const RowFields: CollectionConfig = {
|
||||
slug: rowFieldsSlug,
|
||||
versions: true,
|
||||
admin: {
|
||||
defaultColumns: ['title', 'id'],
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'id',
|
||||
label: 'Custom ID',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
type: 'row',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
label: 'Title within a row',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default RowFields;
|
||||
@@ -1,133 +0,0 @@
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
|
||||
const SelectFields: CollectionConfig = {
|
||||
slug: 'select-fields',
|
||||
fields: [
|
||||
{
|
||||
name: 'select',
|
||||
type: 'select',
|
||||
admin: {
|
||||
isClearable: true,
|
||||
},
|
||||
options: [
|
||||
{
|
||||
label: 'Value One',
|
||||
value: 'one',
|
||||
},
|
||||
{
|
||||
label: 'Value Two',
|
||||
value: 'two',
|
||||
},
|
||||
{
|
||||
label: 'Value Three',
|
||||
value: 'three',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'selectReadOnly',
|
||||
type: 'select',
|
||||
admin: {
|
||||
readOnly: true,
|
||||
},
|
||||
options: [
|
||||
{
|
||||
label: 'Value One',
|
||||
value: 'one',
|
||||
},
|
||||
{
|
||||
label: 'Value Two',
|
||||
value: 'two',
|
||||
},
|
||||
{
|
||||
label: 'Value Three',
|
||||
value: 'three',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'selectHasMany',
|
||||
hasMany: true,
|
||||
type: 'select',
|
||||
admin: {
|
||||
isClearable: true,
|
||||
isSortable: true,
|
||||
},
|
||||
options: [
|
||||
{
|
||||
label: 'Value One',
|
||||
value: 'one',
|
||||
},
|
||||
{
|
||||
label: 'Value Two',
|
||||
value: 'two',
|
||||
},
|
||||
{
|
||||
label: 'Value Three',
|
||||
value: 'three',
|
||||
},
|
||||
{
|
||||
label: 'Value Four',
|
||||
value: 'four',
|
||||
},
|
||||
{
|
||||
label: 'Value Five',
|
||||
value: 'five',
|
||||
},
|
||||
{
|
||||
label: 'Value Six',
|
||||
value: 'six',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'selectHasManyLocalized',
|
||||
type: 'select',
|
||||
hasMany: true,
|
||||
localized: true,
|
||||
options: [
|
||||
{
|
||||
label: 'Value One',
|
||||
value: 'one',
|
||||
},
|
||||
{
|
||||
label: 'Value Two',
|
||||
value: 'two',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'selectI18n',
|
||||
type: 'select',
|
||||
admin: {
|
||||
isClearable: true,
|
||||
},
|
||||
options: [
|
||||
{
|
||||
value: 'one',
|
||||
label: { en: 'One', es: 'Uno' },
|
||||
},
|
||||
{
|
||||
value: 'two',
|
||||
label: { en: 'Two', es: 'Dos' },
|
||||
},
|
||||
{
|
||||
value: 'three',
|
||||
label: { en: 'Three', es: 'Tres' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'simple',
|
||||
type: 'select',
|
||||
options: ['One', 'Two', 'Three'],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const selectsDoc = {
|
||||
select: 'one',
|
||||
selectHasMany: ['two', 'four'],
|
||||
};
|
||||
|
||||
export default SelectFields;
|
||||
@@ -1,7 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
export const UIField: React.FC = () => {
|
||||
return (
|
||||
<p>This is a UI field within a tab component.</p>
|
||||
);
|
||||
};
|
||||
@@ -1,324 +0,0 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
import { blocksField, blocksFieldSeedData } from '../Blocks';
|
||||
import { UIField } from './UIField';
|
||||
|
||||
export const tabsSlug = 'tabs-fields';
|
||||
|
||||
export const namedTabText = 'Some text in a named tab';
|
||||
export const namedTabDefaultValue = 'default text inside of a named tab';
|
||||
export const localizedTextValue = 'localized text';
|
||||
|
||||
const TabsFields: CollectionConfig = {
|
||||
slug: tabsSlug,
|
||||
access: {
|
||||
read: () => true,
|
||||
},
|
||||
versions: true,
|
||||
fields: [
|
||||
{
|
||||
type: 'tabs',
|
||||
tabs: [
|
||||
{
|
||||
label: 'Tab with Array',
|
||||
description: 'This tab has an array.',
|
||||
fields: [
|
||||
{
|
||||
type: 'ui',
|
||||
name: 'demoUIField',
|
||||
label: 'Demo UI Field',
|
||||
admin: {
|
||||
components: {
|
||||
Field: UIField,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'array',
|
||||
labels: {
|
||||
singular: 'Item',
|
||||
plural: 'Items',
|
||||
},
|
||||
type: 'array',
|
||||
required: true,
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Tab with Blocks',
|
||||
description: 'Blocks are rendered here to ensure they populate and render correctly.',
|
||||
fields: [blocksField],
|
||||
},
|
||||
{
|
||||
label: 'Tab with Group',
|
||||
description: 'This tab has a group, which should not render its top border or margin.',
|
||||
fields: [
|
||||
{
|
||||
name: 'group',
|
||||
type: 'group',
|
||||
label: 'Group',
|
||||
fields: [
|
||||
{
|
||||
name: 'number',
|
||||
type: 'number',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Tab with Row',
|
||||
description: 'This tab has a row field.',
|
||||
fields: [
|
||||
{
|
||||
type: 'row',
|
||||
fields: [
|
||||
{
|
||||
name: 'textInRow',
|
||||
type: 'text',
|
||||
required: true,
|
||||
admin: {
|
||||
width: '50%',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'numberInRow',
|
||||
type: 'number',
|
||||
required: true,
|
||||
admin: {
|
||||
width: '50%',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'tab',
|
||||
label: 'Tab with Name',
|
||||
description: 'This tab has a name, which should namespace the contained fields.',
|
||||
fields: [
|
||||
{
|
||||
name: 'array',
|
||||
labels: {
|
||||
singular: 'Item',
|
||||
plural: 'Items',
|
||||
},
|
||||
type: 'array',
|
||||
required: true,
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'defaultValue',
|
||||
type: 'text',
|
||||
defaultValue: namedTabDefaultValue,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'namedTabWithDefaultValue',
|
||||
description: 'This tab has a name, which should namespace the contained fields.',
|
||||
fields: [
|
||||
{
|
||||
name: 'defaultValue',
|
||||
type: 'text',
|
||||
defaultValue: namedTabDefaultValue,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'localizedTab',
|
||||
label: { en: 'Localized Tab en', es: 'Localized Tab es' },
|
||||
localized: true,
|
||||
description: 'This tab is localized and requires a name',
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'accessControlTab',
|
||||
access: {
|
||||
read: () => false,
|
||||
},
|
||||
description: 'This tab is cannot be read',
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'hooksTab',
|
||||
label: 'Hooks Tab',
|
||||
hooks: {
|
||||
beforeValidate: [
|
||||
({ data = {} }) => {
|
||||
if (!data.hooksTab) data.hooksTab = {};
|
||||
data.hooksTab.beforeValidate = true;
|
||||
return data.hooksTab;
|
||||
},
|
||||
],
|
||||
beforeChange: [
|
||||
({ data = {} }) => {
|
||||
if (!data.hooksTab) data.hooksTab = {};
|
||||
data.hooksTab.beforeChange = true;
|
||||
return data.hooksTab;
|
||||
},
|
||||
],
|
||||
afterChange: [
|
||||
({ originalDoc }) => {
|
||||
originalDoc.hooksTab.afterChange = true;
|
||||
return originalDoc.hooksTab;
|
||||
},
|
||||
],
|
||||
afterRead: [
|
||||
({ data = {} }) => {
|
||||
if (!data.hooksTab) data.hooksTab = {};
|
||||
data.hooksTab.afterRead = true;
|
||||
return data.hooksTab;
|
||||
},
|
||||
],
|
||||
},
|
||||
description: 'This tab has hooks',
|
||||
fields: [
|
||||
{
|
||||
name: 'beforeValidate',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
name: 'beforeChange',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
name: 'afterChange',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
name: 'afterRead',
|
||||
type: 'checkbox',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'collapsible',
|
||||
label: 'Tabs within Collapsible',
|
||||
fields: [
|
||||
{
|
||||
type: 'tabs',
|
||||
tabs: [
|
||||
{
|
||||
label: 'Nested Tab One',
|
||||
description: 'Here is a description for a nested tab',
|
||||
fields: [
|
||||
{
|
||||
name: 'textarea',
|
||||
type: 'textarea',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Nested Tab Two',
|
||||
description: 'Description for tab two',
|
||||
fields: [
|
||||
{
|
||||
name: 'anotherText',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'nestedTab',
|
||||
label: 'Nested Tab with Name',
|
||||
description: 'This tab has a name, which should namespace the contained fields.',
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const tabsDoc = {
|
||||
array: [
|
||||
{
|
||||
text: "Hello, I'm the first row",
|
||||
},
|
||||
{
|
||||
text: 'Second row here',
|
||||
},
|
||||
{
|
||||
text: 'Here is some data for the third row',
|
||||
},
|
||||
],
|
||||
blocks: blocksFieldSeedData,
|
||||
group: {
|
||||
number: 12,
|
||||
},
|
||||
nestedTab: {
|
||||
text: 'Some text in a nested, named tab',
|
||||
},
|
||||
tab: {
|
||||
array: [
|
||||
{
|
||||
text: "Hello, I'm the first row, in a named tab",
|
||||
},
|
||||
{
|
||||
text: 'Second row here, in a named tab',
|
||||
},
|
||||
{
|
||||
text: 'Here is some data for the third row, in a named tab',
|
||||
},
|
||||
],
|
||||
text: namedTabText,
|
||||
},
|
||||
text: 'localized',
|
||||
localizedTab: {
|
||||
text: localizedTextValue,
|
||||
},
|
||||
accessControlTab: {
|
||||
text: 'cannot be read',
|
||||
},
|
||||
hooksTab: {
|
||||
beforeValidate: false,
|
||||
beforeChange: false,
|
||||
afterChange: false,
|
||||
afterRead: false,
|
||||
},
|
||||
textarea: 'Here is some text that goes in a textarea',
|
||||
anotherText: 'Super tired of writing this text',
|
||||
textInRow: 'hello',
|
||||
numberInRow: 235,
|
||||
};
|
||||
|
||||
export default TabsFields;
|
||||
@@ -1,88 +0,0 @@
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
|
||||
export const defaultText = 'default-text';
|
||||
export const textFieldsSlug = 'text-fields';
|
||||
|
||||
const TextFields: CollectionConfig = {
|
||||
slug: textFieldsSlug,
|
||||
admin: {
|
||||
useAsTitle: 'text',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'localizedText',
|
||||
type: 'text',
|
||||
localized: true,
|
||||
},
|
||||
{
|
||||
name: 'i18nText',
|
||||
type: 'text',
|
||||
label: {
|
||||
en: 'Text en',
|
||||
es: 'Text es',
|
||||
},
|
||||
admin: {
|
||||
placeholder: {
|
||||
en: 'en placeholder',
|
||||
es: 'es placeholder',
|
||||
},
|
||||
description: {
|
||||
en: 'en description',
|
||||
es: 'es description',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'defaultFunction',
|
||||
type: 'text',
|
||||
defaultValue: () => (defaultText),
|
||||
},
|
||||
{
|
||||
name: 'defaultAsync',
|
||||
type: 'text',
|
||||
defaultValue: async (): Promise<string> => {
|
||||
return new Promise((resolve) => setTimeout(() => {
|
||||
resolve(defaultText);
|
||||
}, 1));
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Override the 40k text length default',
|
||||
name: 'overrideLength',
|
||||
type: 'text',
|
||||
maxLength: 50000,
|
||||
},
|
||||
{
|
||||
name: 'fieldWithDefaultValue',
|
||||
type: 'text',
|
||||
defaultValue: async () => {
|
||||
const defaultValue = new Promise((resolve) => setTimeout(() => resolve('some-value'), 1000));
|
||||
|
||||
return defaultValue;
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'dependentOnFieldWithDefaultValue',
|
||||
type: 'text',
|
||||
hooks: {
|
||||
beforeChange: [
|
||||
({ data }) => {
|
||||
return data?.fieldWithDefaultValue || '';
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const textDoc = {
|
||||
text: 'Seeded text document',
|
||||
localizedText: 'Localized text',
|
||||
};
|
||||
|
||||
export default TextFields;
|
||||
1
test/fields/collections/Upload/.gitignore
vendored
1
test/fields/collections/Upload/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
uploads
|
||||
@@ -1,35 +0,0 @@
|
||||
import path from 'path';
|
||||
import { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
|
||||
const Uploads: CollectionConfig = {
|
||||
slug: 'uploads',
|
||||
upload: {
|
||||
staticDir: path.resolve(__dirname, './uploads'),
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'text',
|
||||
},
|
||||
{
|
||||
type: 'upload',
|
||||
name: 'media',
|
||||
relationTo: 'uploads',
|
||||
filterOptions: {
|
||||
mimeType: {
|
||||
equals: 'image/png',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'richText',
|
||||
name: 'richText',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const uploadsDoc = {
|
||||
text: 'An upload here',
|
||||
};
|
||||
|
||||
export default Uploads;
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 119 KiB |
1
test/fields/collections/Upload2/.gitignore
vendored
1
test/fields/collections/Upload2/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
uploads2
|
||||
@@ -1,30 +0,0 @@
|
||||
import path from 'path';
|
||||
import { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
|
||||
const Uploads2: CollectionConfig = {
|
||||
slug: 'uploads2',
|
||||
upload: {
|
||||
staticDir: path.resolve(__dirname, './uploads2'),
|
||||
},
|
||||
labels: {
|
||||
singular: 'Upload 2',
|
||||
plural: 'Uploads 2',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'text',
|
||||
},
|
||||
{
|
||||
type: 'upload',
|
||||
name: 'media',
|
||||
relationTo: 'uploads2',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const uploadsDoc = {
|
||||
text: 'An upload here',
|
||||
};
|
||||
|
||||
export default Uploads2;
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 119 KiB |
1
test/fields/collections/Uploads3/.gitignore
vendored
1
test/fields/collections/Uploads3/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
uploads3
|
||||
@@ -1,33 +0,0 @@
|
||||
import path from 'path';
|
||||
import { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
|
||||
const Uploads3: CollectionConfig = {
|
||||
slug: 'uploads3',
|
||||
upload: {
|
||||
staticDir: path.resolve(__dirname, './uploads3'),
|
||||
},
|
||||
labels: {
|
||||
singular: 'Upload 3',
|
||||
plural: 'Uploads 3',
|
||||
},
|
||||
admin: {
|
||||
enableRichTextRelationship: false,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
type: 'upload',
|
||||
name: 'media',
|
||||
relationTo: 'uploads3',
|
||||
},
|
||||
{
|
||||
type: 'richText',
|
||||
name: 'richText',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const uploadsDoc = {
|
||||
text: 'An upload here',
|
||||
};
|
||||
|
||||
export default Uploads3;
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 119 KiB |
@@ -1,151 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { buildConfigWithDefaults } from '../buildConfigWithDefaults';
|
||||
import { devUser } from '../credentials';
|
||||
import ArrayFields, { arrayDoc } from './collections/Array';
|
||||
import BlockFields, { blocksDoc } from './collections/Blocks';
|
||||
import CollapsibleFields, { collapsibleDoc } from './collections/Collapsible';
|
||||
import ConditionalLogic, { conditionalLogicDoc } from './collections/ConditionalLogic';
|
||||
import DateFields, { dateDoc } from './collections/Date';
|
||||
import RichTextFields, { richTextBulletsDoc, richTextDoc } from './collections/RichText';
|
||||
import SelectFields, { selectsDoc } from './collections/Select';
|
||||
import TabsFields, { tabsDoc } from './collections/Tabs';
|
||||
import TextFields, { textDoc, textFieldsSlug } from './collections/Text';
|
||||
import PointFields, { pointDoc } from './collections/Point';
|
||||
import GroupFields, { groupDoc } from './collections/Group';
|
||||
import getFileByPath from '../../src/uploads/getFileByPath';
|
||||
import Uploads, { uploadsDoc } from './collections/Upload';
|
||||
import IndexedFields from './collections/Indexed';
|
||||
import NumberFields, { numberDoc } from './collections/Number';
|
||||
import CodeFields, { codeDoc } from './collections/Code';
|
||||
import JSONFields, { jsonDoc } from './collections/JSON';
|
||||
import RelationshipFields from './collections/Relationship';
|
||||
import RadioFields, { radiosDoc } from './collections/Radio';
|
||||
import Uploads2 from './collections/Upload2';
|
||||
import Uploads3 from './collections/Uploads3';
|
||||
import RowFields from './collections/Row';
|
||||
|
||||
export default buildConfigWithDefaults({
|
||||
admin: {
|
||||
webpack: (config) => ({
|
||||
...config,
|
||||
resolve: {
|
||||
...config.resolve,
|
||||
alias: {
|
||||
...config?.resolve?.alias,
|
||||
fs: path.resolve(__dirname, './mocks/emptyModule.js'),
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
collections: [
|
||||
{
|
||||
slug: 'users',
|
||||
auth: true,
|
||||
admin: {
|
||||
useAsTitle: 'email',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'canViewConditionalField',
|
||||
type: 'checkbox',
|
||||
defaultValue: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
ArrayFields,
|
||||
BlockFields,
|
||||
CodeFields,
|
||||
CollapsibleFields,
|
||||
ConditionalLogic,
|
||||
DateFields,
|
||||
RadioFields,
|
||||
GroupFields,
|
||||
RowFields,
|
||||
IndexedFields,
|
||||
JSONFields,
|
||||
NumberFields,
|
||||
PointFields,
|
||||
RelationshipFields,
|
||||
RichTextFields,
|
||||
SelectFields,
|
||||
TabsFields,
|
||||
TextFields,
|
||||
Uploads,
|
||||
Uploads2,
|
||||
Uploads3,
|
||||
],
|
||||
localization: {
|
||||
defaultLocale: 'en',
|
||||
locales: ['en', 'es'],
|
||||
fallback: true,
|
||||
},
|
||||
onInit: async (payload) => {
|
||||
await payload.create({
|
||||
collection: 'users',
|
||||
data: {
|
||||
email: devUser.email,
|
||||
password: devUser.password,
|
||||
},
|
||||
});
|
||||
|
||||
const createdArrayDoc = await payload.create({ collection: 'array-fields', data: arrayDoc });
|
||||
await payload.create({ collection: 'collapsible-fields', data: collapsibleDoc });
|
||||
await payload.create({ collection: 'conditional-logic', data: conditionalLogicDoc });
|
||||
await payload.create({ collection: 'group-fields', data: groupDoc });
|
||||
await payload.create({ collection: 'select-fields', data: selectsDoc });
|
||||
await payload.create({ collection: 'radio-fields', data: radiosDoc });
|
||||
await payload.create({ collection: 'tabs-fields', data: tabsDoc });
|
||||
await payload.create({ collection: 'point-fields', data: pointDoc });
|
||||
await payload.create({ collection: 'date-fields', data: dateDoc });
|
||||
await payload.create({ collection: 'code-fields', data: codeDoc });
|
||||
await payload.create({ collection: 'json-fields', data: jsonDoc });
|
||||
|
||||
const createdTextDoc = await payload.create({ collection: textFieldsSlug, data: textDoc });
|
||||
|
||||
const uploadsDir = path.resolve(__dirname, './collections/Upload/uploads');
|
||||
|
||||
if (fs.existsSync(uploadsDir)) fs.readdirSync(uploadsDir).forEach((f) => fs.rmSync(`${uploadsDir}/${f}`));
|
||||
|
||||
const pngPath = path.resolve(__dirname, './uploads/payload.png');
|
||||
const pngFile = await getFileByPath(pngPath);
|
||||
const createdPNGDoc = await payload.create({ collection: 'uploads', data: {}, file: pngFile });
|
||||
|
||||
const jpgPath = path.resolve(__dirname, './collections/Upload/payload.jpg');
|
||||
const jpgFile = await getFileByPath(jpgPath);
|
||||
const createdJPGDoc = await payload.create({
|
||||
collection: 'uploads',
|
||||
data: {
|
||||
...uploadsDoc,
|
||||
media: createdPNGDoc.id,
|
||||
},
|
||||
file: jpgFile,
|
||||
});
|
||||
|
||||
const richTextDocWithRelId = JSON.parse(JSON.stringify(richTextDoc).replace(/{{ARRAY_DOC_ID}}/g, createdArrayDoc.id));
|
||||
const richTextDocWithRelationship = { ...richTextDocWithRelId };
|
||||
|
||||
const richTextRelationshipIndex = richTextDocWithRelationship.richText.findIndex(({ type }) => type === 'relationship');
|
||||
richTextDocWithRelationship.richText[richTextRelationshipIndex].value = { id: createdTextDoc.id };
|
||||
richTextDocWithRelationship.richTextReadOnly[richTextRelationshipIndex].value = { id: createdTextDoc.id };
|
||||
|
||||
const richTextUploadIndex = richTextDocWithRelationship.richText.findIndex(({ type }) => type === 'upload');
|
||||
richTextDocWithRelationship.richText[richTextUploadIndex].value = { id: createdJPGDoc.id };
|
||||
richTextDocWithRelationship.richTextReadOnly[richTextUploadIndex].value = { id: createdJPGDoc.id };
|
||||
|
||||
await payload.create({ collection: 'rich-text-fields', data: richTextBulletsDoc });
|
||||
await payload.create({ collection: 'rich-text-fields', data: richTextDocWithRelationship });
|
||||
|
||||
await payload.create({ collection: 'number-fields', data: numberDoc });
|
||||
|
||||
const blocksDocWithRichText = { ...blocksDoc };
|
||||
|
||||
// @ts-ignore
|
||||
blocksDocWithRichText.blocks[0].richText = richTextDocWithRelationship.richText;
|
||||
// @ts-ignore
|
||||
blocksDocWithRichText.localizedBlocks[0].richText = richTextDocWithRelationship.richText;
|
||||
|
||||
await payload.create({ collection: 'block-fields', data: blocksDocWithRichText });
|
||||
},
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,780 +0,0 @@
|
||||
import type { IndexDirection, IndexOptions } from 'mongoose';
|
||||
import { GraphQLClient } from 'graphql-request';
|
||||
import { initPayloadTest } from '../helpers/configHelpers';
|
||||
import { RESTClient } from '../helpers/rest';
|
||||
import configPromise from '../uploads/config';
|
||||
import payload from '../../src';
|
||||
import { pointDoc } from './collections/Point';
|
||||
import { arrayDefaultValue, arrayDoc, arrayFieldsSlug } from './collections/Array';
|
||||
import { groupDefaultChild, groupDefaultValue, groupDoc, groupFieldsSlug } from './collections/Group';
|
||||
import { defaultText } from './collections/Text';
|
||||
import { blocksFieldSeedData } from './collections/Blocks';
|
||||
import { localizedTextValue, namedTabDefaultValue, namedTabText, tabsDoc, tabsSlug } from './collections/Tabs';
|
||||
import { defaultNumber, numberDoc } from './collections/Number';
|
||||
import { dateDoc } from './collections/Date';
|
||||
import type { RichTextField } from './payload-types';
|
||||
import type { PaginatedDocs } from '../../src/database/types';
|
||||
import type { MongooseAdapter } from '../../packages/db-mongodb/src';
|
||||
|
||||
let client;
|
||||
let graphQLClient: GraphQLClient;
|
||||
let serverURL;
|
||||
let config;
|
||||
let token;
|
||||
|
||||
describe('Fields', () => {
|
||||
beforeAll(async () => {
|
||||
({ serverURL } = await initPayloadTest({ __dirname, init: { local: false } }));
|
||||
config = await configPromise;
|
||||
|
||||
client = new RESTClient(config, { serverURL, defaultSlug: 'point-fields' });
|
||||
const graphQLURL = `${serverURL}${config.routes.api}${config.routes.graphQL}`;
|
||||
graphQLClient = new GraphQLClient(graphQLURL);
|
||||
token = await client.login();
|
||||
});
|
||||
|
||||
describe('text', () => {
|
||||
let doc;
|
||||
const text = 'text field';
|
||||
beforeAll(async () => {
|
||||
doc = await payload.create({
|
||||
collection: 'text-fields',
|
||||
data: { text },
|
||||
});
|
||||
});
|
||||
|
||||
it('creates with default values', () => {
|
||||
expect(doc.text).toEqual(text);
|
||||
expect(doc.defaultFunction).toEqual(defaultText);
|
||||
expect(doc.defaultAsync).toEqual(defaultText);
|
||||
});
|
||||
|
||||
it('should populate default values in beforeValidate hook', async () => {
|
||||
const { fieldWithDefaultValue, dependentOnFieldWithDefaultValue } = await payload.create({
|
||||
collection: 'text-fields',
|
||||
data: { text },
|
||||
});
|
||||
|
||||
await expect(fieldWithDefaultValue).toEqual(dependentOnFieldWithDefaultValue);
|
||||
});
|
||||
});
|
||||
|
||||
describe('timestamps', () => {
|
||||
const tenMinutesAgo = new Date(Date.now() - 1000 * 60 * 10);
|
||||
let doc;
|
||||
beforeAll(async () => {
|
||||
doc = await payload.create({
|
||||
collection: 'date-fields',
|
||||
data: dateDoc,
|
||||
});
|
||||
});
|
||||
|
||||
it('should query updatedAt', async () => {
|
||||
const { docs } = await payload.find({
|
||||
collection: 'date-fields',
|
||||
depth: 0,
|
||||
where: {
|
||||
updatedAt: {
|
||||
greater_than_equal: tenMinutesAgo,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(docs.map(({ id }) => id)).toContain(doc.id);
|
||||
});
|
||||
|
||||
it('should query createdAt', async () => {
|
||||
const result = await payload.find({
|
||||
collection: 'date-fields',
|
||||
depth: 0,
|
||||
where: {
|
||||
createdAt: {
|
||||
greater_than_equal: tenMinutesAgo,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.docs[0].id).toEqual(doc.id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('select', () => {
|
||||
let doc;
|
||||
beforeAll(async () => {
|
||||
const { id } = await payload.create({
|
||||
collection: 'select-fields',
|
||||
locale: 'en',
|
||||
data: {
|
||||
selectHasManyLocalized: ['one', 'two'],
|
||||
},
|
||||
});
|
||||
doc = await payload.findByID({
|
||||
collection: 'select-fields',
|
||||
locale: 'all',
|
||||
id,
|
||||
});
|
||||
});
|
||||
|
||||
it('creates with hasMany localized', () => {
|
||||
expect(doc.selectHasManyLocalized.en).toEqual(['one', 'two']);
|
||||
});
|
||||
|
||||
it('retains hasMany updates', async () => {
|
||||
const { id } = await payload.create({
|
||||
collection: 'select-fields',
|
||||
data: {
|
||||
selectHasMany: ['one', 'two'],
|
||||
},
|
||||
});
|
||||
|
||||
const updatedDoc = await payload.update({
|
||||
collection: 'select-fields',
|
||||
id,
|
||||
data: {
|
||||
select: 'one',
|
||||
},
|
||||
});
|
||||
|
||||
expect(Array.isArray(updatedDoc.selectHasMany)).toBe(true);
|
||||
expect(updatedDoc.selectHasMany).toEqual(['one', 'two']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('number', () => {
|
||||
let doc;
|
||||
beforeAll(async () => {
|
||||
doc = await payload.create({
|
||||
collection: 'number-fields',
|
||||
data: numberDoc,
|
||||
});
|
||||
});
|
||||
|
||||
it('creates with default values', async () => {
|
||||
expect(doc.number).toEqual(numberDoc.number);
|
||||
expect(doc.min).toEqual(numberDoc.min);
|
||||
expect(doc.max).toEqual(numberDoc.max);
|
||||
expect(doc.positiveNumber).toEqual(numberDoc.positiveNumber);
|
||||
expect(doc.negativeNumber).toEqual(numberDoc.negativeNumber);
|
||||
expect(doc.decimalMin).toEqual(numberDoc.decimalMin);
|
||||
expect(doc.decimalMax).toEqual(numberDoc.decimalMax);
|
||||
expect(doc.defaultNumber).toEqual(defaultNumber);
|
||||
});
|
||||
|
||||
it('should not create number below minimum', async () => {
|
||||
await expect(async () => payload.create({
|
||||
collection: 'number-fields',
|
||||
data: {
|
||||
min: 5,
|
||||
},
|
||||
})).rejects.toThrow('The following field is invalid: min');
|
||||
});
|
||||
it('should not create number above max', async () => {
|
||||
await expect(async () => payload.create({
|
||||
collection: 'number-fields',
|
||||
data: {
|
||||
max: 15,
|
||||
},
|
||||
})).rejects.toThrow('The following field is invalid: max');
|
||||
});
|
||||
|
||||
it('should not create number below 0', async () => {
|
||||
await expect(async () => payload.create({
|
||||
collection: 'number-fields',
|
||||
data: {
|
||||
positiveNumber: -5,
|
||||
},
|
||||
})).rejects.toThrow('The following field is invalid: positiveNumber');
|
||||
});
|
||||
|
||||
it('should not create number above 0', async () => {
|
||||
await expect(async () => payload.create({
|
||||
collection: 'number-fields',
|
||||
data: {
|
||||
negativeNumber: 5,
|
||||
},
|
||||
})).rejects.toThrow('The following field is invalid: negativeNumber');
|
||||
});
|
||||
it('should not create a decimal number below min', async () => {
|
||||
await expect(async () => payload.create({
|
||||
collection: 'number-fields',
|
||||
data: {
|
||||
decimalMin: -0.25,
|
||||
},
|
||||
})).rejects.toThrow('The following field is invalid: decimalMin');
|
||||
});
|
||||
|
||||
it('should not create a decimal number above max', async () => {
|
||||
await expect(async () => payload.create({
|
||||
collection: 'number-fields',
|
||||
data: {
|
||||
decimalMax: 1.5,
|
||||
},
|
||||
})).rejects.toThrow('The following field is invalid: decimalMax');
|
||||
});
|
||||
it('should localize an array of numbers using hasMany', async () => {
|
||||
const localizedHasMany = [5, 10];
|
||||
const { id } = await payload.create({
|
||||
collection: 'number-fields',
|
||||
locale: 'en',
|
||||
data: {
|
||||
localizedHasMany,
|
||||
},
|
||||
});
|
||||
const localizedDoc = await payload.findByID({
|
||||
collection: 'number-fields',
|
||||
locale: 'all',
|
||||
id,
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
expect(localizedDoc.localizedHasMany.en).toEqual(localizedHasMany);
|
||||
});
|
||||
});
|
||||
|
||||
describe('indexes', () => {
|
||||
let indexes;
|
||||
const definitions: Record<string, IndexDirection> = {};
|
||||
const options: Record<string, IndexOptions> = {};
|
||||
|
||||
beforeAll(() => {
|
||||
indexes = (payload.db as MongooseAdapter).collections['indexed-fields'].schema.indexes() as [Record<string, IndexDirection>, IndexOptions];
|
||||
|
||||
indexes.forEach((index) => {
|
||||
const field = Object.keys(index[0])[0];
|
||||
definitions[field] = index[0][field];
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
options[field] = index[1];
|
||||
});
|
||||
});
|
||||
|
||||
it('should have indexes', () => {
|
||||
expect(definitions.text).toEqual(1);
|
||||
});
|
||||
it('should have unique indexes', () => {
|
||||
expect(definitions.uniqueText).toEqual(1);
|
||||
expect(options.uniqueText).toMatchObject({ unique: true });
|
||||
});
|
||||
it('should have 2dsphere indexes on point fields', () => {
|
||||
expect(definitions.point).toEqual('2dsphere');
|
||||
});
|
||||
it('should have 2dsphere indexes on point fields in groups', () => {
|
||||
expect(definitions['group.point']).toEqual('2dsphere');
|
||||
});
|
||||
it('should have a sparse index on a unique localized field in a group', () => {
|
||||
expect(definitions['group.localizedUnique.en']).toEqual(1);
|
||||
expect(options['group.localizedUnique.en']).toMatchObject({ unique: true, sparse: true });
|
||||
expect(definitions['group.localizedUnique.es']).toEqual(1);
|
||||
expect(options['group.localizedUnique.es']).toMatchObject({ unique: true, sparse: true });
|
||||
});
|
||||
it('should have unique indexes in a collapsible', () => {
|
||||
expect(definitions['collapsibleLocalizedUnique.en']).toEqual(1);
|
||||
expect(options['collapsibleLocalizedUnique.en']).toMatchObject({ unique: true, sparse: true });
|
||||
expect(definitions.collapsibleTextUnique).toEqual(1);
|
||||
expect(options.collapsibleTextUnique).toMatchObject({ unique: true });
|
||||
});
|
||||
it('should have unique compound indexes', () => {
|
||||
expect(definitions.partOne).toEqual(1);
|
||||
expect(options.partOne).toMatchObject({ unique: true, name: 'compound-index', sparse: true });
|
||||
});
|
||||
it('should throw validation error saving on unique fields', async () => {
|
||||
const data = {
|
||||
text: 'a',
|
||||
uniqueText: 'a',
|
||||
};
|
||||
await payload.create({
|
||||
collection: 'indexed-fields',
|
||||
data,
|
||||
});
|
||||
expect(async () => {
|
||||
const result = await payload.create({
|
||||
collection: 'indexed-fields',
|
||||
data,
|
||||
});
|
||||
return result.error;
|
||||
}).toBeDefined();
|
||||
});
|
||||
it('should throw validation error saving on unique combined fields', async () => {
|
||||
await payload.delete({ collection: 'indexed-fields', where: {} });
|
||||
const data1 = {
|
||||
text: 'a',
|
||||
uniqueText: 'a',
|
||||
partOne: 'u',
|
||||
partTwo: 'u',
|
||||
};
|
||||
const data2 = {
|
||||
text: 'b',
|
||||
uniqueText: 'b',
|
||||
partOne: 'u',
|
||||
partTwo: 'u',
|
||||
};
|
||||
await payload.create({
|
||||
collection: 'indexed-fields',
|
||||
data: data1,
|
||||
});
|
||||
expect(async () => {
|
||||
const result = await payload.create({
|
||||
collection: 'indexed-fields',
|
||||
data: data2,
|
||||
});
|
||||
return result.error;
|
||||
}).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('version indexes', () => {
|
||||
let indexes;
|
||||
const definitions: Record<string, IndexDirection> = {};
|
||||
const options: Record<string, IndexOptions> = {};
|
||||
|
||||
beforeAll(() => {
|
||||
indexes = (payload.db as MongooseAdapter).versions['indexed-fields'].schema.indexes() as [Record<string, IndexDirection>, IndexOptions];
|
||||
indexes.forEach((index) => {
|
||||
const field = Object.keys(index[0])[0];
|
||||
definitions[field] = index[0][field];
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
options[field] = index[1];
|
||||
});
|
||||
});
|
||||
|
||||
it('should have versions indexes', () => {
|
||||
expect(definitions['version.text']).toEqual(1);
|
||||
});
|
||||
it('should have version indexes from collection indexes', () => {
|
||||
expect(definitions['version.partOne']).toEqual(1);
|
||||
expect(options['version.partOne']).toMatchObject({ unique: true, name: 'compound-index', sparse: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe('point', () => {
|
||||
let doc;
|
||||
const point = [7, -7];
|
||||
const localized = [5, -2];
|
||||
const group = { point: [1, 9] };
|
||||
|
||||
beforeAll(async () => {
|
||||
const findDoc = await payload.find({
|
||||
collection: 'point-fields',
|
||||
pagination: false,
|
||||
});
|
||||
[doc] = findDoc.docs;
|
||||
});
|
||||
|
||||
it('should read', async () => {
|
||||
const find = await payload.find({
|
||||
collection: 'point-fields',
|
||||
pagination: false,
|
||||
});
|
||||
|
||||
[doc] = find.docs;
|
||||
|
||||
expect(doc.point).toEqual(pointDoc.point);
|
||||
expect(doc.localized).toEqual(pointDoc.localized);
|
||||
expect(doc.group).toMatchObject(pointDoc.group);
|
||||
});
|
||||
|
||||
it('should create', async () => {
|
||||
doc = await payload.create({
|
||||
collection: 'point-fields',
|
||||
data: {
|
||||
point,
|
||||
localized,
|
||||
group,
|
||||
},
|
||||
});
|
||||
|
||||
expect(doc.point).toEqual(point);
|
||||
expect(doc.localized).toEqual(localized);
|
||||
expect(doc.group).toMatchObject(group);
|
||||
});
|
||||
|
||||
it('should not create duplicate point when unique', async () => {
|
||||
await expect(() => payload.create({
|
||||
collection: 'point-fields',
|
||||
data: {
|
||||
point,
|
||||
localized,
|
||||
group,
|
||||
},
|
||||
}))
|
||||
.rejects
|
||||
.toThrow(Error);
|
||||
|
||||
await expect(async () => payload.create({
|
||||
collection: 'number-fields',
|
||||
data: {
|
||||
min: 5,
|
||||
},
|
||||
})).rejects.toThrow('The following field is invalid: min');
|
||||
|
||||
expect(doc.point).toEqual(point);
|
||||
expect(doc.localized).toEqual(localized);
|
||||
expect(doc.group).toMatchObject(group);
|
||||
});
|
||||
});
|
||||
describe('array', () => {
|
||||
let doc;
|
||||
const collection = arrayFieldsSlug;
|
||||
|
||||
beforeAll(async () => {
|
||||
doc = await payload.create({
|
||||
collection,
|
||||
data: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should return undefined arrays when no data present', async () => {
|
||||
const document = await payload.create({
|
||||
collection: arrayFieldsSlug,
|
||||
data: arrayDoc,
|
||||
});
|
||||
|
||||
expect(document.potentiallyEmptyArray).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should create with ids and nested ids', async () => {
|
||||
const docWithIDs = await payload.create({
|
||||
collection: groupFieldsSlug,
|
||||
data: groupDoc,
|
||||
});
|
||||
expect(docWithIDs.group.subGroup.arrayWithinGroup[0].id).toBeDefined();
|
||||
});
|
||||
|
||||
it('should create with defaultValue', async () => {
|
||||
expect(doc.items).toMatchObject(arrayDefaultValue);
|
||||
expect(doc.localized).toMatchObject(arrayDefaultValue);
|
||||
});
|
||||
|
||||
it('should update without overwriting other locales with defaultValue', async () => {
|
||||
const localized = [{ text: 'unique' }];
|
||||
const enText = 'english';
|
||||
const esText = 'spanish';
|
||||
const { id } = await payload.create({
|
||||
collection,
|
||||
data: {
|
||||
localized,
|
||||
},
|
||||
});
|
||||
|
||||
const enDoc = await payload.update({
|
||||
collection,
|
||||
id,
|
||||
locale: 'en',
|
||||
data: {
|
||||
localized: [{ text: enText }],
|
||||
},
|
||||
});
|
||||
|
||||
const esDoc = await payload.update({
|
||||
collection,
|
||||
id,
|
||||
locale: 'es',
|
||||
data: {
|
||||
localized: [{ text: esText }],
|
||||
},
|
||||
});
|
||||
|
||||
const allLocales = await payload.findByID({
|
||||
collection,
|
||||
id,
|
||||
locale: 'all',
|
||||
}) as unknown as { localized: { en: unknown, es: unknown } };
|
||||
|
||||
expect(enDoc.localized[0].text).toStrictEqual(enText);
|
||||
expect(esDoc.localized[0].text).toStrictEqual(esText);
|
||||
expect(allLocales.localized.en[0].text).toStrictEqual(enText);
|
||||
expect(allLocales.localized.es[0].text).toStrictEqual(esText);
|
||||
});
|
||||
});
|
||||
|
||||
describe('group', () => {
|
||||
let document;
|
||||
|
||||
beforeAll(async () => {
|
||||
document = await payload.create({
|
||||
collection: groupFieldsSlug,
|
||||
data: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should create with defaultValue', async () => {
|
||||
expect(document.group.defaultParent).toStrictEqual(groupDefaultValue);
|
||||
expect(document.group.defaultChild).toStrictEqual(groupDefaultChild);
|
||||
});
|
||||
});
|
||||
|
||||
describe('tabs', () => {
|
||||
let document;
|
||||
|
||||
beforeAll(async () => {
|
||||
document = await payload.create({
|
||||
collection: tabsSlug,
|
||||
data: tabsDoc,
|
||||
});
|
||||
});
|
||||
|
||||
it('should create with fields inside a named tab', async () => {
|
||||
expect(document.tab.text).toStrictEqual(namedTabText);
|
||||
});
|
||||
|
||||
it('should create with defaultValue inside a named tab', async () => {
|
||||
expect(document.tab.defaultValue).toStrictEqual(namedTabDefaultValue);
|
||||
});
|
||||
|
||||
it('should create with defaultValue inside a named tab with no other values', async () => {
|
||||
expect(document.namedTabWithDefaultValue.defaultValue).toStrictEqual(namedTabDefaultValue);
|
||||
});
|
||||
|
||||
it('should create with localized text inside a named tab', async () => {
|
||||
document = await payload.findByID({
|
||||
collection: tabsSlug,
|
||||
id: document.id,
|
||||
locale: 'all',
|
||||
});
|
||||
expect(document.localizedTab.en.text).toStrictEqual(localizedTextValue);
|
||||
});
|
||||
|
||||
it('should allow access control on a named tab', async () => {
|
||||
document = await payload.findByID({
|
||||
collection: tabsSlug,
|
||||
id: document.id,
|
||||
overrideAccess: false,
|
||||
});
|
||||
expect(document.accessControlTab).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should allow hooks on a named tab', async () => {
|
||||
const newDocument = await payload.create({
|
||||
collection: tabsSlug,
|
||||
data: tabsDoc,
|
||||
});
|
||||
expect(newDocument.hooksTab.beforeValidate).toBe(true);
|
||||
expect(newDocument.hooksTab.beforeChange).toBe(true);
|
||||
expect(newDocument.hooksTab.afterChange).toBe(true);
|
||||
expect(newDocument.hooksTab.afterRead).toBe(true);
|
||||
});
|
||||
|
||||
it('should return empty object for groups when no data present', async () => {
|
||||
const doc = await payload.create({
|
||||
collection: groupFieldsSlug,
|
||||
data: groupDoc,
|
||||
});
|
||||
|
||||
expect(doc.potentiallyEmptyGroup).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('blocks', () => {
|
||||
it('should retrieve doc with blocks', async () => {
|
||||
const blockFields = await payload.find({
|
||||
collection: 'block-fields',
|
||||
});
|
||||
|
||||
expect(blockFields.docs[0].blocks[0].blockType).toEqual(blocksFieldSeedData[0].blockType);
|
||||
expect(blockFields.docs[0].blocks[0].text).toEqual(blocksFieldSeedData[0].text);
|
||||
|
||||
expect(blockFields.docs[0].blocks[2].blockType).toEqual(blocksFieldSeedData[2].blockType);
|
||||
expect(blockFields.docs[0].blocks[2].blockName).toEqual(blocksFieldSeedData[2].blockName);
|
||||
expect(blockFields.docs[0].blocks[2].subBlocks[0].number).toEqual(blocksFieldSeedData[2].subBlocks[0].number);
|
||||
expect(blockFields.docs[0].blocks[2].subBlocks[1].text).toEqual(blocksFieldSeedData[2].subBlocks[1].text);
|
||||
});
|
||||
|
||||
it('should query based on richtext data within a block', async () => {
|
||||
const blockFieldsSuccess = await payload.find({
|
||||
collection: 'block-fields',
|
||||
where: {
|
||||
'blocks.richText.children.text': {
|
||||
like: 'fun',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(blockFieldsSuccess.docs).toHaveLength(1);
|
||||
|
||||
const blockFieldsFail = await payload.find({
|
||||
collection: 'block-fields',
|
||||
where: {
|
||||
'blocks.richText.children.text': {
|
||||
like: 'funny',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(blockFieldsFail.docs).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should query based on richtext data within a localized block, specifying locale', async () => {
|
||||
const blockFieldsSuccess = await payload.find({
|
||||
collection: 'block-fields',
|
||||
where: {
|
||||
'localizedBlocks.en.richText.children.text': {
|
||||
like: 'fun',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(blockFieldsSuccess.docs).toHaveLength(1);
|
||||
|
||||
const blockFieldsFail = await payload.find({
|
||||
collection: 'block-fields',
|
||||
where: {
|
||||
'localizedBlocks.en.richText.children.text': {
|
||||
like: 'funny',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(blockFieldsFail.docs).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should query based on richtext data within a localized block, without specifying locale', async () => {
|
||||
const blockFieldsSuccess = await payload.find({
|
||||
collection: 'block-fields',
|
||||
where: {
|
||||
'localizedBlocks.richText.children.text': {
|
||||
like: 'fun',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(blockFieldsSuccess.docs).toHaveLength(1);
|
||||
|
||||
const blockFieldsFail = await payload.find({
|
||||
collection: 'block-fields',
|
||||
where: {
|
||||
'localizedBlocks.richText.children.text': {
|
||||
like: 'funny',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(blockFieldsFail.docs).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('json', () => {
|
||||
it('should save json data', async () => {
|
||||
const json = { foo: 'bar' };
|
||||
const doc = await payload.create({
|
||||
collection: 'json-fields',
|
||||
data: {
|
||||
json,
|
||||
},
|
||||
});
|
||||
|
||||
expect(doc.json).toStrictEqual({ foo: 'bar' });
|
||||
});
|
||||
|
||||
it('should validate json', async () => {
|
||||
await expect(async () => payload.create({
|
||||
collection: 'json-fields',
|
||||
data: {
|
||||
json: '{ bad input: true }',
|
||||
},
|
||||
})).rejects.toThrow('The following field is invalid: json');
|
||||
});
|
||||
|
||||
it('should save empty json objects', async () => {
|
||||
const jsonFieldsDoc = await payload.create({
|
||||
collection: 'json-fields',
|
||||
data: {
|
||||
json: {
|
||||
state: {},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(jsonFieldsDoc.json.state).toEqual({});
|
||||
|
||||
const updatedJsonFieldsDoc = await payload.update({
|
||||
collection: 'json-fields',
|
||||
id: jsonFieldsDoc.id,
|
||||
data: {
|
||||
json: {
|
||||
state: {},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(updatedJsonFieldsDoc.json.state).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('richText', () => {
|
||||
it('should allow querying on rich text content', async () => {
|
||||
const emptyRichTextQuery = await payload.find({
|
||||
collection: 'rich-text-fields',
|
||||
where: {
|
||||
'richText.children.text': {
|
||||
like: 'doesnt exist',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(emptyRichTextQuery.docs).toHaveLength(0);
|
||||
|
||||
const workingRichTextQuery = await payload.find({
|
||||
collection: 'rich-text-fields',
|
||||
where: {
|
||||
'richText.children.text': {
|
||||
like: 'hello',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(workingRichTextQuery.docs).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should show center alignment', async () => {
|
||||
const query = await payload.find({
|
||||
collection: 'rich-text-fields',
|
||||
where: {
|
||||
'richText.children.text': {
|
||||
like: 'hello',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(query.docs[0].richText[0].textAlign).toEqual('center');
|
||||
});
|
||||
|
||||
it('should populate link relationship', async () => {
|
||||
const query = await payload.find({
|
||||
collection: 'rich-text-fields',
|
||||
where: {
|
||||
'richText.children.linkType': {
|
||||
equals: 'internal',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const nodes = query.docs[0].richText;
|
||||
expect(nodes).toBeDefined();
|
||||
const child = nodes.flatMap((n) => n.children)
|
||||
.find((c) => c.doc);
|
||||
expect(child).toMatchObject({
|
||||
type: 'link',
|
||||
linkType: 'internal',
|
||||
});
|
||||
expect(child.doc.relationTo).toEqual('array-fields');
|
||||
expect(typeof child.doc.value.id).toBe('string');
|
||||
expect(child.doc.value.items).toHaveLength(6);
|
||||
});
|
||||
|
||||
it('should respect rich text depth parameter', async () => {
|
||||
const query = `query {
|
||||
RichTextFields {
|
||||
docs {
|
||||
richText(depth: 2)
|
||||
}
|
||||
}
|
||||
}`;
|
||||
const response = await graphQLClient.request(query, {}, {
|
||||
Authorization: `JWT ${token}`,
|
||||
});
|
||||
const { docs }: PaginatedDocs<RichTextField> = response.RichTextFields;
|
||||
const uploadElement = docs[0].richText.find((el) => el.type === 'upload') as any;
|
||||
expect(uploadElement.value.media.filename).toStrictEqual('payload.png');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1 +0,0 @@
|
||||
export default {};
|
||||
@@ -1,592 +0,0 @@
|
||||
/* tslint:disable */
|
||||
/**
|
||||
* This file was automatically generated by Payload.
|
||||
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
|
||||
* and re-run `payload generate:types` to regenerate this file.
|
||||
*/
|
||||
|
||||
export interface Config {
|
||||
collections: {
|
||||
users: User;
|
||||
'array-fields': ArrayField;
|
||||
'block-fields': BlockField;
|
||||
'code-fields': CodeField;
|
||||
'collapsible-fields': CollapsibleField;
|
||||
'conditional-logic': ConditionalLogic;
|
||||
'date-fields': DateField;
|
||||
'radio-fields': RadioField;
|
||||
'group-fields': GroupField;
|
||||
'row-fields': RowField;
|
||||
'indexed-fields': IndexedField;
|
||||
'json-fields': JsonField;
|
||||
'number-fields': NumberField;
|
||||
'point-fields': PointField;
|
||||
'relationship-fields': RelationshipField;
|
||||
'rich-text-fields': RichTextField;
|
||||
'select-fields': SelectField;
|
||||
'tabs-fields': TabsField;
|
||||
'text-fields': TextField;
|
||||
uploads: Upload;
|
||||
uploads2: Uploads2;
|
||||
uploads3: Uploads3;
|
||||
};
|
||||
globals: {};
|
||||
}
|
||||
export interface User {
|
||||
id: string;
|
||||
canViewConditionalField?: boolean;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
email: string;
|
||||
resetPasswordToken?: string;
|
||||
resetPasswordExpiration?: string;
|
||||
salt?: string;
|
||||
hash?: string;
|
||||
loginAttempts?: number;
|
||||
lockUntil?: string;
|
||||
password?: string;
|
||||
}
|
||||
export interface ArrayField {
|
||||
id: string;
|
||||
items: {
|
||||
text: string;
|
||||
id?: string;
|
||||
}[];
|
||||
collapsedArray?: {
|
||||
text: string;
|
||||
id?: string;
|
||||
}[];
|
||||
localized: {
|
||||
text: string;
|
||||
id?: string;
|
||||
}[];
|
||||
readOnly?: {
|
||||
text?: string;
|
||||
id?: string;
|
||||
}[];
|
||||
potentiallyEmptyArray?: {
|
||||
text?: string;
|
||||
id?: string;
|
||||
}[];
|
||||
rowLabelAsFunction?: {
|
||||
title?: string;
|
||||
id?: string;
|
||||
}[];
|
||||
rowLabelAsComponent?: {
|
||||
title?: string;
|
||||
id?: string;
|
||||
}[];
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface BlockField {
|
||||
id: string;
|
||||
blocks: (
|
||||
| {
|
||||
text: string;
|
||||
richText?: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'text';
|
||||
}
|
||||
| {
|
||||
number: number;
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'number';
|
||||
}
|
||||
| {
|
||||
subBlocks?: (
|
||||
| {
|
||||
text: string;
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'text';
|
||||
}
|
||||
| {
|
||||
number: number;
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'number';
|
||||
}
|
||||
)[];
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'subBlocks';
|
||||
}
|
||||
| {
|
||||
textInCollapsible?: string;
|
||||
textInRow?: string;
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'tabs';
|
||||
}
|
||||
)[];
|
||||
collapsedByDefaultBlocks: (
|
||||
| {
|
||||
text: string;
|
||||
richText?: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'text';
|
||||
}
|
||||
| {
|
||||
number: number;
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'number';
|
||||
}
|
||||
| {
|
||||
subBlocks?: (
|
||||
| {
|
||||
text: string;
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'text';
|
||||
}
|
||||
| {
|
||||
number: number;
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'number';
|
||||
}
|
||||
)[];
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'subBlocks';
|
||||
}
|
||||
| {
|
||||
textInCollapsible?: string;
|
||||
textInRow?: string;
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'tabs';
|
||||
}
|
||||
)[];
|
||||
localizedBlocks: (
|
||||
| {
|
||||
text: string;
|
||||
richText?: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'text';
|
||||
}
|
||||
| {
|
||||
number: number;
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'number';
|
||||
}
|
||||
| {
|
||||
subBlocks?: (
|
||||
| {
|
||||
text: string;
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'text';
|
||||
}
|
||||
| {
|
||||
number: number;
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'number';
|
||||
}
|
||||
)[];
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'subBlocks';
|
||||
}
|
||||
| {
|
||||
textInCollapsible?: string;
|
||||
textInRow?: string;
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'tabs';
|
||||
}
|
||||
)[];
|
||||
i18nBlocks?: {
|
||||
text?: string;
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'text';
|
||||
}[];
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface CodeField {
|
||||
id: string;
|
||||
javascript?: string;
|
||||
typescript?: string;
|
||||
json?: string;
|
||||
html?: string;
|
||||
css?: string;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface CollapsibleField {
|
||||
id: string;
|
||||
text: string;
|
||||
group?: {
|
||||
textWithinGroup?: string;
|
||||
subGroup?: {
|
||||
textWithinSubGroup?: string;
|
||||
};
|
||||
};
|
||||
someText?: string;
|
||||
functionTitleField?: string;
|
||||
componentTitleField?: string;
|
||||
nestedTitle?: string;
|
||||
arrayWithCollapsibles?: {
|
||||
innerCollapsible?: string;
|
||||
id?: string;
|
||||
}[];
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface ConditionalLogic {
|
||||
id: string;
|
||||
text: string;
|
||||
toggleField?: boolean;
|
||||
fieldToToggle: string;
|
||||
userConditional?: string;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface DateField {
|
||||
id: string;
|
||||
default: string;
|
||||
timeOnly?: string;
|
||||
dayOnly?: string;
|
||||
dayAndTime?: string;
|
||||
monthOnly?: string;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface RadioField {
|
||||
id: string;
|
||||
radio?: 'one' | 'two' | 'three';
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface GroupField {
|
||||
id: string;
|
||||
group: {
|
||||
text: string;
|
||||
defaultParent?: string;
|
||||
defaultChild?: string;
|
||||
subGroup?: {
|
||||
textWithinGroup?: string;
|
||||
arrayWithinGroup?: {
|
||||
textWithinArray?: string;
|
||||
id?: string;
|
||||
}[];
|
||||
};
|
||||
};
|
||||
potentiallyEmptyGroup?: {
|
||||
text?: string;
|
||||
};
|
||||
groupInRow?: {
|
||||
field?: string;
|
||||
secondField?: string;
|
||||
thirdField?: string;
|
||||
};
|
||||
secondGroupInRow?: {
|
||||
field?: string;
|
||||
nestedGroup?: {
|
||||
nestedField?: string;
|
||||
};
|
||||
};
|
||||
groups: {
|
||||
groupInRow?: {
|
||||
field?: string;
|
||||
secondField?: string;
|
||||
thirdField?: string;
|
||||
};
|
||||
secondGroupInRow?: {
|
||||
field?: string;
|
||||
nestedGroup?: {
|
||||
nestedField?: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface RowField {
|
||||
id: string;
|
||||
title: string;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface IndexedField {
|
||||
id: string;
|
||||
text: string;
|
||||
uniqueText?: string;
|
||||
/**
|
||||
* @minItems 2
|
||||
* @maxItems 2
|
||||
*/
|
||||
point?: [number, number];
|
||||
group?: {
|
||||
localizedUnique?: string;
|
||||
/**
|
||||
* @minItems 2
|
||||
* @maxItems 2
|
||||
*/
|
||||
point?: [number, number];
|
||||
};
|
||||
collapsibleLocalizedUnique?: string;
|
||||
collapsibleTextUnique?: string;
|
||||
partOne?: string;
|
||||
partTwo?: string;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface JsonField {
|
||||
id: string;
|
||||
json?:
|
||||
| {
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| unknown[]
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface NumberField {
|
||||
id: string;
|
||||
number?: number;
|
||||
min?: number;
|
||||
max?: number;
|
||||
positiveNumber?: number;
|
||||
negativeNumber?: number;
|
||||
decimalMin?: number;
|
||||
decimalMax?: number;
|
||||
defaultNumber?: number;
|
||||
hasMany?: number[];
|
||||
validatesHasMany?: number[];
|
||||
localizedHasMany?: number[];
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface PointField {
|
||||
id: string;
|
||||
/**
|
||||
* @minItems 2
|
||||
* @maxItems 2
|
||||
*/
|
||||
point: [number, number];
|
||||
/**
|
||||
* @minItems 2
|
||||
* @maxItems 2
|
||||
*/
|
||||
localized?: [number, number];
|
||||
group?: {
|
||||
/**
|
||||
* @minItems 2
|
||||
* @maxItems 2
|
||||
*/
|
||||
point?: [number, number];
|
||||
};
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface RelationshipField {
|
||||
id: string;
|
||||
relationship:
|
||||
| {
|
||||
value: string | TextField;
|
||||
relationTo: 'text-fields';
|
||||
}
|
||||
| {
|
||||
value: string | ArrayField;
|
||||
relationTo: 'array-fields';
|
||||
};
|
||||
relationToSelf?: string | RelationshipField;
|
||||
relationToSelfSelectOnly?: string | RelationshipField;
|
||||
relationWithDynamicDefault?: string | User;
|
||||
relationHasManyWithDynamicDefault?: {
|
||||
value: string | User;
|
||||
relationTo: 'users';
|
||||
};
|
||||
relationshipWithMin?: string[] | TextField[];
|
||||
relationshipWithMax?: string[] | TextField[];
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface TextField {
|
||||
id: string;
|
||||
text: string;
|
||||
localizedText?: string;
|
||||
i18nText?: string;
|
||||
defaultFunction?: string;
|
||||
defaultAsync?: string;
|
||||
overrideLength?: string;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface RichTextField {
|
||||
id: string;
|
||||
title: string;
|
||||
selectHasMany?: ('one' | 'two' | 'three' | 'four' | 'five' | 'six')[];
|
||||
richText: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
richTextCustomFields?: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
richTextReadOnly?: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface SelectField {
|
||||
id: string;
|
||||
select?: 'one' | 'two' | 'three';
|
||||
selectReadOnly?: 'one' | 'two' | 'three';
|
||||
selectHasMany?: ('one' | 'two' | 'three' | 'four' | 'five' | 'six')[];
|
||||
selectHasManyLocalized?: ('one' | 'two')[];
|
||||
selectI18n?: 'one' | 'two' | 'three';
|
||||
simple?: 'One' | 'Two' | 'Three';
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface TabsField {
|
||||
id: string;
|
||||
array: {
|
||||
text: string;
|
||||
id?: string;
|
||||
}[];
|
||||
blocks: (
|
||||
| {
|
||||
text: string;
|
||||
richText?: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'text';
|
||||
}
|
||||
| {
|
||||
number: number;
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'number';
|
||||
}
|
||||
| {
|
||||
subBlocks?: (
|
||||
| {
|
||||
text: string;
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'text';
|
||||
}
|
||||
| {
|
||||
number: number;
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'number';
|
||||
}
|
||||
)[];
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'subBlocks';
|
||||
}
|
||||
| {
|
||||
textInCollapsible?: string;
|
||||
textInRow?: string;
|
||||
id?: string;
|
||||
blockName?: string;
|
||||
blockType: 'tabs';
|
||||
}
|
||||
)[];
|
||||
group: {
|
||||
number: number;
|
||||
};
|
||||
textInRow: string;
|
||||
numberInRow: number;
|
||||
tab: {
|
||||
array: {
|
||||
text: string;
|
||||
id?: string;
|
||||
}[];
|
||||
text?: string;
|
||||
defaultValue?: string;
|
||||
};
|
||||
namedTabWithDefaultValue: {
|
||||
defaultValue?: string;
|
||||
};
|
||||
localizedTab: {
|
||||
text?: string;
|
||||
};
|
||||
accessControlTab: {
|
||||
text?: string;
|
||||
};
|
||||
hooksTab: {
|
||||
beforeValidate?: boolean;
|
||||
beforeChange?: boolean;
|
||||
afterChange?: boolean;
|
||||
afterRead?: boolean;
|
||||
};
|
||||
textarea?: string;
|
||||
anotherText: string;
|
||||
nestedTab: {
|
||||
text?: string;
|
||||
};
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface Upload {
|
||||
id: string;
|
||||
text?: string;
|
||||
media?: string | Upload;
|
||||
richText?: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
url?: string;
|
||||
filename?: string;
|
||||
mimeType?: string;
|
||||
filesize?: number;
|
||||
width?: number;
|
||||
height?: number;
|
||||
}
|
||||
export interface Uploads2 {
|
||||
id: string;
|
||||
text?: string;
|
||||
media?: string | Uploads2;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
url?: string;
|
||||
filename?: string;
|
||||
mimeType?: string;
|
||||
filesize?: number;
|
||||
width?: number;
|
||||
height?: number;
|
||||
}
|
||||
export interface Uploads3 {
|
||||
id: string;
|
||||
media?: string | Uploads3;
|
||||
richText?: {
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
url?: string;
|
||||
filename?: string;
|
||||
mimeType?: string;
|
||||
filesize?: number;
|
||||
width?: number;
|
||||
height?: number;
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 341 KiB |
Reference in New Issue
Block a user