diff --git a/src/admin/components/elements/ListControls/types.ts b/src/admin/components/elements/ListControls/types.ts index 6c22078440..5121943d58 100644 --- a/src/admin/components/elements/ListControls/types.ts +++ b/src/admin/components/elements/ListControls/types.ts @@ -7,3 +7,8 @@ export type Props = { collection: CollectionConfig, handleChange: (newState) => void, } + +export type ListControls = { + where?: unknown + columns?: string[] +} diff --git a/src/admin/components/elements/Table/types.ts b/src/admin/components/elements/Table/types.ts index df9fcd4424..287b203ac1 100644 --- a/src/admin/components/elements/Table/types.ts +++ b/src/admin/components/elements/Table/types.ts @@ -1,12 +1,14 @@ import React from 'react'; -export type Props = { - columns: { - accessor: string, - components: { - Heading: React.ReactNode, - renderCell: (row: any, data: any) => React.ReactNode, - }, - }[], - data: [] +export type Column = { + accessor: string, + components: { + Heading: React.ReactNode, + renderCell: (row: any, data: any) => React.ReactNode, + }, +} + +export type Props = { + columns: Column[], + data: unknown[] } diff --git a/src/admin/components/elements/UploadGallery/index.tsx b/src/admin/components/elements/UploadGallery/index.tsx index 8821a561d5..88d4131ea8 100644 --- a/src/admin/components/elements/UploadGallery/index.tsx +++ b/src/admin/components/elements/UploadGallery/index.tsx @@ -16,7 +16,7 @@ const UploadGallery: React.FC = (props) => { {docs.map((doc, i) => (
  • onCardClick(doc)} /> diff --git a/src/admin/components/elements/UploadGallery/types.ts b/src/admin/components/elements/UploadGallery/types.ts index ca42a34bab..d8db9c6f11 100644 --- a/src/admin/components/elements/UploadGallery/types.ts +++ b/src/admin/components/elements/UploadGallery/types.ts @@ -1,5 +1,7 @@ +import { CollectionConfig } from '../../../../collections/config/types'; + export type Props = { - docs?: [], - collection: unknown, + docs?: unknown[], + collection: CollectionConfig, onCardClick: (doc) => void, } diff --git a/src/admin/components/forms/Label/types.ts b/src/admin/components/forms/Label/types.ts index 16ded9d019..970fd16d25 100644 --- a/src/admin/components/forms/Label/types.ts +++ b/src/admin/components/forms/Label/types.ts @@ -1,5 +1,5 @@ export type Props = { - label?: string + label?: string | JSX.Element required?: boolean htmlFor?: string } diff --git a/src/admin/components/forms/RenderFields/types.ts b/src/admin/components/forms/RenderFields/types.ts index e211e63f31..3bdd3045da 100644 --- a/src/admin/components/forms/RenderFields/types.ts +++ b/src/admin/components/forms/RenderFields/types.ts @@ -11,8 +11,8 @@ export type Context = { export type Props = { className?: string operation?: Operation - readOnly: boolean - permissions: { + readOnly?: boolean + permissions?: { [field: string]: FieldPermissions } filter?: (field: Field) => boolean diff --git a/src/admin/components/forms/field-types/Text/index.tsx b/src/admin/components/forms/field-types/Text/index.tsx index c7941672f9..2be32aa210 100644 --- a/src/admin/components/forms/field-types/Text/index.tsx +++ b/src/admin/components/forms/field-types/Text/index.tsx @@ -32,7 +32,7 @@ const Text: React.FC = (props) => { return validationResult; }, [validate, maxLength, minLength, required]); - const fieldType = useFieldType({ + const fieldType = useFieldType({ path, validate: memoizedValidate, enableDebouncedValue: true, @@ -70,7 +70,7 @@ const Text: React.FC = (props) => { required={required} /> = (props) => { { +const useFieldType = (options: Options): FieldType => { const { path, validate, diff --git a/src/admin/components/forms/useFieldType/types.ts b/src/admin/components/forms/useFieldType/types.ts index 52f4fdb97b..6803bb9cd4 100644 --- a/src/admin/components/forms/useFieldType/types.ts +++ b/src/admin/components/forms/useFieldType/types.ts @@ -9,8 +9,8 @@ export type Options = { stringify?: boolean } -export type FieldType = { - value: unknown +export type FieldType = { + value: T errorMessage?: string showError: boolean formSubmitted: boolean diff --git a/src/admin/components/views/Account/index.tsx b/src/admin/components/views/Account/index.tsx index 703bd6b5be..305d82ac74 100644 --- a/src/admin/components/views/Account/index.tsx +++ b/src/admin/components/views/Account/index.tsx @@ -11,7 +11,7 @@ import RenderCustomComponent from '../../utilities/RenderCustomComponent'; import { NegativeFieldGutterProvider } from '../../forms/FieldTypeGutter/context'; const AccountView: React.FC = () => { - const { state: locationState } = useLocation(); + const { state: locationState } = useLocation<{ data: unknown }>(); const locale = useLocale(); const { setStepNav } = useStepNav(); const { user, permissions } = useAuth(); diff --git a/src/admin/components/views/CreateFirstUser/index.tsx b/src/admin/components/views/CreateFirstUser/index.tsx index c4970caeb6..d91d2fb45b 100644 --- a/src/admin/components/views/CreateFirstUser/index.tsx +++ b/src/admin/components/views/CreateFirstUser/index.tsx @@ -1,20 +1,22 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { useConfig } from '@payloadcms/config-provider'; +import { useConfig, useAuth } from '@payloadcms/config-provider'; import MinimalTemplate from '../../templates/Minimal'; import Meta from '../../utilities/Meta'; import Form from '../../forms/Form'; import RenderFields from '../../forms/RenderFields'; import fieldTypes from '../../forms/field-types'; import FormSubmit from '../../forms/Submit'; -import { useAuth } from '@payloadcms/config-provider'; +import { Props } from './types'; +import { Field } from '../../../../fields/config/types'; + import { NegativeFieldGutterProvider } from '../../forms/FieldTypeGutter/context'; import './index.scss'; const baseClass = 'create-first-user'; -const CreateFirstUser = (props) => { +const CreateFirstUser: React.FC = (props) => { const { setInitialized } = props; const { setToken } = useAuth(); const { @@ -43,7 +45,7 @@ const CreateFirstUser = (props) => { type: 'password', required: true, }, - ]; + ] as Field[]; return ( @@ -56,7 +58,7 @@ const CreateFirstUser = (props) => { />
    diff --git a/src/admin/components/views/CreateFirstUser/types.ts b/src/admin/components/views/CreateFirstUser/types.ts new file mode 100644 index 0000000000..e68aa3cb90 --- /dev/null +++ b/src/admin/components/views/CreateFirstUser/types.ts @@ -0,0 +1,3 @@ +export type Props = { + setInitialized: (initialized: boolean) => void +} diff --git a/src/admin/components/views/Dashboard/index.tsx b/src/admin/components/views/Dashboard/index.tsx index 367a7ff8b1..16bc225e59 100644 --- a/src/admin/components/views/Dashboard/index.tsx +++ b/src/admin/components/views/Dashboard/index.tsx @@ -5,7 +5,7 @@ import { useStepNav } from '../../elements/StepNav'; import RenderCustomComponent from '../../utilities/RenderCustomComponent'; import DefaultDashboard from './Default'; -const Dashboard = () => { +const Dashboard: React.FC = () => { const { permissions } = useAuth(); const { setStepNav } = useStepNav(); const [filteredGlobals, setFilteredGlobals] = useState([]); @@ -15,7 +15,9 @@ const Dashboard = () => { globals, admin: { components: { - Dashboard: CustomDashboard, + views: { + Dashboard: CustomDashboard, + } = {}, } = {}, } = {}, } = useConfig(); diff --git a/src/admin/components/views/ForgotPassword/index.tsx b/src/admin/components/views/ForgotPassword/index.tsx index e4553e00b1..bd67b99e53 100644 --- a/src/admin/components/views/ForgotPassword/index.tsx +++ b/src/admin/components/views/ForgotPassword/index.tsx @@ -1,20 +1,20 @@ import React, { useState } from 'react'; import { Link } from 'react-router-dom'; import { toast } from 'react-toastify'; -import { useConfig } from '@payloadcms/config-provider'; +import { useConfig, useAuth } from '@payloadcms/config-provider'; import MinimalTemplate from '../../templates/Minimal'; import Form from '../../forms/Form'; import Email from '../../forms/field-types/Email'; import FormSubmit from '../../forms/Submit'; import Button from '../../elements/Button'; import Meta from '../../utilities/Meta'; -import { useAuth } from '@payloadcms/config-provider'; + import './index.scss'; const baseClass = 'forgot-password'; -const ForgotPassword = () => { +const ForgotPassword: React.FC = () => { const [hasSubmitted, setHasSubmitted] = useState(false); const { user } = useAuth(); const { @@ -78,9 +78,8 @@ const ForgotPassword = () => { return (

    Forgot Password

    @@ -88,7 +87,7 @@ const ForgotPassword = () => { Submit diff --git a/src/admin/components/views/Global/Default.tsx b/src/admin/components/views/Global/Default.tsx index 379d9a9c79..dfeacec0f7 100644 --- a/src/admin/components/views/Global/Default.tsx +++ b/src/admin/components/views/Global/Default.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import PropTypes from 'prop-types'; import format from 'date-fns/format'; import Eyebrow from '../../elements/Eyebrow'; import Form from '../../forms/Form'; @@ -10,12 +9,13 @@ import CopyToClipboard from '../../elements/CopyToClipboard'; import Meta from '../../utilities/Meta'; import fieldTypes from '../../forms/field-types'; import LeaveWithoutSaving from '../../modals/LeaveWithoutSaving'; +import { Props } from './types'; import './index.scss'; const baseClass = 'global-edit'; -const DefaultGlobalView = (props) => { +const DefaultGlobalView: React.FC = (props) => { const { global, data, onSave, permissions, action, apiURL, initialState, } = props; @@ -58,7 +58,7 @@ const DefaultGlobalView = (props) => { operation="update" readOnly={!hasSavePermission} permissions={permissions.fields} - filter={(field) => (!field.position || (field.position && field.position !== 'sidebar'))} + filter={(field) => (!field.admin.position || (field.admin.position && field.admin.position !== 'sidebar'))} fieldTypes={fieldTypes} fieldSchema={fields} /> @@ -92,8 +92,7 @@ const DefaultGlobalView = (props) => { operation="update" readOnly={!hasSavePermission} permissions={permissions.fields} - filter={(field) => field.position === 'sidebar'} - position="sidebar" + filter={(field) => field.admin.position === 'sidebar'} fieldTypes={fieldTypes} fieldSchema={fields} /> @@ -103,7 +102,7 @@ const DefaultGlobalView = (props) => { {data.updatedAt && (
  • Last Modified
    -
    {format(new Date(data.updatedAt), 'MMMM do yyyy, h:mm a')}
    +
    {format(new Date(data.updatedAt as string), 'MMMM do yyyy, h:mm a')}
  • )} @@ -114,29 +113,4 @@ const DefaultGlobalView = (props) => { ); }; -DefaultGlobalView.defaultProps = { - data: undefined, -}; - -DefaultGlobalView.propTypes = { - global: PropTypes.shape({ - label: PropTypes.string.isRequired, - fields: PropTypes.arrayOf(PropTypes.shape({})), - preview: PropTypes.func, - }).isRequired, - data: PropTypes.shape({ - updatedAt: PropTypes.string, - }), - onSave: PropTypes.func.isRequired, - permissions: PropTypes.shape({ - update: PropTypes.shape({ - permission: PropTypes.bool, - }), - fields: PropTypes.shape({}), - }).isRequired, - action: PropTypes.string.isRequired, - apiURL: PropTypes.string.isRequired, - initialState: PropTypes.shape({}).isRequired, -}; - export default DefaultGlobalView; diff --git a/src/admin/components/views/Global/index.tsx b/src/admin/components/views/Global/index.tsx index 1f9edb39ec..9bb13692e8 100644 --- a/src/admin/components/views/Global/index.tsx +++ b/src/admin/components/views/Global/index.tsx @@ -1,5 +1,4 @@ import React, { useState, useEffect } from 'react'; -import PropTypes from 'prop-types'; import { useHistory, useLocation } from 'react-router-dom'; import { useConfig, useAuth } from '@payloadcms/config-provider'; import { useStepNav } from '../../elements/StepNav'; @@ -11,9 +10,10 @@ import RenderCustomComponent from '../../utilities/RenderCustomComponent'; import DefaultGlobal from './Default'; import buildStateFromSchema from '../../forms/Form/buildStateFromSchema'; import { NegativeFieldGutterProvider } from '../../forms/FieldTypeGutter/context'; +import { IndexProps } from './types'; -const GlobalView = (props) => { - const { state: locationState } = useLocation(); +const GlobalView: React.FC = (props) => { + const { state: locationState } = useLocation<{data?: Record}>(); const history = useHistory(); const locale = useLocale(); const { setStepNav } = useStepNav(); @@ -97,18 +97,4 @@ const GlobalView = (props) => { ); }; - -GlobalView.propTypes = { - global: PropTypes.shape({ - label: PropTypes.string.isRequired, - slug: PropTypes.string.isRequired, - fields: PropTypes.arrayOf(PropTypes.shape({})), - admin: PropTypes.shape({ - components: PropTypes.shape({ - Edit: PropTypes.node, - }), - }), - }).isRequired, -}; - export default GlobalView; diff --git a/src/admin/components/views/Global/types.ts b/src/admin/components/views/Global/types.ts new file mode 100644 index 0000000000..09aadbcbdb --- /dev/null +++ b/src/admin/components/views/Global/types.ts @@ -0,0 +1,17 @@ +import { GlobalPermission } from '../../../../auth/types'; +import { GlobalConfig } from '../../../../globals/config/types'; +import { Fields } from '../../forms/Form/types'; + +export type IndexProps = { + global: GlobalConfig +} + +export type Props = { + global: GlobalConfig + data: Record + onSave: () => void + permissions: GlobalPermission + action: string + apiURL: string + initialState: Fields +} diff --git a/src/admin/components/views/Login/index.tsx b/src/admin/components/views/Login/index.tsx index 02f4703731..9ab34ce830 100644 --- a/src/admin/components/views/Login/index.tsx +++ b/src/admin/components/views/Login/index.tsx @@ -15,7 +15,7 @@ import './index.scss'; const baseClass = 'login'; -const Login = () => { +const Login: React.FC = () => { const history = useHistory(); const { user, setToken } = useAuth(); const { admin: { user: userSlug }, serverURL, routes: { admin, api } } = useConfig(); @@ -71,17 +71,16 @@ const Login = () => { disableSuccessStatus waitForAutocomplete onSuccess={onSuccess} - method="POST" + method="post" action={`${serverURL}${api}/${userSlug}/login`} > { +const Logout: React.FC<{inactivity?: boolean}> = (props) => { const { inactivity } = props; const { logOut } = useAuth(); @@ -47,12 +46,4 @@ const Logout = (props) => { ); }; -Logout.defaultProps = { - inactivity: false, -}; - -Logout.propTypes = { - inactivity: PropTypes.bool, -}; - export default Logout; diff --git a/src/admin/components/views/NotFound/index.tsx b/src/admin/components/views/NotFound/index.tsx index ccea4e4585..27e22c8626 100644 --- a/src/admin/components/views/NotFound/index.tsx +++ b/src/admin/components/views/NotFound/index.tsx @@ -5,7 +5,7 @@ import { useStepNav } from '../../elements/StepNav'; import Button from '../../elements/Button'; import Meta from '../../utilities/Meta'; -const NotFound = () => { +const NotFound: React.FC = () => { const { setStepNav } = useStepNav(); const { routes: { admin } } = useConfig(); diff --git a/src/admin/components/views/ResetPassword/index.tsx b/src/admin/components/views/ResetPassword/index.tsx index 0082eedd17..9001d805a0 100644 --- a/src/admin/components/views/ResetPassword/index.tsx +++ b/src/admin/components/views/ResetPassword/index.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Link, useHistory, useParams } from 'react-router-dom'; -import { useConfig } from '@payloadcms/config-provider'; +import { useConfig, useAuth } from '@payloadcms/config-provider'; import MinimalTemplate from '../../templates/Minimal'; import Form from '../../forms/Form'; import Password from '../../forms/field-types/Password'; @@ -8,16 +8,16 @@ import ConfirmPassword from '../../forms/field-types/ConfirmPassword'; import FormSubmit from '../../forms/Submit'; import Button from '../../elements/Button'; import Meta from '../../utilities/Meta'; -import { useAuth } from '@payloadcms/config-provider'; + import './index.scss'; import HiddenInput from '../../forms/field-types/HiddenInput'; const baseClass = 'reset-password'; -const ResetPassword = () => { +const ResetPassword: React.FC = () => { const { admin: { user: userSlug }, serverURL, routes: { admin, api } } = useConfig(); - const { token } = useParams(); + const { token } = useParams<{token?: string}>(); const history = useHistory(); const { user, setToken } = useAuth(); @@ -65,12 +65,11 @@ const ResetPassword = () => {

    Reset Password

    { +const Unauthorized: React.FC = () => { const { routes: { admin } } = useConfig(); return ( diff --git a/src/admin/components/views/Verify/index.tsx b/src/admin/components/views/Verify/index.tsx index 0de2b3cfe1..c676f19c03 100644 --- a/src/admin/components/views/Verify/index.tsx +++ b/src/admin/components/views/Verify/index.tsx @@ -1,23 +1,22 @@ import React, { useEffect, useState } from 'react'; -import PropTypes from 'prop-types'; import { useParams } from 'react-router-dom'; +import { useConfig, useAuth } from '@payloadcms/config-provider'; import Logo from '../../graphics/Logo'; import MinimalTemplate from '../../templates/Minimal'; import Button from '../../elements/Button'; import Meta from '../../utilities/Meta'; +import { CollectionConfig } from '../../../../collections/config/types'; -import { useConfig } from '@payloadcms/config-provider'; -import { useAuth } from '@payloadcms/config-provider'; import Login from '../Login'; import './index.scss'; const baseClass = 'verify'; -const Verify = ({ collection }) => { +const Verify: React.FC<{ collection: CollectionConfig }> = ({ collection }) => { const { slug: collectionSlug } = collection; const { user } = useAuth(); - const { token } = useParams(); + const { token } = useParams<{token?: string}>(); const { serverURL, routes: { admin: adminRoute }, admin: { user: adminUser } } = useConfig(); const isAdminUser = collectionSlug === adminUser; @@ -66,10 +65,4 @@ const Verify = ({ collection }) => {
    ); }; - -Verify.propTypes = { - collection: PropTypes.shape({ - slug: PropTypes.string, - }).isRequired, -}; export default Verify; diff --git a/src/admin/components/views/collections/Edit/Auth/APIKey.tsx b/src/admin/components/views/collections/Edit/Auth/APIKey.tsx index 167a39c108..9cdd099324 100644 --- a/src/admin/components/views/collections/Edit/Auth/APIKey.tsx +++ b/src/admin/components/views/collections/Edit/Auth/APIKey.tsx @@ -13,7 +13,7 @@ const path = 'apiKey'; const baseClass = 'api-key'; const validate = (val) => text(val, { minLength: 24, maxLength: 48 }); -const APIKey = () => { +const APIKey: React.FC = () => { const [initialAPIKey, setInitialAPIKey] = useState(null); const [highlightedField, setHighlightedField] = useState(false); @@ -28,7 +28,7 @@ const APIKey = () => { API Key - + ), [apiKeyValue]); @@ -83,9 +83,9 @@ const APIKey = () => { label={APIKeyLabel} /> = (props) => { )} { return true; }; -const File = (props) => { - const inputRef = useRef(); - const dropRef = useRef(); +const File: React.FC = (props) => { + const inputRef = useRef(null); + const dropRef = useRef(null); const [fileList, setFileList] = useState(undefined); const [selectingFile, setSelectingFile] = useState(false); const [dragging, setDragging] = useState(false); @@ -34,7 +34,9 @@ const File = (props) => { const [replacingFile, setReplacingFile] = useState(false); const { - data = {}, adminThumbnail, staticURL, + data = {} as Data, + adminThumbnail, + staticURL, } = props; const { filename } = data; @@ -44,7 +46,7 @@ const File = (props) => { setValue, showError, errorMessage, - } = useFieldType({ + } = useFieldType<{name: string}>({ path: 'file', validate, }); @@ -111,7 +113,7 @@ const File = (props) => { }; } - return () => { }; + return () => null; }, [handleDragIn, handleDragOut, handleDrop, dropRef]); useEffect(() => { @@ -197,20 +199,4 @@ const File = (props) => { ); }; -File.defaultProps = { - data: undefined, - adminThumbnail: undefined, -}; - -File.propTypes = { - fieldTypes: PropTypes.shape({}).isRequired, - data: PropTypes.shape({ - filename: PropTypes.string, - mimeType: PropTypes.string, - filesize: PropTypes.number, - }), - staticURL: PropTypes.string.isRequired, - adminThumbnail: PropTypes.string, -}; - export default File; diff --git a/src/admin/components/views/collections/Edit/Upload/types.ts b/src/admin/components/views/collections/Edit/Upload/types.ts new file mode 100644 index 0000000000..60d97343a5 --- /dev/null +++ b/src/admin/components/views/collections/Edit/Upload/types.ts @@ -0,0 +1,11 @@ +export type Data = { + filename: string + mimeType: string + filesize: number +} + +export type Props = { + data?: Data + adminThumbnail?: string + staticURL: string +} diff --git a/src/admin/components/views/collections/Edit/index.tsx b/src/admin/components/views/collections/Edit/index.tsx index 23eebbc70b..6be3f62f0c 100644 --- a/src/admin/components/views/collections/Edit/index.tsx +++ b/src/admin/components/views/collections/Edit/index.tsx @@ -4,16 +4,15 @@ import { useConfig, useAuth } from '@payloadcms/config-provider'; import { useStepNav } from '../../../elements/StepNav'; import usePayloadAPI from '../../../../hooks/usePayloadAPI'; - import RenderCustomComponent from '../../../utilities/RenderCustomComponent'; import DefaultEdit from './Default'; import buildStateFromSchema from '../../../forms/Form/buildStateFromSchema'; import { NegativeFieldGutterProvider } from '../../../forms/FieldTypeGutter/context'; import { useLocale } from '../../../utilities/Locale'; -import { Props } from './types'; +import { IndexProps } from './types'; import { StepNavItem } from '../../../elements/StepNav/types'; -const EditView: React.FC = (props) => { +const EditView: React.FC = (props) => { const { collection, isEditing } = props; const { diff --git a/src/admin/components/views/collections/Edit/types.ts b/src/admin/components/views/collections/Edit/types.ts index 60f4fe4c19..2254e5632e 100644 --- a/src/admin/components/views/collections/Edit/types.ts +++ b/src/admin/components/views/collections/Edit/types.ts @@ -5,7 +5,7 @@ import { Fields } from '../../../forms/Form/types'; export type IndexProps = { collection: CollectionConfig - isEditing: boolean + isEditing?: boolean } export type Props = IndexProps & { diff --git a/src/admin/components/views/collections/List/Cell/cellTypes.spec.tsx b/src/admin/components/views/collections/List/Cell/cellTypes.spec.tsx index deae9f2983..c6bbc9923d 100644 --- a/src/admin/components/views/collections/List/Cell/cellTypes.spec.tsx +++ b/src/admin/components/views/collections/List/Cell/cellTypes.spec.tsx @@ -1,9 +1,9 @@ /* eslint-disable react/jsx-max-props-per-line */ import React from 'react'; import { render } from '@testing-library/react'; -import BlocksCell from './types/Blocks'; -import DateCell from './types/Date'; -import Checkbox from './types/Checkbox'; +import BlocksCell from './field-types/Blocks'; +import DateCell from './field-types/Date'; +import Checkbox from './field-types/Checkbox'; describe('Cell Types', () => { describe('Blocks', () => { diff --git a/src/admin/components/views/collections/List/Cell/types/Array/index.tsx b/src/admin/components/views/collections/List/Cell/field-types/Array/index.tsx similarity index 100% rename from src/admin/components/views/collections/List/Cell/types/Array/index.tsx rename to src/admin/components/views/collections/List/Cell/field-types/Array/index.tsx diff --git a/src/admin/components/views/collections/List/Cell/types/Blocks/index.tsx b/src/admin/components/views/collections/List/Cell/field-types/Blocks/index.tsx similarity index 74% rename from src/admin/components/views/collections/List/Cell/types/Blocks/index.tsx rename to src/admin/components/views/collections/List/Cell/field-types/Blocks/index.tsx index b89a98cfd5..4581e9532e 100644 --- a/src/admin/components/views/collections/List/Cell/types/Blocks/index.tsx +++ b/src/admin/components/views/collections/List/Cell/field-types/Blocks/index.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import PropTypes from 'prop-types'; const BlocksCell = ({ data, field }) => { const selectedBlocks = data ? data.map(({ blockType }) => blockType) : []; @@ -24,21 +23,4 @@ const BlocksCell = ({ data, field }) => { {label} ); }; - -BlocksCell.defaultProps = { - data: [], -}; - -BlocksCell.propTypes = { - data: PropTypes.arrayOf( - PropTypes.shape({}), - ), - field: PropTypes.shape({ - label: PropTypes.string, - blocks: PropTypes.arrayOf( - PropTypes.shape({}), - ), - }).isRequired, -}; - export default BlocksCell; diff --git a/src/admin/components/views/collections/List/Cell/types/Checkbox/index.scss b/src/admin/components/views/collections/List/Cell/field-types/Checkbox/index.scss similarity index 100% rename from src/admin/components/views/collections/List/Cell/types/Checkbox/index.scss rename to src/admin/components/views/collections/List/Cell/field-types/Checkbox/index.scss diff --git a/src/admin/components/views/collections/List/Cell/types/Checkbox/index.tsx b/src/admin/components/views/collections/List/Cell/field-types/Checkbox/index.tsx similarity index 61% rename from src/admin/components/views/collections/List/Cell/types/Checkbox/index.tsx rename to src/admin/components/views/collections/List/Cell/field-types/Checkbox/index.tsx index aa34d6d982..cfa37789b4 100644 --- a/src/admin/components/views/collections/List/Cell/types/Checkbox/index.tsx +++ b/src/admin/components/views/collections/List/Cell/field-types/Checkbox/index.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import PropTypes from 'prop-types'; import './index.scss'; @@ -9,13 +8,4 @@ const Checkbox = ({ data }) => ( {JSON.stringify(data)} ); - -Checkbox.defaultProps = { - data: undefined, -}; - -Checkbox.propTypes = { - data: PropTypes.bool, -}; - export default Checkbox; diff --git a/src/admin/components/views/collections/List/Cell/types/Code/index.scss b/src/admin/components/views/collections/List/Cell/field-types/Code/index.scss similarity index 100% rename from src/admin/components/views/collections/List/Cell/types/Code/index.scss rename to src/admin/components/views/collections/List/Cell/field-types/Code/index.scss diff --git a/src/admin/components/views/collections/List/Cell/types/Code/index.tsx b/src/admin/components/views/collections/List/Cell/field-types/Code/index.tsx similarity index 68% rename from src/admin/components/views/collections/List/Cell/types/Code/index.tsx rename to src/admin/components/views/collections/List/Cell/field-types/Code/index.tsx index 8385932442..8271d5478c 100644 --- a/src/admin/components/views/collections/List/Cell/types/Code/index.tsx +++ b/src/admin/components/views/collections/List/Cell/field-types/Code/index.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import PropTypes from 'prop-types'; import './index.scss'; @@ -12,12 +11,4 @@ const CodeCell = ({ data }) => { ); }; -CodeCell.defaultProps = { - data: '', -}; - -CodeCell.propTypes = { - data: PropTypes.string, -}; - export default CodeCell; diff --git a/src/admin/components/views/collections/List/Cell/types/Date/index.tsx b/src/admin/components/views/collections/List/Cell/field-types/Date/index.tsx similarity index 60% rename from src/admin/components/views/collections/List/Cell/types/Date/index.tsx rename to src/admin/components/views/collections/List/Cell/field-types/Date/index.tsx index dc8915044b..4aa8abd5bd 100644 --- a/src/admin/components/views/collections/List/Cell/types/Date/index.tsx +++ b/src/admin/components/views/collections/List/Cell/field-types/Date/index.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import PropTypes from 'prop-types'; import format from 'date-fns/format'; const DateCell = ({ data }) => ( @@ -8,12 +7,4 @@ const DateCell = ({ data }) => ( ); -DateCell.defaultProps = { - data: undefined, -}; - -DateCell.propTypes = { - data: PropTypes.string, -}; - export default DateCell; diff --git a/src/admin/components/views/collections/List/Cell/types/Relationship/index.tsx b/src/admin/components/views/collections/List/Cell/field-types/Relationship/index.tsx similarity index 79% rename from src/admin/components/views/collections/List/Cell/types/Relationship/index.tsx rename to src/admin/components/views/collections/List/Cell/field-types/Relationship/index.tsx index ecb5216ed8..4b3ade4f2e 100644 --- a/src/admin/components/views/collections/List/Cell/types/Relationship/index.tsx +++ b/src/admin/components/views/collections/List/Cell/field-types/Relationship/index.tsx @@ -1,5 +1,4 @@ import React, { useState, useEffect } from 'react'; -import PropTypes from 'prop-types'; import { useConfig } from '@payloadcms/config-provider'; const RelationshipCell = (props) => { @@ -48,24 +47,4 @@ const RelationshipCell = (props) => { ); }; -RelationshipCell.defaultProps = { - data: undefined, -}; - -RelationshipCell.propTypes = { - data: PropTypes.oneOfType([ - PropTypes.shape({}), - PropTypes.array, - PropTypes.string, - ]), - field: PropTypes.shape({ - relationTo: PropTypes.oneOfType([ - PropTypes.arrayOf( - PropTypes.string, - ), - PropTypes.string, - ]), - }).isRequired, -}; - export default RelationshipCell; diff --git a/src/admin/components/views/collections/List/Cell/field-types/Richtext/index.tsx b/src/admin/components/views/collections/List/Cell/field-types/Richtext/index.tsx new file mode 100644 index 0000000000..7cf4601c54 --- /dev/null +++ b/src/admin/components/views/collections/List/Cell/field-types/Richtext/index.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +const RichTextCell = ({ data }) => { + const flattenedText = data?.map((i) => i?.children?.map((c) => c.text)).join(' '); + const textToShow = flattenedText.length > 100 ? `${flattenedText.slice(0, 100)}\u2026` : flattenedText; + return ( + {textToShow} + ); +}; + +export default RichTextCell; diff --git a/src/admin/components/views/collections/List/Cell/field-types/Select/index.tsx b/src/admin/components/views/collections/List/Cell/field-types/Select/index.tsx new file mode 100644 index 0000000000..26e43c35c6 --- /dev/null +++ b/src/admin/components/views/collections/List/Cell/field-types/Select/index.tsx @@ -0,0 +1,24 @@ +import React from 'react'; + +const SelectCell = ({ data, field }) => { + const findLabel = (items) => items.map((i) => { + const found = field.options.filter((f) => f.value === i)?.[0]?.label; + return found; + }).join(', '); + + let content = ''; + if (field?.options?.[0]?.value) { + content = (Array.isArray(data)) + ? findLabel(data) // hasMany + : findLabel([data]); + } else { + content = data.join(', '); + } + return ( + + {content} + + ); +}; + +export default SelectCell; diff --git a/src/admin/components/views/collections/List/Cell/types/Textarea/index.tsx b/src/admin/components/views/collections/List/Cell/field-types/Textarea/index.tsx similarity index 51% rename from src/admin/components/views/collections/List/Cell/types/Textarea/index.tsx rename to src/admin/components/views/collections/List/Cell/field-types/Textarea/index.tsx index 9657868eeb..84f3015ec0 100644 --- a/src/admin/components/views/collections/List/Cell/types/Textarea/index.tsx +++ b/src/admin/components/views/collections/List/Cell/field-types/Textarea/index.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import PropTypes from 'prop-types'; const TextareaCell = ({ data }) => { const textToShow = data.length > 100 ? `${data.substr(0, 100)}\u2026` : data; @@ -8,15 +7,4 @@ const TextareaCell = ({ data }) => { ); }; -TextareaCell.defaultProps = { - data: [], -}; - -TextareaCell.propTypes = { - data: PropTypes.string, - field: PropTypes.shape({ - label: PropTypes.string, - }).isRequired, -}; - export default TextareaCell; diff --git a/src/admin/components/views/collections/List/Cell/types/Upload/index.scss b/src/admin/components/views/collections/List/Cell/field-types/Upload/index.scss similarity index 100% rename from src/admin/components/views/collections/List/Cell/types/Upload/index.scss rename to src/admin/components/views/collections/List/Cell/field-types/Upload/index.scss diff --git a/src/admin/components/views/collections/List/Cell/types/Upload/index.tsx b/src/admin/components/views/collections/List/Cell/field-types/Upload/index.tsx similarity index 54% rename from src/admin/components/views/collections/List/Cell/types/Upload/index.tsx rename to src/admin/components/views/collections/List/Cell/field-types/Upload/index.tsx index a0ccf78b6a..de02912141 100644 --- a/src/admin/components/views/collections/List/Cell/types/Upload/index.tsx +++ b/src/admin/components/views/collections/List/Cell/field-types/Upload/index.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import PropTypes from 'prop-types'; import './index.scss'; @@ -16,18 +15,4 @@ const UploadCell = ({ data }) => ( ); -UploadCell.defaultProps = { - data: {}, -}; - -UploadCell.propTypes = { - data: PropTypes.oneOfType([ - PropTypes.shape({ - filename: PropTypes.string, - mimeType: PropTypes.string, - }), - PropTypes.string, - ]), -}; - export default UploadCell; diff --git a/src/admin/components/views/collections/List/Cell/types/index.tsx b/src/admin/components/views/collections/List/Cell/field-types/index.tsx similarity index 100% rename from src/admin/components/views/collections/List/Cell/types/index.tsx rename to src/admin/components/views/collections/List/Cell/field-types/index.tsx diff --git a/src/admin/components/views/collections/List/Cell/index.tsx b/src/admin/components/views/collections/List/Cell/index.tsx index 23a2fcd412..4c0007c71a 100644 --- a/src/admin/components/views/collections/List/Cell/index.tsx +++ b/src/admin/components/views/collections/List/Cell/index.tsx @@ -1,11 +1,11 @@ import React from 'react'; -import PropTypes from 'prop-types'; import { Link } from 'react-router-dom'; import { useConfig } from '@payloadcms/config-provider'; import RenderCustomComponent from '../../../../utilities/RenderCustomComponent'; -import cellComponents from './types'; +import cellComponents from './field-types'; +import { Props } from './types'; -const DefaultCell = (props) => { +const DefaultCell: React.FC = (props) => { const { field, colIndex, @@ -20,9 +20,11 @@ const DefaultCell = (props) => { const { routes: { admin } } = useConfig(); - let WrapElement = 'span'; + let WrapElement: React.ComponentType | string = 'span'; - const wrapElementProps = {}; + const wrapElementProps: { + to?: string + } = {}; if (colIndex === 0) { WrapElement = Link; @@ -52,7 +54,7 @@ const DefaultCell = (props) => { ); }; -const Cell = (props) => { +const Cell: React.FC = (props) => { const { colIndex, collection, @@ -83,44 +85,4 @@ const Cell = (props) => { ); }; -const defaultProps = { - cellData: undefined, -}; - -const propTypes = { - colIndex: PropTypes.number.isRequired, - collection: PropTypes.shape({ - slug: PropTypes.string, - upload: PropTypes.shape({ - adminThumbnail: PropTypes.string, - }), - }).isRequired, - cellData: PropTypes.oneOfType([ - PropTypes.shape({}), - PropTypes.string, - PropTypes.number, - PropTypes.instanceOf(Date), - PropTypes.array, - PropTypes.bool, - ]), - rowData: PropTypes.shape({ - id: PropTypes.string, - }).isRequired, - field: PropTypes.shape({ - name: PropTypes.string, - type: PropTypes.string, - label: PropTypes.string, - admin: PropTypes.shape({ - components: PropTypes.shape({ - Cell: PropTypes.func, - }), - }), - }).isRequired, -}; - -DefaultCell.defaultProps = defaultProps; -DefaultCell.propTypes = propTypes; -Cell.defaultProps = defaultProps; -Cell.propTypes = propTypes; - export default Cell; diff --git a/src/admin/components/views/collections/List/Cell/types.ts b/src/admin/components/views/collections/List/Cell/types.ts new file mode 100644 index 0000000000..892d1c2de0 --- /dev/null +++ b/src/admin/components/views/collections/List/Cell/types.ts @@ -0,0 +1,12 @@ +import { Field } from '../../../../../../fields/config/types'; +import { CollectionConfig } from '../../../../../../collections/config/types'; + +export type Props = { + field: Field + colIndex: number + collection: CollectionConfig + cellData: unknown + rowData: { + [path: string]: unknown + } +} diff --git a/src/admin/components/views/collections/List/Cell/types/Richtext/index.tsx b/src/admin/components/views/collections/List/Cell/types/Richtext/index.tsx deleted file mode 100644 index 100b57ff5f..0000000000 --- a/src/admin/components/views/collections/List/Cell/types/Richtext/index.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -const RichTextCell = ({ data }) => { - const flattenedText = data?.map((i) => i?.children?.map((c) => c.text)).join(' '); - const textToShow = flattenedText.length > 100 ? `${flattenedText.slice(0, 100)}\u2026` : flattenedText; - return ( - {textToShow} - ); -}; - -RichTextCell.defaultProps = { - data: [], -}; - -RichTextCell.propTypes = { - data: PropTypes.arrayOf( - PropTypes.shape({ - children: PropTypes.arrayOf( - PropTypes.shape({ - bold: PropTypes.string, - text: PropTypes.string, - }), - ), - }), - ), - - - field: PropTypes.shape({ - label: PropTypes.string, - }).isRequired, -}; - -export default RichTextCell; diff --git a/src/admin/components/views/collections/List/Cell/types/Select/index.tsx b/src/admin/components/views/collections/List/Cell/types/Select/index.tsx deleted file mode 100644 index 4ab5b8f1f9..0000000000 --- a/src/admin/components/views/collections/List/Cell/types/Select/index.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -const SelectCell = ({ data, field }) => { - const findLabel = (items) => items.map((i) => { - const found = field.options.filter((f) => f.value === i)?.[0]?.label; - return found; - }).join(', '); - - let content = ''; - if (field?.options?.[0]?.value) { - content = (Array.isArray(data)) - ? findLabel(data) // hasMany - : findLabel([data]); - } else { - content = data.join(', '); - } - return ( - - {content} - - ); -}; - -SelectCell.defaultProps = { - data: [], -}; - -SelectCell.propTypes = { - data: PropTypes.oneOfType( - [ - PropTypes.string, - PropTypes.arrayOf(PropTypes.string), - PropTypes.arrayOf(PropTypes.shape({ - value: PropTypes.string, - label: PropTypes.string, - })), - ], - ), - field: PropTypes.shape({ - label: PropTypes.string, - options: PropTypes.arrayOf( - PropTypes.oneOfType([ - PropTypes.string, - PropTypes.shape({ - value: PropTypes.string, - label: PropTypes.string, - }), - ]), - ), - }).isRequired, -}; - -export default SelectCell; diff --git a/src/admin/components/views/collections/List/Default.tsx b/src/admin/components/views/collections/List/Default.tsx index bb89a60ec1..c0994a8783 100644 --- a/src/admin/components/views/collections/List/Default.tsx +++ b/src/admin/components/views/collections/List/Default.tsx @@ -1,6 +1,5 @@ import React from 'react'; import { useHistory, useLocation } from 'react-router-dom'; -import PropTypes from 'prop-types'; import { useConfig } from '@payloadcms/config-provider'; import UploadGallery from '../../../elements/UploadGallery'; import Eyebrow from '../../../elements/Eyebrow'; @@ -10,12 +9,13 @@ import Pill from '../../../elements/Pill'; import Button from '../../../elements/Button'; import Table from '../../../elements/Table'; import Meta from '../../../utilities/Meta'; +import { Props } from './types'; import './index.scss'; const baseClass = 'collection-list'; -const DefaultList = (props) => { +const DefaultList: React.FC = (props) => { const { collection, collection: { @@ -132,49 +132,4 @@ const DefaultList = (props) => { ); }; -DefaultList.defaultProps = { - data: null, -}; - -DefaultList.propTypes = { - collection: PropTypes.shape({ - upload: PropTypes.shape({}), - labels: PropTypes.shape({ - singular: PropTypes.string, - plural: PropTypes.string, - }), - slug: PropTypes.string, - admin: PropTypes.shape({ - useAsTitle: PropTypes.string, - }), - fields: PropTypes.arrayOf(PropTypes.shape), - timestamps: PropTypes.bool, - }).isRequired, - newDocumentURL: PropTypes.string.isRequired, - data: PropTypes.shape({ - docs: PropTypes.arrayOf( - PropTypes.shape({}), - ), - limit: PropTypes.number, - nextPage: PropTypes.number, - prevPage: PropTypes.number, - totalDocs: PropTypes.number, - hasNextPage: PropTypes.bool, - hasPrevPage: PropTypes.bool, - page: PropTypes.number, - totalPages: PropTypes.number, - }), - setListControls: PropTypes.func.isRequired, - setSort: PropTypes.func.isRequired, - listControls: PropTypes.shape({ - columns: PropTypes.arrayOf( - PropTypes.string, - ), - }).isRequired, - hasCreatePermission: PropTypes.bool.isRequired, - columns: PropTypes.arrayOf( - PropTypes.shape({}), - ).isRequired, -}; - export default DefaultList; diff --git a/src/admin/components/views/collections/List/buildColumns.tsx b/src/admin/components/views/collections/List/buildColumns.tsx index dd551aafb9..9f7ddd9230 100644 --- a/src/admin/components/views/collections/List/buildColumns.tsx +++ b/src/admin/components/views/collections/List/buildColumns.tsx @@ -1,8 +1,11 @@ import React from 'react'; import Cell from './Cell'; import SortColumn from '../../../elements/SortColumn'; +import { CollectionConfig } from '../../../../../collections/config/types'; +import { Column } from '../../../elements/Table/types'; +import { fieldHasSubFields, Field } from '../../../../../fields/config/types'; -const buildColumns = (collection, columns, setSort) => (columns || []).reduce((cols, col, colIndex) => { +const buildColumns = (collection: CollectionConfig, columns: string[], setSort: (sort: string) => void): Column[] => (columns || []).reduce((cols, col, colIndex) => { let field = null; const fields = [ @@ -11,17 +14,17 @@ const buildColumns = (collection, columns, setSort) => (columns || []).reduce((c name: 'id', type: 'text', label: 'ID', - }, + } as Field, { name: 'updatedAt', type: 'date', label: 'Updated At', - }, + } as Field, { name: 'createdAt', type: 'date', label: 'Created At', - }, + } as Field, ]; fields.forEach((fieldToCheck) => { @@ -29,7 +32,7 @@ const buildColumns = (collection, columns, setSort) => (columns || []).reduce((c field = fieldToCheck; } - if (!fieldToCheck.name && Array.isArray(fieldToCheck.fields)) { + if (!fieldToCheck.name && fieldHasSubFields(fieldToCheck)) { fieldToCheck.fields.forEach((subField) => { if (subField.name === col) { field = subField; diff --git a/src/admin/components/views/collections/List/index.tsx b/src/admin/components/views/collections/List/index.tsx index 7e4e34b782..c2bb6bb58f 100644 --- a/src/admin/components/views/collections/List/index.tsx +++ b/src/admin/components/views/collections/List/index.tsx @@ -1,5 +1,4 @@ import React, { useEffect, useState } from 'react'; -import PropTypes from 'prop-types'; import queryString from 'qs'; import { useLocation } from 'react-router-dom'; import { useConfig, useAuth } from '@payloadcms/config-provider'; @@ -8,10 +7,12 @@ import usePayloadAPI from '../../../../hooks/usePayloadAPI'; import DefaultList from './Default'; import RenderCustomComponent from '../../../utilities/RenderCustomComponent'; import { useStepNav } from '../../../elements/StepNav'; +import { ListControls } from '../../../elements/ListControls/types'; import formatFields from './formatFields'; import buildColumns from './buildColumns'; +import { ListIndexProps } from './types'; -const ListView = (props) => { +const ListView: React.FC = (props) => { const { collection, collection: { @@ -21,8 +22,14 @@ const ListView = (props) => { }, admin: { components: { - List: CustomList, - } = {}, + views: { + List: CustomList, + }, + } = { + views: { + List: undefined, + }, + }, }, }, } = props; @@ -33,7 +40,7 @@ const ListView = (props) => { const { setStepNav } = useStepNav(); const [fields] = useState(() => formatFields(collection)); - const [listControls, setListControls] = useState({}); + const [listControls, setListControls] = useState({}); const [columns, setColumns] = useState([]); const [sort, setSort] = useState(null); @@ -51,6 +58,9 @@ const ListView = (props) => { useEffect(() => { const params = { depth: 1, + page: undefined, + sort: undefined, + where: undefined, }; if (page) params.page = page; @@ -90,21 +100,4 @@ const ListView = (props) => { ); }; -ListView.propTypes = { - collection: PropTypes.shape({ - labels: PropTypes.shape({ - singular: PropTypes.string, - plural: PropTypes.string, - }), - admin: PropTypes.shape({ - components: PropTypes.shape({ - List: PropTypes.node, - }), - }), - slug: PropTypes.string, - fields: PropTypes.arrayOf(PropTypes.shape), - timestamps: PropTypes.bool, - }).isRequired, -}; - export default ListView; diff --git a/src/admin/components/views/collections/List/types.ts b/src/admin/components/views/collections/List/types.ts new file mode 100644 index 0000000000..cc2661d67f --- /dev/null +++ b/src/admin/components/views/collections/List/types.ts @@ -0,0 +1,16 @@ +import { CollectionConfig, PaginatedDocs } from '../../../../../collections/config/types'; +import { Column } from '../../../elements/Table/types'; + +export type Props = { + collection: CollectionConfig + data: PaginatedDocs + newDocumentURL: string + setListControls: (controls: unknown) => void + setSort: (sort: string) => void + columns: Column[] + hasCreatePermission: boolean +} + +export type ListIndexProps = { + collection: CollectionConfig +} diff --git a/src/admin/hooks/useIntersect.tsx b/src/admin/hooks/useIntersect.tsx index c38cbe210d..a143d1a390 100644 --- a/src/admin/hooks/useIntersect.tsx +++ b/src/admin/hooks/useIntersect.tsx @@ -15,7 +15,7 @@ const useIntersect = ({ const [node, setNode] = useState(null); const observer = useRef( - new window.IntersectionObserver(([entry]) => updateEntry(entry), { + new window.IntersectionObserver(([ent]) => updateEntry(ent), { root, rootMargin, threshold, diff --git a/src/config/types.ts b/src/config/types.ts index 38a26c00d2..6f7d0fa1a1 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -69,6 +69,9 @@ export type PayloadConfig = { Icon?: React.ComponentType Logo?: React.ComponentType } + views?: { + Dashboard?: React.ComponentType + } } }; collections?: PayloadCollectionConfig[]; diff --git a/src/globals/config/types.ts b/src/globals/config/types.ts index 98ae68b617..d67a3bafc7 100644 --- a/src/globals/config/types.ts +++ b/src/globals/config/types.ts @@ -1,3 +1,4 @@ +import React from 'react'; import { Model, Document } from 'mongoose'; import { DeepRequired } from 'ts-essentials'; import { Access } from '../../config/types'; @@ -8,6 +9,7 @@ export type GlobalModel = Model export type PayloadGlobalConfig = { slug: string label?: string + preview?: (doc: Document, token: string) => string access?: { create?: Access; read?: Access; @@ -16,6 +18,13 @@ export type PayloadGlobalConfig = { admin?: Access; } fields: Field[]; + admin?: { + components?: { + views?: { + Edit?: React.ComponentType + } + } + } } export type GlobalConfig = DeepRequired