Free and open-source under MIT license (#565)
* feat: free and open-source under MIT license
This commit is contained in:
@@ -2,13 +2,13 @@ import React, { Suspense, lazy, useState, useEffect } from 'react';
|
||||
import {
|
||||
Route, Switch, withRouter, Redirect,
|
||||
} from 'react-router-dom';
|
||||
import { useConfig, useAuth } from '@payloadcms/config-provider';
|
||||
import { useAuth } from './utilities/Auth';
|
||||
import { useConfig } from './utilities/Config';
|
||||
import List from './views/collections/List';
|
||||
import DefaultTemplate from './templates/Default';
|
||||
import { requests } from '../api';
|
||||
import Loading from './elements/Loading';
|
||||
import StayLoggedIn from './modals/StayLoggedIn';
|
||||
import Unlicensed from './views/Unlicensed';
|
||||
import Versions from './views/Versions';
|
||||
import Version from './views/Version';
|
||||
import { DocumentInfoProvider } from './utilities/DocumentInfo';
|
||||
@@ -24,7 +24,6 @@ const Edit = lazy(() => import('./views/collections/Edit'));
|
||||
const EditGlobal = lazy(() => import('./views/Global'));
|
||||
const ResetPassword = lazy(() => import('./views/ResetPassword'));
|
||||
const Unauthorized = lazy(() => import('./views/Unauthorized'));
|
||||
const UnauthorizedUser = lazy(() => import('./views/UnauthorizedUser'));
|
||||
const Account = lazy(() => import('./views/Account'));
|
||||
|
||||
const Routes = () => {
|
||||
@@ -108,12 +107,6 @@ const Routes = () => {
|
||||
<Route path={`${match.url}/reset/:token`}>
|
||||
<ResetPassword />
|
||||
</Route>
|
||||
<Route path={`${match.url}/unlicensed-domain`}>
|
||||
<Unlicensed />
|
||||
</Route>
|
||||
<Route path={`${match.url}/unauthorized-user`}>
|
||||
<UnauthorizedUser />
|
||||
</Route>
|
||||
|
||||
{collections.map((collection) => {
|
||||
if (collection?.auth?.verify) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { formatDistance } from 'date-fns';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { toast } from 'react-toastify';
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import { useWatchForm, useFormModified } from '../../forms/Form/context';
|
||||
import { useLocale } from '../../utilities/Locale';
|
||||
import { Props } from './types';
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useState, useCallback } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { Modal, useModal } from '@faceless-ui/modal';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import Button from '../Button';
|
||||
import MinimalTemplate from '../../templates/Minimal';
|
||||
import { useForm } from '../../forms/Form/context';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import { Props } from './types';
|
||||
import Button from '../Button';
|
||||
import { useForm } from '../../forms/Form/context';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../../utilities/Config';
|
||||
import CopyToClipboard from '../../CopyToClipboard';
|
||||
import formatFilesize from '../../../../../uploads/formatFilesize';
|
||||
import { Props } from './types';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import qs from 'qs';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import { useLocale } from '../../utilities/Locale';
|
||||
import { useSearchParams } from '../../utilities/SearchParams';
|
||||
import Popup from '../Popup';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { NavLink, Link, useHistory } from 'react-router-dom';
|
||||
import { useConfig, useAuth } from '@payloadcms/config-provider';
|
||||
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import { useAuth } from '../../utilities/Auth';
|
||||
import RenderCustomComponent from '../../utilities/RenderCustomComponent';
|
||||
import Chevron from '../../icons/Chevron';
|
||||
import LogOut from '../../icons/LogOut';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useAuth } from '@payloadcms/config-provider';
|
||||
import { useAuth } from '../../utilities/Auth';
|
||||
import Button from '../Button';
|
||||
import { Props } from './types';
|
||||
import { useLocale } from '../../utilities/Locale';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import FormSubmit from '../../forms/Submit';
|
||||
import { useForm, useFormModified } from '../../forms/Form/context';
|
||||
import { useDocumentInfo } from '../../utilities/DocumentInfo';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { toast } from 'react-toastify';
|
||||
import { Modal, useModal } from '@faceless-ui/modal';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import { Props } from './types';
|
||||
import { useDocumentInfo } from '../../utilities/DocumentInfo';
|
||||
import Button from '../Button';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import React from 'react';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import Button from '../Button';
|
||||
import { Props } from './types';
|
||||
import { useDocumentInfo } from '../../utilities/DocumentInfo';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useReducer, useState, useCallback, useEffect } from 'react';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../../../utilities/Config';
|
||||
import { Props, Option, ValueWithRelation, GetResults } from './types';
|
||||
import optionsReducer from './optionsReducer';
|
||||
import useDebounce from '../../../../../hooks/useDebounce';
|
||||
|
||||
@@ -6,7 +6,7 @@ import isDeepEqual from 'deep-equal';
|
||||
import { serialize } from 'object-to-formdata';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { toast } from 'react-toastify';
|
||||
import { useAuth } from '@payloadcms/config-provider';
|
||||
import { useAuth } from '../../utilities/Auth';
|
||||
import { useLocale } from '../../utilities/Locale';
|
||||
import { useDocumentInfo } from '../../utilities/DocumentInfo';
|
||||
import { requests } from '../../../api';
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useCallback, useEffect, useReducer, useState } from 'react';
|
||||
import { DragDropContext, Droppable } from 'react-beautiful-dnd';
|
||||
|
||||
import { useAuth } from '@payloadcms/config-provider';
|
||||
import { useAuth } from '../../../utilities/Auth';
|
||||
import withCondition from '../../withCondition';
|
||||
import Button from '../../../elements/Button';
|
||||
import DraggableSection from '../../DraggableSection';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useCallback, useEffect, useReducer, useState } from 'react';
|
||||
import { DragDropContext, Droppable } from 'react-beautiful-dnd';
|
||||
|
||||
import { useAuth } from '@payloadcms/config-provider';
|
||||
import { useAuth } from '../../../utilities/Auth';
|
||||
import { usePreferences } from '../../../utilities/Preferences';
|
||||
import { useLocale } from '../../../utilities/Locale';
|
||||
import withCondition from '../../withCondition';
|
||||
|
||||
@@ -2,8 +2,9 @@ import React, {
|
||||
useCallback, useEffect, useState, useReducer,
|
||||
} from 'react';
|
||||
import equal from 'deep-equal';
|
||||
import { useAuth, useConfig } from '@payloadcms/config-provider';
|
||||
import qs from 'qs';
|
||||
import { useConfig } from '../../../utilities/Config';
|
||||
import { useAuth } from '../../../utilities/Auth';
|
||||
import withCondition from '../../withCondition';
|
||||
import ReactSelect from '../../../elements/ReactSelect';
|
||||
import { Value } from '../../../elements/ReactSelect/types';
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { Fragment, useState, useEffect } from 'react';
|
||||
import { useConfig, useAuth } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../../../../../../utilities/Config';
|
||||
import { useAuth } from '../../../../../../../utilities/Auth';
|
||||
import { useWatchForm } from '../../../../../../Form/context';
|
||||
import Relationship from '../../../../../Relationship';
|
||||
import Select from '../../../../../Select';
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { Fragment, useCallback, useEffect, useState } from 'react';
|
||||
import { Modal, useModal } from '@faceless-ui/modal';
|
||||
import { Transforms } from 'slate';
|
||||
import { ReactEditor, useSlate } from 'slate-react';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../../../../../utilities/Config';
|
||||
import ElementButton from '../../Button';
|
||||
import RelationshipIcon from '../../../../../../icons/Relationship';
|
||||
import Form from '../../../../../Form';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useFocused, useSelected } from 'slate-react';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../../../../../utilities/Config';
|
||||
import RelationshipIcon from '../../../../../../icons/Relationship';
|
||||
import usePayloadAPI from '../../../../../../../hooks/usePayloadAPI';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { Fragment, useEffect, useState } from 'react';
|
||||
import { Modal, useModal } from '@faceless-ui/modal';
|
||||
import { Transforms } from 'slate';
|
||||
import { ReactEditor, useSlate } from 'slate-react';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../../../../../utilities/Config';
|
||||
import ElementButton from '../../Button';
|
||||
import UploadIcon from '../../../../../../icons/Upload';
|
||||
import usePayloadAPI from '../../../../../../../hooks/usePayloadAPI';
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { Transforms, Element } from 'slate';
|
||||
import { ReactEditor, useSlateStatic } from 'slate-react';
|
||||
import { Modal } from '@faceless-ui/modal';
|
||||
import { useAuth } from '@payloadcms/config-provider';
|
||||
import { useAuth } from '../../../../../../../utilities/Auth';
|
||||
import { SanitizedCollectionConfig } from '../../../../../../../../../collections/config/types';
|
||||
import buildStateFromSchema from '../../../../../../Form/buildStateFromSchema';
|
||||
import MinimalTemplate from '../../../../../../../templates/Minimal';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as React from 'react';
|
||||
import { Modal } from '@faceless-ui/modal';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { Element, Transforms } from 'slate';
|
||||
import { ReactEditor, useSlateStatic } from 'slate-react';
|
||||
import { useConfig } from '../../../../../../../utilities/Config';
|
||||
import { SanitizedCollectionConfig } from '../../../../../../../../../collections/config/types';
|
||||
import usePayloadAPI from '../../../../../../../../hooks/usePayloadAPI';
|
||||
import MinimalTemplate from '../../../../../../../templates/Minimal';
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { useModal } from '@faceless-ui/modal';
|
||||
import { Transforms } from 'slate';
|
||||
import { ReactEditor, useSlateStatic, useFocused, useSelected } from 'slate-react';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../../../../../utilities/Config';
|
||||
import usePayloadAPI from '../../../../../../../hooks/usePayloadAPI';
|
||||
import FileGraphic from '../../../../../../graphics/File';
|
||||
import useThumbnail from '../../../../../../../hooks/useThumbnail';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { Modal, useModal } from '@faceless-ui/modal';
|
||||
import { useConfig, useAuth } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../../../utilities/Config';
|
||||
import { useAuth } from '../../../../utilities/Auth';
|
||||
import MinimalTemplate from '../../../../templates/Minimal';
|
||||
import Form from '../../../Form';
|
||||
import Button from '../../../../elements/Button';
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React, { Fragment, useState, useEffect } from 'react';
|
||||
import equal from 'deep-equal';
|
||||
import { Modal, useModal } from '@faceless-ui/modal';
|
||||
import { useAuth, useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../../../utilities/Config';
|
||||
import { useAuth } from '../../../../utilities/Auth';
|
||||
import { Where } from '../../../../../../types';
|
||||
import MinimalTemplate from '../../../../templates/Minimal';
|
||||
import Button from '../../../../elements/Button';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../../utilities/Config';
|
||||
import useField from '../../useField';
|
||||
import withCondition from '../../withCondition';
|
||||
import { upload } from '../../../../../fields/validations';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
useCallback, useEffect, useState,
|
||||
} from 'react';
|
||||
import { useAuth } from '@payloadcms/config-provider';
|
||||
import { useAuth } from '../../utilities/Auth';
|
||||
import { useFormProcessing, useFormSubmitted, useFormModified, useForm } from '../Form/context';
|
||||
import useDebounce from '../../../hooks/useDebounce';
|
||||
import { Options, FieldType } from './types';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import RenderCustomComponent from '../../utilities/RenderCustomComponent';
|
||||
|
||||
const PayloadIcon: React.FC = () => (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import RenderCustomComponent from '../../utilities/RenderCustomComponent';
|
||||
|
||||
const PayloadLogo: React.FC = () => (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import NavigationPrompt from 'react-router-navigation-prompt';
|
||||
import { useAuth } from '@payloadcms/config-provider';
|
||||
import { useAuth } from '../../utilities/Auth';
|
||||
import { useFormModified } from '../../forms/Form/context';
|
||||
import MinimalTemplate from '../../templates/Minimal';
|
||||
import Button from '../../elements/Button';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { useModal, Modal } from '@faceless-ui/modal';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import MinimalTemplate from '../../templates/Minimal';
|
||||
import Button from '../../elements/Button';
|
||||
import { Props } from './types';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import DefaultNav from '../../elements/Nav';
|
||||
import RenderCustomComponent from '../../utilities/RenderCustomComponent';
|
||||
import Meta from '../../utilities/Meta';
|
||||
|
||||
171
src/admin/components/utilities/Auth/index.tsx
Normal file
171
src/admin/components/utilities/Auth/index.tsx
Normal file
@@ -0,0 +1,171 @@
|
||||
import React, {
|
||||
useState, createContext, useContext, useEffect, useCallback,
|
||||
} from 'react';
|
||||
import jwtDecode from 'jwt-decode';
|
||||
import { useLocation, useHistory } from 'react-router-dom';
|
||||
import { useModal } from '@faceless-ui/modal';
|
||||
import { User, Permissions } from '../../../../auth/types';
|
||||
import { useConfig } from '../Config';
|
||||
import { requests } from '../../../api';
|
||||
import useDebounce from '../../../hooks/useDebounce';
|
||||
import { AuthContext } from './types';
|
||||
|
||||
const Context = createContext({} as AuthContext);
|
||||
|
||||
export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
const [user, setUser] = useState<User | null>();
|
||||
const [tokenInMemory, setTokenInMemory] = useState<string>();
|
||||
const { pathname } = useLocation();
|
||||
const { push } = useHistory();
|
||||
|
||||
const config = useConfig();
|
||||
|
||||
const {
|
||||
admin: {
|
||||
user: userSlug,
|
||||
},
|
||||
serverURL,
|
||||
routes: {
|
||||
admin,
|
||||
api,
|
||||
},
|
||||
} = config;
|
||||
|
||||
const exp = user?.exp;
|
||||
|
||||
const [permissions, setPermissions] = useState<Permissions>();
|
||||
|
||||
|
||||
const { open: openModal, closeAll: closeAllModals } = useModal();
|
||||
const [lastLocationChange, setLastLocationChange] = useState(0);
|
||||
const debouncedLocationChange = useDebounce(lastLocationChange, 10000);
|
||||
|
||||
const email = user?.email;
|
||||
|
||||
const refreshCookie = useCallback(() => {
|
||||
const now = Math.round((new Date()).getTime() / 1000);
|
||||
const remainingTime = (exp as number || 0) - now;
|
||||
|
||||
if (exp && remainingTime < 120) {
|
||||
setTimeout(async () => {
|
||||
const request = await requests.post(`${serverURL}${api}/${userSlug}/refresh-token`);
|
||||
|
||||
if (request.status === 200) {
|
||||
const json = await request.json();
|
||||
setUser(json.user);
|
||||
} else {
|
||||
setUser(null);
|
||||
push(`${admin}/logout-inactivity`);
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
}, [setUser, push, exp, admin, api, serverURL, userSlug]);
|
||||
|
||||
const setToken = useCallback((token: string) => {
|
||||
const decoded = jwtDecode(token) as User;
|
||||
setUser(decoded);
|
||||
setTokenInMemory(token);
|
||||
}, []);
|
||||
|
||||
const logOut = () => {
|
||||
setUser(null);
|
||||
setTokenInMemory(undefined);
|
||||
requests.post(`${serverURL}${api}/${userSlug}/logout`);
|
||||
};
|
||||
|
||||
// On mount, get user and set
|
||||
useEffect(() => {
|
||||
const fetchMe = async () => {
|
||||
const request = await requests.get(`${serverURL}${api}/${userSlug}/me`);
|
||||
|
||||
if (request.status === 200) {
|
||||
const json = await request.json();
|
||||
|
||||
setUser(json?.user || null);
|
||||
|
||||
if (json?.token) {
|
||||
setToken(json.token);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fetchMe();
|
||||
}, [setToken, api, serverURL, userSlug]);
|
||||
|
||||
// When location changes, refresh cookie
|
||||
useEffect(() => {
|
||||
if (email) {
|
||||
refreshCookie();
|
||||
}
|
||||
}, [debouncedLocationChange, refreshCookie, email]);
|
||||
|
||||
useEffect(() => {
|
||||
setLastLocationChange(Date.now());
|
||||
}, [pathname]);
|
||||
|
||||
// When user changes, get new access
|
||||
useEffect(() => {
|
||||
async function getPermissions() {
|
||||
const request = await requests.get(`${serverURL}${api}/access`);
|
||||
|
||||
if (request.status === 200) {
|
||||
const json: Permissions = await request.json();
|
||||
setPermissions(json);
|
||||
}
|
||||
}
|
||||
|
||||
if (email) {
|
||||
getPermissions();
|
||||
}
|
||||
}, [email, api, serverURL]);
|
||||
|
||||
useEffect(() => {
|
||||
let reminder: ReturnType<typeof setTimeout>;
|
||||
const now = Math.round((new Date()).getTime() / 1000);
|
||||
const remainingTime = exp as number - now;
|
||||
|
||||
if (remainingTime > 0) {
|
||||
reminder = setTimeout(() => {
|
||||
openModal('stay-logged-in');
|
||||
}, ((remainingTime - 60) * 1000));
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (reminder) clearTimeout(reminder);
|
||||
};
|
||||
}, [exp, openModal]);
|
||||
|
||||
useEffect(() => {
|
||||
let forceLogOut: ReturnType<typeof setTimeout>;
|
||||
const now = Math.round((new Date()).getTime() / 1000);
|
||||
const remainingTime = exp as number - now;
|
||||
|
||||
if (remainingTime > 0) {
|
||||
forceLogOut = setTimeout(() => {
|
||||
setUser(null);
|
||||
push(`${admin}/logout-inactivity`);
|
||||
closeAllModals();
|
||||
}, remainingTime * 1000);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (forceLogOut) clearTimeout(forceLogOut);
|
||||
};
|
||||
}, [exp, push, closeAllModals, admin]);
|
||||
|
||||
return (
|
||||
<Context.Provider value={{
|
||||
user,
|
||||
logOut,
|
||||
refreshCookie,
|
||||
permissions,
|
||||
setToken,
|
||||
token: tokenInMemory,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Context.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useAuth = (): AuthContext => useContext(Context);
|
||||
10
src/admin/components/utilities/Auth/types.ts
Normal file
10
src/admin/components/utilities/Auth/types.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { User, Permissions } from '../../../../auth/types';
|
||||
|
||||
export type AuthContext = {
|
||||
user?: User | null
|
||||
logOut: () => void
|
||||
refreshCookie: () => void
|
||||
setToken: (token: string) => void
|
||||
token?: string
|
||||
permissions?: Permissions
|
||||
}
|
||||
12
src/admin/components/utilities/Config/index.tsx
Normal file
12
src/admin/components/utilities/Config/index.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import React, { createContext, useContext } from 'react';
|
||||
import { SanitizedConfig } from '../../../../config/types';
|
||||
|
||||
const Context = createContext<SanitizedConfig>({} as SanitizedConfig);
|
||||
|
||||
export const ConfigProvider: React.FC<{config: SanitizedConfig, children: React.ReactNode}> = ({ children, config }) => (
|
||||
<Context.Provider value={config}>
|
||||
{children}
|
||||
</Context.Provider>
|
||||
);
|
||||
|
||||
export const useConfig = (): SanitizedConfig => useContext(Context);
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../Config';
|
||||
|
||||
const NestProviders = ({ providers, children }) => {
|
||||
const Component = providers[0];
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React, {
|
||||
createContext, useCallback, useContext, useEffect, useState,
|
||||
} from 'react';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import qs from 'qs';
|
||||
import { useConfig } from '../Config';
|
||||
import { PaginatedDocs } from '../../../../mongoose/types';
|
||||
import { ContextType, Props, Version } from './types';
|
||||
import { TypeWithID } from '../../../../globals/config/types';
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React, {
|
||||
createContext, useContext, useState, useEffect,
|
||||
} from 'react';
|
||||
import { useAuth, useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../Config';
|
||||
import { useAuth } from '../Auth';
|
||||
import { usePreferences } from '../Preferences';
|
||||
import { useSearchParams } from '../SearchParams';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../Config';
|
||||
import { Props } from './types';
|
||||
import payloadFavicon from '../../../assets/images/favicon.svg';
|
||||
import payloadOgImage from '../../../assets/images/og-image.png';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { createContext, useCallback, useContext, useEffect, useRef } from 'react';
|
||||
|
||||
import { useAuth, useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../Config';
|
||||
import { useAuth } from '../Auth';
|
||||
import { requests } from '../../../api';
|
||||
|
||||
type PreferencesContext = {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import format from 'date-fns/format';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import Eyebrow from '../../elements/Eyebrow';
|
||||
import Form from '../../forms/Form';
|
||||
import PreviewButton from '../../elements/PreviewButton';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { useConfig, useAuth } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import { useAuth } from '../../utilities/Auth';
|
||||
import { useStepNav } from '../../elements/StepNav';
|
||||
|
||||
import usePayloadAPI from '../../../hooks/usePayloadAPI';
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { useConfig, useAuth } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import { useAuth } from '../../utilities/Auth';
|
||||
import MinimalTemplate from '../../templates/Minimal';
|
||||
import Meta from '../../utilities/Meta';
|
||||
import Form from '../../forms/Form';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
|
||||
import Eyebrow from '../../elements/Eyebrow';
|
||||
import Card from '../../elements/Card';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useConfig, useAuth } from '@payloadcms/config-provider';
|
||||
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import { useAuth } from '../../utilities/Auth';
|
||||
import { useStepNav } from '../../elements/StepNav';
|
||||
import RenderCustomComponent from '../../utilities/RenderCustomComponent';
|
||||
import DefaultDashboard from './Default';
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { toast } from 'react-toastify';
|
||||
import { useConfig, useAuth } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import { useAuth } from '../../utilities/Auth';
|
||||
import MinimalTemplate from '../../templates/Minimal';
|
||||
import Form from '../../forms/Form';
|
||||
import Email from '../../forms/field-types/Email';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import format from 'date-fns/format';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import Eyebrow from '../../elements/Eyebrow';
|
||||
import Form from '../../forms/Form';
|
||||
import PreviewButton from '../../elements/PreviewButton';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { useConfig, useAuth } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import { useAuth } from '../../utilities/Auth';
|
||||
import { useStepNav } from '../../elements/StepNav';
|
||||
import usePayloadAPI from '../../../hooks/usePayloadAPI';
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { Link, useHistory } from 'react-router-dom';
|
||||
import { useConfig, useAuth } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import { useAuth } from '../../utilities/Auth';
|
||||
import Logo from '../../graphics/Logo';
|
||||
import MinimalTemplate from '../../templates/Minimal';
|
||||
import Form from '../../forms/Form';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { useConfig, useAuth } from '@payloadcms/config-provider';
|
||||
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import { useAuth } from '../../utilities/Auth';
|
||||
import Minimal from '../../templates/Minimal';
|
||||
import Button from '../../elements/Button';
|
||||
import Meta from '../../utilities/Meta';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import Eyebrow from '../../elements/Eyebrow';
|
||||
import { useStepNav } from '../../elements/StepNav';
|
||||
import Button from '../../elements/Button';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { Link, useHistory, useParams } from 'react-router-dom';
|
||||
import { useConfig, useAuth } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import { useAuth } from '../../utilities/Auth';
|
||||
import MinimalTemplate from '../../templates/Minimal';
|
||||
import Form from '../../forms/Form';
|
||||
import Password from '../../forms/field-types/Password';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import Button from '../../elements/Button';
|
||||
import Meta from '../../utilities/Meta';
|
||||
import MinimalTemplate from '../../templates/Minimal';
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
@import '../../../scss/styles.scss';
|
||||
|
||||
.unauthorized-user {
|
||||
&__plan-name {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
&__button-group {
|
||||
display: flex;
|
||||
|
||||
> *:first-child {
|
||||
margin-right: base(.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
import React from 'react';
|
||||
import { useAuth, useConfig } from '@payloadcms/config-provider';
|
||||
import Button from '../../elements/Button';
|
||||
import Meta from '../../utilities/Meta';
|
||||
import Banner from '../../elements/Banner';
|
||||
import MinimalTemplate from '../../templates/Minimal';
|
||||
import X from '../../icons/X';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
const baseClass = 'unauthorized-user';
|
||||
|
||||
const UnauthorizedUser: React.FC = () => {
|
||||
const { licensePlan, user } = useAuth();
|
||||
const {
|
||||
routes: {
|
||||
admin,
|
||||
},
|
||||
} = useConfig();
|
||||
|
||||
return (
|
||||
<MinimalTemplate className={baseClass}>
|
||||
<Meta
|
||||
title="Unauthorized User"
|
||||
description="Unauthorized User"
|
||||
keywords="Unauthorized, Payload, CMS"
|
||||
/>
|
||||
<h2>Your user account is unauthorized</h2>
|
||||
<Banner
|
||||
type="error"
|
||||
alignIcon="left"
|
||||
icon={<X />}
|
||||
>
|
||||
Sorry, the
|
||||
{' '}
|
||||
<strong className={`${baseClass}__plan-name`}>
|
||||
{licensePlan}
|
||||
</strong>
|
||||
{' '}
|
||||
license associated with this domain does not grant access to your email address (
|
||||
<strong>{user?.email}</strong>
|
||||
).
|
||||
</Banner>
|
||||
<p>
|
||||
Don't worry—your Payload API is still accessible, but you can only access the Payload admin panel with user(s) that are specifically whitelisted by the owner of this Payload license.
|
||||
</p>
|
||||
<p>The user accounts that are granted access can be configured within the Payload CMS website. Contact the owner of the license to learn more.</p>
|
||||
<div className={`${baseClass}__button-group`}>
|
||||
<Button
|
||||
el="link"
|
||||
url={`${admin}/logout`}
|
||||
>
|
||||
Log out
|
||||
</Button>
|
||||
<Button
|
||||
el="anchor"
|
||||
url="https://payloadcms.com/login"
|
||||
buttonStyle="secondary"
|
||||
newTab
|
||||
>
|
||||
Go to the Payload CMS website
|
||||
</Button>
|
||||
</div>
|
||||
</MinimalTemplate>
|
||||
);
|
||||
};
|
||||
|
||||
export default UnauthorizedUser;
|
||||
@@ -1,43 +0,0 @@
|
||||
import React from 'react';
|
||||
import Button from '../../elements/Button';
|
||||
import Meta from '../../utilities/Meta';
|
||||
import Banner from '../../elements/Banner';
|
||||
import MinimalTemplate from '../../templates/Minimal';
|
||||
import X from '../../icons/X';
|
||||
|
||||
const Unlicensed: React.FC = () => (
|
||||
<MinimalTemplate className="unlicensed">
|
||||
<Meta
|
||||
title="Unlicensed"
|
||||
description="Unlicensed"
|
||||
keywords="Unlicensed, Payload, CMS"
|
||||
/>
|
||||
<h2>Your Payload license is invalid</h2>
|
||||
<Banner
|
||||
type="error"
|
||||
alignIcon="left"
|
||||
icon={<X />}
|
||||
>
|
||||
Sorry, but your license appears to be invalid for the domain
|
||||
{' '}
|
||||
<strong>
|
||||
{window.location.hostname}
|
||||
</strong>
|
||||
.
|
||||
</Banner>
|
||||
<p>
|
||||
Don't worry—your Payload API is still accessible, but a valid license is required to use the Payload admin panel on a live domain. Your payment method may have expired, or your license may not be properly tied to this domain.
|
||||
</p>
|
||||
<p>You can manage your licenses, including changing the domain that the license is attached to, through the Payload website.</p>
|
||||
<br />
|
||||
<Button
|
||||
el="anchor"
|
||||
url="https://payloadcms.com/login"
|
||||
newTab
|
||||
>
|
||||
Review your licenses
|
||||
</Button>
|
||||
</MinimalTemplate>
|
||||
);
|
||||
|
||||
export default Unlicensed;
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useConfig, useAuth } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import { useAuth } from '../../utilities/Auth';
|
||||
import Logo from '../../graphics/Logo';
|
||||
import MinimalTemplate from '../../templates/Minimal';
|
||||
import Button from '../../elements/Button';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useState, useCallback, useEffect } from 'react';
|
||||
import qs from 'qs';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import format from 'date-fns/format';
|
||||
import { useConfig } from '../../../utilities/Config';
|
||||
import { Props } from './types';
|
||||
import ReactSelect from '../../../elements/ReactSelect';
|
||||
import { PaginatedDocs } from '../../../../../mongoose/types';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import React from 'react';
|
||||
import ReactDiffViewer from 'react-diff-viewer';
|
||||
import { useConfig } from '../../../../../utilities/Config';
|
||||
import { useLocale } from '../../../../../utilities/Locale';
|
||||
import { SanitizedCollectionConfig } from '../../../../../../../collections/config/types';
|
||||
import { fieldAffectsData, fieldIsPresentationalOnly, RelationshipField } from '../../../../../../../fields/config/types';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React, { Fragment, useCallback, useState } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
import { Modal, useModal } from '@faceless-ui/modal';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { useConfig } from '../../../utilities/Config';
|
||||
import { Button, MinimalTemplate, Pill } from '../../..';
|
||||
import { Props } from './types';
|
||||
import { requests } from '../../../../api';
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useAuth, useConfig } from '@payloadcms/config-provider';
|
||||
import { useRouteMatch } from 'react-router-dom';
|
||||
import format from 'date-fns/format';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import { useAuth } from '../../utilities/Auth';
|
||||
import usePayloadAPI from '../../../hooks/usePayloadAPI';
|
||||
import Eyebrow from '../../elements/Eyebrow';
|
||||
import Loading from '../../elements/Loading';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { Link, useRouteMatch } from 'react-router-dom';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import format from 'date-fns/format';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import { Column } from '../../elements/Table/types';
|
||||
import SortColumn from '../../elements/SortColumn';
|
||||
import { SanitizedCollectionConfig } from '../../../../collections/config/types';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useRouteMatch } from 'react-router-dom';
|
||||
import format from 'date-fns/format';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import usePayloadAPI from '../../../hooks/usePayloadAPI';
|
||||
import Eyebrow from '../../elements/Eyebrow';
|
||||
import Loading from '../../elements/Loading';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../../../utilities/Config';
|
||||
import Email from '../../../../forms/field-types/Email';
|
||||
import Password from '../../../../forms/field-types/Password';
|
||||
import Checkbox from '../../../../forms/field-types/Checkbox';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { Link, useRouteMatch } from 'react-router-dom';
|
||||
import format from 'date-fns/format';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../../utilities/Config';
|
||||
import Eyebrow from '../../../elements/Eyebrow';
|
||||
import Form from '../../../forms/Form';
|
||||
import Loading from '../../../elements/Loading';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { Redirect, useRouteMatch, useHistory, useLocation } from 'react-router-dom';
|
||||
import { useConfig, useAuth } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../../utilities/Config';
|
||||
import { useAuth } from '../../../utilities/Auth';
|
||||
import { useStepNav } from '../../../elements/StepNav';
|
||||
import usePayloadAPI from '../../../../hooks/usePayloadAPI';
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import Checkbox from './field-types/Checkbox';
|
||||
import Textarea from './field-types/Textarea';
|
||||
import Select from './field-types/Select';
|
||||
|
||||
jest.mock('@payloadcms/config-provider', () => ({
|
||||
jest.mock('../../../../utilities/Config', () => ({
|
||||
useConfig: () => ({ admin: { dateFormat: 'MMMM do yyyy, h:mm a' } }),
|
||||
}));
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import format from 'date-fns/format';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../../../../../utilities/Config';
|
||||
|
||||
const DateCell = ({ data }) => {
|
||||
const { admin: { dateFormat } } = useConfig();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../../../../../utilities/Config';
|
||||
|
||||
const RelationshipCell = (props) => {
|
||||
const { field, data: cellData } = props;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../../../utilities/Config';
|
||||
import RenderCustomComponent from '../../../../utilities/RenderCustomComponent';
|
||||
import cellComponents from './field-types';
|
||||
import { Props } from './types';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { useHistory, useLocation } from 'react-router-dom';
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../../../utilities/Config';
|
||||
import UploadGallery from '../../../elements/UploadGallery';
|
||||
import Eyebrow from '../../../elements/Eyebrow';
|
||||
import Paginator from '../../../elements/Paginator';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
import { useConfig, useAuth } from '@payloadcms/config-provider';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import queryString from 'qs';
|
||||
|
||||
import { useConfig } from '../../../utilities/Config';
|
||||
import { useAuth } from '../../../utilities/Auth';
|
||||
import usePayloadAPI from '../../../../hooks/usePayloadAPI';
|
||||
import DefaultList from './Default';
|
||||
import RenderCustomComponent from '../../../utilities/RenderCustomComponent';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useConfig } from '@payloadcms/config-provider';
|
||||
import { useConfig } from '../components/utilities/Config';
|
||||
import { SanitizedCollectionConfig } from '../../collections/config/types';
|
||||
import isImage from '../../uploads/isImage';
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@ import { ScrollInfoProvider } from '@faceless-ui/scroll-info';
|
||||
import { WindowInfoProvider } from '@faceless-ui/window-info';
|
||||
import { ModalProvider, ModalContainer } from '@faceless-ui/modal';
|
||||
import { ToastContainer, Slide } from 'react-toastify';
|
||||
import { ConfigProvider, AuthProvider } from '@payloadcms/config-provider';
|
||||
import { AuthProvider } from './components/utilities/Auth';
|
||||
import { ConfigProvider } from './components/utilities/Config';
|
||||
import { PreferencesProvider } from './components/utilities/Preferences';
|
||||
import { CustomProvider } from './components/utilities/CustomProvider';
|
||||
import { SearchParamsProvider } from './components/utilities/SearchParams';
|
||||
|
||||
Reference in New Issue
Block a user