From 1c3a257244e322c04164f6630772a40baf256da7 Mon Sep 17 00:00:00 2001 From: Jessica Boezwinkle Date: Tue, 3 Jan 2023 10:26:10 +0000 Subject: [PATCH 01/14] fix: updatesmargin for group field within a row --- .../forms/field-types/Group/index.scss | 12 +++++- .../forms/field-types/Group/index.tsx | 3 ++ .../forms/field-types/Row/index.tsx | 25 ++++++----- .../forms/field-types/Row/provider.tsx | 17 ++++++++ test/fields/collections/Group/index.ts | 43 +++++++++++++++++++ 5 files changed, 88 insertions(+), 12 deletions(-) create mode 100644 src/admin/components/forms/field-types/Row/provider.tsx diff --git a/src/admin/components/forms/field-types/Group/index.scss b/src/admin/components/forms/field-types/Group/index.scss index b5d738be26..5e975b31b7 100644 --- a/src/admin/components/forms/field-types/Group/index.scss +++ b/src/admin/components/forms/field-types/Group/index.scss @@ -29,6 +29,12 @@ border-bottom: 0; } + &--within-row { + margin: 0; + border-top: 0; + border-bottom: 0; + } + &--within-tab:first-child { margin-top: 0; border-top: 0; @@ -80,4 +86,8 @@ .group-field--within-collapsible+.group-field--within-collapsible { margin-top: base(-1); -} \ No newline at end of file +} + +.group-field--within-row+.group-field--within-row { + margin-top: 0; +} diff --git a/src/admin/components/forms/field-types/Group/index.tsx b/src/admin/components/forms/field-types/Group/index.tsx index fa601a65fc..6a7eb80eed 100644 --- a/src/admin/components/forms/field-types/Group/index.tsx +++ b/src/admin/components/forms/field-types/Group/index.tsx @@ -6,6 +6,7 @@ import FieldDescription from '../../FieldDescription'; import { Props } from './types'; import { useCollapsible } from '../../../elements/Collapsible/provider'; import { GroupProvider, useGroup } from './provider'; +import { useRow } from '../Row/provider'; import { useTabs } from '../Tabs/provider'; import { getTranslation } from '../../../../../utilities/getTranslation'; import { createNestedFieldPath } from '../../Form/createNestedFieldPath'; @@ -35,6 +36,7 @@ const Group: React.FC = (props) => { const isWithinCollapsible = useCollapsible(); const isWithinGroup = useGroup(); + const isWithinRow = useRow(); const isWithinTab = useTabs(); const { i18n } = useTranslation(); @@ -48,6 +50,7 @@ const Group: React.FC = (props) => { baseClass, isWithinCollapsible && `${baseClass}--within-collapsible`, isWithinGroup && `${baseClass}--within-group`, + isWithinRow && `${baseClass}--within-row`, isWithinTab && `${baseClass}--within-tab`, (!hideGutter && isWithinGroup) && `${baseClass}--gutter`, className, diff --git a/src/admin/components/forms/field-types/Row/index.tsx b/src/admin/components/forms/field-types/Row/index.tsx index c03e4bc953..0baf167187 100644 --- a/src/admin/components/forms/field-types/Row/index.tsx +++ b/src/admin/components/forms/field-types/Row/index.tsx @@ -3,6 +3,7 @@ import RenderFields from '../../RenderFields'; import withCondition from '../../withCondition'; import { Props } from './types'; import { createNestedFieldPath } from '../../Form/createNestedFieldPath'; +import { RowProvider } from './provider'; import './index.scss'; @@ -26,17 +27,19 @@ const Row: React.FC = (props) => { ].filter(Boolean).join(' '); return ( - ({ - ...field, - path: createNestedFieldPath(path, field), - }))} - /> + + ({ + ...field, + path: createNestedFieldPath(path, field), + }))} + /> + ); }; export default withCondition(Row); diff --git a/src/admin/components/forms/field-types/Row/provider.tsx b/src/admin/components/forms/field-types/Row/provider.tsx new file mode 100644 index 0000000000..65bb3f6314 --- /dev/null +++ b/src/admin/components/forms/field-types/Row/provider.tsx @@ -0,0 +1,17 @@ +import React, { + createContext, useContext, +} from 'react'; + +const Context = createContext(false); + +export const RowProvider: React.FC<{ children?: React.ReactNode, withinRow?: boolean }> = ({ children, withinRow = true }) => { + return ( + + {children} + + ); +}; + +export const useRow = (): boolean => useContext(Context); + +export default Context; diff --git a/test/fields/collections/Group/index.ts b/test/fields/collections/Group/index.ts index 2b7c78c407..617838f93a 100644 --- a/test/fields/collections/Group/index.ts +++ b/test/fields/collections/Group/index.ts @@ -67,6 +67,49 @@ const GroupFields: CollectionConfig = { }, ], }, + { + type: 'row', + fields: [ + { + name: 'groupInRow', + type: 'group', + fields: [ + { + name: 'field', + type: 'text', + }, + { + name: 'secondField', + type: 'text', + }, + { + name: 'thirdField', + type: 'text', + }, + ], + }, + { + name: 'secondGroupInRow', + type: 'group', + fields: [ + { + name: 'field', + type: 'text', + }, + { + name: 'nestedGroup', + type: 'group', + fields: [ + { + name: 'nestedField', + type: 'text', + }, + ], + }, + ], + }, + ], + }, ], }; From 6c3bc6fb3458c0a272cae60129529b8daada78a2 Mon Sep 17 00:00:00 2001 From: James Date: Thu, 5 Jan 2023 13:32:38 -0500 Subject: [PATCH 02/14] chore: moves graphql types for globals onto payload class --- src/globals/config/types.ts | 15 +++++++------ src/globals/graphql/init.ts | 45 +++++++++++++++++++------------------ 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/globals/config/types.ts b/src/globals/config/types.ts index e65cd30729..3a90637f75 100644 --- a/src/globals/config/types.ts +++ b/src/globals/config/types.ts @@ -89,18 +89,19 @@ export type GlobalConfig = { } } -export interface SanitizedGlobalConfig extends Omit, 'fields' | 'versions' | 'graphQL'> { +export interface SanitizedGlobalConfig extends Omit, 'fields' | 'versions'> { fields: Field[] versions: SanitizedGlobalVersions - graphQL?: { - name?: string - type: GraphQLObjectType - mutationInputType: GraphQLNonNull - versionType?: GraphQLObjectType - } } export type Globals = { Model: GlobalModel config: SanitizedGlobalConfig[] + graphQL?: { + [slug: string]: { + type: GraphQLObjectType + mutationInputType: GraphQLNonNull + versionType?: GraphQLObjectType + } + } } diff --git a/src/globals/graphql/init.ts b/src/globals/graphql/init.ts index e07eec698c..05b931ad3f 100644 --- a/src/globals/graphql/init.ts +++ b/src/globals/graphql/init.ts @@ -30,27 +30,28 @@ function initGlobalsGraphQL(payload: Payload): void { const formattedName = global.graphQL?.name ? global.graphQL.name : singular(toWords(global.slug, true)); - global.graphQL = {} as SanitizedGlobalConfig['graphQL']; - const forceNullableObjectType = Boolean(versions?.drafts); - global.graphQL.type = buildObjectType({ - payload, - name: formattedName, - parentName: formattedName, - fields, - forceNullable: forceNullableObjectType, - }); + if (!payload.globals.graphQL) payload.globals.graphQL = {}; - global.graphQL.mutationInputType = new GraphQLNonNull(buildMutationInputType( - payload, - formattedName, - fields, - formattedName, - )); + payload.globals.graphQL[slug] = { + type: buildObjectType({ + payload, + name: formattedName, + parentName: formattedName, + fields, + forceNullable: forceNullableObjectType, + }), + mutationInputType: new GraphQLNonNull(buildMutationInputType( + payload, + formattedName, + fields, + formattedName, + )), + }; payload.Query.fields[formattedName] = { - type: global.graphQL.type, + type: payload.globals.graphQL[slug].type, args: { draft: { type: GraphQLBoolean }, ...(payload.config.localization ? { @@ -62,9 +63,9 @@ function initGlobalsGraphQL(payload: Payload): void { }; payload.Mutation.fields[`update${formattedName}`] = { - type: global.graphQL.type, + type: payload.globals.graphQL[slug].type, args: { - data: { type: global.graphQL.mutationInputType }, + data: { type: payload.globals.graphQL[slug].mutationInputType }, draft: { type: GraphQLBoolean }, ...(payload.config.localization ? { locale: { type: payload.types.localeInputType }, @@ -102,7 +103,7 @@ function initGlobalsGraphQL(payload: Payload): void { }, ]; - global.graphQL.versionType = buildObjectType({ + payload.globals.graphQL[slug].versionType = buildObjectType({ payload, name: `${formattedName}Version`, parentName: `${formattedName}Version`, @@ -111,7 +112,7 @@ function initGlobalsGraphQL(payload: Payload): void { }); payload.Query.fields[`version${formatName(formattedName)}`] = { - type: global.graphQL.versionType, + type: payload.globals.graphQL[slug].versionType, args: { id: { type: GraphQLString }, ...(payload.config.localization ? { @@ -122,7 +123,7 @@ function initGlobalsGraphQL(payload: Payload): void { resolve: findVersionByIDResolver(global), }; payload.Query.fields[`versions${formattedName}`] = { - type: buildPaginatedListType(`versions${formatName(formattedName)}`, global.graphQL.versionType), + type: buildPaginatedListType(`versions${formatName(formattedName)}`, payload.globals.graphQL[slug].versionType), args: { where: { type: buildWhereInputType( @@ -142,7 +143,7 @@ function initGlobalsGraphQL(payload: Payload): void { resolve: findVersionsResolver(global), }; payload.Mutation.fields[`restoreVersion${formatName(formattedName)}`] = { - type: global.graphQL.type, + type: payload.globals.graphQL[slug].type, args: { id: { type: GraphQLString }, }, From 5a7972fbf8cda6e80acf8ff7f51de615dad17722 Mon Sep 17 00:00:00 2001 From: James Date: Thu, 5 Jan 2023 13:53:39 -0500 Subject: [PATCH 03/14] chore(release): v1.5.3 --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36d22526ea..1714dd6a0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ +## [1.5.3](https://github.com/payloadcms/payload/compare/v1.5.2...v1.5.3) (2023-01-05) + + +### Bug Fixes + +* theme flicker on code editor ([6567454](https://github.com/payloadcms/payload/commit/6567454ae4e4808303da9b80d26633bc77e1445d)) + ## [1.5.2](https://github.com/payloadcms/payload/compare/v1.5.1...v1.5.2) (2023-01-04) diff --git a/package.json b/package.json index 576e98e170..19ba7595cd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "payload", - "version": "1.5.2", + "version": "1.5.3", "description": "Node, React and MongoDB Headless CMS and Application Framework", "license": "MIT", "engines": { From 25e5ab7ceebfb36960b6969db543a2b4ae7127d2 Mon Sep 17 00:00:00 2001 From: Supakarn Laorattanakul Date: Fri, 6 Jan 2023 20:23:27 +0700 Subject: [PATCH 04/14] fix: fix miss typo in Thai translation --- src/translations/th.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/translations/th.json b/src/translations/th.json index 0c9fc18518..4f8d5f6d6b 100644 --- a/src/translations/th.json +++ b/src/translations/th.json @@ -188,7 +188,7 @@ "newPassword": "รหัสผ่านใหม่", "noFiltersSet": "ไม่มีการกรอง", "noLabel": "<ไม่มี {{label}}>", - "noResults": "ไม่พบ {{label}} อาจเป็นเพราะยังไม่มี {{label}} หรือไม่มี {{label}} ใดตรงกับการกร้องด้านบน", + "noResults": "ไม่พบ {{label}} เนื่องจากยังไม่มี {{label}} หรือไม่มี {{label}} ใดตรงกับการกรองด้านบน", "noValue": "ไม่มีค่า", "none": "ไม่มี", "notFound": "ไม่พบ", From 84e00bf7b3dfc1c23367765eec60bec45b81617b Mon Sep 17 00:00:00 2001 From: James Date: Fri, 6 Jan 2023 11:23:55 -0500 Subject: [PATCH 05/14] feat: allows init to accept a pre-built config --- src/config/types.ts | 1 + src/init.ts | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/config/types.ts b/src/config/types.ts index 2f0c24701e..0b81ad5cfe 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -108,6 +108,7 @@ export type InitOptions = { * See Pino Docs for options: https://getpino.io/#/docs/api?id=options */ loggerOptions?: LoggerOptions; + config?: SanitizedConfig }; /** diff --git a/src/init.ts b/src/init.ts index f2ea9020c0..fb1f2e61e5 100644 --- a/src/init.ts +++ b/src/init.ts @@ -1,6 +1,7 @@ /* eslint-disable no-param-reassign */ import express, { NextFunction, Response } from 'express'; import crypto from 'crypto'; +import path from 'path'; import mongoose from 'mongoose'; import { InitOptions } from './config/types'; @@ -30,6 +31,7 @@ import Logger from './utilities/logger'; import { getDataLoader } from './collections/dataloader'; import mountEndpoints from './express/mountEndpoints'; import PreferencesModel from './preferences/model'; +import findConfig from './config/find'; export const init = (payload: Payload, options: InitOptions): void => { payload.logger.info('Starting Payload...'); @@ -52,7 +54,21 @@ export const init = (payload: Payload, options: InitOptions): void => { payload.local = options.local; - payload.config = loadConfig(payload.logger); + if (options.config) { + payload.config = options.config; + const configPath = findConfig(); + + payload.config = { + ...options.config, + paths: { + configDir: path.dirname(configPath), + config: configPath, + rawConfig: configPath, + }, + }; + } else { + payload.config = loadConfig(payload.logger); + } // If not initializing locally, scaffold router if (!payload.local) { From c21c6b8013ca9f3f6ddc14d185666f6a60dafc0d Mon Sep 17 00:00:00 2001 From: James Date: Fri, 6 Jan 2023 11:36:26 -0500 Subject: [PATCH 06/14] chore(release): v1.5.4 --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1714dd6a0c..95326c9e3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ +## [1.5.4](https://github.com/payloadcms/payload/compare/v1.5.3...v1.5.4) (2023-01-06) + + +### Features + +* allows init to accept a pre-built config ([84e00bf](https://github.com/payloadcms/payload/commit/84e00bf7b3dfc1c23367765eec60bec45b81617b)) + ## [1.5.3](https://github.com/payloadcms/payload/compare/v1.5.2...v1.5.3) (2023-01-05) diff --git a/package.json b/package.json index 19ba7595cd..b465fed993 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "payload", - "version": "1.5.3", + "version": "1.5.4", "description": "Node, React and MongoDB Headless CMS and Application Framework", "license": "MIT", "engines": { From bf1242aafa3fa7e72e81af10284f4ddade28c4a0 Mon Sep 17 00:00:00 2001 From: Elliot Lintz <45725915+Elliot67@users.noreply.github.com> Date: Sat, 7 Jan 2023 03:38:40 +0100 Subject: [PATCH 07/14] fix: wrong translation and punctuation spacing --- src/translations/fr.json | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/translations/fr.json b/src/translations/fr.json index c1ed9f334b..57785f8ecd 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -20,10 +20,10 @@ "forceUnlock": "Forcer le déverrouillage", "forgotPassword": "Mot de passe oublié", "forgotPasswordEmailInstructions": "Veuillez saisir votre e-mail ci-dessous. Vous recevrez un e-mail avec des instructions concernant comment réinitialiser votre mot de passe.", - "forgotPasswordQuestion": "Mot de passe oublié?", + "forgotPasswordQuestion": "Mot de passe oublié ?", "generate": "Générer", "generateNewAPIKey": "Générer une nouvelle clé API", - "generatingNewAPIKeyWillInvalidate": "La génération d'une nouvelle clé API <1>invalidera la clé précédente. Êtes-vous sûr de vouloir continuer?", + "generatingNewAPIKeyWillInvalidate": "La génération d'une nouvelle clé API <1>invalidera la clé précédente. Êtes-vous sûr de vouloir continuer ?", "lockUntil": "Verrouiller jusqu'à", "logBackIn": "Se reconnecter", "logOut": "Se déconnecter", @@ -52,8 +52,8 @@ "verify": "Vérifier", "verifyUser": "Vérifier l'utilisateur", "verifyYourEmail": "Vérifiez votre e-mail", - "youAreInactive": "Vous n'avez pas été actif depuis un moment alors vous serez bientôt automatiquement déconnecté pour votre propre sécurité. Souhaitez-vous rester connecté ?", - "youAreReceivingResetPassword": "Vous recevez ceci parce que vous (ou quelqu'un d'autre) avez demandé la réinitialisation du mot de passe de votre compte. Veuillez cliquer sur le lien suivant ou le coller dans votre navigateur pour terminer le processus:", + "youAreInactive": "Vous n'avez pas été actif depuis un moment alors vous serez bientôt automatiquement déconnecté pour votre propre sécurité. Souhaitez-vous rester connecté ?", + "youAreReceivingResetPassword": "Vous recevez ceci parce que vous (ou quelqu'un d'autre) avez demandé la réinitialisation du mot de passe de votre compte. Veuillez cliquer sur le lien suivant ou le coller dans votre navigateur pour terminer le processus :", "youDidNotRequestPassword": "Si vous ne l'avez pas demandé, veuillez ignorer cet e-mail et votre mot de passe restera inchangé." }, "error": { @@ -63,11 +63,11 @@ "deletingFile": "Une erreur s'est produite lors de la suppression du fichier.", "deletingTitle": "Une erreur s'est produite lors de la suppression de {{title}}. Veuillez vérifier votre connexion puis réessayer.", "emailOrPasswordIncorrect": "L'adresse e-mail ou le mot de passe fourni est incorrect.", - "followingFieldsInvalid_many": "Les champs suivants ne sont pas valides:", - "followingFieldsInvalid_one": "Le champ suivant n'est pas valide:", + "followingFieldsInvalid_many": "Les champs suivants ne sont pas valides :", + "followingFieldsInvalid_one": "Le champ suivant n'est pas valide :", "incorrectCollection": "Collection incorrecte", "invalidFileType": "Type de fichier invalide", - "invalidFileTypeValue": "Type de fichier invalide: {{value}}", + "invalidFileTypeValue": "Type de fichier invalide : {{value}}", "loadingDocument": "Un problème est survenu lors du chargement du document qui a pour identifiant {{id}}.", "missingEmail": "E-mail manquant.", "missingIDOfDocument": "Il manque l'identifiant du document à mettre à jour.", @@ -118,13 +118,13 @@ "searchForBlock": "Rechercher un bloc", "selectExistingLabel": "Sélectionnez {{label}} existant", "showAll": "Afficher tout", - "swapRelationship": "Relation D'échange", + "swapRelationship": "Changer de relation", "swapUpload": "Changer de Fichier", "toggleBlock": "Bloc bascule", "uploadNewLabel": "Téléverser un(e) nouveau ou nouvelle {{label}}" }, "general": { - "aboutToDelete": "Vous êtes sur le point de supprimer ce ou cette {{label}} <1>{{title}}. Êtes-vous sûr?", + "aboutToDelete": "Vous êtes sur le point de supprimer ce ou cette {{label}} <1>{{title}}. Êtes-vous sûr ?", "addBelow": "Ajoutez ci-dessous", "addFilter": "Ajouter un filtre", "adminTheme": "Thème d'administration", @@ -207,7 +207,7 @@ "thisLanguage": "Français", "titleDeleted": "{{label}} \"{{title}}\" supprimé(e) avec succès.", "unauthorized": "Non autorisé", - "unsavedChangesDuplicate": "Vous avez des changements non enregistrés. Souhaitez-vous continuer la duplication?", + "unsavedChangesDuplicate": "Vous avez des changements non enregistrés. Souhaitez-vous continuer la duplication ?", "untitled": "Sans titre", "updatedAt": "Modifié le", "updatedSuccessfully": "Mis à jour avec succés.", @@ -235,7 +235,7 @@ "greaterThanMax": "\"{{value}}\" est supérieur à la valeur maximale autorisée de {{max}}.", "invalidInput": "Ce champ a une entrée invalide.", "invalidSelection": "Ce champ a une sélection invalide.", - "invalidSelections": "Ce champ contient des sélections invalides suivantes:", + "invalidSelections": "Ce champ contient des sélections invalides suivantes :", "lessThanMin": "\"{{value}}\" est inférieur à la valeur minimale autorisée de {{min}}.", "longerThanMin": "Cette valeur doit être supérieure à la longueur minimale de {{minLength}} caractères.", "notValidDate": "\"{{value}}\" n'est pas une date valide.", @@ -250,13 +250,13 @@ "version": { "aboutToRestore": "Vous êtes sur le point de restaurer le document {{label}} à l'état où il se trouvait le {{versionDate}}.", "aboutToRestoreGlobal": "Vous êtes sur le point de restaurer le ou la {{label}} global(e) à l'état où il ou elle se trouvait le {{versionDate}}.", - "aboutToRevertToPublished": "Vous êtes sur le point de rétablir les modifications apportées à ce document à la version publiée. Êtes-vous sûr?", - "aboutToUnpublish": "Vous êtes sur le point d'annuler la publication de ce document. Êtes-vous sûr?", + "aboutToRevertToPublished": "Vous êtes sur le point de rétablir les modifications apportées à ce document à la version publiée. Êtes-vous sûr ?", + "aboutToUnpublish": "Vous êtes sur le point d'annuler la publication de ce document. Êtes-vous sûr ?", "autosave": "Enregistrement automatique", "autosavedSuccessfully": "Enregistrement automatique réussi.", "autosavedVersion": "Version enregistrée automatiquement", "changed": "Modifié", - "compareVersion": "Comparez cette version à:", + "compareVersion": "Comparez cette version à :", "confirmRevertToSaved": "Confirmer la restauration", "confirmUnpublish": "Confirmer l'annulation", "confirmVersionRestoration": "Confirmer la restauration de la version", @@ -278,7 +278,7 @@ "saveDraft": "Enregistrer le brouillon", "selectLocals": "Sélectionnez les paramètres régionaux à afficher", "selectVersionToCompare": "Sélectionnez une version à comparer", - "showLocales": "Afficher les paramètres régionaux:", + "showLocales": "Afficher les paramètres régionaux :", "status": "Statut", "type": "Type", "unpublish": "Annuler la publication", @@ -287,7 +287,7 @@ "versionCount_many": "{{count}} versions trouvées", "versionCount_none": "Aucune version trouvée", "versionCount_one": "{{count}} version trouvée", - "versionCreatedOn": "{{version}} créé(e) le:", + "versionCreatedOn": "{{version}} créé(e) le :", "versionID": "Identifiant de la version", "versions": "Versions", "viewingVersion": "Affichage de la version de ou du {{entityLabel}} {{documentTitle}}", From 84e1417b711e0823753f0b9174c145e40b68e0be Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Sun, 8 Jan 2023 23:04:33 -0500 Subject: [PATCH 08/14] fix: prevents uploads drawer from crashing when no uploads are enabled --- .../elements/ListDrawer/DrawerContent.tsx | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/admin/components/elements/ListDrawer/DrawerContent.tsx b/src/admin/components/elements/ListDrawer/DrawerContent.tsx index 665a5fa1d8..9796e8dae2 100644 --- a/src/admin/components/elements/ListDrawer/DrawerContent.tsx +++ b/src/admin/components/elements/ListDrawer/DrawerContent.tsx @@ -58,13 +58,16 @@ const shouldIncludeCollection = ({ collectionSlugs, }) => (enableRichTextRelationship && ((uploads && Boolean(upload)) || collectionSlugs?.includes(slug))); -export const ListDrawerContent: React.FC = ({ +const DrawerContent: React.FC = ({ drawerSlug, onSelect, customHeader, collectionSlugs, uploads, selectedCollection, + enabledCollectionConfigs }) => { const { t, i18n } = useTranslation(['upload', 'general']); const { permissions } = useAuth(); @@ -75,7 +78,7 @@ export const ListDrawerContent: React.FC = ({ const [page, setPage] = useState(1); const [where, setWhere] = useState(null); const { serverURL, routes: { api }, collections } = useConfig(); - const [enabledCollectionConfigs] = useState(() => collections.filter((coll) => shouldIncludeCollection({ coll, uploads, collectionSlugs }))); + const [selectedCollectionConfig, setSelectedCollectionConfig] = useState(() => { let initialSelection: SanitizedCollectionConfig; if (selectedCollection) { @@ -92,7 +95,9 @@ export const ListDrawerContent: React.FC = ({ }); const [selectedOption, setSelectedOption] = useState<{ label: string, value: string }>(() => (selectedCollectionConfig ? { label: getTranslation(selectedCollectionConfig.labels.singular, i18n), value: selectedCollectionConfig.slug } : undefined)); + const [fields, setFields] = useState(() => formatFields(selectedCollectionConfig, t)); + const [tableColumns, setTableColumns] = useState(() => { const initialColumns = getInitialColumnState(fields, selectedCollectionConfig.admin.useAsTitle, selectedCollectionConfig.admin.defaultColumns); return buildColumns({ @@ -308,3 +313,25 @@ export const ListDrawerContent: React.FC = ({ ); }; + +export const ListDrawerContent: React.FC = (props) => { + const { + collectionSlugs, + uploads, + } = props; + + const { collections } = useConfig(); + + const [enabledCollectionConfigs] = useState(() => collections.filter((coll) => shouldIncludeCollection({ coll, uploads, collectionSlugs }))); + + if (enabledCollectionConfigs.length === 0){ + return null; + } + + return ( + + ) +} From ed7cfff45c262206495580509a77adb72a646ddb Mon Sep 17 00:00:00 2001 From: Jessica Chowdhury <67977755+JessChowdhury@users.noreply.github.com> Date: Mon, 9 Jan 2023 15:23:40 +0000 Subject: [PATCH 09/14] fix: bug when clearing relationship field without hasMany: true (#1829) * fix: bug when clearing relationship field without hasMany: true * fix: checks for null value within function --- src/fields/config/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fields/config/types.ts b/src/fields/config/types.ts index 0e7114b68e..6bdc16d905 100644 --- a/src/fields/config/types.ts +++ b/src/fields/config/types.ts @@ -297,7 +297,7 @@ export type ValueWithRelation = { } export function valueIsValueWithRelation(value: unknown): value is ValueWithRelation { - return typeof value === 'object' && 'relationTo' in value && 'value' in value; + return value !== null && typeof value === 'object' && 'relationTo' in value && 'value' in value; } export type RelationshipValue = (string | number) From d40e1369472f212b5f85bfc72fac01dc708aa507 Mon Sep 17 00:00:00 2001 From: James Date: Mon, 9 Jan 2023 10:43:42 -0500 Subject: [PATCH 10/14] fix: ensures upload file data is available for conditions --- src/uploads/getBaseFields.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/uploads/getBaseFields.ts b/src/uploads/getBaseFields.ts index 4693551b48..035db45730 100644 --- a/src/uploads/getBaseFields.ts +++ b/src/uploads/getBaseFields.ts @@ -21,7 +21,7 @@ const getBaseUploadFields = ({ config, collection }: Options): Field[] => { type: 'text', admin: { readOnly: true, - disabled: true, + hidden: true, }, }; @@ -31,7 +31,7 @@ const getBaseUploadFields = ({ config, collection }: Options): Field[] => { type: 'text', admin: { readOnly: true, - disabled: true, + hidden: true, }, }; @@ -41,7 +41,7 @@ const getBaseUploadFields = ({ config, collection }: Options): Field[] => { type: 'number', admin: { readOnly: true, - disabled: true, + hidden: true, }, }; @@ -51,7 +51,7 @@ const getBaseUploadFields = ({ config, collection }: Options): Field[] => { type: 'number', admin: { readOnly: true, - disabled: true, + hidden: true, }, }; @@ -61,7 +61,7 @@ const getBaseUploadFields = ({ config, collection }: Options): Field[] => { type: 'number', admin: { readOnly: true, - disabled: true, + hidden: true, }, }; @@ -73,7 +73,7 @@ const getBaseUploadFields = ({ config, collection }: Options): Field[] => { unique: true, admin: { readOnly: true, - disabled: true, + hidden: true, }, }; @@ -110,14 +110,14 @@ const getBaseUploadFields = ({ config, collection }: Options): Field[] => { label: labels['upload:Sizes'], type: 'group', admin: { - disabled: true, + hidden: true, }, fields: uploadOptions.imageSizes.map((size) => ({ label: size.name, name: size.name, type: 'group', admin: { - disabled: true, + hidden: true, }, fields: [ { From 82961767e3643985ced8b41be64c22cb7154b80e Mon Sep 17 00:00:00 2001 From: Christian Schurr Date: Mon, 9 Jan 2023 17:24:22 +0100 Subject: [PATCH 11/14] feat!: enforces payload.init is async * Run connectMongoose before starting payload init * - reverted changes - added deprecated to init - docs: changed all payload.init to payload.initAsync - changed all internal init calls * forgotten inits in docs * reverted back - removed init and renamed initAsync to init --- docs/authentication/using-middleware.mdx | 27 ++++++++++++------------ docs/getting-started/installation.mdx | 11 +++++----- src/bin/generateGraphQLSchema.ts | 4 ++-- src/index.ts | 8 ++----- src/init.ts | 15 ------------- test/devServer.ts | 2 +- test/helpers/configHelpers.ts | 2 +- 7 files changed, 26 insertions(+), 43 deletions(-) diff --git a/docs/authentication/using-middleware.mdx b/docs/authentication/using-middleware.mdx index e26b924e04..607d493faf 100644 --- a/docs/authentication/using-middleware.mdx +++ b/docs/authentication/using-middleware.mdx @@ -25,24 +25,25 @@ payload.init({ secret: 'PAYLOAD_SECRET_KEY', mongoURL: 'mongodb://localhost/payload', express: app, -}); + onInit: async () => { + const router = express.Router(); -const router = express.Router(); + router.use(payload.authenticate); // highlight-line -router.use(payload.authenticate); // highlight-line + router.get('/', (req, res) => { + if (req.user) { + return res.send(`Authenticated successfully as ${req.user.email}.`); + } -router.get('/', (req, res) => { - if (req.user) { - return res.send(`Authenticated successfully as ${req.user.email}.`); - } + return res.send('Not authenticated'); + }); - return res.send('Not authenticated'); -}); + app.use('/some-route-here', router); -app.use('/some-route-here', router); - -app.listen(3000, async () => { - payload.logger.info(`listening on ${3000}...`); + app.listen(3000, async () => { + payload.logger.info(`listening on ${3000}...`); + }); + }, }); ``` diff --git a/docs/getting-started/installation.mdx b/docs/getting-started/installation.mdx index cc2dcecac2..a0a8499fc3 100644 --- a/docs/getting-started/installation.mdx +++ b/docs/getting-started/installation.mdx @@ -66,7 +66,7 @@ app.listen(3000, async () => { }); ``` -This server doesn't do anything just yet. But, after you have this in place, we can initialize Payload via its `init()` method, which accepts a small set of arguments to tell it how to operate. For a full list of `init` arguments, please consult the [main configuration](/docs/configuration/overview#init) docs. +This server doesn't do anything just yet. But, after you have this in place, we can initialize Payload via its `init()` method, which accepts a small set of arguments to tell it how to operate. For a full list of `init` arguments, please consult the [main configuration](/docs/configuration/overview) docs. To initialize Payload, update your `server.js` file to reflect the following code: @@ -80,12 +80,13 @@ payload.init({ secret: 'SECRET_KEY', mongoURL: 'mongodb://localhost/payload', express: app, + onInit: () => { + app.listen(3000, async () => { + console.log('Express is now listening for incoming connections on port 3000.') + }); + } }) -app.listen(3000, async () => { - console.log('Express is now listening for incoming connections on port 3000.') -}); - ``` Here is a list of all properties available to pass through `payload.init`: diff --git a/src/bin/generateGraphQLSchema.ts b/src/bin/generateGraphQLSchema.ts index 1f58ed3eff..5c4ae8a5f0 100644 --- a/src/bin/generateGraphQLSchema.ts +++ b/src/bin/generateGraphQLSchema.ts @@ -5,11 +5,11 @@ import Logger from '../utilities/logger'; import loadConfig from '../config/load'; import payload from '..'; -export function generateGraphQLSchema(): void { +export async function generateGraphQLSchema(): Promise { const logger = Logger(); const config = loadConfig(); - payload.init({ + await payload.init({ secret: '--unused--', mongoURL: false, local: true, diff --git a/src/index.ts b/src/index.ts index 319a5e9fc5..a0bd676449 100644 --- a/src/index.ts +++ b/src/index.ts @@ -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 { initSync, initAsync } from './init'; +import { initAsync } from './init'; require('isomorphic-fetch'); @@ -121,11 +121,7 @@ export class Payload { * @description Initializes Payload * @param options */ - init(options: InitOptions): void { - initSync(this, options); - } - - async initAsync(options: InitOptions): Promise { + async init(options: InitOptions): Promise { await initAsync(this, options); } diff --git a/src/init.ts b/src/init.ts index fb1f2e61e5..04cf2b1ede 100644 --- a/src/init.ts +++ b/src/init.ts @@ -161,18 +161,3 @@ export const initAsync = async (payload: Payload, options: InitOptions): Promise 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); -}; diff --git a/test/devServer.ts b/test/devServer.ts index 9d452d9a1a..49138309ba 100644 --- a/test/devServer.ts +++ b/test/devServer.ts @@ -5,7 +5,7 @@ import payload from '../src'; const expressApp = express(); const init = async () => { - await payload.initAsync({ + await payload.init({ secret: uuid(), mongoURL: process.env.MONGO_URL || 'mongodb://localhost/payload', express: expressApp, diff --git a/test/helpers/configHelpers.ts b/test/helpers/configHelpers.ts index 3144a8921e..bd1d30e5cc 100644 --- a/test/helpers/configHelpers.ts +++ b/test/helpers/configHelpers.ts @@ -40,7 +40,7 @@ export async function initPayloadTest(options: Options): Promise<{ serverURL: st initOptions.express = express(); } - await payload.initAsync(initOptions); + await payload.init(initOptions); if (initOptions.express) { initOptions.express.listen(port); From 78af86f9d12726f162ab363746505170e8909c81 Mon Sep 17 00:00:00 2001 From: James Date: Mon, 9 Jan 2023 11:27:00 -0500 Subject: [PATCH 12/14] chore: simplifies init code --- src/index.ts | 4 ++-- src/init.ts | 22 +++++++++------------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/index.ts b/src/index.ts index a0bd676449..1d31742b03 100644 --- a/src/index.ts +++ b/src/index.ts @@ -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 { initAsync } from './init'; +import { initPayload } from './init'; require('isomorphic-fetch'); @@ -122,7 +122,7 @@ export class Payload { * @param options */ async init(options: InitOptions): Promise { - await initAsync(this, options); + await initPayload(this, options); } getAdminURL = (): string => `${this.config.serverURL}${this.config.routes.admin}`; diff --git a/src/init.ts b/src/init.ts index 04cf2b1ede..5f87c76d2d 100644 --- a/src/init.ts +++ b/src/init.ts @@ -33,7 +33,15 @@ import mountEndpoints from './express/mountEndpoints'; import PreferencesModel from './preferences/model'; import findConfig from './config/find'; -export const init = (payload: Payload, options: InitOptions): void => { +export const initPayload = async (payload: Payload, options: InitOptions): Promise => { + 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); + } + payload.logger.info('Starting Payload...'); if (!options.secret) { throw new Error( @@ -145,18 +153,6 @@ export const init = (payload: Payload, options: InitOptions): void => { } serverInitTelemetry(payload); -}; - -export const initAsync = async (payload: Payload, options: InitOptions): Promise => { - 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); From ee54c1481cdb8d6669864f20584fa6ef072c9097 Mon Sep 17 00:00:00 2001 From: James Date: Mon, 9 Jan 2023 12:58:13 -0500 Subject: [PATCH 13/14] fix: #1808, arrays and blocks now save localized nested field data upon reordering rows --- .vscode/launch.json | 2 +- .../hooks/beforeChange/getExistingRowDoc.ts | 14 ++++-- src/fields/hooks/beforeChange/promise.ts | 8 ++-- test/fields/payload-types.ts | 11 +++++ test/localization/config.ts | 44 +++++++++++++++++++ test/localization/int.spec.ts | 22 ++++++++++ test/localization/payload-types.ts | 11 +++++ tsconfig.json | 1 + 8 files changed, 105 insertions(+), 8 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 37077c2e2f..523bcd5302 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -39,7 +39,7 @@ "--nolazy" ], "args": [ - "fields" + "localization" ] }, ] diff --git a/src/fields/hooks/beforeChange/getExistingRowDoc.ts b/src/fields/hooks/beforeChange/getExistingRowDoc.ts index 84e237d304..20f229ab09 100644 --- a/src/fields/hooks/beforeChange/getExistingRowDoc.ts +++ b/src/fields/hooks/beforeChange/getExistingRowDoc.ts @@ -5,9 +5,17 @@ * Otherwise, return an empty object. */ -export const getExistingRowDoc = (incomingRow: Record, existingRow?: Record): Record => { - if (incomingRow.id && incomingRow.id === existingRow?.id) { - return existingRow; +export const getExistingRowDoc = (incomingRow: Record, existingRows?: unknown): Record => { + if (incomingRow.id && Array.isArray(existingRows)) { + const matchedExistingRow = existingRows.find((existingRow) => { + if (typeof existingRow === 'object' && 'id' in existingRow) { + if (existingRow.id === incomingRow.id) return existingRow; + } + + return false; + }); + + if (matchedExistingRow) return matchedExistingRow; } return {}; diff --git a/src/fields/hooks/beforeChange/promise.ts b/src/fields/hooks/beforeChange/promise.ts index 21797897f6..ba7f61e7e5 100644 --- a/src/fields/hooks/beforeChange/promise.ts +++ b/src/fields/hooks/beforeChange/promise.ts @@ -223,8 +223,8 @@ export const promise = async ({ path: `${path}${field.name}.${i}.`, req, siblingData: row, - siblingDoc: getExistingRowDoc(row, siblingDoc[field.name]?.[i]), - siblingDocWithLocales: getExistingRowDoc(row, siblingDocWithLocales[field.name]?.[i]), + siblingDoc: getExistingRowDoc(row, siblingDoc[field.name]), + siblingDocWithLocales: getExistingRowDoc(row, siblingDocWithLocales[field.name]), skipValidation: skipValidationFromHere, })); }); @@ -257,8 +257,8 @@ export const promise = async ({ path: `${path}${field.name}.${i}.`, req, siblingData: row, - siblingDoc: getExistingRowDoc(row, siblingDoc[field.name]?.[i]), - siblingDocWithLocales: getExistingRowDoc(row, siblingDocWithLocales[field.name]?.[i]), + siblingDoc: getExistingRowDoc(row, siblingDoc[field.name]), + siblingDocWithLocales: getExistingRowDoc(row, siblingDocWithLocales[field.name]), skipValidation: skipValidationFromHere, })); } diff --git a/test/fields/payload-types.ts b/test/fields/payload-types.ts index 9179ed9425..622484aa1a 100644 --- a/test/fields/payload-types.ts +++ b/test/fields/payload-types.ts @@ -282,6 +282,17 @@ export interface GroupField { potentiallyEmptyGroup: { text?: string; }; + groupInRow: { + field?: string; + secondField?: string; + thirdField?: string; + }; + secondGroupInRow: { + field?: string; + nestedGroup: { + nestedField?: string; + }; + }; createdAt: string; updatedAt: string; } diff --git a/test/localization/config.ts b/test/localization/config.ts index ad067cce9d..b77e01a3a7 100644 --- a/test/localization/config.ts +++ b/test/localization/config.ts @@ -1,5 +1,6 @@ import { buildConfig } from '../buildConfig'; import { devUser } from '../credentials'; +import { GlobalArray } from './Array'; import { LocalizedPost, RelationshipLocalized } from './payload-types'; import { defaultLocale, @@ -175,6 +176,24 @@ export default buildConfig({ ], }, ], + globals: [ + { + slug: 'global-array', + fields: [ + { + name: 'array', + type: 'array', + fields: [ + { + name: 'text', + type: 'text', + localized: true, + }, + ], + }, + ], + }, + ], onInit: async (payload) => { const collection = slug; @@ -266,5 +285,30 @@ export default buildConfig({ ], }, }); + + const globalArray = await payload.updateGlobal({ + slug: 'global-array', + data: { + array: [ + { + text: 'test en 1', + }, + { + text: 'test en 2', + }, + ], + }, + }); + + await payload.updateGlobal({ + slug: 'global-array', + locale: 'es', + data: { + array: globalArray.array.map((row, i) => ({ + ...row, + text: `test es ${i + 1}`, + })), + }, + }); }, }); diff --git a/test/localization/int.spec.ts b/test/localization/int.spec.ts index c44808e52d..c017201089 100644 --- a/test/localization/int.spec.ts +++ b/test/localization/int.spec.ts @@ -7,6 +7,7 @@ import type { WithLocalizedRelationship, LocalizedRequired, RelationshipLocalized, + GlobalArray, } from './payload-types'; import type { LocalizedPostAllLocale } from './config'; import config, { relationshipLocalizedSlug, slug, withLocalizedRelSlug, withRequiredLocalizedFields } from './config'; @@ -477,6 +478,27 @@ describe('Localization', () => { }); }); + describe('Localized - arrays with nested localized fields', () => { + it('should allow moving rows and retain existing row locale data', async () => { + const globalArray = await payload.findGlobal({ + slug: 'global-array', + }); + + const reversedArrayRows = [...globalArray.array].reverse(); + + const updatedGlobal = await payload.updateGlobal({ + slug: 'global-array', + locale: 'all', + data: { + array: reversedArrayRows, + }, + }); + + expect(updatedGlobal.array[0].text.en).toStrictEqual('test en 2'); + expect(updatedGlobal.array[0].text.es).toStrictEqual('test es 2'); + }); + }); + describe('Localized - required', () => { it('should update without passing all required fields', async () => { const newDoc = await payload.create({ diff --git a/test/localization/payload-types.ts b/test/localization/payload-types.ts index d0ddb398dc..c7aa42b862 100644 --- a/test/localization/payload-types.ts +++ b/test/localization/payload-types.ts @@ -6,6 +6,17 @@ */ export interface Config {} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "global-array". + */ +export interface GlobalArray { + id: string; + array: { + text?: string; + id?: string; + }[]; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users". diff --git a/tsconfig.json b/tsconfig.json index d7e93c627d..9772585039 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,7 @@ { "compilerOptions": { "target": "es2019", + "sourceMap": true, "module": "commonjs", "allowJs": true, /* Allow javascript files to be compiled. */ "checkJs": false, /* Report errors in .js files. */ From febbea55508aff3c6c1b4ceef58e5c532d2483bd Mon Sep 17 00:00:00 2001 From: James Date: Mon, 9 Jan 2023 12:59:36 -0500 Subject: [PATCH 14/14] chore: restores debugger to use fields test suite --- .vscode/launch.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 523bcd5302..37077c2e2f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -39,7 +39,7 @@ "--nolazy" ], "args": [ - "localization" + "fields" ] }, ]