init of the sanitize config rework and custom component config setup

This commit is contained in:
Jarrod Flesch
2020-02-27 16:38:15 -05:00
parent 147d6aac1c
commit d800097b38
24 changed files with 189 additions and 176 deletions

View File

@@ -1,9 +1,8 @@
import React, { useState, useEffect, Fragment } from 'react'; import React, { useState, useEffect } from 'react';
import { import {
Route, Switch, withRouter, Redirect, Route, Switch, withRouter, Redirect,
} from 'react-router-dom'; } from 'react-router-dom';
import customComponents from 'payload-custom-components'; import getSanitizedClientConfig from '../config/getSanitizedClientConfig';
import getSanitizedConfig from '../config/getSanitizedConfig';
import { useUser } from './data/User'; import { useUser } from './data/User';
import Dashboard from './views/Dashboard'; import Dashboard from './views/Dashboard';
import Login from './views/Login'; import Login from './views/Login';
@@ -16,11 +15,11 @@ import List from './views/collections/List';
import EditGlobal from './views/globals/Edit'; import EditGlobal from './views/globals/Edit';
import { requests } from '../api'; import { requests } from '../api';
const config = getSanitizedConfig(); const config = getSanitizedClientConfig();
const RenderCollectionRoutes = ({ match }) => { const CollectionRoutes = ({ match }) => {
const collectionRoutes = config?.collections.reduce((routesToRender, collection) => { const collectionRoutes = config?.collections.reduce((routesToRender, collection) => {
const ListComponent = customComponents?.collections?.[collection.slug]?.views?.List || List; const ListComponent = List;
routesToRender.push({ routesToRender.push({
path: `${match.url}/collections/${collection.slug}`, path: `${match.url}/collections/${collection.slug}`,
component: ListComponent, component: ListComponent,
@@ -127,7 +126,7 @@ const Routes = () => {
<Dashboard /> <Dashboard />
</Route> </Route>
<RenderCollectionRoutes match={match} /> <CollectionRoutes match={match} />
{config.globals && config.globals.map((global) => { {config.globals && config.globals.map((global) => {
return ( return (

View File

@@ -4,7 +4,7 @@ import Cookies from 'universal-cookie';
import some from 'async-some'; import some from 'async-some';
import ReactSelect from '../../../modules/ReactSelect'; import ReactSelect from '../../../modules/ReactSelect';
import useFieldType from '../../useFieldType'; import useFieldType from '../../useFieldType';
import getSanitizedConfig from '../../../../config/getSanitizedConfig'; import getSanitizedClientConfig from '../../../../config/getSanitizedClientConfig';
import Label from '../../Label'; import Label from '../../Label';
import Error from '../../Error'; import Error from '../../Error';
@@ -12,7 +12,7 @@ import './index.scss';
const cookies = new Cookies(); const cookies = new Cookies();
const { serverURL, collections } = getSanitizedConfig(); const { serverURL, collections } = getSanitizedClientConfig();
const defaultError = 'Please make a selection.'; const defaultError = 'Please make a selection.';
const defaultValidate = value => value.length > 0; const defaultValidate = value => value.length > 0;
@@ -49,8 +49,8 @@ class Relationship extends Component {
some(relationsToSearch, async (relation, callback) => { some(relationsToSearch, async (relation, callback) => {
const response = await fetch(`${serverURL}/${relation}?limit=${maxResultsPerRequest}&page=${lastLoadedPage}`, { const response = await fetch(`${serverURL}/${relation}?limit=${maxResultsPerRequest}&page=${lastLoadedPage}`, {
headers: { headers: {
Authorization: `Bearer ${token}` Authorization: `Bearer ${token}`,
} },
}); });
const data = await response.json(); const data = await response.json();
@@ -59,7 +59,7 @@ class Relationship extends Component {
return callback(false, { return callback(false, {
data, data,
relation, relation,
}) });
} }
callback({ relation, data }); callback({ relation, data });
@@ -73,10 +73,9 @@ class Relationship extends Component {
this.setState({ this.setState({
lastFullyLoadedRelation: relations.indexOf(relation), lastFullyLoadedRelation: relations.indexOf(relation),
lastLoadedPage: 1, lastLoadedPage: 1,
}) });
} }
});
})
} }
} }
@@ -131,10 +130,10 @@ class Relationship extends Component {
this.setState({ this.setState({
options: [ options: [
...options, ...options,
...data.docs.map((doc) => ({ ...data.docs.map(doc => ({
label: doc[collection.useAsTitle], label: doc[collection.useAsTitle],
value: doc.id, value: doc.id,
})) })),
], ],
}); });
} else { } else {
@@ -147,9 +146,9 @@ class Relationship extends Component {
value: { value: {
relationTo: collection.slug, relationTo: collection.slug,
value: doc.id, value: doc.id,
} },
} };
}) });
if (optionsToAddTo) { if (optionsToAddTo) {
optionsToAddTo.options = [ optionsToAddTo.options = [
@@ -167,7 +166,7 @@ class Relationship extends Component {
options: [ options: [
...allOptionGroups, ...allOptionGroups,
], ],
}) });
} }
this.setState({ this.setState({
@@ -177,8 +176,8 @@ class Relationship extends Component {
handleInputChange = (search) => { handleInputChange = (search) => {
this.setState({ this.setState({
search search,
}) });
} }
handleMenuScrollToBottom = () => { handleMenuScrollToBottom = () => {
@@ -213,9 +212,9 @@ class Relationship extends Component {
const valueToRender = this.findValueInOptions(options, value); const valueToRender = this.findValueInOptions(options, value);
///////////////////////////////////////////// // ///////////////////////////////////////////
// TODO: simplify formatValue pattern seen below with react select // TODO: simplify formatValue pattern seen below with react select
///////////////////////////////////////////// // ///////////////////////////////////////////
return ( return (
<div <div
@@ -306,23 +305,23 @@ const RelationshipFieldType = (props) => {
if (hasMultipleRelations) { if (hasMultipleRelations) {
return { return {
...valueToFormat, ...valueToFormat,
value: valueToFormat.value.id value: valueToFormat.value.id,
}; };
} }
return valueToFormat.id; return valueToFormat.id;
} };
if (defaultValue) { if (defaultValue) {
if (hasMany && Array.isArray(defaultValue)) { if (hasMany && Array.isArray(defaultValue)) {
let formattedDefaultValue = []; const formattedDefaultValue = [];
defaultValue.forEach((individualValue) => { defaultValue.forEach((individualValue) => {
formattedDefaultValue.push(formatDefaultValue(individualValue)); formattedDefaultValue.push(formatDefaultValue(individualValue));
}) });
setFormattedDefaultValue(formattedDefaultValue); setFormattedDefaultValue(formattedDefaultValue);
} else { } else {
setFormattedDefaultValue(formatDefaultValue(defaultValue)); setFormattedDefaultValue(formatDefaultValue(defaultValue));
}; }
} }
}, [defaultValue]); }, [defaultValue]);

View File

@@ -1,6 +1,6 @@
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Sidebar from '../Sidebar'; import Sidebar from 'payload/Sidebar';
import StepNav, { useStepNav, StepNavProvider } from '../../modules/StepNav'; import StepNav, { useStepNav, StepNavProvider } from '../../modules/StepNav';
import { StatusListProvider } from '../../modules/Status'; import { StatusListProvider } from '../../modules/Status';
import Localizer from '../../modules/Localizer'; import Localizer from '../../modules/Localizer';

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { useLocation, NavLink, Link } from 'react-router-dom'; import { useLocation, NavLink, Link } from 'react-router-dom';
import getSanitizedConfig from '../../../config/getSanitizedConfig'; import getSanitizedClientConfig from '../../../config/getSanitizedClientConfig';
import Arrow from '../../graphics/Arrow'; import Arrow from '../../graphics/Arrow';
import Icon from '../../graphics/Icon'; import Icon from '../../graphics/Icon';
@@ -13,7 +13,7 @@ const {
routes: { routes: {
admin, admin,
}, },
} = getSanitizedConfig(); } = getSanitizedClientConfig();
const Sidebar = () => { const Sidebar = () => {
const location = useLocation(); const location = useLocation();

View File

@@ -2,9 +2,9 @@ import React, { Component } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import Filter from '../Filter'; import Filter from '../Filter';
import Table from '../../layout/Table'; import Table from '../../layout/Table';
import getSanitizedConfig from '../../../config/getSanitizedConfig'; import getSanitizedClientConfig from '../../../config/getSanitizedClientConfig';
const { routes: { admin } } = getSanitizedConfig(); const { routes: { admin } } = getSanitizedClientConfig();
class SearchableTable extends Component { class SearchableTable extends Component {
constructor(props) { constructor(props) {

View File

@@ -2,115 +2,127 @@ import React, { Component } from 'react';
import { createPortal } from 'react-dom'; import { createPortal } from 'react-dom';
import Button from '../../controls/Button'; import Button from '../../controls/Button';
import api from '../../../api'; import api from '../../../api';
import getSanitizedConfig from '../../../config/getSanitizedConfig'; import getSanitizedClientConfig from '../../../config/getSanitizedClientConfig';
import './index.scss'; import './index.scss';
const config = getSanitizedConfig(); const config = getSanitizedClientConfig();
class UploadMedia extends Component { class UploadMedia extends Component {
constructor() { constructor() {
super(); super();
this.state = { this.state = {
dragging: false, dragging: false,
selectingFile: false, selectingFile: false,
files: null files: null,
} };
this.dropRef = React.createRef(); this.dropRef = React.createRef();
this.dragCounter = 0; this.dragCounter = 0;
} }
componentDidMount() { componentDidMount() {
let div = this.dropRef.current const div = this.dropRef.current;
div.addEventListener('dragenter', this.handleDragIn) div.addEventListener('dragenter', this.handleDragIn);
div.addEventListener('dragleave', this.handleDragOut) div.addEventListener('dragleave', this.handleDragOut);
div.addEventListener('dragover', this.handleDrag) div.addEventListener('dragover', this.handleDrag);
div.addEventListener('drop', this.handleDrop) div.addEventListener('drop', this.handleDrop);
} }
componentWillUnmount() { componentWillUnmount() {
let div = this.dropRef.current const div = this.dropRef.current;
div.removeEventListener('dragenter', this.handleDragIn) div.removeEventListener('dragenter', this.handleDragIn);
div.removeEventListener('dragleave', this.handleDragOut) div.removeEventListener('dragleave', this.handleDragOut);
div.removeEventListener('dragover', this.handleDrag) div.removeEventListener('dragover', this.handleDrag);
div.removeEventListener('drop', this.handleDrop) div.removeEventListener('drop', this.handleDrop);
} }
handleDrag = e => { handleDrag = (e) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
} }
handleDragIn = e => { handleDragIn = (e) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
this.dragCounter++; this.dragCounter++;
if (e.dataTransfer.items && e.dataTransfer.items.length > 0) { if (e.dataTransfer.items && e.dataTransfer.items.length > 0) {
this.setState({ dragging: true }) this.setState({ dragging: true });
} }
} }
handleDragOut = e => { handleDragOut = (e) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
this.dragCounter--; this.dragCounter--;
if (this.dragCounter > 0) return; if (this.dragCounter > 0) return;
this.setState({ dragging: false }) this.setState({ dragging: false });
} }
handleDrop = e => { handleDrop = (e) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
this.setState({ dragging: false }) this.setState({ dragging: false });
if (e.dataTransfer.files && e.dataTransfer.files.length > 0) { if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
this.setState({ this.setState({
files: e.dataTransfer.files, files: e.dataTransfer.files,
dragging: false dragging: false,
}) });
e.dataTransfer.clearData(); e.dataTransfer.clearData();
this.dragCounter = 0; this.dragCounter = 0;
} else { } else {
this.setState({ dragging: false }) this.setState({ dragging: false });
} }
} }
handleSelectFile = e => { handleSelectFile = (e) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
this.setState({ this.setState({
selectingFile: true selectingFile: true,
}) });
} }
setSelectingFile = selectingFile => { setSelectingFile = (selectingFile) => {
this.setState({ selectingFile }) this.setState({ selectingFile });
} }
render() { render() {
return ( return (
<div ref={this.dropRef} className={`upload-media${this.state.dragging ? ' dragging' : ''}`}> <div
ref={this.dropRef}
className={`upload-media${this.state.dragging ? ' dragging' : ''}`}
>
<span className="instructions">Drag and drop a file here</span> <span className="instructions">Drag and drop a file here</span>
<span className="or">&mdash;or&mdash;</span> <span className="or">&mdash;or&mdash;</span>
<Button className="select-file" type="secondary" onClick={this.handleSelectFile}>Select a File</Button> <Button
<UploadMediaForm files={this.state.files} selectingFile={this.state.selectingFile} config={config} setSelectingFile={this.setSelectingFile} /> className="select-file"
type="secondary"
onClick={this.handleSelectFile}
>
Select a File
</Button>
<UploadMediaForm
files={this.state.files}
selectingFile={this.state.selectingFile}
config={config}
setSelectingFile={this.setSelectingFile}
/>
</div> </div>
) );
} }
} }
// Need to set up a separate component with a Portal // Need to set up a separate component with a Portal
// to make sure forms are not embedded within other forms // to make sure forms are not embedded within other forms
class UploadMediaForm extends Component { class UploadMediaForm extends Component {
constructor() { constructor() {
super(); super();
this.state = { this.state = {
submitted: false submitted: false,
} };
this.formRef = React.createRef(); this.formRef = React.createRef();
this.inputRef = React.createRef(); this.inputRef = React.createRef();
} }
@@ -148,18 +160,23 @@ class UploadMediaForm extends Component {
const data = new FormData(this.formRef.current); const data = new FormData(this.formRef.current);
api.requests.post(`${this.props.config.serverURL}/upload`, data).then( api.requests.post(`${this.props.config.serverURL}/upload`, data).then(
res => console.log(res), res => console.log(res),
err => { (err) => {
console.warn(err); console.warn(err);
} },
); );
} }
render() { render() {
return createPortal( return createPortal(
<form ref={this.formRef}> <form ref={this.formRef}>
<input type="file" name="files" ref={this.inputRef} /> <input
type="file"
name="files"
ref={this.inputRef}
/>
</form>, </form>,
document.getElementById('portal')) document.getElementById('portal'),
);
} }
} }

View File

@@ -7,7 +7,7 @@ import ContentBlock from '../../layout/ContentBlock';
import Form from '../../forms/Form'; import Form from '../../forms/Form';
import RenderFields from '../../forms/RenderFields'; import RenderFields from '../../forms/RenderFields';
import FormSubmit from '../../forms/Submit'; import FormSubmit from '../../forms/Submit';
import getSanitizedConfig from '../../../config/getSanitizedConfig'; import getSanitizedClientConfig from '../../../config/getSanitizedClientConfig';
import { useUser } from '../../data/User'; import { useUser } from '../../data/User';
import './index.scss'; import './index.scss';
@@ -16,7 +16,7 @@ const {
routes: { routes: {
admin, admin,
}, },
} = getSanitizedConfig(); } = getSanitizedClientConfig();
const passwordField = { const passwordField = {
name: 'password', name: 'password',

View File

@@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import DefaultTemplate from '../../layout/DefaultTemplate'; import DefaultTemplate from '../../layout/DefaultTemplate';
import getSanitizedConfig from '../../../config/getSanitizedConfig'; import getSanitizedClientConfig from '../../../config/getSanitizedClientConfig';
import './index.scss'; import './index.scss';
@@ -9,7 +9,7 @@ const {
routes: { routes: {
admin, admin,
}, },
} = getSanitizedConfig(); } = getSanitizedClientConfig();
const baseClass = 'dashboard'; const baseClass = 'dashboard';

View File

@@ -6,7 +6,7 @@ import Form from '../../forms/Form';
import Email from '../../forms/field-types/Email'; import Email from '../../forms/field-types/Email';
import Password from '../../forms/field-types/Password'; import Password from '../../forms/field-types/Password';
import FormSubmit from '../../forms/Submit'; import FormSubmit from '../../forms/Submit';
import getSanitizedConfig from '../../../config/getSanitizedConfig'; import getSanitizedClientConfig from '../../../config/getSanitizedClientConfig';
import Button from '../../controls/Button'; import Button from '../../controls/Button';
import { useUser } from '../../data/User'; import { useUser } from '../../data/User';
@@ -18,7 +18,7 @@ const {
routes: { routes: {
admin, admin,
}, },
} = getSanitizedConfig(); } = getSanitizedClientConfig();
const Login = () => { const Login = () => {
const { addStatus } = useStatusList(); const { addStatus } = useStatusList();

View File

@@ -1,7 +1,7 @@
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import { useUser } from '../../data/User'; import { useUser } from '../../data/User';
import ContentBlock from '../../layout/ContentBlock'; import ContentBlock from '../../layout/ContentBlock';
import getSanitizedConfig from '../../../config/getSanitizedConfig'; import getSanitizedClientConfig from '../../../config/getSanitizedClientConfig';
import Button from '../../controls/Button'; import Button from '../../controls/Button';
import './index.scss'; import './index.scss';
@@ -12,7 +12,7 @@ const {
routes: { routes: {
admin, admin,
}, },
} = getSanitizedConfig(); } = getSanitizedClientConfig();
const Logout = () => { const Logout = () => {
const { logOut } = useUser(); const { logOut } = useUser();

View File

@@ -1,9 +1,9 @@
import React from 'react'; import React from 'react';
import getSanitizedConfig from '../../../config/getSanitizedConfig'; import getSanitizedClientConfig from '../../../config/getSanitizedClientConfig';
import Button from '../../controls/Button'; import Button from '../../controls/Button';
import DefaultTemplate from '../../layout/DefaultTemplate'; import DefaultTemplate from '../../layout/DefaultTemplate';
const { routes: { admin } } = getSanitizedConfig(); const { routes: { admin } } = getSanitizedClientConfig();
const NotFound = () => { const NotFound = () => {
return ( return (

View File

@@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useRouteMatch, useHistory } from 'react-router-dom'; import { useRouteMatch, useHistory } from 'react-router-dom';
import getSanitizedConfig from '../../../../config/getSanitizedConfig'; import getSanitizedClientConfig from '../../../../config/getSanitizedClientConfig';
import DefaultTemplate from '../../../layout/DefaultTemplate'; import DefaultTemplate from '../../../layout/DefaultTemplate';
import usePayloadAPI from '../../../../hooks/usePayloadAPI'; import usePayloadAPI from '../../../../hooks/usePayloadAPI';
import Form from '../../../forms/Form'; import Form from '../../../forms/Form';
@@ -16,9 +16,9 @@ import './index.scss';
const { const {
serverURL, serverURL,
routes: { routes: {
admin admin,
} },
} = getSanitizedConfig(); } = getSanitizedClientConfig();
const baseClass = 'collection-edit'; const baseClass = 'collection-edit';
@@ -33,14 +33,14 @@ const EditView = (props) => {
status: { status: {
message: json.message, message: json.message,
type: 'success', type: 'success',
} },
}); });
}); });
} : null; } : null;
const [{ data }] = usePayloadAPI( const [{ data }] = usePayloadAPI(
(isEditing ? `${serverURL}/${collection.slug}/${id}` : null), (isEditing ? `${serverURL}/${collection.slug}/${id}` : null),
{ initialParams: { 'fallback-locale': 'null' } } { initialParams: { 'fallback-locale': 'null' } },
); );
const nav = [{ const nav = [{
@@ -50,12 +50,12 @@ const EditView = (props) => {
if (isEditing) { if (isEditing) {
nav.push({ nav.push({
label: data ? data[collection.useAsTitle] : '' label: data ? data[collection.useAsTitle] : '',
}) });
} else { } else {
nav.push({ nav.push({
label: 'Create New' label: 'Create New',
}) });
} }
return ( return (
@@ -66,26 +66,45 @@ const EditView = (props) => {
<header className={`${baseClass}__header`}> <header className={`${baseClass}__header`}>
{isEditing && ( {isEditing && (
<h1> <h1>
Edit {Object.keys(data).length > 0 && Edit
(data[collection.useAsTitle] ? data[collection.useAsTitle] : '[Untitled]') {' '}
{Object.keys(data).length > 0
&& (data[collection.useAsTitle] ? data[collection.useAsTitle] : '[Untitled]')
} }
</h1> </h1>
)} )}
{!isEditing && {!isEditing
<h1>Create New {collection.labels.singular}</h1> && (
<h1>
Create New
{' '}
{collection.labels.singular}
</h1>
)
} }
</header> </header>
<Form className={`${baseClass}__form`} method={id ? 'put' : 'post'} action={`${serverURL}/${collection.slug}${id ? `/${id}` : ''}`} handleAjaxResponse={handleAjaxResponse}> <Form
<StickyHeader showStatus={true} className={`${baseClass}__form`}
method={id ? 'put' : 'post'}
action={`${serverURL}/${collection.slug}${id ? `/${id}` : ''}`}
handleAjaxResponse={handleAjaxResponse}
>
<StickyHeader
showStatus
content={ content={
<APIURL url={isEditing && `${serverURL}/${collection.slug}/${data.id}`} /> <APIURL url={isEditing && `${serverURL}/${collection.slug}/${data.id}`} />
} action={ }
action={(
<> <>
<Button type="secondary">Preview</Button> <Button type="secondary">Preview</Button>
<FormSubmit>Save</FormSubmit> <FormSubmit>Save</FormSubmit>
</> </>
} /> )}
<RenderFields fields={collection.fields} initialData={data} /> />
<RenderFields
fields={collection.fields}
initialData={data}
/>
</Form> </Form>
</DefaultTemplate> </DefaultTemplate>
); );

View File

@@ -3,7 +3,7 @@ import { useLocation } from 'react-router-dom';
import queryString from 'qs'; import queryString from 'qs';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import usePayloadAPI from '../../../../hooks/usePayloadAPI'; import usePayloadAPI from '../../../../hooks/usePayloadAPI';
import getSanitizedConfig from '../../../../config/getSanitizedConfig'; import getSanitizedClientConfig from '../../../../config/getSanitizedClientConfig';
import DefaultTemplate from '../../../layout/DefaultTemplate'; import DefaultTemplate from '../../../layout/DefaultTemplate';
import HeadingButton from '../../../modules/HeadingButton'; import HeadingButton from '../../../modules/HeadingButton';
import SearchableTable from '../../../modules/SearchableTable'; import SearchableTable from '../../../modules/SearchableTable';
@@ -16,7 +16,7 @@ const {
routes: { routes: {
admin, admin,
}, },
} = getSanitizedConfig(); } = getSanitizedClientConfig();
const ListView = (props) => { const ListView = (props) => {
const { collection } = props; const { collection } = props;

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import getSanitizedConfig from '../../../../config/getSanitizedConfig'; import getSanitizedClientConfig from '../../../../config/getSanitizedClientConfig';
import DefaultTemplate from '../../../layout/DefaultTemplate'; import DefaultTemplate from '../../../layout/DefaultTemplate';
import usePayloadAPI from '../../../../hooks/usePayloadAPI'; import usePayloadAPI from '../../../../hooks/usePayloadAPI';
import Form from '../../../forms/Form'; import Form from '../../../forms/Form';
@@ -15,9 +15,9 @@ import './index.scss';
const { const {
serverURL, serverURL,
routes: { routes: {
admin admin,
} },
} = getSanitizedConfig(); } = getSanitizedClientConfig();
const baseClass = 'global-edit'; const baseClass = 'global-edit';
@@ -26,7 +26,7 @@ const EditView = (props) => {
const [{ data }] = usePayloadAPI( const [{ data }] = usePayloadAPI(
`${serverURL}/globals/${global.slug}`, `${serverURL}/globals/${global.slug}`,
{ initialParams: { 'fallback-locale': 'null' } } { initialParams: { 'fallback-locale': 'null' } },
); );
const nav = [{ const nav = [{
@@ -41,20 +41,32 @@ const EditView = (props) => {
> >
<header className={`${baseClass}__header`}> <header className={`${baseClass}__header`}>
<h1> <h1>
Edit {global.label} Edit
{' '}
{global.label}
</h1> </h1>
</header> </header>
<Form className={`${baseClass}__form`} method={data ? 'put' : 'post'} action={`${serverURL}/globals/${global.slug}`}> <Form
<StickyHeader showStatus={true} className={`${baseClass}__form`}
method={data ? 'put' : 'post'}
action={`${serverURL}/globals/${global.slug}`}
>
<StickyHeader
showStatus
content={ content={
<APIURL url={`${serverURL}/globals/${global.slug}`} /> <APIURL url={`${serverURL}/globals/${global.slug}`} />
} action={ }
action={(
<> <>
<Button type="secondary">Preview</Button> <Button type="secondary">Preview</Button>
<FormSubmit>Save</FormSubmit> <FormSubmit>Save</FormSubmit>
</> </>
} /> )}
<RenderFields fields={global.fields} initialData={data} /> />
<RenderFields
fields={global.fields}
initialData={data}
/>
</Form> </Form>
</DefaultTemplate> </DefaultTemplate>
); );

View File

@@ -0,0 +1,5 @@
import config from 'payload-config';
import sanitizeConfig from '../../utilities/sanitizeConfig';
const getSanitizedClientConfig = () => sanitizeConfig(config);
export default getSanitizedClientConfig;

View File

@@ -104,8 +104,8 @@ module.exports = (config) => {
modules: ['node_modules', path.resolve(__dirname, '../../../node_modules')], modules: ['node_modules', path.resolve(__dirname, '../../../node_modules')],
alias: { alias: {
'payload-scss-overrides': config.paths.scssOverrides, 'payload-scss-overrides': config.paths.scssOverrides,
'payload-custom-components': config.paths.components,
'payload-config': config.paths.config, 'payload-config': config.paths.config,
'payload/Sidebar': (config.customComponents.layout && config.customComponents.layout.Sidebar) ? config.customComponents.layout.Sidebar : path.resolve(__dirname, '../components/layout/Sidebar/index.js'),
}, },
}, },
}; };

View File

@@ -11,13 +11,13 @@ const baseUserFields = require('./auth/baseFields');
const baseUploadFields = require('./uploads/baseUploadFields'); const baseUploadFields = require('./uploads/baseUploadFields');
const baseImageFields = require('./uploads/baseImageFields'); const baseImageFields = require('./uploads/baseImageFields');
const registerUploadRoutes = require('./uploads/routes'); const registerUploadRoutes = require('./uploads/routes');
const registerConfigRoute = require('./routes/config');
const validateCollection = require('./collections/validate'); const validateCollection = require('./collections/validate');
const buildCollectionSchema = require('./collections/buildSchema'); const buildCollectionSchema = require('./collections/buildSchema');
const registerCollectionRoutes = require('./collections/registerRoutes'); const registerCollectionRoutes = require('./collections/registerRoutes');
const validateGlobals = require('./globals/validate'); const validateGlobals = require('./globals/validate');
const registerGlobalSchema = require('./globals/registerSchema'); const registerGlobalSchema = require('./globals/registerSchema');
const registerGlobalRoutes = require('./globals/registerRoutes'); const registerGlobalRoutes = require('./globals/registerRoutes');
const sanitizeConfig = require('./utilities/sanitizeConfig');
class Payload { class Payload {
constructor(options) { constructor(options) {
@@ -28,19 +28,18 @@ class Payload {
this.getCollections.bind(this); this.getCollections.bind(this);
this.getGlobals.bind(this); this.getGlobals.bind(this);
// Setup & initialization
connectMongoose(options.config.mongoURL);
registerExpressMiddleware(options);
initPassport(options.app);
initUploads(options);
initCORS(options);
registerConfigRoute(options, this.getCollections, this.getGlobals);
// Bind options, app, router // Bind options, app, router
this.config = options.config;
this.app = options.app; this.app = options.app;
this.config = sanitizeConfig(options.config);
this.router = options.router; this.router = options.router;
// Setup & initialization
connectMongoose(this.config.mongoURL);
registerExpressMiddleware(this.app, this.config, this.router);
initPassport(this.app);
initUploads(this.app, this.config);
initCORS(this.app, this.config);
// Register and bind required collections // Register and bind required collections
this.registerUser(); this.registerUser();
this.registerUpload(); this.registerUpload();
@@ -61,7 +60,7 @@ class Payload {
this.registerGlobals(this.config.globals); this.registerGlobals(this.config.globals);
// Enable client webpack // Enable client webpack
if (!this.config.disableAdmin) initWebpack(options); if (!this.config.disableAdmin) initWebpack(this.app, this.config);
} }
registerUser() { registerUser() {

View File

@@ -1,4 +1,4 @@
const initCORS = ({ config, app }) => { const initCORS = (app, config) => {
if (config.cors) { if (config.cors) {
app.use((req, res, next) => { app.use((req, res, next) => {
if (config.cors.indexOf(req.headers.origin) > -1) { if (config.cors.indexOf(req.headers.origin) > -1) {

View File

@@ -4,7 +4,7 @@ const bodyParser = require('body-parser');
const methodOverride = require('method-override'); const methodOverride = require('method-override');
const localizationMiddleware = require('../localization/middleware'); const localizationMiddleware = require('../localization/middleware');
const registerExpressMiddleware = ({ app, config, router }) => { const registerExpressMiddleware = (app, config, router) => {
app.use(express.json()); app.use(express.json());
app.use(methodOverride('X-HTTP-Method-Override')); app.use(methodOverride('X-HTTP-Method-Override'));
app.use(express.urlencoded({ extended: true })); app.use(express.urlencoded({ extended: true }));

View File

@@ -1,6 +1,6 @@
const express = require('express'); const express = require('express');
const initUploads = ({ config, app }) => { const initUploads = (app, config) => {
const staticUrl = config.staticUrl ? config.staticUrl : `/${config.staticDir}`; const staticUrl = config.staticUrl ? config.staticUrl : `/${config.staticDir}`;
app.use(staticUrl, express.static(config.staticDir)); app.use(staticUrl, express.static(config.staticDir));
}; };

View File

@@ -1,10 +1,9 @@
const webpack = require('webpack'); const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware'); const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware'); const webpackHotMiddleware = require('webpack-hot-middleware');
const path = require('path');
const getWebpackDevConfig = require('../client/config/getWebpackDevConfig'); const getWebpackDevConfig = require('../client/config/getWebpackDevConfig');
const initWebpack = ({ config, app }) => { const initWebpack = (app, config) => {
const webpackDevConfig = getWebpackDevConfig(config); const webpackDevConfig = getWebpackDevConfig(config);
const compiler = webpack(webpackDevConfig); const compiler = webpack(webpackDevConfig);

View File

@@ -1,35 +0,0 @@
const passport = require('passport');
const registerConfigRoute = ({ router, config }, getCollections, getGlobals) => {
router.use('/config',
passport.authenticate('jwt', { session: false }),
(req, res) => {
const registeredCollections = getCollections();
const globals = getGlobals();
const collections = {};
const contentBlocks = {};
Object.keys(registeredCollections).forEach((key) => {
const fullConfig = registeredCollections[key].config;
const collectionConfig = { ...fullConfig };
delete collectionConfig.plugins;
delete collectionConfig.policies;
if (collectionConfig.useAsContentBlock) {
contentBlocks[collectionConfig.slug] = collectionConfig;
}
collections[collectionConfig.slug] = collectionConfig;
});
res.json({
...config,
collections,
globals,
contentBlocks,
});
});
};
module.exports = registerConfigRoute;

View File

@@ -1,14 +1,13 @@
import config from 'payload-config'; const sanitizeConfig = (config) => {
const getSanitizedConfig = () => {
const sanitizedConfig = { ...config }; const sanitizedConfig = { ...config };
sanitizedConfig.routes = { sanitizedConfig.routes = {
admin: (config.routes && config.routes.admin) ? config.routes.admin : '/admin', admin: (config.routes && config.routes.admin) ? config.routes.admin : '/admin',
api: (config.routes && config.routes.api) ? config.routes.api : '/api', api: (config.routes && config.routes.api) ? config.routes.api : '/api',
}; };
sanitizedConfig.customComponents = { ...(config.customComponents || {}) };
return sanitizedConfig; return sanitizedConfig;
}; };
export default getSanitizedConfig; module.exports = sanitizeConfig;

View File

@@ -1,7 +1,7 @@
import usePayloadAPI from './src/client/hooks/usePayloadAPI'; import usePayloadAPI from './src/client/hooks/usePayloadAPI';
import getSanitizedConfig from './src/client/config/getSanitizedConfig'; import getSanitizedClientConfig from './src/client/config/getSanitizedClientConfig';
export default { export default {
usePayloadAPI, usePayloadAPI,
getSanitizedConfig, getSanitizedClientConfig,
}; };