Merge remote-tracking branch 'origin' into feat/1180-loading-ui-enhancements

This commit is contained in:
Jarrod Flesch
2023-01-13 12:02:16 -05:00
31 changed files with 277 additions and 60 deletions

View File

@@ -1,7 +1,7 @@
import React, { Fragment, useId, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { ReactEditor, useSlate } from 'slate-react';
import { Transforms, Range } from 'slate';
import { Transforms, Range, Editor } from 'slate';
import { useModal } from '@faceless-ui/modal';
import ElementButton from '../../Button';
import LinkIcon from '../../../../../../icons/Link';
@@ -15,6 +15,10 @@ import { getBaseFields } from '../LinkDrawer/baseFields';
import { LinkDrawer } from '../LinkDrawer';
import { Field } from '../../../../../../../../fields/config/types';
import { Props as RichTextFieldProps } from '../../../types';
import buildStateFromSchema from '../../../../../Form/buildStateFromSchema';
import { useAuth } from '../../../../../../utilities/Auth';
import { Fields } from '../../../../../Form/types';
import { useLocale } from '../../../../../../utilities/Locale';
const insertLink = (editor, fields) => {
const isCollapsed = editor.selection && Range.isCollapsed(editor.selection);
@@ -56,6 +60,9 @@ export const LinkButton: React.FC<{
fieldProps: RichTextFieldProps
}> = ({ fieldProps }) => {
const customFieldSchema = fieldProps?.admin?.link?.fields;
const { user } = useAuth();
const locale = useLocale();
const [initialState, setInitialState] = useState<Fields>({});
const { t } = useTranslation(['upload', 'general']);
const editor = useSlate();
@@ -99,11 +106,22 @@ export const LinkButton: React.FC<{
format="link"
tooltip={t('fields:addLink')}
className="link"
onClick={() => {
onClick={async () => {
if (isElementActive(editor, 'link')) {
unwrapLink(editor);
} else {
openModal(drawerSlug);
const isCollapsed = editor.selection && Range.isCollapsed(editor.selection);
if (!isCollapsed) {
const data = {
text: editor.selection ? Editor.string(editor, editor.selection) : '',
};
const state = await buildStateFromSchema({ fieldSchema, data, user, operation: 'create', locale, t });
setInitialState(state);
}
}
}}
>
@@ -115,6 +133,7 @@ export const LinkButton: React.FC<{
insertLink(editor, fields);
closeModal(drawerSlug);
}}
initialState={initialState}
fieldSchema={fieldSchema}
handleClose={() => {
closeModal(drawerSlug);

View File

@@ -3,6 +3,7 @@ import forgotPassword, { Result } from '../forgotPassword';
import { Payload } from '../../..';
import { getDataLoader } from '../../../collections/dataloader';
import i18n from '../../../translations/init';
import { APIError } from '../../../errors';
export type Options = {
collection: string
@@ -25,6 +26,10 @@ async function localForgotPassword(payload: Payload, options: Options): Promise<
const collection = payload.collections[collectionSlug];
if (!collection) {
throw new APIError(`The collection with slug ${collectionSlug} can't be found.`);
}
req.payloadAPI = 'local';
req.i18n = i18n(payload.config.i18n);

View File

@@ -5,6 +5,7 @@ import { TypeWithID } from '../../../collections/config/types';
import { Payload } from '../../..';
import { getDataLoader } from '../../../collections/dataloader';
import i18n from '../../../translations/init';
import { APIError } from '../../../errors';
export type Options = {
collection: string
@@ -21,7 +22,7 @@ export type Options = {
showHiddenFields?: boolean
}
async function localLogin<T extends TypeWithID = any>(payload: Payload, options: Options): Promise<Result & { user: T}> {
async function localLogin<T extends TypeWithID = any>(payload: Payload, options: Options): Promise<Result & { user: T }> {
const {
collection: collectionSlug,
req = {} as PayloadRequest,
@@ -36,6 +37,10 @@ async function localLogin<T extends TypeWithID = any>(payload: Payload, options:
const collection = payload.collections[collectionSlug];
if (!collection) {
throw new APIError(`The collection with slug ${collectionSlug} can't be found.`);
}
req.payloadAPI = 'local';
req.payload = payload;
req.i18n = i18n(payload.config.i18n);

View File

@@ -3,6 +3,7 @@ import resetPassword, { Result } from '../resetPassword';
import { PayloadRequest } from '../../../express/types';
import { getDataLoader } from '../../../collections/dataloader';
import i18n from '../../../translations/init';
import { APIError } from '../../../errors';
export type Options = {
collection: string
@@ -24,6 +25,10 @@ async function localResetPassword(payload: Payload, options: Options): Promise<R
const collection = payload.collections[collectionSlug];
if (!collection) {
throw new APIError(`The collection with slug ${collectionSlug} can't be found.`);
}
req.payload = payload;
req.payloadAPI = 'local';
req.i18n = i18n(payload.config.i18n);

View File

@@ -3,6 +3,7 @@ import { Payload } from '../../..';
import unlock from '../unlock';
import { getDataLoader } from '../../../collections/dataloader';
import i18n from '../../../translations/init';
import { APIError } from '../../../errors';
export type Options = {
collection: string
@@ -23,6 +24,10 @@ async function localUnlock(payload: Payload, options: Options): Promise<boolean>
const collection = payload.collections[collectionSlug];
if (!collection) {
throw new APIError(`The collection with slug ${collectionSlug} can't be found.`);
}
req.payload = payload;
req.payloadAPI = 'local';
req.i18n = i18n(payload.config.i18n);

View File

@@ -1,3 +1,4 @@
import { APIError } from '../../../errors';
import { Payload } from '../../../index';
import verifyEmail from '../verifyEmail';
@@ -14,6 +15,10 @@ async function localVerifyEmail(payload: Payload, options: Options): Promise<boo
const collection = payload.collections[collectionSlug];
if (!collection) {
throw new APIError(`The collection with slug ${collectionSlug} can't be found.`);
}
return verifyEmail({
token,
collection,

View File

@@ -5,11 +5,11 @@ import Logger from '../utilities/logger';
import loadConfig from '../config/load';
import payload from '..';
export async function generateGraphQLSchema(): Promise<void> {
export function generateGraphQLSchema(): void {
const logger = Logger();
const config = loadConfig();
await payload.init({
payload.init({
secret: '--unused--',
mongoURL: false,
local: true,

View File

@@ -7,6 +7,7 @@ import create from '../create';
import { getDataLoader } from '../../dataloader';
import { File } from '../../../uploads/types';
import i18n from '../../../translations/init';
import { APIError } from '../../../errors';
export type Options<T> = {
collection: string
@@ -46,6 +47,10 @@ export default async function createLocal<T = any>(payload: Payload, options: Op
const collection = payload.collections[collectionSlug];
const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null;
if (!collection) {
throw new APIError(`The collection with slug ${collectionSlug} can't be found.`);
}
req.payloadAPI = 'local';
req.locale = locale ?? req?.locale ?? defaultLocale;
req.fallbackLocale = fallbackLocale ?? req?.fallbackLocale ?? defaultLocale;

View File

@@ -5,6 +5,7 @@ import { Payload } from '../../../index';
import deleteOperation from '../delete';
import { getDataLoader } from '../../dataloader';
import i18n from '../../../translations/init';
import { APIError } from '../../../errors';
export type Options = {
collection: string
@@ -32,6 +33,11 @@ export default async function deleteLocal<T extends TypeWithID = any>(payload: P
const collection = payload.collections[collectionSlug];
const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null;
if (!collection) {
throw new APIError(`The collection with slug ${collectionSlug} can't be found.`);
}
const req = {
user,
payloadAPI: 'local',

View File

@@ -6,6 +6,7 @@ import { PayloadRequest } from '../../../express/types';
import find from '../find';
import { getDataLoader } from '../../dataloader';
import i18n from '../../../translations/init';
import { APIError } from '../../../errors';
export type Options = {
collection: string
@@ -50,6 +51,10 @@ export default async function findLocal<T extends TypeWithID = any>(payload: Pay
const collection = payload.collections[collectionSlug];
const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null;
if (!collection) {
throw new APIError(`The collection with slug ${collectionSlug} can't be found.`);
}
req.payloadAPI = 'local';
req.locale = locale ?? req?.locale ?? defaultLocale;
req.fallbackLocale = fallbackLocale ?? req?.fallbackLocale ?? defaultLocale;

View File

@@ -5,6 +5,7 @@ import findByID from '../findByID';
import { Payload } from '../../..';
import { getDataLoader } from '../../dataloader';
import i18n from '../../../translations/init';
import { APIError } from '../../../errors';
export type Options = {
collection: string
@@ -41,6 +42,10 @@ export default async function findByIDLocal<T extends TypeWithID = any>(payload:
const collection = payload.collections[collectionSlug];
const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null;
if (!collection) {
throw new APIError(`The collection with slug ${collectionSlug} can't be found.`);
}
req.payloadAPI = 'local';
req.locale = locale ?? req?.locale ?? defaultLocale;
req.fallbackLocale = fallbackLocale ?? req?.fallbackLocale ?? defaultLocale;

View File

@@ -5,6 +5,7 @@ import { TypeWithVersion } from '../../../versions/types';
import findVersionByID from '../findVersionByID';
import { getDataLoader } from '../../dataloader';
import i18n from '../../../translations/init';
import { APIError } from '../../../errors';
export type Options = {
collection: string
@@ -35,6 +36,10 @@ export default async function findVersionByIDLocal<T extends TypeWithVersion<T>
const collection = payload.collections[collectionSlug];
const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null;
if (!collection) {
throw new APIError(`The collection with slug ${collectionSlug} can't be found.`);
}
req.payloadAPI = 'local';
req.locale = locale ?? req?.locale ?? defaultLocale;
req.fallbackLocale = fallbackLocale ?? req?.fallbackLocale ?? defaultLocale;

View File

@@ -6,6 +6,7 @@ import { PayloadRequest } from '../../../express/types';
import findVersions from '../findVersions';
import { getDataLoader } from '../../dataloader';
import i18nInit from '../../../translations/init';
import { APIError } from '../../../errors';
export type Options = {
collection: string
@@ -39,6 +40,10 @@ export default async function findVersionsLocal<T extends TypeWithVersion<T> = a
const collection = payload.collections[collectionSlug];
const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null;
if (!collection) {
throw new APIError(`The collection with slug ${collectionSlug} can't be found.`);
}
const i18n = i18nInit(payload.config.i18n);
const req = {
user,

View File

@@ -5,6 +5,7 @@ import { TypeWithVersion } from '../../../versions/types';
import { getDataLoader } from '../../dataloader';
import restoreVersion from '../restoreVersion';
import i18nInit from '../../../translations/init';
import { APIError } from '../../../errors';
export type Options = {
collection: string
@@ -30,6 +31,11 @@ export default async function restoreVersionLocal<T extends TypeWithVersion<T> =
} = options;
const collection = payload.collections[collectionSlug];
if (!collection) {
throw new APIError(`The collection with slug ${collectionSlug} can't be found.`);
}
const i18n = i18nInit(payload.config.i18n);
const req = {
user,

View File

@@ -6,6 +6,7 @@ import { PayloadRequest } from '../../../express/types';
import { getDataLoader } from '../../dataloader';
import { File } from '../../../uploads/types';
import i18nInit from '../../../translations/init';
import { APIError } from '../../../errors';
export type Options<T> = {
collection: string
@@ -43,6 +44,11 @@ export default async function updateLocal<T = any>(payload: Payload, options: Op
} = options;
const collection = payload.collections[collectionSlug];
if (!collection) {
throw new APIError(`The collection with slug ${collectionSlug} can't be found.`);
}
const i18n = i18nInit(payload.config.i18n);
const defaultLocale = payload.config.localization ? payload.config.localization?.defaultLocale : null;

View File

@@ -5,6 +5,7 @@ import { Document } from '../../../types';
import { TypeWithID } from '../../config/types';
import findOne from '../findOne';
import i18nInit from '../../../translations/init';
import { APIError } from '../../../errors';
export type Options = {
slug: string
@@ -32,6 +33,11 @@ export default async function findOneLocal<T extends TypeWithID = any>(payload:
const globalConfig = payload.globals.config.find((config) => config.slug === globalSlug);
const i18n = i18nInit(payload.config.i18n);
if (!globalConfig) {
throw new APIError(`The global with slug ${globalSlug} can't be found.`);
}
const req = {
user,
payloadAPI: 'local',

View File

@@ -5,6 +5,7 @@ import { Document } from '../../../types';
import { TypeWithVersion } from '../../../versions/types';
import findVersionByID from '../findVersionByID';
import i18nInit from '../../../translations/init';
import { APIError } from '../../../errors';
export type Options = {
slug: string
@@ -34,6 +35,10 @@ export default async function findVersionByIDLocal<T extends TypeWithVersion<T>
const globalConfig = payload.globals.config.find((config) => config.slug === globalSlug);
const i18n = i18nInit(payload.config.i18n);
if (!globalConfig) {
throw new APIError(`The global with slug ${globalSlug} can't be found.`);
}
const req = {
user,
payloadAPI: 'local',

View File

@@ -6,6 +6,7 @@ import { PayloadRequest } from '../../../express/types';
import findVersions from '../findVersions';
import { getDataLoader } from '../../../collections/dataloader';
import i18nInit from '../../../translations/init';
import { APIError } from '../../../errors';
export type Options = {
slug: string
@@ -39,6 +40,10 @@ export default async function findVersionsLocal<T extends TypeWithVersion<T> = a
const globalConfig = payload.globals.config.find((config) => config.slug === globalSlug);
const i18n = i18nInit(payload.config.i18n);
if (!globalConfig) {
throw new APIError(`The global with slug ${globalSlug} can't be found.`);
}
const req = {
user,
payloadAPI: 'local',

View File

@@ -5,6 +5,7 @@ import { Document } from '../../../types';
import { TypeWithVersion } from '../../../versions/types';
import restoreVersion from '../restoreVersion';
import i18nInit from '../../../translations/init';
import { APIError } from '../../../errors';
export type Options = {
slug: string
@@ -32,6 +33,10 @@ export default async function restoreVersionLocal<T extends TypeWithVersion<T> =
const globalConfig = payload.globals.config.find((config) => config.slug === globalSlug);
const i18n = i18nInit(payload.config.i18n);
if (!globalConfig) {
throw new APIError(`The global with slug ${globalSlug} can't be found.`);
}
const req = {
user,
payloadAPI: 'local',

View File

@@ -5,6 +5,7 @@ import { TypeWithID } from '../../config/types';
import update from '../update';
import { getDataLoader } from '../../../collections/dataloader';
import i18nInit from '../../../translations/init';
import { APIError } from '../../../errors';
export type Options = {
slug: string
@@ -34,6 +35,10 @@ export default async function updateLocal<T extends TypeWithID = any>(payload: P
const globalConfig = payload.globals.config.find((config) => config.slug === globalSlug);
const i18n = i18nInit(payload.config.i18n);
if (!globalConfig) {
throw new APIError(`The global with slug ${globalSlug} can't be found.`);
}
const req = {
user,
payloadAPI: 'local',

View File

@@ -44,7 +44,7 @@ import { Result as ResetPasswordResult } from './auth/operations/resetPassword';
import { Result as LoginResult } from './auth/operations/login';
import { Options as FindGlobalOptions } from './globals/operations/local/findOne';
import { Options as UpdateGlobalOptions } from './globals/operations/local/update';
import { initPayload } from './init';
import { initSync, initAsync } from './init';
require('isomorphic-fetch');
@@ -121,8 +121,12 @@ export class Payload {
* @description Initializes Payload
* @param options
*/
async init(options: InitOptions): Promise<void> {
await initPayload(this, options);
init(options: InitOptions): void {
initSync(this, options);
}
async initAsync(options: InitOptions): Promise<void> {
await initAsync(this, options);
}
getAdminURL = (): string => `${this.config.serverURL}${this.config.routes.admin}`;

View File

@@ -33,15 +33,7 @@ import mountEndpoints from './express/mountEndpoints';
import PreferencesModel from './preferences/model';
import findConfig from './config/find';
export const initPayload = async (payload: Payload, options: InitOptions): Promise<void> => {
payload.logger = Logger('payload', options.loggerOptions);
payload.mongoURL = options.mongoURL;
if (payload.mongoURL) {
mongoose.set('strictQuery', false);
payload.mongoMemoryServer = await connectMongoose(payload.mongoURL, options.mongoOptions, payload.logger);
}
export const init = (payload: Payload, options: InitOptions): void => {
payload.logger.info('Starting Payload...');
if (!options.secret) {
throw new Error(
@@ -153,7 +145,34 @@ export const initPayload = async (payload: Payload, options: InitOptions): Promi
}
serverInitTelemetry(payload);
};
export const initAsync = async (payload: Payload, options: InitOptions): Promise<void> => {
payload.logger = Logger('payload', options.loggerOptions);
payload.mongoURL = options.mongoURL;
if (payload.mongoURL) {
mongoose.set('strictQuery', false);
payload.mongoMemoryServer = await connectMongoose(payload.mongoURL, options.mongoOptions, payload.logger);
}
init(payload, options);
if (typeof options.onInit === 'function') await options.onInit(payload);
if (typeof payload.config.onInit === 'function') await payload.config.onInit(payload);
};
export const initSync = (payload: Payload, options: InitOptions): void => {
payload.logger = Logger('payload', options.loggerOptions);
payload.mongoURL = options.mongoURL;
if (payload.mongoURL) {
mongoose.set('strictQuery', false);
connectMongoose(payload.mongoURL, options.mongoOptions, payload.logger);
}
init(payload, options);
if (typeof options.onInit === 'function') options.onInit(payload);
if (typeof payload.config.onInit === 'function') payload.config.onInit(payload);
};

View File

@@ -5,7 +5,6 @@ import { PaginatedDocs } from '../../mongoose/types';
import { Collection, CollectionModel, TypeWithID } from '../../collections/config/types';
import { hasWhereAccessResult } from '../../auth';
import { appendVersionToQueryKey } from './appendVersionToQueryKey';
import sanitizeInternalFields from '../../utilities/sanitizeInternalFields';
import replaceWithDraftIfAvailable from './replaceWithDraftIfAvailable';
type AggregateVersion<T> = {
@@ -100,6 +99,28 @@ export const mergeDrafts = async <T extends TypeWithID>({
createdAt: { $first: '$createdAt' },
},
},
{
$addFields: {
id: {
$toObjectId: '$_id',
},
},
},
{
$lookup: {
from: collection.config.slug,
localField: 'id',
foreignField: '_id',
as: 'parent',
},
},
{
$match: {
parent: {
$size: 1,
},
},
},
{ $match: versionQuery },
{ $limit: paginationOptions.limit },
]).then((res) => res.reduce<VersionCollectionMatchMap<T>>((map, { _id, updatedAt, createdAt, version }) => {
@@ -125,6 +146,9 @@ export const mergeDrafts = async <T extends TypeWithID>({
updatedAt: {
$gt: parentDocUpdatedAt,
},
parent: {
$eq: parentDocID,
},
}, {}, { limit: 1 }).lean();
// If there are,
@@ -152,8 +176,8 @@ export const mergeDrafts = async <T extends TypeWithID>({
finalQueryToBuild.where.and.push(accessResult);
}
if (where) {
finalQueryToBuild.where.and[0].or.push(where);
if (incomingWhere) {
finalQueryToBuild.where.and[0].or.push(incomingWhere);
}
if (includedParentIDs.length > 0) {
@@ -165,7 +189,7 @@ export const mergeDrafts = async <T extends TypeWithID>({
}
if (excludedParentIDs.length > 0) {
finalQueryToBuild.where.and[0].or.push({
finalQueryToBuild.where.and.push({
id: {
not_in: excludedParentIDs,
},
@@ -179,15 +203,11 @@ export const mergeDrafts = async <T extends TypeWithID>({
result = {
...result,
docs: await Promise.all(result.docs.map(async (doc) => {
let sanitizedDoc = JSON.parse(JSON.stringify(doc));
sanitizedDoc.id = sanitizedDoc._id;
sanitizedDoc = sanitizeInternalFields(sanitizedDoc);
const matchedVersion = versionCollectionMatchMap[doc.id];
const matchedVersion = versionCollectionMatchMap[sanitizedDoc.id];
if (matchedVersion) {
if (matchedVersion && matchedVersion.updatedAt > doc.updatedAt) {
return {
...sanitizedDoc,
...doc,
...matchedVersion.version,
createdAt: matchedVersion.createdAt,
updatedAt: matchedVersion.updatedAt,
@@ -199,7 +219,7 @@ export const mergeDrafts = async <T extends TypeWithID>({
payload,
entity: collection.config,
entityType: 'collection',
doc: sanitizedDoc,
doc,
locale,
});
})),