merge ts-final
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import Select from 'react-select';
|
||||
import { Props } from './types';
|
||||
import Chevron from '../../icons/Chevron';
|
||||
|
||||
|
||||
@@ -5,10 +5,10 @@ import { objectToFormData } from 'object-to-formdata';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import { toast } from 'react-toastify';
|
||||
import { useAuth } from '@payloadcms/config-provider';
|
||||
import { useLocale } from '../../utilities/Locale';
|
||||
import { requests } from '../../../api';
|
||||
import useThrottledEffect from '../../../hooks/useThrottledEffect';
|
||||
import { useAuth } from '@payloadcms/config-provider';
|
||||
import fieldReducer from './fieldReducer';
|
||||
import initContextState from './initContextState';
|
||||
import reduceFieldsToValues from './reduceFieldsToValues';
|
||||
@@ -24,7 +24,7 @@ import './index.scss';
|
||||
|
||||
const baseClass = 'form';
|
||||
|
||||
const Form = (props) => {
|
||||
const Form: React.FC = (props) => {
|
||||
const {
|
||||
disabled,
|
||||
onSubmit,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { createContext, useEffect, useContext, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import RenderCustomComponent from '../../utilities/RenderCustomComponent';
|
||||
import useIntersect from '../../../hooks/useIntersect';
|
||||
import { Props, Context } from './types';
|
||||
|
||||
const baseClass = 'render-fields';
|
||||
|
||||
@@ -9,11 +9,11 @@ const intersectionObserverOptions = {
|
||||
rootMargin: '1000px',
|
||||
};
|
||||
|
||||
const RenderedFieldContext = createContext({});
|
||||
const RenderedFieldContext = createContext({} as Context);
|
||||
|
||||
export const useRenderedFields = () => useContext(RenderedFieldContext);
|
||||
export const useRenderedFields = (): Context => useContext(RenderedFieldContext);
|
||||
|
||||
const RenderFields = (props) => {
|
||||
const RenderFields: React.FC<Props> = (props) => {
|
||||
const {
|
||||
fieldSchema,
|
||||
fieldTypes,
|
||||
@@ -135,26 +135,4 @@ const RenderFields = (props) => {
|
||||
return null;
|
||||
};
|
||||
|
||||
RenderFields.defaultProps = {
|
||||
filter: null,
|
||||
readOnly: false,
|
||||
permissions: {},
|
||||
operation: undefined,
|
||||
className: undefined,
|
||||
};
|
||||
|
||||
RenderFields.propTypes = {
|
||||
fieldSchema: PropTypes.arrayOf(
|
||||
PropTypes.shape({}),
|
||||
).isRequired,
|
||||
fieldTypes: PropTypes.shape({
|
||||
hidden: PropTypes.function,
|
||||
}).isRequired,
|
||||
filter: PropTypes.func,
|
||||
permissions: PropTypes.shape({}),
|
||||
readOnly: PropTypes.bool,
|
||||
operation: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
export default RenderFields;
|
||||
|
||||
17
src/admin/components/forms/RenderFields/types.ts
Normal file
17
src/admin/components/forms/RenderFields/types.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { CollectionPermission, GlobalPermission } from '../../../../auth/types';
|
||||
import { Field } from '../../../../fields/config/types';
|
||||
|
||||
export type Operation = 'create' | 'update'
|
||||
|
||||
export type Context = {
|
||||
operation: Operation
|
||||
}
|
||||
|
||||
export type Props = {
|
||||
className?: string
|
||||
operation: Operation
|
||||
readOnly: boolean
|
||||
permissions: CollectionPermission | GlobalPermission
|
||||
filter: (field: Field) => boolean
|
||||
fieldSchema: Field[]
|
||||
}
|
||||
@@ -2,14 +2,16 @@ import React, {
|
||||
Component, useCallback,
|
||||
} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import some from 'async-some';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import some from '../../../../../utilities/asyncSome';
|
||||
import withCondition from '../../withCondition';
|
||||
import ReactSelect from '../../../elements/ReactSelect';
|
||||
import useFieldType from '../../useFieldType';
|
||||
import Label from '../../Label';
|
||||
import Error from '../../Error';
|
||||
import { relationship } from '../../../../../fields/validations';
|
||||
import { PaginatedDocs } from '../../../../../collections/config/types';
|
||||
import { RelationshipProps, OptionsPage } from './types';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
@@ -17,7 +19,7 @@ const maxResultsPerRequest = 10;
|
||||
|
||||
const baseClass = 'relationship';
|
||||
|
||||
class Relationship extends Component {
|
||||
class Relationship extends Component<RelationshipProps> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -77,7 +79,7 @@ class Relationship extends Component {
|
||||
const fieldToSearch = collection?.admin?.useAsTitle || 'id';
|
||||
const searchParam = search ? `&where[${fieldToSearch}][like]=${search}` : '';
|
||||
const response = await fetch(`${serverURL}${api}/${relation}?limit=${maxResultsPerRequest}&page=${lastLoadedPage}${searchParam}`);
|
||||
const data = await response.json();
|
||||
const data: PaginatedDocs = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
if (data.hasNextPage) {
|
||||
@@ -87,7 +89,7 @@ class Relationship extends Component {
|
||||
});
|
||||
}
|
||||
|
||||
return callback({ relation, data });
|
||||
return callback(true, { relation, data });
|
||||
}
|
||||
|
||||
let error = 'There was a problem loading options for this field.';
|
||||
@@ -99,7 +101,7 @@ class Relationship extends Component {
|
||||
return this.setState({
|
||||
errorLoading: error,
|
||||
});
|
||||
}, (lastPage, nextPage) => {
|
||||
}, (lastPage: OptionsPage, nextPage: OptionsPage) => {
|
||||
if (nextPage) {
|
||||
const { data, relation } = nextPage;
|
||||
this.addOptions(data, relation);
|
||||
|
||||
25
src/admin/components/forms/field-types/Relationship/types.ts
Normal file
25
src/admin/components/forms/field-types/Relationship/types.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import { PaginatedDocs } from '../../../../../collections/config/types';
|
||||
import { Config } from '../../../../../config/types';
|
||||
|
||||
export type OptionsPage = {
|
||||
relation: string
|
||||
data: PaginatedDocs
|
||||
}
|
||||
|
||||
export type RelationshipProps = {
|
||||
required: boolean
|
||||
errorMessage: string
|
||||
hasMany: boolean
|
||||
showError: boolean
|
||||
value: unknown
|
||||
path: string
|
||||
formProcessing: boolean
|
||||
admin: {
|
||||
readOnly: boolean
|
||||
style: React.CSSProperties
|
||||
width: string
|
||||
}
|
||||
relationTo: string | string[]
|
||||
config: Config
|
||||
}
|
||||
@@ -1,20 +1,20 @@
|
||||
import React from 'react';
|
||||
import NavigationPrompt from 'react-router-navigation-prompt';
|
||||
import { useAuth } from '@payloadcms/config-provider';
|
||||
import { useFormModified } from '../../forms/Form/context';
|
||||
import MinimalTemplate from '../../templates/Minimal';
|
||||
import Button from '../../elements/Button';
|
||||
import { useAuth } from '@payloadcms/config-provider';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
const modalSlug = 'leave-without-saving';
|
||||
|
||||
const LeaveWithoutSaving = () => {
|
||||
const LeaveWithoutSaving: React.FC = () => {
|
||||
const modified = useFormModified();
|
||||
const { user } = useAuth();
|
||||
|
||||
return (
|
||||
<NavigationPrompt when={modified && user}>
|
||||
<NavigationPrompt when={Boolean(modified && user)}>
|
||||
{({ onConfirm, onCancel }) => (
|
||||
<div className={modalSlug}>
|
||||
<MinimalTemplate>
|
||||
|
||||
@@ -5,12 +5,13 @@ import { useModal, Modal } from '@faceless-ui/modal';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import MinimalTemplate from '../../templates/Minimal';
|
||||
import Button from '../../elements/Button';
|
||||
import { Props } from './types';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
const baseClass = 'stay-logged-in';
|
||||
|
||||
const StayLoggedInModal = (props) => {
|
||||
const StayLoggedInModal: React.FC<Props> = (props) => {
|
||||
const { refreshCookie } = props;
|
||||
const history = useHistory();
|
||||
const { routes: { admin } } = useConfig();
|
||||
|
||||
4
src/admin/components/modals/StayLoggedIn/types.ts
Normal file
4
src/admin/components/modals/StayLoggedIn/types.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
export type Props = {
|
||||
refreshCookie: () => void
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import DefaultNav from '../../elements/Nav';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import DefaultNav from '../../elements/Nav';
|
||||
import { StepNavProvider } from '../../elements/StepNav';
|
||||
import RenderCustomComponent from '../../utilities/RenderCustomComponent';
|
||||
import Meta from '../../utilities/Meta';
|
||||
import { Props } from './types';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
const baseClass = 'template-default';
|
||||
|
||||
const Default = ({ children, className }) => {
|
||||
const Default: React.FC<Props> = ({ children, className }) => {
|
||||
const {
|
||||
admin: {
|
||||
components: {
|
||||
@@ -44,16 +44,4 @@ const Default = ({ children, className }) => {
|
||||
);
|
||||
};
|
||||
|
||||
Default.defaultProps = {
|
||||
className: '',
|
||||
};
|
||||
|
||||
Default.propTypes = {
|
||||
children: PropTypes.oneOfType([
|
||||
PropTypes.arrayOf(PropTypes.node),
|
||||
PropTypes.node,
|
||||
]).isRequired,
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
export default Default;
|
||||
|
||||
3
src/admin/components/templates/Default/types.ts
Normal file
3
src/admin/components/templates/Default/types.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export type Props = {
|
||||
className?: string,
|
||||
};
|
||||
@@ -1,13 +1,16 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Props } from './types';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
const baseClass = 'template-minimal';
|
||||
|
||||
const Minimal = (props) => {
|
||||
const Minimal: React.FC<Props> = (props) => {
|
||||
const {
|
||||
className, style, children, width,
|
||||
className,
|
||||
style = {},
|
||||
children,
|
||||
width = 'normal',
|
||||
} = props;
|
||||
|
||||
const classes = [
|
||||
@@ -28,17 +31,4 @@ const Minimal = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
Minimal.defaultProps = {
|
||||
className: null,
|
||||
style: {},
|
||||
width: 'normal',
|
||||
};
|
||||
|
||||
Minimal.propTypes = {
|
||||
className: PropTypes.string,
|
||||
style: PropTypes.shape({}),
|
||||
children: PropTypes.node.isRequired,
|
||||
width: PropTypes.oneOf(['normal', 'wide']),
|
||||
};
|
||||
|
||||
export default Minimal;
|
||||
|
||||
7
src/admin/components/templates/Minimal/types.ts
Normal file
7
src/admin/components/templates/Minimal/types.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
export type Props = {
|
||||
className?: string,
|
||||
width?: 'normal' | 'wide'
|
||||
style?: React.CSSProperties
|
||||
};
|
||||
@@ -5,17 +5,17 @@ import PropTypes from 'prop-types';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useSearchParams } from '../SearchParams';
|
||||
|
||||
const Context = createContext({});
|
||||
const Context = createContext('');
|
||||
|
||||
export const LocaleProvider = ({ children }) => {
|
||||
export const LocaleProvider: React.FC = ({ children }) => {
|
||||
const { localization } = useConfig();
|
||||
const defaultLocale = (localization && localization.defaultLocale) ? localization.defaultLocale : 'en';
|
||||
const [locale, setLocale] = useState(defaultLocale);
|
||||
const [locale, setLocale] = useState<string>(defaultLocale);
|
||||
const searchParams = useSearchParams();
|
||||
const localeFromParams = searchParams.locale;
|
||||
|
||||
useEffect(() => {
|
||||
if (localeFromParams && localization.locales.indexOf(localeFromParams) > -1) setLocale(localeFromParams);
|
||||
if (localeFromParams && localization.locales.indexOf(localeFromParams as string) > -1) setLocale(localeFromParams as string);
|
||||
}, [localeFromParams, localization]);
|
||||
|
||||
return (
|
||||
@@ -25,7 +25,7 @@ export const LocaleProvider = ({ children }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const useLocale = () => useContext(Context);
|
||||
export const useLocale = (): string => useContext(Context);
|
||||
|
||||
LocaleProvider.propTypes = {
|
||||
children: PropTypes.oneOfType([
|
||||
|
||||
@@ -13,9 +13,9 @@ const Meta: React.FC<Props> = ({
|
||||
keywords = 'CMS, Admin, Dashboard',
|
||||
}) => {
|
||||
const config = useConfig();
|
||||
const titleSuffix = config?.admin?.meta?.titleSuffix ?? '- Payload';
|
||||
const favicon = config?.admin?.meta?.favicon ?? payloadFavicon;
|
||||
const ogImage = config?.admin?.meta?.ogImage ?? payloadOgImage;
|
||||
const titleSuffix = config.admin.meta?.titleSuffix ?? '- Payload';
|
||||
const favicon = config.admin.meta.favicon ?? payloadFavicon;
|
||||
const ogImage = config.admin.meta.ogImage ?? payloadOgImage;
|
||||
|
||||
return (
|
||||
<Helmet
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
const Portal = ({ children }) => ReactDOM.createPortal(children, document.getElementById('portal'));
|
||||
const Portal = ({ children }: { children: React.ReactNode}): React.ReactPortal => ReactDOM.createPortal(children, document.getElementById('portal'));
|
||||
|
||||
export default Portal;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Props } from './types';
|
||||
|
||||
const RenderCustomComponent = (props) => {
|
||||
const RenderCustomComponent: React.FC<Props> = (props) => {
|
||||
const { CustomComponent, DefaultComponent, componentProps } = props;
|
||||
|
||||
if (CustomComponent) {
|
||||
@@ -15,22 +15,4 @@ const RenderCustomComponent = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
RenderCustomComponent.defaultProps = {
|
||||
path: undefined,
|
||||
componentProps: {},
|
||||
CustomComponent: null,
|
||||
};
|
||||
|
||||
RenderCustomComponent.propTypes = {
|
||||
path: PropTypes.string,
|
||||
DefaultComponent: PropTypes.oneOfType([
|
||||
PropTypes.shape({}),
|
||||
PropTypes.func,
|
||||
PropTypes.node,
|
||||
PropTypes.element,
|
||||
]).isRequired,
|
||||
CustomComponent: PropTypes.func,
|
||||
componentProps: PropTypes.shape({}),
|
||||
};
|
||||
|
||||
export default RenderCustomComponent;
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
export type Props = {
|
||||
CustomComponent: React.ComponentType
|
||||
DefaultComponent: React.ComponentType
|
||||
componentProps?: unknown
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import qs from 'qs';
|
||||
|
||||
const Context = createContext({});
|
||||
|
||||
export const SearchParamsProvider = ({ children }) => {
|
||||
export const SearchParamsProvider: React.FC = ({ children }) => {
|
||||
const location = useLocation();
|
||||
|
||||
const params = qs.parse(
|
||||
@@ -27,4 +27,4 @@ SearchParamsProvider.propTypes = {
|
||||
]).isRequired,
|
||||
};
|
||||
|
||||
export const useSearchParams = () => useContext(Context);
|
||||
export const useSearchParams = (): qs.ParsedQs => useContext(Context);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
// Our hook
|
||||
export default function useDebounce(value, delay) {
|
||||
export default function useDebounce(value: unknown, delay: number): unknown {
|
||||
// State and setters for debounced value
|
||||
const [debouncedValue, setDebouncedValue] = useState(value);
|
||||
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
/* eslint-disable no-shadow */
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
export default ({ root = null, rootMargin, threshold = 0 } = {}) => {
|
||||
const [entry, updateEntry] = useState({});
|
||||
type Intersect = [
|
||||
setNode: React.Dispatch<Element>,
|
||||
entry: IntersectionObserverEntry
|
||||
]
|
||||
|
||||
const useIntersect = ({
|
||||
root = null,
|
||||
rootMargin = '0px',
|
||||
threshold = 0,
|
||||
} = {}): Intersect => {
|
||||
const [entry, updateEntry] = useState<IntersectionObserverEntry>();
|
||||
const [node, setNode] = useState(null);
|
||||
|
||||
const observer = useRef(
|
||||
@@ -27,3 +36,5 @@ export default ({ root = null, rootMargin, threshold = 0 } = {}) => {
|
||||
|
||||
return [setNode, entry];
|
||||
};
|
||||
|
||||
export default useIntersect;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
const useMountEffect = func => useEffect(func, []);
|
||||
const useMountEffect = (func: () => void): void => useEffect(func, []);
|
||||
|
||||
export default useMountEffect;
|
||||
|
||||
@@ -3,11 +3,28 @@ import queryString from 'qs';
|
||||
import { useLocale } from '../components/utilities/Locale';
|
||||
import { requests } from '../api';
|
||||
|
||||
const usePayloadAPI = (url, options = {}) => {
|
||||
type Result = [
|
||||
{
|
||||
isLoading: boolean
|
||||
isError: boolean
|
||||
data: unknown
|
||||
},
|
||||
{
|
||||
setParams: React.Dispatch<unknown>
|
||||
}
|
||||
]
|
||||
|
||||
type Options = {
|
||||
initialParams?: unknown
|
||||
initialData?: unknown
|
||||
}
|
||||
|
||||
type UsePayloadAPI = (url: string, options?: Options) => Result;
|
||||
|
||||
const usePayloadAPI: UsePayloadAPI = (url, options = {}) => {
|
||||
const {
|
||||
initialParams = {},
|
||||
initialData = {},
|
||||
onLoad,
|
||||
} = options;
|
||||
|
||||
const [data, setData] = useState(initialData);
|
||||
@@ -18,8 +35,8 @@ const usePayloadAPI = (url, options = {}) => {
|
||||
|
||||
const search = queryString.stringify({
|
||||
locale,
|
||||
...params,
|
||||
}, { depth: 10 });
|
||||
...(typeof params === 'object' ? params : {}),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
@@ -48,7 +65,7 @@ const usePayloadAPI = (url, options = {}) => {
|
||||
setIsError(false);
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [url, locale, search, onLoad]);
|
||||
}, [url, locale, search]);
|
||||
|
||||
return [{ data, isLoading, isError }, { setParams }];
|
||||
};
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
const useThrottledEffect = (callback, delay, deps = []) => {
|
||||
type useThrottledEffect = (callback: React.EffectCallback, delay: number, deps: React.DependencyList) => void;
|
||||
|
||||
const useThrottledEffect: useThrottledEffect = (callback, delay, deps = []) => {
|
||||
const lastRan = useRef(Date.now());
|
||||
|
||||
useEffect(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useFormFields } from '../components/forms/Form/context';
|
||||
|
||||
const useTitle = (useAsTitle) => {
|
||||
const useTitle = (useAsTitle: string): string => {
|
||||
const { getField } = useFormFields();
|
||||
const titleField = getField(useAsTitle);
|
||||
return titleField?.value;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const useUnmountEffect = (callback) => useEffect(() => callback, []);
|
||||
const useUnmountEffect = (callback: React.EffectCallback): void => useEffect(() => callback, []);
|
||||
|
||||
export default useUnmountEffect;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
/* eslint-disable global-require */
|
||||
/* eslint-disable import/no-dynamic-require */
|
||||
|
||||
@@ -5,14 +6,31 @@ import webpack from 'webpack';
|
||||
import getWebpackProdConfig from '../webpack/getWebpackProdConfig';
|
||||
import findConfig from '../config/find';
|
||||
import loadConfig from '../config/load';
|
||||
import { buildConfig } from '../config/build';
|
||||
import getBabelConfig from '../babel.config';
|
||||
|
||||
const babelConfig = getBabelConfig({
|
||||
env: () => false,
|
||||
});
|
||||
|
||||
const configPath = findConfig();
|
||||
|
||||
const build = () => {
|
||||
const build = (): void => {
|
||||
try {
|
||||
const unsanitizedConfig = loadConfig();
|
||||
const config = buildConfig(unsanitizedConfig);
|
||||
require('@babel/register')({
|
||||
...babelConfig,
|
||||
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||
plugins: [
|
||||
[
|
||||
require('babel-plugin-ignore-html-and-css-imports'),
|
||||
{
|
||||
removeExtensions: ['.svg', '.css', '.scss', '.png', '.jpg'],
|
||||
},
|
||||
],
|
||||
...babelConfig.plugins,
|
||||
],
|
||||
});
|
||||
|
||||
const config = loadConfig();
|
||||
|
||||
const webpackProdConfig = getWebpackProdConfig({
|
||||
...config,
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import minimist from 'minimist';
|
||||
import build from './build';
|
||||
|
||||
|
||||
@@ -158,3 +158,16 @@ export type AfterForgotPasswordHook = (args?: {
|
||||
}) => any;
|
||||
|
||||
export type AfterErrorHook = (args?: { [p: string]: any }, response?: any) => any;
|
||||
|
||||
export type PaginatedDocs = {
|
||||
docs: unknown[]
|
||||
totalDocs: number
|
||||
limit: number
|
||||
totalPages: number
|
||||
page: number
|
||||
pagingCounter: number
|
||||
hasPrevPage: boolean
|
||||
hasNextPage: boolean
|
||||
prevPage: number | null
|
||||
nextPage: number | null
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import findUp from 'find-up';
|
||||
|
||||
const findConfig = (): string => {
|
||||
// If the developer has specified a config path,
|
||||
@@ -12,30 +12,21 @@ const findConfig = (): string => {
|
||||
return path.resolve(process.cwd(), process.env.PAYLOAD_CONFIG_PATH);
|
||||
}
|
||||
|
||||
// By default, Payload is installed as a node_module.
|
||||
// Traverse up three levels and check for config
|
||||
const defaultPath = path.resolve(__dirname, '../../../payload.config.js');
|
||||
const configPath = findUp.sync((dir) => {
|
||||
const tsPath = path.join(dir, 'payload.config.ts');
|
||||
const hasTS = findUp.sync.exists(tsPath);
|
||||
|
||||
if (fs.existsSync(defaultPath)) {
|
||||
return defaultPath;
|
||||
}
|
||||
if (hasTS) return tsPath;
|
||||
|
||||
const defaultTSPath = path.resolve(__dirname, '../../../payload.config.ts');
|
||||
const jsPath = path.join(dir, 'payload.config.js');
|
||||
const hasJS = findUp.sync.exists(jsPath);
|
||||
|
||||
if (fs.existsSync(defaultTSPath)) {
|
||||
return defaultTSPath;
|
||||
}
|
||||
if (hasJS) return jsPath;
|
||||
|
||||
// Check for config in current working directory
|
||||
const cwdJSPath = path.resolve(process.cwd(), 'payload.config.js');
|
||||
if (fs.existsSync(cwdJSPath)) {
|
||||
return cwdJSPath;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
const cwdTSPath = path.resolve(process.cwd(), 'payload.config.ts');
|
||||
if (fs.existsSync(cwdTSPath)) {
|
||||
return cwdTSPath;
|
||||
}
|
||||
if (configPath) return configPath;
|
||||
|
||||
throw new Error('Error: cannot find Payload config. Please create a configuration file located at the root of your current working directory called "payload.config.js" or "payload.config.ts".');
|
||||
};
|
||||
|
||||
@@ -57,6 +57,9 @@ export type PayloadConfig = {
|
||||
}
|
||||
disable?: boolean;
|
||||
indexHTML?: string;
|
||||
components?: {
|
||||
Nav: React.ComponentType
|
||||
}
|
||||
};
|
||||
collections?: PayloadCollectionConfig[];
|
||||
globals?: Global[];
|
||||
@@ -93,7 +96,8 @@ export type PayloadConfig = {
|
||||
};
|
||||
};
|
||||
localization?: {
|
||||
locales: string[];
|
||||
locales: string[]
|
||||
defaultLocale: string
|
||||
};
|
||||
defaultLocale?: string;
|
||||
fallback?: boolean;
|
||||
|
||||
@@ -39,7 +39,7 @@ type FieldBase = {
|
||||
readOnly?: boolean;
|
||||
disabled?: boolean;
|
||||
condition?: (...args: any[]) => any | void;
|
||||
components?: { [key: string]: JSX.Element | (() => JSX.Element) };
|
||||
components?: { [key: string]: React.ComponentType };
|
||||
};
|
||||
access?: {
|
||||
create?: Access;
|
||||
@@ -52,6 +52,7 @@ type FieldBase = {
|
||||
}
|
||||
|
||||
export type StandardField = FieldBase & {
|
||||
type: string;
|
||||
fields?: Field[];
|
||||
}
|
||||
|
||||
@@ -120,6 +121,7 @@ export type RadioField = FieldBase & {
|
||||
value: string;
|
||||
label: string;
|
||||
}[];
|
||||
hasMany?: boolean;
|
||||
}
|
||||
|
||||
export type Block = {
|
||||
@@ -135,23 +137,16 @@ export type BlockField = FieldBase & {
|
||||
type: 'blocks';
|
||||
minRows?: number;
|
||||
maxRows?: number;
|
||||
blocks?: Block[];
|
||||
blocks?: Field[];
|
||||
};
|
||||
|
||||
export type Field = NumberField
|
||||
| TextField
|
||||
| EmailField
|
||||
| TextareaField
|
||||
| CodeField
|
||||
| CheckboxField
|
||||
| DateField
|
||||
export type Field =
|
||||
| StandardField
|
||||
| BlockField
|
||||
| RadioField
|
||||
| RelationshipField
|
||||
| ArrayField
|
||||
| RichTextField
|
||||
| GroupField
|
||||
| RowField
|
||||
| SelectField
|
||||
| SelectManyField
|
||||
| UploadField;
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
/* eslint-disable no-use-before-define */
|
||||
import { Schema } from 'mongoose';
|
||||
import { MissingFieldInputOptions } from '../errors';
|
||||
import { ArrayField, BlockField, CheckboxField, CodeField, DateField, EmailField, Field, GroupField, NumberField, RadioField, RelationshipField, RichTextField, RowField, SelectField, TextareaField, TextField, UploadField } from '../fields/config/types';
|
||||
import { ArrayField, BlockField, Field, RadioField, RelationshipField, SelectField, StandardField, UploadField } from '../fields/config/types';
|
||||
|
||||
const setBlockDiscriminators = (fields: Field[], schema) => {
|
||||
fields.forEach((field) => {
|
||||
if (field.type === 'blocks' && field.blocks && field.blocks.length > 0) {
|
||||
field.blocks.forEach((block) => {
|
||||
const blockFieldType = field as BlockField;
|
||||
if (blockFieldType.type === 'blocks' && blockFieldType.blocks && blockFieldType.blocks.length > 0) {
|
||||
blockFieldType.blocks.forEach((blockItem: StandardField) => {
|
||||
let blockSchemaFields = {};
|
||||
|
||||
block.fields.forEach((blockField) => {
|
||||
// TODO: Would this blow up on a relationship since it doesn't have fields?
|
||||
blockItem.fields.forEach((blockField) => {
|
||||
const fieldSchema = fieldToSchemaMap[blockField.type];
|
||||
if (fieldSchema) {
|
||||
blockSchemaFields = fieldSchema(blockField, blockSchemaFields);
|
||||
@@ -17,9 +19,9 @@ const setBlockDiscriminators = (fields: Field[], schema) => {
|
||||
});
|
||||
|
||||
const blockSchema = new Schema(blockSchemaFields, { _id: false });
|
||||
schema.path(field.name).discriminator(block.slug, blockSchema);
|
||||
schema.path(field.name).discriminator(blockItem.slug, blockSchema);
|
||||
|
||||
setBlockDiscriminators(block.fields, blockSchema);
|
||||
setBlockDiscriminators(blockItem.fields, blockSchema);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -58,27 +60,27 @@ const buildSchema = (configFields: Field[], options = {}): Schema => {
|
||||
};
|
||||
|
||||
const fieldToSchemaMap = {
|
||||
number: (field: NumberField, fields: Field[]) => ({
|
||||
number: (field: Field, fields: Field[]) => ({
|
||||
...fields,
|
||||
[field.name]: { ...formatBaseSchema(field), type: Number },
|
||||
}),
|
||||
text: (field: TextField, fields: Field[]) => ({
|
||||
text: (field: Field, fields: Field[]) => ({
|
||||
...fields,
|
||||
[field.name]: { ...formatBaseSchema(field), type: String },
|
||||
}),
|
||||
email: (field: EmailField, fields: Field[]) => ({
|
||||
email: (field: Field, fields: Field[]) => ({
|
||||
...fields,
|
||||
[field.name]: { ...formatBaseSchema(field), type: String },
|
||||
}),
|
||||
textarea: (field: TextareaField, fields: Field[]) => ({
|
||||
textarea: (field: Field, fields: Field[]) => ({
|
||||
...fields,
|
||||
[field.name]: { ...formatBaseSchema(field), type: String },
|
||||
}),
|
||||
richText: (field: RichTextField, fields: Field[]) => ({
|
||||
richText: (field: Field, fields: Field[]) => ({
|
||||
...fields,
|
||||
[field.name]: { ...formatBaseSchema(field), type: Schema.Types.Mixed },
|
||||
}),
|
||||
code: (field: CodeField, fields: Field[]) => ({
|
||||
code: (field: Field, fields: Field[]) => ({
|
||||
...fields,
|
||||
[field.name]: { ...formatBaseSchema(field), type: String },
|
||||
}),
|
||||
@@ -101,11 +103,11 @@ const fieldToSchemaMap = {
|
||||
[field.name]: field.hasMany ? [schema] : schema, // TODO: radio group with hasMany??
|
||||
};
|
||||
},
|
||||
checkbox: (field: CheckboxField, fields: Field[]) => ({
|
||||
checkbox: (field: Field, fields: Field[]) => ({
|
||||
...fields,
|
||||
[field.name]: { ...formatBaseSchema(field), type: Boolean },
|
||||
}),
|
||||
date: (field: DateField, fields: Field[]) => ({
|
||||
date: (field: Field, fields: Field[]) => ({
|
||||
...fields,
|
||||
[field.name]: { ...formatBaseSchema(field), type: Date },
|
||||
}),
|
||||
@@ -147,10 +149,10 @@ const fieldToSchemaMap = {
|
||||
[field.name]: schema,
|
||||
};
|
||||
},
|
||||
row: (field: RowField, fields: Field[]) => {
|
||||
row: (field: StandardField, fields: Field[]) => {
|
||||
const newFields = { ...fields };
|
||||
|
||||
field.fields.forEach((rowField) => {
|
||||
field.fields.forEach((rowField: Field) => {
|
||||
const fieldSchemaMap = fieldToSchemaMap[rowField.type];
|
||||
|
||||
if (fieldSchemaMap) {
|
||||
@@ -172,7 +174,7 @@ const fieldToSchemaMap = {
|
||||
},
|
||||
};
|
||||
},
|
||||
group: (field: GroupField, fields: Field[]) => {
|
||||
group: (field: StandardField, fields: Field[]) => {
|
||||
const schema = buildSchema(field.fields, { _id: false, id: false });
|
||||
|
||||
return {
|
||||
|
||||
22
src/types/assets/index.d.ts
vendored
22
src/types/assets/index.d.ts
vendored
@@ -1,22 +0,0 @@
|
||||
declare module '*.svg' {
|
||||
import React = require('react');
|
||||
|
||||
export const ReactComponent: React.SFC<React.SVGProps<SVGSVGElement>>;
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.jpg' {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
|
||||
declare module '*.png' {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
|
||||
declare module '*.json' {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
56
src/utilities/asyncSome.ts
Normal file
56
src/utilities/asyncSome.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
/* eslint-disable no-use-before-define */
|
||||
/* eslint-disable consistent-return */
|
||||
import wrappy from 'wrappy';
|
||||
import asap from 'asap';
|
||||
|
||||
type Reduce = (er: boolean, result: unknown) => void;
|
||||
type Callback = (last: unknown, next: unknown) => void;
|
||||
|
||||
const ensureFutureTick = wrappy((cb: Callback) => {
|
||||
let sync = true;
|
||||
asap(() => {
|
||||
sync = false;
|
||||
});
|
||||
|
||||
return function safe(...args: unknown[]) {
|
||||
if (sync) {
|
||||
asap(() => {
|
||||
cb.apply(this, args);
|
||||
});
|
||||
} else { cb.apply(this, args); }
|
||||
};
|
||||
});
|
||||
|
||||
function some(list: unknown[], predicate: (item: unknown, reduce: Reduce) => void, cb: Callback): void {
|
||||
const array = slice(list);
|
||||
let index = 0;
|
||||
const { length } = array;
|
||||
const hecomes = ensureFutureTick(cb);
|
||||
|
||||
|
||||
const reduce: Reduce = (er, result) => {
|
||||
if (er) return hecomes(er, false);
|
||||
if (result) return hecomes(null, result);
|
||||
|
||||
index += 1;
|
||||
map();
|
||||
};
|
||||
|
||||
map();
|
||||
|
||||
function map() {
|
||||
if (index >= length) return hecomes(null, false);
|
||||
|
||||
predicate(array[index], reduce);
|
||||
}
|
||||
}
|
||||
|
||||
function slice(args: unknown[]) {
|
||||
const l = args.length;
|
||||
const a = [];
|
||||
let i: number;
|
||||
for (i = 0; i < l; i += 1) a[i] = args[i];
|
||||
return a;
|
||||
}
|
||||
|
||||
export default some;
|
||||
@@ -74,7 +74,6 @@ export default (config: PayloadConfig): Configuration => {
|
||||
crypto: false,
|
||||
https: false,
|
||||
http: false,
|
||||
assert: false,
|
||||
},
|
||||
modules: ['node_modules', path.resolve(__dirname, '../../node_modules')],
|
||||
alias: {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||
import TerserJSPlugin from 'terser-webpack-plugin';
|
||||
import MiniCSSExtractPlugin from 'mini-css-extract-plugin';
|
||||
import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin';
|
||||
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
|
||||
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
|
||||
import path from 'path';
|
||||
import webpack, { Configuration } from 'webpack';
|
||||
import { Config } from '../config/types';
|
||||
import babelConfig from '../babel.config';
|
||||
|
||||
const mockModulePath = path.resolve(__dirname, '../mocks/emptyModule.js');
|
||||
const mockModulePath = path.resolve(__dirname, './mocks/emptyModule.js');
|
||||
|
||||
export default (config: Config): Configuration => {
|
||||
let webpackConfig: Configuration = {
|
||||
@@ -25,7 +25,7 @@ export default (config: Config): Configuration => {
|
||||
devtool: 'source-map',
|
||||
stats: 'errors-only',
|
||||
optimization: {
|
||||
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
|
||||
minimizer: [new TerserJSPlugin({}), new CssMinimizerPlugin()],
|
||||
splitChunks: {
|
||||
cacheGroups: {
|
||||
styles: {
|
||||
@@ -41,53 +41,40 @@ export default (config: Config): Configuration => {
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
test: /\.(t|j|)sx?$/,
|
||||
exclude: /node_modules[\\/](?!(@payloadcms[\\/]payload)[\\/]).*/,
|
||||
use: {
|
||||
loader: require.resolve('babel-loader'),
|
||||
options: babelConfig({ env: () => false }),
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
test: /\.(sa|sc|c)ss$/,
|
||||
sideEffects: true,
|
||||
use: [
|
||||
MiniCSSExtractPlugin.loader,
|
||||
require.resolve('css-loader'),
|
||||
{
|
||||
loader: require.resolve('postcss-loader'),
|
||||
options: {
|
||||
postcssOptions: {
|
||||
plugins: [require.resolve('postcss-preset-env')],
|
||||
},
|
||||
},
|
||||
},
|
||||
require.resolve('sass-loader'),
|
||||
],
|
||||
},
|
||||
{
|
||||
oneOf: [
|
||||
{
|
||||
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
|
||||
loader: require.resolve('url-loader'),
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: 'static/media/[name].[hash:8].[ext]',
|
||||
},
|
||||
test: /\.(?:ico|gif|png|jpg|jpeg)$/i,
|
||||
type: 'asset/resource',
|
||||
},
|
||||
{
|
||||
test: /\.(sa|sc|c)ss$/,
|
||||
sideEffects: true,
|
||||
use: [
|
||||
MiniCSSExtractPlugin.loader,
|
||||
require.resolve('css-loader'),
|
||||
{
|
||||
loader: require.resolve('postcss-loader'),
|
||||
options: {
|
||||
postcssOptions: {
|
||||
plugins: [
|
||||
[
|
||||
require.resolve('postcss-preset-env'),
|
||||
{
|
||||
// Options
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
require.resolve('sass-loader'),
|
||||
],
|
||||
},
|
||||
{
|
||||
exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/],
|
||||
loader: require.resolve('file-loader'),
|
||||
options: {
|
||||
name: 'static/media/[name].[hash:8].[ext]',
|
||||
},
|
||||
test: /\.(woff(2)?|eot|ttf|otf|svg|)$/,
|
||||
type: 'asset/inline',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -99,20 +86,23 @@ export default (config: Config): Configuration => {
|
||||
crypto: false,
|
||||
https: false,
|
||||
http: false,
|
||||
assert: false,
|
||||
},
|
||||
modules: ['node_modules', path.resolve(__dirname, '../../node_modules')],
|
||||
alias: {
|
||||
'payload/config': config.paths.config,
|
||||
'@payloadcms/payload$': mockModulePath,
|
||||
},
|
||||
extensions: ['.ts', '.tsx', '.js', '.json'],
|
||||
},
|
||||
plugins: [
|
||||
new webpack.ProvidePlugin(
|
||||
{ process: 'process/browser' },
|
||||
),
|
||||
new HtmlWebpackPlugin({
|
||||
template: config.admin && config.admin.indexHTML
|
||||
? path.join(config.paths.configDir, config.admin.indexHTML)
|
||||
: path.resolve(__dirname, '../admin/index.html'),
|
||||
filename: './index.html',
|
||||
filename: path.normalize('./index.html'),
|
||||
}),
|
||||
new webpack.DefinePlugin(Object.entries(config.publicENV).reduce((values, [key, val]) => ({
|
||||
...values,
|
||||
@@ -142,7 +132,7 @@ export default (config: Config): Configuration => {
|
||||
}
|
||||
|
||||
if (config.webpack && typeof config.webpack === 'function') {
|
||||
webpackConfig = config.webpack(webpackConfig, 'production');
|
||||
webpackConfig = config.webpack(webpackConfig);
|
||||
}
|
||||
|
||||
return webpackConfig;
|
||||
|
||||
Reference in New Issue
Block a user