Merge branch 'alpha' of github.com:payloadcms/payload into feat/config-i18n
This commit is contained in:
66
.github/workflows/main.yml
vendored
66
.github/workflows/main.yml
vendored
@@ -39,7 +39,7 @@ jobs:
|
|||||||
echo "needs_build: ${{ steps.filter.outputs.needs_build }}"
|
echo "needs_build: ${{ steps.filter.outputs.needs_build }}"
|
||||||
echo "templates: ${{ steps.filter.outputs.templates }}"
|
echo "templates: ${{ steps.filter.outputs.templates }}"
|
||||||
|
|
||||||
core-build:
|
build:
|
||||||
needs: changes
|
needs: changes
|
||||||
if: ${{ needs.changes.outputs.needs_build == 'true' }}
|
if: ${{ needs.changes.outputs.needs_build == 'true' }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -65,65 +65,29 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
||||||
|
|
||||||
- uses: actions/cache@v4
|
- name: Setup pnpm cache
|
||||||
name: Setup pnpm cache
|
uses: actions/cache@v4
|
||||||
|
timeout-minutes: 720
|
||||||
with:
|
with:
|
||||||
path: ${{ env.STORE_PATH }}
|
path: ${{ env.STORE_PATH }}
|
||||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
key: pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-pnpm-store-
|
pnpm-store-
|
||||||
${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||||
|
|
||||||
- run: pnpm install
|
- run: pnpm install
|
||||||
- run: pnpm run build:core
|
- run: pnpm run build:all
|
||||||
|
|
||||||
- name: Cache build
|
- name: Cache build
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
|
timeout-minutes: 10
|
||||||
with:
|
with:
|
||||||
path: ./*
|
path: ./*
|
||||||
key: ${{ github.sha }}-${{ github.run_number }}
|
key: ${{ github.sha }}-${{ github.run_number }}
|
||||||
|
|
||||||
plugins-build:
|
|
||||||
needs: changes
|
|
||||||
if: ${{ needs.changes.outputs.needs_build == 'true' }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 25
|
|
||||||
|
|
||||||
- name: Use Node.js 18
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
|
|
||||||
- name: Install pnpm
|
|
||||||
uses: pnpm/action-setup@v3
|
|
||||||
with:
|
|
||||||
version: 8
|
|
||||||
run_install: false
|
|
||||||
|
|
||||||
- name: Get pnpm store directory
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- uses: actions/cache@v4
|
|
||||||
name: Setup pnpm cache
|
|
||||||
with:
|
|
||||||
path: ${{ env.STORE_PATH }}
|
|
||||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-pnpm-store-
|
|
||||||
${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
|
||||||
|
|
||||||
- run: pnpm install
|
|
||||||
- run: pnpm run build:plugins
|
|
||||||
|
|
||||||
tests-unit:
|
tests-unit:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: core-build
|
needs: build
|
||||||
if: false # Disable until tests are updated for 3.0
|
if: false # Disable until tests are updated for 3.0
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -140,6 +104,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Restore build
|
- name: Restore build
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
|
timeout-minutes: 10
|
||||||
with:
|
with:
|
||||||
path: ./*
|
path: ./*
|
||||||
key: ${{ github.sha }}-${{ github.run_number }}
|
key: ${{ github.sha }}-${{ github.run_number }}
|
||||||
@@ -151,7 +116,7 @@ jobs:
|
|||||||
|
|
||||||
tests-int:
|
tests-int:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: core-build
|
needs: build
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -184,6 +149,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Restore build
|
- name: Restore build
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
|
timeout-minutes: 10
|
||||||
with:
|
with:
|
||||||
path: ./*
|
path: ./*
|
||||||
key: ${{ github.sha }}-${{ github.run_number }}
|
key: ${{ github.sha }}-${{ github.run_number }}
|
||||||
@@ -242,7 +208,7 @@ jobs:
|
|||||||
|
|
||||||
tests-e2e:
|
tests-e2e:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: core-build
|
needs: build
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -282,6 +248,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Restore build
|
- name: Restore build
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
|
timeout-minutes: 10
|
||||||
with:
|
with:
|
||||||
path: ./*
|
path: ./*
|
||||||
key: ${{ github.sha }}-${{ github.run_number }}
|
key: ${{ github.sha }}-${{ github.run_number }}
|
||||||
@@ -302,7 +269,7 @@ jobs:
|
|||||||
tests-type-generation:
|
tests-type-generation:
|
||||||
if: false # This should be replaced with gen on a real Payload project
|
if: false # This should be replaced with gen on a real Payload project
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: core-build
|
needs: build
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Use Node.js 18
|
- name: Use Node.js 18
|
||||||
@@ -318,6 +285,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Restore build
|
- name: Restore build
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
|
timeout-minutes: 10
|
||||||
with:
|
with:
|
||||||
path: ./*
|
path: ./*
|
||||||
key: ${{ github.sha }}-${{ github.run_number }}
|
key: ${{ github.sha }}-${{ github.run_number }}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "payload-monorepo",
|
"name": "payload-monorepo",
|
||||||
"version": "3.0.0-alpha.59",
|
"version": "3.0.0-alpha.60",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"workspaces:": [
|
"workspaces:": [
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "create-payload-app",
|
"name": "create-payload-app",
|
||||||
"version": "3.0.0-alpha.59",
|
"version": "3.0.0-alpha.60",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"homepage": "https://payloadcms.com",
|
"homepage": "https://payloadcms.com",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@payloadcms/db-mongodb",
|
"name": "@payloadcms/db-mongodb",
|
||||||
"version": "3.0.0-alpha.59",
|
"version": "3.0.0-alpha.60",
|
||||||
"description": "The officially supported MongoDB database adapter for Payload",
|
"description": "The officially supported MongoDB database adapter for Payload",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@payloadcms/db-postgres",
|
"name": "@payloadcms/db-postgres",
|
||||||
"version": "3.0.0-alpha.59",
|
"version": "3.0.0-alpha.60",
|
||||||
"description": "The officially supported Postgres database adapter for Payload",
|
"description": "The officially supported Postgres database adapter for Payload",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@payloadcms/graphql",
|
"name": "@payloadcms/graphql",
|
||||||
"version": "3.0.0-alpha.59",
|
"version": "3.0.0-alpha.60",
|
||||||
"main": "./src/index.ts",
|
"main": "./src/index.ts",
|
||||||
"types": "./src/index.d.ts",
|
"types": "./src/index.d.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@payloadcms/next",
|
"name": "@payloadcms/next",
|
||||||
"version": "3.0.0-alpha.59",
|
"version": "3.0.0-alpha.60",
|
||||||
"main": "./src/index.js",
|
"main": "./src/index.js",
|
||||||
"types": "./src/index.js",
|
"types": "./src/index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ import type { I18n } from '@payloadcms/translations'
|
|||||||
import type { Metadata } from 'next'
|
import type { Metadata } from 'next'
|
||||||
import type { AdminViewComponent, SanitizedConfig } from 'payload/types'
|
import type { AdminViewComponent, SanitizedConfig } from 'payload/types'
|
||||||
|
|
||||||
import { getNextI18n } from '@payloadcms/next/utilities'
|
|
||||||
import { HydrateClientUser } from '@payloadcms/ui/elements/HydrateClientUser'
|
import { HydrateClientUser } from '@payloadcms/ui/elements/HydrateClientUser'
|
||||||
import { DefaultTemplate } from '@payloadcms/ui/templates/Default'
|
import { DefaultTemplate } from '@payloadcms/ui/templates/Default'
|
||||||
import React, { Fragment } from 'react'
|
import React, { Fragment } from 'react'
|
||||||
|
|
||||||
import { initPage } from '../../utilities/initPage.js'
|
import { initPage } from '../../utilities/initPage.js'
|
||||||
|
import { getNextI18n } from '.././../utilities/getNextI18n.js'
|
||||||
import { NotFoundClient } from './index.client.js'
|
import { NotFoundClient } from './index.client.js'
|
||||||
|
|
||||||
export const generatePageMetadata = async ({
|
export const generatePageMetadata = async ({
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "payload",
|
"name": "payload",
|
||||||
"version": "3.0.0-alpha.59",
|
"version": "3.0.0-alpha.60",
|
||||||
"description": "Node, React and MongoDB Headless CMS and Application Framework",
|
"description": "Node, React and MongoDB Headless CMS and Application Framework",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./src/index.ts",
|
"main": "./src/index.ts",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@payloadcms/plugin-cloud-storage",
|
"name": "@payloadcms/plugin-cloud-storage",
|
||||||
"description": "The official cloud storage plugin for Payload CMS",
|
"description": "The official cloud storage plugin for Payload CMS",
|
||||||
"version": "3.0.0-alpha.59",
|
"version": "3.0.0-alpha.60",
|
||||||
"main": "./src/index.ts",
|
"main": "./src/index.ts",
|
||||||
"types": "./src/index.ts",
|
"types": "./src/index.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@payloadcms/plugin-cloud",
|
"name": "@payloadcms/plugin-cloud",
|
||||||
"description": "The official Payload Cloud plugin",
|
"description": "The official Payload Cloud plugin",
|
||||||
"version": "3.0.0-alpha.59",
|
"version": "3.0.0-alpha.60",
|
||||||
"main": "./src/index.ts",
|
"main": "./src/index.ts",
|
||||||
"types": "./src/index.ts",
|
"types": "./src/index.ts",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@payloadcms/plugin-form-builder",
|
"name": "@payloadcms/plugin-form-builder",
|
||||||
"description": "Form builder plugin for Payload CMS",
|
"description": "Form builder plugin for Payload CMS",
|
||||||
"version": "3.0.0-alpha.59",
|
"version": "3.0.0-alpha.60",
|
||||||
"homepage:": "https://payloadcms.com",
|
"homepage:": "https://payloadcms.com",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@payloadcms/plugin-nested-docs",
|
"name": "@payloadcms/plugin-nested-docs",
|
||||||
"version": "3.0.0-alpha.59",
|
"version": "3.0.0-alpha.60",
|
||||||
"description": "The official Nested Docs plugin for Payload",
|
"description": "The official Nested Docs plugin for Payload",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@payloadcms/plugin-redirects",
|
"name": "@payloadcms/plugin-redirects",
|
||||||
"version": "3.0.0-alpha.59",
|
"version": "3.0.0-alpha.60",
|
||||||
"homepage:": "https://payloadcms.com",
|
"homepage:": "https://payloadcms.com",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@payloadcms/plugin-search",
|
"name": "@payloadcms/plugin-search",
|
||||||
"version": "3.0.0-alpha.59",
|
"version": "3.0.0-alpha.60",
|
||||||
"homepage:": "https://payloadcms.com",
|
"homepage:": "https://payloadcms.com",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@payloadcms/plugin-seo",
|
"name": "@payloadcms/plugin-seo",
|
||||||
"version": "3.0.0-alpha.59",
|
"version": "3.0.0-alpha.60",
|
||||||
"homepage:": "https://payloadcms.com",
|
"homepage:": "https://payloadcms.com",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@payloadcms/richtext-lexical",
|
"name": "@payloadcms/richtext-lexical",
|
||||||
"version": "3.0.0-alpha.59",
|
"version": "3.0.0-alpha.60",
|
||||||
"description": "The officially supported Lexical richtext adapter for Payload",
|
"description": "The officially supported Lexical richtext adapter for Payload",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@@ -246,10 +246,10 @@ export const TOGGLE_LINK_COMMAND: LexicalCommand<LinkPayload | null> =
|
|||||||
export function toggleLink(payload: LinkPayload): void {
|
export function toggleLink(payload: LinkPayload): void {
|
||||||
const selection = $getSelection()
|
const selection = $getSelection()
|
||||||
|
|
||||||
if (!$isRangeSelection(selection)) {
|
if (!$isRangeSelection(selection) && !payload.selectedNodes.length) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const nodes = selection.extract()
|
const nodes = $isRangeSelection(selection) ? selection.extract() : payload.selectedNodes
|
||||||
|
|
||||||
if (payload === null) {
|
if (payload === null) {
|
||||||
// Remove LinkNodes
|
// Remove LinkNodes
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ const { useLexicalComposerContext } = lexicalComposerContextImport
|
|||||||
|
|
||||||
import lexicalUtilsImport from '@lexical/utils'
|
import lexicalUtilsImport from '@lexical/utils'
|
||||||
const { $findMatchingParent, mergeRegister } = lexicalUtilsImport
|
const { $findMatchingParent, mergeRegister } = lexicalUtilsImport
|
||||||
|
import type { LexicalNode } from 'lexical'
|
||||||
|
|
||||||
import { getTranslation } from '@payloadcms/translations'
|
import { getTranslation } from '@payloadcms/translations'
|
||||||
import lexicalImport from 'lexical'
|
import lexicalImport from 'lexical'
|
||||||
const {
|
const {
|
||||||
@@ -57,6 +59,8 @@ export function LinkEditor({ anchorElem }: { anchorElem: HTMLElement }): React.R
|
|||||||
const { closeModal, toggleModal } = useModal()
|
const { closeModal, toggleModal } = useModal()
|
||||||
const editDepth = useEditDepth()
|
const editDepth = useEditDepth()
|
||||||
const [isLink, setIsLink] = useState(false)
|
const [isLink, setIsLink] = useState(false)
|
||||||
|
const [selectedNodes, setSelectedNodes] = useState<LexicalNode[]>([])
|
||||||
|
|
||||||
const [isAutoLink, setIsAutoLink] = useState(false)
|
const [isAutoLink, setIsAutoLink] = useState(false)
|
||||||
|
|
||||||
const drawerSlug = formatDrawerSlug({
|
const drawerSlug = formatDrawerSlug({
|
||||||
@@ -78,6 +82,7 @@ export function LinkEditor({ anchorElem }: { anchorElem: HTMLElement }): React.R
|
|||||||
setIsAutoLink(false)
|
setIsAutoLink(false)
|
||||||
setLinkUrl('')
|
setLinkUrl('')
|
||||||
setLinkLabel('')
|
setLinkLabel('')
|
||||||
|
setSelectedNodes([])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,6 +120,8 @@ export function LinkEditor({ anchorElem }: { anchorElem: HTMLElement }): React.R
|
|||||||
|
|
||||||
setStateData(data)
|
setStateData(data)
|
||||||
setIsLink(true)
|
setIsLink(true)
|
||||||
|
setSelectedNodes(selection ? selection?.getNodes() : [])
|
||||||
|
|
||||||
if ($isAutoLinkNode(linkParent)) {
|
if ($isAutoLinkNode(linkParent)) {
|
||||||
setIsAutoLink(true)
|
setIsAutoLink(true)
|
||||||
} else {
|
} else {
|
||||||
@@ -291,17 +298,25 @@ export function LinkEditor({ anchorElem }: { anchorElem: HTMLElement }): React.R
|
|||||||
|
|
||||||
const newLinkPayload: LinkPayload = data as LinkPayload
|
const newLinkPayload: LinkPayload = data as LinkPayload
|
||||||
|
|
||||||
|
newLinkPayload.selectedNodes = selectedNodes
|
||||||
|
|
||||||
// See: https://github.com/facebook/lexical/pull/5536. This updates autolink nodes to link nodes whenever a change was made (which is good!).
|
// See: https://github.com/facebook/lexical/pull/5536. This updates autolink nodes to link nodes whenever a change was made (which is good!).
|
||||||
editor.update(() => {
|
editor.update(() => {
|
||||||
const selection = $getSelection()
|
const selection = $getSelection()
|
||||||
|
let linkParent = null
|
||||||
if ($isRangeSelection(selection)) {
|
if ($isRangeSelection(selection)) {
|
||||||
const parent = getSelectedNode(selection).getParent()
|
linkParent = getSelectedNode(selection).getParent()
|
||||||
if ($isAutoLinkNode(parent)) {
|
} else {
|
||||||
|
if (selectedNodes.length) {
|
||||||
|
linkParent = selectedNodes[0].getParent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (linkParent && $isAutoLinkNode(linkParent)) {
|
||||||
const linkNode = $createLinkNode({
|
const linkNode = $createLinkNode({
|
||||||
fields: newLinkPayload.fields,
|
fields: newLinkPayload.fields,
|
||||||
})
|
})
|
||||||
parent.replace(linkNode, true)
|
linkParent.replace(linkNode, true)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import type { LexicalNode } from 'lexical'
|
||||||
|
|
||||||
import type { LinkFields } from '../../nodes/types.js'
|
import type { LinkFields } from '../../nodes/types.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -6,6 +8,7 @@ import type { LinkFields } from '../../nodes/types.js'
|
|||||||
*/
|
*/
|
||||||
export type LinkPayload = {
|
export type LinkPayload = {
|
||||||
fields: LinkFields
|
fields: LinkFields
|
||||||
|
selectedNodes?: LexicalNode[]
|
||||||
/**
|
/**
|
||||||
* The text content of the link node - will be displayed in the drawer
|
* The text content of the link node - will be displayed in the drawer
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ type FilteredCollectionsT = (
|
|||||||
|
|
||||||
const filterRichTextCollections: FilteredCollectionsT = (collections, options) => {
|
const filterRichTextCollections: FilteredCollectionsT = (collections, options) => {
|
||||||
return collections.filter(({ slug, admin: { enableRichTextRelationship }, upload }) => {
|
return collections.filter(({ slug, admin: { enableRichTextRelationship }, upload }) => {
|
||||||
if (options.visibleEntities.collections.includes(slug)) {
|
if (!options.visibleEntities.collections.includes(slug)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@payloadcms/richtext-slate",
|
"name": "@payloadcms/richtext-slate",
|
||||||
"version": "3.0.0-alpha.59",
|
"version": "3.0.0-alpha.60",
|
||||||
"description": "The officially supported Slate richtext adapter for Payload",
|
"description": "The officially supported Slate richtext adapter for Payload",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@payloadcms/translations",
|
"name": "@payloadcms/translations",
|
||||||
"version": "3.0.0-alpha.59",
|
"version": "3.0.0-alpha.60",
|
||||||
"main": "./src/exports/index.ts",
|
"main": "./src/exports/index.ts",
|
||||||
"types": "./src/types.ts",
|
"types": "./src/types.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@payloadcms/ui",
|
"name": "@payloadcms/ui",
|
||||||
"version": "3.0.0-alpha.59",
|
"version": "3.0.0-alpha.60",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"homepage": "https://payloadcms.com",
|
"homepage": "https://payloadcms.com",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
@@ -6,19 +6,23 @@ import execa from 'execa'
|
|||||||
import fse from 'fs-extra'
|
import fse from 'fs-extra'
|
||||||
import minimist from 'minimist'
|
import minimist from 'minimist'
|
||||||
import { fileURLToPath } from 'node:url'
|
import { fileURLToPath } from 'node:url'
|
||||||
import pMap from 'p-map'
|
import pLimit from 'p-limit'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import prompts from 'prompts'
|
import prompts from 'prompts'
|
||||||
import semver from 'semver'
|
import semver from 'semver'
|
||||||
import { simpleGit } from 'simple-git'
|
import { simpleGit } from 'simple-git'
|
||||||
|
|
||||||
|
import type { PackageDetails } from './lib/getPackageDetails.js'
|
||||||
|
|
||||||
import { getPackageDetails } from './lib/getPackageDetails.js'
|
import { getPackageDetails } from './lib/getPackageDetails.js'
|
||||||
import { updateChangelog } from './utils/updateChangelog.js'
|
import { updateChangelog } from './utils/updateChangelog.js'
|
||||||
|
|
||||||
|
const npmPublishLimit = pLimit(2)
|
||||||
|
|
||||||
// Update this list with any packages to publish
|
// Update this list with any packages to publish
|
||||||
const packageWhitelist = [
|
const packageWhitelist = [
|
||||||
'payload',
|
'payload',
|
||||||
// 'translations',
|
'translations',
|
||||||
'ui',
|
'ui',
|
||||||
'next',
|
'next',
|
||||||
'graphql',
|
'graphql',
|
||||||
@@ -27,7 +31,7 @@ const packageWhitelist = [
|
|||||||
'richtext-slate',
|
'richtext-slate',
|
||||||
'richtext-lexical',
|
'richtext-lexical',
|
||||||
|
|
||||||
// 'create-payload-app',
|
'create-payload-app',
|
||||||
|
|
||||||
// Plugins
|
// Plugins
|
||||||
'plugin-cloud',
|
'plugin-cloud',
|
||||||
@@ -143,26 +147,13 @@ async function main() {
|
|||||||
|
|
||||||
await execa('pnpm', ['install'], execaOpts)
|
await execa('pnpm', ['install'], execaOpts)
|
||||||
|
|
||||||
const buildResult = await execa('pnpm', ['build:core', '--output-logs=errors-only'], execaOpts)
|
const buildResult = await execa('pnpm', ['build:all', '--output-logs=errors-only'], execaOpts)
|
||||||
// const buildResult = execSync('pnpm build:all', execOpts)
|
|
||||||
if (buildResult.exitCode !== 0) {
|
if (buildResult.exitCode !== 0) {
|
||||||
console.error(chalk.bold.red('Build failed'))
|
console.error(chalk.bold.red('Build failed'))
|
||||||
console.log(buildResult.stderr)
|
console.log(buildResult.stderr)
|
||||||
abort('Build failed')
|
abort('Build failed')
|
||||||
}
|
}
|
||||||
|
|
||||||
const buildPluginsResult = await execa(
|
|
||||||
'pnpm',
|
|
||||||
['build:plugins', '--output-logs=errors-only'],
|
|
||||||
execaOpts,
|
|
||||||
)
|
|
||||||
|
|
||||||
if (buildPluginsResult.exitCode !== 0) {
|
|
||||||
console.error(chalk.bold.red('Build failed'))
|
|
||||||
console.log(buildPluginsResult.stderr)
|
|
||||||
abort('Build failed')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update changelog
|
// Update changelog
|
||||||
if (changelog) {
|
if (changelog) {
|
||||||
header(`${logPrefix}📝 Updating changelog...`)
|
header(`${logPrefix}📝 Updating changelog...`)
|
||||||
@@ -209,35 +200,8 @@ async function main() {
|
|||||||
abort('2FA code is required')
|
abort('2FA code is required')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Publish
|
const results = await Promise.all(
|
||||||
const results: { name: string; success: boolean; details?: string }[] = await Promise.all(
|
packageDetails.map((pkg) => publishPackageThrottled(pkg, { dryRun, otp })),
|
||||||
packageDetails.map(async (pkg) => {
|
|
||||||
try {
|
|
||||||
console.log(logPrefix, chalk.bold(`🚀 ${pkg.name} publishing...`))
|
|
||||||
const cmdArgs = ['publish', '-C', pkg.packagePath, '--no-git-checks', '--tag', tag]
|
|
||||||
if (dryRun) {
|
|
||||||
cmdArgs.push('--dry-run')
|
|
||||||
} else {
|
|
||||||
cmdArgs.push('--otp', otp)
|
|
||||||
}
|
|
||||||
const { exitCode, stderr } = await execa('pnpm', cmdArgs, {
|
|
||||||
cwd,
|
|
||||||
stdio: ['ignore', 'ignore', 'pipe'],
|
|
||||||
// stdio: 'inherit',
|
|
||||||
})
|
|
||||||
|
|
||||||
if (exitCode !== 0) {
|
|
||||||
console.log(chalk.bold.red(`\n\n❌ ${pkg.name} ERROR: pnpm publish failed\n\n`))
|
|
||||||
return { name: pkg.name, success: false, details: stderr }
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`${logPrefix} ${chalk.green(`✅ ${pkg.name} published`)}`)
|
|
||||||
return { name: pkg.name, success: true }
|
|
||||||
} catch (error) {
|
|
||||||
console.error(chalk.bold.red(`\n\n❌ ${pkg.name} ERROR: ${error.message}\n\n`))
|
|
||||||
return { name: pkg.name, success: false }
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
console.log(chalk.bold.green(`\n\nResults:\n`))
|
console.log(chalk.bold.green(`\n\nResults:\n`))
|
||||||
@@ -270,6 +234,42 @@ main().catch((error) => {
|
|||||||
process.exit(1)
|
process.exit(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/** Publish with promise concurrency throttling */
|
||||||
|
async function publishPackageThrottled(
|
||||||
|
pkg: PackageDetails,
|
||||||
|
opts?: { dryRun?: boolean; otp?: string },
|
||||||
|
) {
|
||||||
|
const { dryRun = false, otp } = opts ?? {}
|
||||||
|
return npmPublishLimit(() => publishSinglePackage(pkg, { dryRun, otp }))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function publishSinglePackage(
|
||||||
|
pkg: PackageDetails,
|
||||||
|
opts?: { dryRun?: boolean; otp?: string },
|
||||||
|
) {
|
||||||
|
const { dryRun = false, otp } = opts ?? {}
|
||||||
|
console.log(chalk.bold(`🚀 ${pkg.name} publishing...`))
|
||||||
|
const cmdArgs = ['publish', '-C', pkg.packagePath, '--no-git-checks', '--json', '--tag', tag]
|
||||||
|
if (dryRun) {
|
||||||
|
cmdArgs.push('--dry-run')
|
||||||
|
} else {
|
||||||
|
cmdArgs.push('--otp', otp)
|
||||||
|
}
|
||||||
|
const { exitCode, stderr } = await execa('pnpm', cmdArgs, {
|
||||||
|
cwd,
|
||||||
|
stdio: ['ignore', 'ignore', 'pipe'],
|
||||||
|
// stdio: 'inherit',
|
||||||
|
})
|
||||||
|
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
console.log(chalk.bold.red(`\n\n❌ ${pkg.name} ERROR: pnpm publish failed\n\n${stderr}`))
|
||||||
|
return { name: pkg.name, success: false, details: stderr }
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`${logPrefix} ${chalk.green(`✅ ${pkg.name} published`)}`)
|
||||||
|
return { name: pkg.name, success: true }
|
||||||
|
}
|
||||||
|
|
||||||
function abort(message = 'Abort', exitCode = 1) {
|
function abort(message = 'Abort', exitCode = 1) {
|
||||||
console.error(chalk.bold.red(`\n${message}\n`))
|
console.error(chalk.bold.red(`\n${message}\n`))
|
||||||
process.exit(exitCode)
|
process.exit(exitCode)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { SerializedBlockNode } from '@payloadcms/richtext-lexical'
|
import type { SerializedBlockNode, SerializedLinkNode } from '@payloadcms/richtext-lexical'
|
||||||
import type { Page } from '@playwright/test'
|
import type { Page } from '@playwright/test'
|
||||||
import type { SerializedEditorState, SerializedParagraphNode, SerializedTextNode } from 'lexical'
|
import type { SerializedEditorState, SerializedParagraphNode, SerializedTextNode } from 'lexical'
|
||||||
import type { Payload } from 'payload'
|
import type { Payload } from 'payload'
|
||||||
@@ -402,7 +402,7 @@ describe('lexical', () => {
|
|||||||
for (let i = 0; i < 18; i++) {
|
for (let i = 0; i < 18; i++) {
|
||||||
await page.keyboard.press('Shift+ArrowRight')
|
await page.keyboard.press('Shift+ArrowRight')
|
||||||
}
|
}
|
||||||
// The following text should now be selected: elationship node 1
|
// The following text should now be selectedelationship node 1
|
||||||
|
|
||||||
const floatingToolbar_formatSection = page.locator(
|
const floatingToolbar_formatSection = page.locator(
|
||||||
'.floating-select-toolbar-popup__section-format',
|
'.floating-select-toolbar-popup__section-format',
|
||||||
@@ -463,6 +463,92 @@ describe('lexical', () => {
|
|||||||
timeout: POLL_TOPASS_TIMEOUT,
|
timeout: POLL_TOPASS_TIMEOUT,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('should be able to select text, make it an external link and receive the updated link value', async () => {
|
||||||
|
// Reproduces https://github.com/payloadcms/payload/issues/4025
|
||||||
|
await navigateToLexicalFields()
|
||||||
|
const richTextField = page.locator('.rich-text-lexical').nth(1) // second
|
||||||
|
await richTextField.scrollIntoViewIfNeeded()
|
||||||
|
await expect(richTextField).toBeVisible()
|
||||||
|
|
||||||
|
// Find span in contentEditable with text "Some text below relationship node"
|
||||||
|
const spanInEditor = richTextField.locator('span').getByText('Upload Node:').first()
|
||||||
|
await expect(spanInEditor).toBeVisible()
|
||||||
|
await spanInEditor.click() // Use click, because focus does not work
|
||||||
|
|
||||||
|
await page.keyboard.press('ArrowRight')
|
||||||
|
// Now select some text
|
||||||
|
for (let i = 0; i < 4; i++) {
|
||||||
|
await page.keyboard.press('Shift+ArrowRight')
|
||||||
|
}
|
||||||
|
// The following text should now be "Node"
|
||||||
|
|
||||||
|
const floatingToolbar = page.locator('.floating-select-toolbar-popup')
|
||||||
|
|
||||||
|
await expect(floatingToolbar).toBeVisible()
|
||||||
|
|
||||||
|
const linkButton = floatingToolbar
|
||||||
|
.locator('.floating-select-toolbar-popup__button-link')
|
||||||
|
.first()
|
||||||
|
|
||||||
|
await expect(linkButton).toBeVisible()
|
||||||
|
await linkButton.click()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In drawer
|
||||||
|
*/
|
||||||
|
const drawerContent = page.locator('.drawer__content').first()
|
||||||
|
await expect(drawerContent).toBeVisible()
|
||||||
|
|
||||||
|
const urlField = drawerContent.locator('input#field-fields__url').first()
|
||||||
|
await expect(urlField).toBeVisible()
|
||||||
|
// Fill with https://www.payloadcms.com
|
||||||
|
await urlField.fill('https://www.payloadcms.com')
|
||||||
|
await expect(urlField).toHaveValue('https://www.payloadcms.com')
|
||||||
|
await drawerContent.locator('.form-submit button').click({ delay: 100 })
|
||||||
|
await expect(drawerContent).toBeHidden()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check if it worked correctly
|
||||||
|
*/
|
||||||
|
|
||||||
|
const linkInEditor = richTextField.locator('a.LexicalEditorTheme__link').first()
|
||||||
|
await expect(linkInEditor).toBeVisible()
|
||||||
|
await expect(linkInEditor).toHaveAttribute('href', 'https://www.payloadcms.com')
|
||||||
|
|
||||||
|
await saveDocAndAssert(page)
|
||||||
|
|
||||||
|
// Check if it persists after saving
|
||||||
|
await expect(linkInEditor).toBeVisible()
|
||||||
|
await expect(linkInEditor).toHaveAttribute('href', 'https://www.payloadcms.com')
|
||||||
|
|
||||||
|
// Make sure it's being returned from the API as well
|
||||||
|
await expect(async () => {
|
||||||
|
const lexicalDoc: LexicalField = (
|
||||||
|
await payload.find({
|
||||||
|
collection: lexicalFieldsSlug,
|
||||||
|
depth: 0,
|
||||||
|
where: {
|
||||||
|
title: {
|
||||||
|
equals: lexicalDocData.title,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
).docs[0] as never
|
||||||
|
|
||||||
|
const lexicalField: SerializedEditorState = lexicalDoc.lexicalWithBlocks
|
||||||
|
|
||||||
|
expect(
|
||||||
|
(
|
||||||
|
(lexicalField.root.children[0] as SerializedParagraphNode)
|
||||||
|
.children[1] as SerializedLinkNode
|
||||||
|
).fields.url,
|
||||||
|
).toBe('https://www.payloadcms.com')
|
||||||
|
}).toPass({
|
||||||
|
timeout: POLL_TOPASS_TIMEOUT,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
test('ensure slash menu is not hidden behind other blocks', async () => {
|
test('ensure slash menu is not hidden behind other blocks', async () => {
|
||||||
// This test makes sure there are no z-index issues here
|
// This test makes sure there are no z-index issues here
|
||||||
await navigateToLexicalFields()
|
await navigateToLexicalFields()
|
||||||
@@ -799,6 +885,22 @@ describe('lexical', () => {
|
|||||||
await shouldRespectRowRemovalTest()
|
await shouldRespectRowRemovalTest()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('ensure pre-seeded uploads node is visible', async () => {
|
||||||
|
// Due to issues with the relationships condition, we had issues with that not being visible. Checking for visibility ensures there is no breakage there again
|
||||||
|
await navigateToLexicalFields()
|
||||||
|
const richTextField = page.locator('.rich-text-lexical').nth(1) // second
|
||||||
|
await richTextField.scrollIntoViewIfNeeded()
|
||||||
|
await expect(richTextField).toBeVisible()
|
||||||
|
|
||||||
|
const uploadBlock = richTextField.locator('.ContentEditable__root > div').first() // Check for the first div, as we wanna make sure it's the first div in the editor (1. node is a paragraph, second node is a div which is the upload node)
|
||||||
|
await uploadBlock.scrollIntoViewIfNeeded()
|
||||||
|
await expect(uploadBlock).toBeVisible()
|
||||||
|
|
||||||
|
await expect(uploadBlock.locator('.lexical-upload__doc-drawer-toggler strong')).toHaveText(
|
||||||
|
'payload.jpg',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
test.skip('should respect required error state in deeply nested text field', async () => {
|
test.skip('should respect required error state in deeply nested text field', async () => {
|
||||||
await navigateToLexicalFields()
|
await navigateToLexicalFields()
|
||||||
const richTextField = page.locator('.rich-text-lexical').nth(1) // second
|
const richTextField = page.locator('.rich-text-lexical').nth(1) // second
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import Uploads from './collections/Upload/index.js'
|
|||||||
import Uploads2 from './collections/Upload2/index.js'
|
import Uploads2 from './collections/Upload2/index.js'
|
||||||
import Uploads3 from './collections/Uploads3/index.js'
|
import Uploads3 from './collections/Uploads3/index.js'
|
||||||
import TabsWithRichText from './globals/TabsWithRichText.js'
|
import TabsWithRichText from './globals/TabsWithRichText.js'
|
||||||
import { seed } from './seed.js'
|
import { clearAndSeedEverything } from './seed.js'
|
||||||
|
|
||||||
export const collectionSlugs: CollectionConfig[] = [
|
export const collectionSlugs: CollectionConfig[] = [
|
||||||
LexicalFields,
|
LexicalFields,
|
||||||
@@ -79,7 +79,7 @@ export default buildConfigWithDefaults({
|
|||||||
},
|
},
|
||||||
onInit: async (payload) => {
|
onInit: async (payload) => {
|
||||||
if (process.env.SEED_IN_CONFIG_ONINIT !== 'false') {
|
if (process.env.SEED_IN_CONFIG_ONINIT !== 'false') {
|
||||||
await seed(payload)
|
await clearAndSeedEverything(payload)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -82,7 +82,7 @@
|
|||||||
"./packages/ui/src/scss/app.scss"
|
"./packages/ui/src/scss/app.scss"
|
||||||
],
|
],
|
||||||
"@payloadcms/next/*": [
|
"@payloadcms/next/*": [
|
||||||
"./packages/next/src/exports/*"
|
"./packages/next/src/*"
|
||||||
],
|
],
|
||||||
"@payloadcms/next": [
|
"@payloadcms/next": [
|
||||||
"./packages/next/src/exports/*"
|
"./packages/next/src/exports/*"
|
||||||
|
|||||||
Reference in New Issue
Block a user