From 972406724263667fe4103f6c8d714001cd34df18 Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Wed, 5 Mar 2025 14:14:35 -0500 Subject: [PATCH] feat: payload admin bar (#3684) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Imports https://github.com/payloadcms/payload-admin-bar into the Payload monorepo. This package will now be regularly maintained directly alongside all Payload packages and now includes its own test suite. A few changes minor have been made between v1.0.7 and latest: 1. The package name has changed from `payload-admin-bar` to `@payloadcms/admin-bar`. ```diff - import { PayloadAdminBar } from 'payload-admin-bar' + import { PayloadAdminBar } from '@payloadcms/admin-bar' ``` 2. The `collection` prop has been renamed to `collectionSlug` 3. The `authCollection` prop has been renamed to `authCollectionSlug` Here's a screenshot of the admin bar in use within the Website Template: Screenshot 2025-03-05 at 1 20 04 PM --------- Co-authored-by: Kalon Robson --- .github/workflows/main.yml | 1 + .gitignore | 2 + package.json | 1 + packages/admin-bar/.prettierignore | 10 + packages/admin-bar/.swcrc | 24 ++ packages/admin-bar/LICENSE.md | 22 ++ packages/admin-bar/README.md | 119 ++++++ packages/admin-bar/eslint.config.js | 18 + packages/admin-bar/package.json | 65 +++ packages/admin-bar/src/AdminBar.tsx | 349 +++++++++++++++++ packages/admin-bar/src/index.ts | 2 + packages/admin-bar/src/types.ts | 67 ++++ packages/admin-bar/tsconfig.json | 9 + pnpm-lock.yaml | 25 ++ test/admin-bar/.gitignore | 2 + .../admin/[[...segments]]/not-found.tsx | 25 ++ .../(payload)/admin/[[...segments]]/page.tsx | 25 ++ .../app/(payload)/admin/importMap.js | 1 + .../app/(payload)/api/[...slug]/route.ts | 10 + .../(payload)/api/graphql-playground/route.ts | 6 + .../app/(payload)/api/graphql/route.ts | 8 + test/admin-bar/app/(payload)/custom.scss | 7 + test/admin-bar/app/(payload)/layout.tsx | 31 ++ test/admin-bar/app/admin-bar/app.scss | 22 ++ test/admin-bar/app/admin-bar/layout.tsx | 29 ++ test/admin-bar/app/admin-bar/page.tsx | 12 + test/admin-bar/collections/Media/index.ts | 33 ++ test/admin-bar/collections/Posts/index.ts | 19 + test/admin-bar/config.ts | 39 ++ test/admin-bar/e2e.spec.ts | 37 ++ test/admin-bar/eslint.config.js | 19 + test/admin-bar/next-env.d.ts | 5 + test/admin-bar/next.config.mjs | 15 + test/admin-bar/payload-types.ts | 370 ++++++++++++++++++ test/admin-bar/tsconfig.eslint.json | 13 + test/admin-bar/tsconfig.json | 5 + test/admin-bar/types.d.ts | 9 + test/generateImportMap.ts | 8 +- test/package.json | 1 + test/setupProd.ts | 1 + test/tsconfig.typecheck.json | 3 + tools/releaser/src/lib/publishList.ts | 1 + tsconfig.base.json | 9 +- tsconfig.json | 4 +- 44 files changed, 1478 insertions(+), 5 deletions(-) create mode 100644 packages/admin-bar/.prettierignore create mode 100644 packages/admin-bar/.swcrc create mode 100644 packages/admin-bar/LICENSE.md create mode 100644 packages/admin-bar/README.md create mode 100644 packages/admin-bar/eslint.config.js create mode 100644 packages/admin-bar/package.json create mode 100644 packages/admin-bar/src/AdminBar.tsx create mode 100644 packages/admin-bar/src/index.ts create mode 100644 packages/admin-bar/src/types.ts create mode 100644 packages/admin-bar/tsconfig.json create mode 100644 test/admin-bar/.gitignore create mode 100644 test/admin-bar/app/(payload)/admin/[[...segments]]/not-found.tsx create mode 100644 test/admin-bar/app/(payload)/admin/[[...segments]]/page.tsx create mode 100644 test/admin-bar/app/(payload)/admin/importMap.js create mode 100644 test/admin-bar/app/(payload)/api/[...slug]/route.ts create mode 100644 test/admin-bar/app/(payload)/api/graphql-playground/route.ts create mode 100644 test/admin-bar/app/(payload)/api/graphql/route.ts create mode 100644 test/admin-bar/app/(payload)/custom.scss create mode 100644 test/admin-bar/app/(payload)/layout.tsx create mode 100644 test/admin-bar/app/admin-bar/app.scss create mode 100644 test/admin-bar/app/admin-bar/layout.tsx create mode 100644 test/admin-bar/app/admin-bar/page.tsx create mode 100644 test/admin-bar/collections/Media/index.ts create mode 100644 test/admin-bar/collections/Posts/index.ts create mode 100644 test/admin-bar/config.ts create mode 100644 test/admin-bar/e2e.spec.ts create mode 100644 test/admin-bar/eslint.config.js create mode 100644 test/admin-bar/next-env.d.ts create mode 100644 test/admin-bar/next.config.mjs create mode 100644 test/admin-bar/payload-types.ts create mode 100644 test/admin-bar/tsconfig.eslint.json create mode 100644 test/admin-bar/tsconfig.json create mode 100644 test/admin-bar/types.d.ts diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f8aa258f6..f46c5e9ae 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -275,6 +275,7 @@ jobs: - admin__e2e__general - admin__e2e__list-view - admin__e2e__document-view + - admin-bar - admin-root - auth - auth-basic diff --git a/.gitignore b/.gitignore index 45f9b3418..fce7617d1 100644 --- a/.gitignore +++ b/.gitignore @@ -306,6 +306,8 @@ $RECYCLE.BIN/ /build .swc app/(payload)/admin/importMap.js +test/admin-bar/app/(payload)/admin/importMap.js +/test/admin-bar/app/(payload)/admin/importMap.js test/live-preview/app/(payload)/admin/importMap.js /test/live-preview/app/(payload)/admin/importMap.js test/admin-root/app/(payload)/admin/importMap.js diff --git a/package.json b/package.json index 1a25ae1ad..7bc109617 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "scripts": { "bf": "pnpm run build:force", "build": "pnpm run build:core", + "build:admin-bar": "turbo build --filter \"@payloadcms/admin-bar\"", "build:all": "turbo build", "build:app": "next build", "build:app:analyze": "cross-env ANALYZE=true next build", diff --git a/packages/admin-bar/.prettierignore b/packages/admin-bar/.prettierignore new file mode 100644 index 000000000..247f3f12d --- /dev/null +++ b/packages/admin-bar/.prettierignore @@ -0,0 +1,10 @@ +.tmp +**/.git +**/.hg +**/.pnp.* +**/.svn +**/.yarn/** +**/build +**/dist/** +**/node_modules +**/temp diff --git a/packages/admin-bar/.swcrc b/packages/admin-bar/.swcrc new file mode 100644 index 000000000..b4fb882ca --- /dev/null +++ b/packages/admin-bar/.swcrc @@ -0,0 +1,24 @@ +{ + "$schema": "https://json.schemastore.org/swcrc", + "sourceMaps": true, + "jsc": { + "target": "esnext", + "parser": { + "syntax": "typescript", + "tsx": true, + "dts": true + }, + "transform": { + "react": { + "runtime": "automatic", + "pragmaFrag": "React.Fragment", + "throwIfNamespace": true, + "development": false, + "useBuiltins": true + } + } + }, + "module": { + "type": "es6" + } +} diff --git a/packages/admin-bar/LICENSE.md b/packages/admin-bar/LICENSE.md new file mode 100644 index 000000000..b31f1fb3a --- /dev/null +++ b/packages/admin-bar/LICENSE.md @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2018-2025 Payload CMS, Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/admin-bar/README.md b/packages/admin-bar/README.md new file mode 100644 index 000000000..9b2e802bb --- /dev/null +++ b/packages/admin-bar/README.md @@ -0,0 +1,119 @@ +# Payload Admin Bar + +An admin bar for React apps using [Payload](https://github.com/payloadcms/payload). + +### Installation + +```bash +pnpm i @payloadcms/admin-bar +``` + +### Basic Usage + +```jsx +import { PayloadAdminBar } from '@payloadcms/admin-bar' + +export const App = () => { + return +} +``` + +Checks for authentication with Payload CMS by hitting the [`/me`](https://payloadcms.com/docs/authentication/operations#me) route. If authenticated, renders an admin bar with simple controls to do the following: + +- Navigate to the admin dashboard +- Navigate to the currently logged-in user's account +- Edit the current collection +- Create a new collection of the same type +- Logout +- Indicate and exit preview mode + +The admin bar ships with very little style and is fully customizable. + +### Dynamic props + +With client-side routing, we need to update the admin bar with a new collection type and document id on each route change. This will depend on your app's specific setup, but here are a some common examples: + +#### NextJS + +For NextJS apps using dynamic-routes, use `getStaticProps`: + +```ts +export const getStaticProps = async ({ params: { slug } }) => { + const props = {} + + const pageReq = await fetch( + `https://cms.website.com/api/pages?where[slug][equals]=${slug}&depth=1`, + ) + const pageData = await pageReq.json() + + if (pageReq.ok) { + const { docs } = pageData + const [doc] = docs + + props = { + ...doc, + collection: 'pages', + collectionLabels: { + singular: 'page', + plural: 'pages', + }, + } + } + + return props +} +``` + +Now your app can forward these props onto the admin bar. Something like this: + +```ts +import { PayloadAdminBar } from '@payloadcms/admin-bar'; + +export const App = (appProps) => { + const { + pageProps: { + collection, + collectionLabels, + id + } + } = appProps; + + return ( + + ) +} +``` + +### Props + +| Property | Type | Required | Default | Description | +| ------------------ | ------------------------------------------------------------------------------------------------------------------------ | -------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | +| cmsURL | `string` | true | `http://localhost:8000` | `serverURL` as defined in your [Payload config](https://payloadcms.com/docs/configuration/overview#options) | +| adminPath | `string` | false | /admin | `routes` as defined in your [Payload config](https://payloadcms.com/docs/configuration/overview#options) | +| apiPath | `string` | false | /api | `routes` as defined in your [Payload config](https://payloadcms.com/docs/configuration/overview#options) | +| authCollectionSlug | `string` | false | 'users' | Slug of your [auth collection](https://payloadcms.com/docs/configuration/collections) | +| collectionSlug | `string` | true | undefined | Slug of your [collection](https://payloadcms.com/docs/configuration/collections) | +| collectionLabels | `{ singular?: string, plural?: string }` | false | undefined | Labels of your [collection](https://payloadcms.com/docs/configuration/collections) | +| id | `string` | true | undefined | id of the document | +| logo | `ReactElement` | false | undefined | Custom logo | +| classNames | `{ logo?: string, user?: string, controls?: string, create?: string, logout?: string, edit?: string, preview?: string }` | false | undefined | Custom class names, one for each rendered element | +| logoProps | `{[key: string]?: unknown}` | false | undefined | Custom props | +| userProps | `{[key: string]?: unknown}` | false | undefined | Custom props | +| divProps | `{[key: string]?: unknown}` | false | undefined | Custom props | +| createProps | `{[key: string]?: unknown}` | false | undefined | Custom props | +| logoutProps | `{[key: string]?: unknown}` | false | undefined | Custom props | +| editProps | `{[key: string]?: unknown}` | false | undefined | Custom props | +| previewProps | `{[key: string]?: unknown}` | false | undefined | Custom props | +| style | `CSSProperties` | false | undefined | Custom inline style | +| unstyled | `boolean` | false | undefined | If true, renders no inline style | +| onAuthChange | `(user: PayloadMeUser) => void` | false | undefined | Fired on each auth change | +| devMode | `boolean` | false | undefined | If true, fakes authentication (useful when dealing with [SameSite cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite)) | +| preview | `boolean` | false | undefined | If true, renders an exit button with your `onPreviewExit` handler) | +| onPreviewExit | `function` | false | undefined | Callback for the preview button `onClick` event) | diff --git a/packages/admin-bar/eslint.config.js b/packages/admin-bar/eslint.config.js new file mode 100644 index 000000000..f9d341be5 --- /dev/null +++ b/packages/admin-bar/eslint.config.js @@ -0,0 +1,18 @@ +import { rootEslintConfig, rootParserOptions } from '../../eslint.config.js' + +/** @typedef {import('eslint').Linter.Config} Config */ + +/** @type {Config[]} */ +export const index = [ + ...rootEslintConfig, + { + languageOptions: { + parserOptions: { + ...rootParserOptions, + tsconfigRootDir: import.meta.dirname, + }, + }, + }, +] + +export default index diff --git a/packages/admin-bar/package.json b/packages/admin-bar/package.json new file mode 100644 index 000000000..8d93001e3 --- /dev/null +++ b/packages/admin-bar/package.json @@ -0,0 +1,65 @@ +{ + "name": "@payloadcms/admin-bar", + "version": "1.0.7", + "description": "An admin bar for React apps using Payload", + "homepage": "https://payloadcms.com", + "repository": { + "type": "git", + "url": "https://github.com/payloadcms/payload.git", + "directory": "packages/admin-bar" + }, + "license": "MIT", + "author": "Payload (https://payloadcms.com)", + "maintainers": [ + { + "name": "Payload", + "email": "info@payloadcms.com", + "url": "https://payloadcms.com" + } + ], + "type": "module", + "exports": { + ".": { + "import": "./src/index.ts", + "types": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "main": "./src/index.ts", + "types": "./src/index.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "pnpm copyfiles && pnpm build:types && pnpm build:swc", + "build:swc": "swc ./src -d ./dist --config-file .swcrc --strip-leading-paths", + "build:types": "tsc --emitDeclarationOnly --outDir dist", + "clean": "rimraf -g {dist,*.tsbuildinfo}", + "copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png,json}\" dist/", + "lint": "eslint .", + "lint:fix": "eslint . --fix", + "prepublishOnly": "pnpm clean && pnpm turbo build" + }, + "devDependencies": { + "@payloadcms/eslint-config": "workspace:*", + "@types/react": "19.0.10", + "@types/react-dom": "19.0.4", + "payload": "workspace:*" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "publishConfig": { + "exports": { + ".": { + "import": "./dist/index.js", + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, + "main": "./dist/index.js", + "registry": "https://registry.npmjs.org/", + "types": "./dist/index.d.ts" + } +} diff --git a/packages/admin-bar/src/AdminBar.tsx b/packages/admin-bar/src/AdminBar.tsx new file mode 100644 index 000000000..371b8f13e --- /dev/null +++ b/packages/admin-bar/src/AdminBar.tsx @@ -0,0 +1,349 @@ +'use client' +import React, { useEffect, useState } from 'react' + +const dummyUser = { + id: '12345', + email: 'dev@email.com', +} + +import type { PayloadAdminBarProps, PayloadMeUser } from './types.js' + +export const PayloadAdminBar: React.FC = (props) => { + const { + id: docID, + adminPath = '/admin', + apiPath = '/api', + authCollectionSlug = 'users', + className, + classNames, + cmsURL = 'http://localhost:8000', + collectionLabels, + collectionSlug, + createProps, + devMode, + divProps, + editProps, + logo, + logoProps, + logoutProps, + onAuthChange, + onPreviewExit, + preview, + previewProps, + style, + unstyled, + userProps, + } = props + + const [user, setUser] = useState() + + useEffect(() => { + const fetchMe = async () => { + try { + const meRequest = await fetch(`${cmsURL}${apiPath}/${authCollectionSlug}/me`, { + credentials: 'include', + method: 'get', + }) + const meResponse = await meRequest.json() + const { user } = meResponse + + if (user) { + setUser(user) + } else { + if (devMode !== true) { + setUser(null) + } else { + setUser(dummyUser) + } + } + } catch (err) { + console.warn(err) + if (devMode === true) { + setUser(dummyUser) + } + } + } + + void fetchMe() + }, [cmsURL, adminPath, apiPath, devMode]) + + useEffect(() => { + if (typeof onAuthChange === 'function') { + onAuthChange(user) + } + }, [user, onAuthChange]) + + if (user) { + const { id: userID, email } = user + + return ( + + ) + } + + return null +} diff --git a/packages/admin-bar/src/index.ts b/packages/admin-bar/src/index.ts new file mode 100644 index 000000000..f41e6be2b --- /dev/null +++ b/packages/admin-bar/src/index.ts @@ -0,0 +1,2 @@ +export { PayloadAdminBar } from './AdminBar.js' +export type { PayloadAdminBarProps, PayloadMeUser } from './types.js' diff --git a/packages/admin-bar/src/types.ts b/packages/admin-bar/src/types.ts new file mode 100644 index 000000000..044aa6edb --- /dev/null +++ b/packages/admin-bar/src/types.ts @@ -0,0 +1,67 @@ +import type { CSSProperties, ReactElement } from 'react' + +export type PayloadMeUser = + | { + email: string + id: string + } + | null + | undefined + +export type PayloadAdminBarProps = { + adminPath?: string + apiPath?: string + authCollectionSlug?: string + className?: string + classNames?: { + controls?: string + create?: string + edit?: string + logo?: string + logout?: string + preview?: string + user?: string + } + cmsURL?: string + collectionLabels?: { + plural?: string + singular?: string + } + collectionSlug?: string + createProps?: { + [key: string]: unknown + style?: CSSProperties + } + devMode?: boolean + divProps?: { + [key: string]: unknown + style?: CSSProperties + } + editProps?: { + [key: string]: unknown + style?: CSSProperties + } + id?: string + logo?: ReactElement + logoProps?: { + [key: string]: unknown + style?: CSSProperties + } + logoutProps?: { + [key: string]: unknown + style?: CSSProperties + } + onAuthChange?: (user: PayloadMeUser) => void + onPreviewExit?: () => void + preview?: boolean + previewProps?: { + [key: string]: unknown + style?: CSSProperties + } + style?: CSSProperties + unstyled?: boolean + userProps?: { + [key: string]: unknown + style?: CSSProperties + } +} diff --git a/packages/admin-bar/tsconfig.json b/packages/admin-bar/tsconfig.json new file mode 100644 index 000000000..14564e071 --- /dev/null +++ b/packages/admin-bar/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + /* TODO: remove the following lines */ + "strict": false, + "noUncheckedIndexedAccess": false, + }, + "references": [{ "path": "../payload" }] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a54df297e..159e22fb0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -191,6 +191,28 @@ importers: specifier: 5.7.3 version: 5.7.3 + packages/admin-bar: + dependencies: + react: + specifier: 19.0.0 + version: 19.0.0 + react-dom: + specifier: 19.0.0 + version: 19.0.0(react@19.0.0) + devDependencies: + '@payloadcms/eslint-config': + specifier: workspace:* + version: link:../eslint-config + '@types/react': + specifier: 19.0.10 + version: 19.0.10 + '@types/react-dom': + specifier: 19.0.4 + version: 19.0.4(@types/react@19.0.10) + payload: + specifier: workspace:* + version: link:../payload + packages/create-payload-app: dependencies: '@clack/prompts': @@ -1657,6 +1679,9 @@ importers: '@next/env': specifier: 15.2.0 version: 15.2.0 + '@payloadcms/admin-bar': + specifier: workspace:* + version: link:../packages/admin-bar '@payloadcms/db-mongodb': specifier: workspace:* version: link:../packages/db-mongodb diff --git a/test/admin-bar/.gitignore b/test/admin-bar/.gitignore new file mode 100644 index 000000000..cce01755f --- /dev/null +++ b/test/admin-bar/.gitignore @@ -0,0 +1,2 @@ +/media +/media-gif diff --git a/test/admin-bar/app/(payload)/admin/[[...segments]]/not-found.tsx b/test/admin-bar/app/(payload)/admin/[[...segments]]/not-found.tsx new file mode 100644 index 000000000..180e6f81c --- /dev/null +++ b/test/admin-bar/app/(payload)/admin/[[...segments]]/not-found.tsx @@ -0,0 +1,25 @@ +/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */ +/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */ +import type { Metadata } from 'next' + +import config from '@payload-config' +import { generatePageMetadata, NotFoundPage } from '@payloadcms/next/views' + +import { importMap } from '../importMap.js' + +type Args = { + params: Promise<{ + segments: string[] + }> + searchParams: Promise<{ + [key: string]: string | string[] + }> +} + +export const generateMetadata = ({ params, searchParams }: Args): Promise => + generatePageMetadata({ config, params, searchParams }) + +const NotFound = ({ params, searchParams }: Args) => + NotFoundPage({ config, importMap, params, searchParams }) + +export default NotFound diff --git a/test/admin-bar/app/(payload)/admin/[[...segments]]/page.tsx b/test/admin-bar/app/(payload)/admin/[[...segments]]/page.tsx new file mode 100644 index 000000000..e59b2d3a8 --- /dev/null +++ b/test/admin-bar/app/(payload)/admin/[[...segments]]/page.tsx @@ -0,0 +1,25 @@ +/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */ +/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */ +import type { Metadata } from 'next' + +import config from '@payload-config' +import { generatePageMetadata, RootPage } from '@payloadcms/next/views' + +import { importMap } from '../importMap.js' + +type Args = { + params: Promise<{ + segments: string[] + }> + searchParams: Promise<{ + [key: string]: string | string[] + }> +} + +export const generateMetadata = ({ params, searchParams }: Args): Promise => + generatePageMetadata({ config, params, searchParams }) + +const Page = ({ params, searchParams }: Args) => + RootPage({ config, importMap, params, searchParams }) + +export default Page diff --git a/test/admin-bar/app/(payload)/admin/importMap.js b/test/admin-bar/app/(payload)/admin/importMap.js new file mode 100644 index 000000000..8ef702138 --- /dev/null +++ b/test/admin-bar/app/(payload)/admin/importMap.js @@ -0,0 +1 @@ +export const importMap = {} diff --git a/test/admin-bar/app/(payload)/api/[...slug]/route.ts b/test/admin-bar/app/(payload)/api/[...slug]/route.ts new file mode 100644 index 000000000..183cf457f --- /dev/null +++ b/test/admin-bar/app/(payload)/api/[...slug]/route.ts @@ -0,0 +1,10 @@ +/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */ +/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */ +import config from '@payload-config' +import { REST_DELETE, REST_GET, REST_OPTIONS, REST_PATCH, REST_POST } from '@payloadcms/next/routes' + +export const GET = REST_GET(config) +export const POST = REST_POST(config) +export const DELETE = REST_DELETE(config) +export const PATCH = REST_PATCH(config) +export const OPTIONS = REST_OPTIONS(config) diff --git a/test/admin-bar/app/(payload)/api/graphql-playground/route.ts b/test/admin-bar/app/(payload)/api/graphql-playground/route.ts new file mode 100644 index 000000000..dffacb345 --- /dev/null +++ b/test/admin-bar/app/(payload)/api/graphql-playground/route.ts @@ -0,0 +1,6 @@ +/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */ +/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */ +import config from '@payload-config' +import { GRAPHQL_PLAYGROUND_GET } from '@payloadcms/next/routes/index.js' + +export const GET = GRAPHQL_PLAYGROUND_GET(config) diff --git a/test/admin-bar/app/(payload)/api/graphql/route.ts b/test/admin-bar/app/(payload)/api/graphql/route.ts new file mode 100644 index 000000000..2069ff86b --- /dev/null +++ b/test/admin-bar/app/(payload)/api/graphql/route.ts @@ -0,0 +1,8 @@ +/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */ +/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */ +import config from '@payload-config' +import { GRAPHQL_POST, REST_OPTIONS } from '@payloadcms/next/routes' + +export const POST = GRAPHQL_POST(config) + +export const OPTIONS = REST_OPTIONS(config) diff --git a/test/admin-bar/app/(payload)/custom.scss b/test/admin-bar/app/(payload)/custom.scss new file mode 100644 index 000000000..f557cd427 --- /dev/null +++ b/test/admin-bar/app/(payload)/custom.scss @@ -0,0 +1,7 @@ +#custom-css { + font-family: monospace; +} + +#custom-css::after { + content: 'custom-css'; +} diff --git a/test/admin-bar/app/(payload)/layout.tsx b/test/admin-bar/app/(payload)/layout.tsx new file mode 100644 index 000000000..93a5fcf45 --- /dev/null +++ b/test/admin-bar/app/(payload)/layout.tsx @@ -0,0 +1,31 @@ +/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */ +/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */ +import type { ServerFunctionClient } from 'payload' + +import config from '@payload-config' +import { handleServerFunctions, RootLayout } from '@payloadcms/next/layouts' +import React from 'react' + +import { importMap } from './admin/importMap.js' +import './custom.scss' + +type Args = { + children: React.ReactNode +} + +const serverFunction: ServerFunctionClient = async function (args) { + 'use server' + return handleServerFunctions({ + ...args, + config, + importMap, + }) +} + +const Layout = ({ children }: Args) => ( + + {children} + +) + +export default Layout diff --git a/test/admin-bar/app/admin-bar/app.scss b/test/admin-bar/app/admin-bar/app.scss new file mode 100644 index 000000000..0c374fce7 --- /dev/null +++ b/test/admin-bar/app/admin-bar/app.scss @@ -0,0 +1,22 @@ +:root { + --font-body: system-ui; +} + +* { + box-sizing: border-box; +} + +html { + -webkit-font-smoothing: antialiased; +} + +html, +body, +#app { + height: 100%; +} + +body { + font-family: var(--font-body); + margin: 0; +} diff --git a/test/admin-bar/app/admin-bar/layout.tsx b/test/admin-bar/app/admin-bar/layout.tsx new file mode 100644 index 000000000..3e797358e --- /dev/null +++ b/test/admin-bar/app/admin-bar/layout.tsx @@ -0,0 +1,29 @@ +import type { Metadata } from 'next' + +import { PayloadAdminBar } from '@payloadcms/admin-bar' +import React from 'react' + +import './app.scss' + +export const metadata: Metadata = { + description: 'Payload Admin Bar', + title: 'Payload Admin Bar', +} + +export default function RootLayout({ children }: { children: React.ReactNode }) { + return ( + + + + {children} + + + ) +} diff --git a/test/admin-bar/app/admin-bar/page.tsx b/test/admin-bar/app/admin-bar/page.tsx new file mode 100644 index 000000000..8be7a4cc9 --- /dev/null +++ b/test/admin-bar/app/admin-bar/page.tsx @@ -0,0 +1,12 @@ +import { Fragment } from 'react' + +const PageTemplate = () => { + return ( + +
+

Payload Admin Bar

+
+ ) +} + +export default PageTemplate diff --git a/test/admin-bar/collections/Media/index.ts b/test/admin-bar/collections/Media/index.ts new file mode 100644 index 000000000..bb5edd034 --- /dev/null +++ b/test/admin-bar/collections/Media/index.ts @@ -0,0 +1,33 @@ +import type { CollectionConfig } from 'payload' + +export const mediaSlug = 'media' + +export const MediaCollection: CollectionConfig = { + slug: mediaSlug, + access: { + create: () => true, + read: () => true, + }, + fields: [], + upload: { + crop: true, + focalPoint: true, + imageSizes: [ + { + name: 'thumbnail', + height: 200, + width: 200, + }, + { + name: 'medium', + height: 800, + width: 800, + }, + { + name: 'large', + height: 1200, + width: 1200, + }, + ], + }, +} diff --git a/test/admin-bar/collections/Posts/index.ts b/test/admin-bar/collections/Posts/index.ts new file mode 100644 index 000000000..ffed2abbd --- /dev/null +++ b/test/admin-bar/collections/Posts/index.ts @@ -0,0 +1,19 @@ +import type { CollectionConfig } from 'payload' + +export const postsSlug = 'posts' + +export const PostsCollection: CollectionConfig = { + slug: postsSlug, + admin: { + useAsTitle: 'title', + }, + fields: [ + { + name: 'title', + type: 'text', + }, + ], + versions: { + drafts: true, + }, +} diff --git a/test/admin-bar/config.ts b/test/admin-bar/config.ts new file mode 100644 index 000000000..5c56404df --- /dev/null +++ b/test/admin-bar/config.ts @@ -0,0 +1,39 @@ +import { fileURLToPath } from 'node:url' +import path from 'path' + +import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js' +import { devUser } from '../credentials.js' +import { MediaCollection } from './collections/Media/index.js' +import { PostsCollection, postsSlug } from './collections/Posts/index.js' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfigWithDefaults({ + // ...extend config here + collections: [PostsCollection, MediaCollection], + admin: { + importMap: { + baseDir: path.resolve(dirname), + }, + }, + onInit: async (payload) => { + await payload.create({ + collection: 'users', + data: { + email: devUser.email, + password: devUser.password, + }, + }) + + await payload.create({ + collection: postsSlug, + data: { + title: 'example post', + }, + }) + }, + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, +}) diff --git a/test/admin-bar/e2e.spec.ts b/test/admin-bar/e2e.spec.ts new file mode 100644 index 000000000..b9c2f9026 --- /dev/null +++ b/test/admin-bar/e2e.spec.ts @@ -0,0 +1,37 @@ +import type { Page } from '@playwright/test' + +import { expect, test } from '@playwright/test' +import * as path from 'path' +import { fileURLToPath } from 'url' + +import { ensureCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js' +import { AdminUrlUtil } from '../helpers/adminUrlUtil.js' +import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' +import { TEST_TIMEOUT_LONG } from '../playwright.config.js' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +test.describe('Admin Bar', () => { + let page: Page + let url: AdminUrlUtil + let serverURL: string + + test.beforeAll(async ({ browser }, testInfo) => { + testInfo.setTimeout(TEST_TIMEOUT_LONG) + + const { payload, serverURL: incomingServerURL } = await initPayloadE2ENoConfig({ dirname }) + url = new AdminUrlUtil(incomingServerURL, 'posts') + serverURL = incomingServerURL + + const context = await browser.newContext() + page = await context.newPage() + initPageConsoleErrorCatch(page) + await ensureCompilationIsDone({ page, serverURL: incomingServerURL }) + }) + + test('should render admin bar', async () => { + await page.goto(`${serverURL}/admin-bar`) + await expect(page.locator('#payload-admin-bar')).toBeVisible() + }) +}) diff --git a/test/admin-bar/eslint.config.js b/test/admin-bar/eslint.config.js new file mode 100644 index 000000000..f295df083 --- /dev/null +++ b/test/admin-bar/eslint.config.js @@ -0,0 +1,19 @@ +import { rootParserOptions } from '../../eslint.config.js' +import { testEslintConfig } from '../eslint.config.js' + +/** @typedef {import('eslint').Linter.Config} Config */ + +/** @type {Config[]} */ +export const index = [ + ...testEslintConfig, + { + languageOptions: { + parserOptions: { + ...rootParserOptions, + tsconfigRootDir: import.meta.dirname, + }, + }, + }, +] + +export default index diff --git a/test/admin-bar/next-env.d.ts b/test/admin-bar/next-env.d.ts new file mode 100644 index 000000000..1b3be0840 --- /dev/null +++ b/test/admin-bar/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/test/admin-bar/next.config.mjs b/test/admin-bar/next.config.mjs new file mode 100644 index 000000000..f6969a828 --- /dev/null +++ b/test/admin-bar/next.config.mjs @@ -0,0 +1,15 @@ +import nextConfig from '../../next.config.mjs' + +import path from 'path' +import { fileURLToPath } from 'url' + +const __filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(__filename) + +export default { + ...nextConfig, + env: { + PAYLOAD_CORE_DEV: 'true', + ROOT_DIR: path.resolve(dirname), + }, +} diff --git a/test/admin-bar/payload-types.ts b/test/admin-bar/payload-types.ts new file mode 100644 index 000000000..34e0e5fb4 --- /dev/null +++ b/test/admin-bar/payload-types.ts @@ -0,0 +1,370 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * This file was automatically generated by Payload. + * DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config, + * and re-run `payload generate:types` to regenerate this file. + */ + +/** + * Supported timezones in IANA format. + * + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "supportedTimezones". + */ +export type SupportedTimezones = + | 'Pacific/Midway' + | 'Pacific/Niue' + | 'Pacific/Honolulu' + | 'Pacific/Rarotonga' + | 'America/Anchorage' + | 'Pacific/Gambier' + | 'America/Los_Angeles' + | 'America/Tijuana' + | 'America/Denver' + | 'America/Phoenix' + | 'America/Chicago' + | 'America/Guatemala' + | 'America/New_York' + | 'America/Bogota' + | 'America/Caracas' + | 'America/Santiago' + | 'America/Buenos_Aires' + | 'America/Sao_Paulo' + | 'Atlantic/South_Georgia' + | 'Atlantic/Azores' + | 'Atlantic/Cape_Verde' + | 'Europe/London' + | 'Europe/Berlin' + | 'Africa/Lagos' + | 'Europe/Athens' + | 'Africa/Cairo' + | 'Europe/Moscow' + | 'Asia/Riyadh' + | 'Asia/Dubai' + | 'Asia/Baku' + | 'Asia/Karachi' + | 'Asia/Tashkent' + | 'Asia/Calcutta' + | 'Asia/Dhaka' + | 'Asia/Almaty' + | 'Asia/Jakarta' + | 'Asia/Bangkok' + | 'Asia/Shanghai' + | 'Asia/Singapore' + | 'Asia/Tokyo' + | 'Asia/Seoul' + | 'Australia/Sydney' + | 'Pacific/Guam' + | 'Pacific/Noumea' + | 'Pacific/Auckland' + | 'Pacific/Fiji'; + +export interface Config { + auth: { + users: UserAuthOperations; + }; + blocks: {}; + collections: { + posts: Post; + media: Media; + users: User; + 'payload-locked-documents': PayloadLockedDocument; + 'payload-preferences': PayloadPreference; + 'payload-migrations': PayloadMigration; + }; + collectionsJoins: {}; + collectionsSelect: { + posts: PostsSelect | PostsSelect; + media: MediaSelect | MediaSelect; + users: UsersSelect | UsersSelect; + 'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect; + 'payload-preferences': PayloadPreferencesSelect | PayloadPreferencesSelect; + 'payload-migrations': PayloadMigrationsSelect | PayloadMigrationsSelect; + }; + db: { + defaultIDType: string; + }; + globals: {}; + globalsSelect: {}; + locale: null; + user: User & { + collection: 'users'; + }; + jobs: { + tasks: unknown; + workflows: unknown; + }; +} +export interface UserAuthOperations { + forgotPassword: { + email: string; + password: string; + }; + login: { + email: string; + password: string; + }; + registerFirstUser: { + email: string; + password: string; + }; + unlock: { + email: string; + password: string; + }; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "posts". + */ +export interface Post { + id: string; + title?: string | null; + updatedAt: string; + createdAt: string; + _status?: ('draft' | 'published') | null; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "media". + */ +export interface Media { + id: string; + updatedAt: string; + createdAt: string; + url?: string | null; + thumbnailURL?: string | null; + filename?: string | null; + mimeType?: string | null; + filesize?: number | null; + width?: number | null; + height?: number | null; + focalX?: number | null; + focalY?: number | null; + sizes?: { + thumbnail?: { + url?: string | null; + width?: number | null; + height?: number | null; + mimeType?: string | null; + filesize?: number | null; + filename?: string | null; + }; + medium?: { + url?: string | null; + width?: number | null; + height?: number | null; + mimeType?: string | null; + filesize?: number | null; + filename?: string | null; + }; + large?: { + url?: string | null; + width?: number | null; + height?: number | null; + mimeType?: string | null; + filesize?: number | null; + filename?: string | null; + }; + }; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "users". + */ +export interface User { + id: string; + updatedAt: string; + createdAt: string; + email: string; + resetPasswordToken?: string | null; + resetPasswordExpiration?: string | null; + salt?: string | null; + hash?: string | null; + loginAttempts?: number | null; + lockUntil?: string | null; + password?: string | null; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-locked-documents". + */ +export interface PayloadLockedDocument { + id: string; + document?: + | ({ + relationTo: 'posts'; + value: string | Post; + } | null) + | ({ + relationTo: 'media'; + value: string | Media; + } | null) + | ({ + relationTo: 'users'; + value: string | User; + } | null); + globalSlug?: string | null; + user: { + relationTo: 'users'; + value: string | User; + }; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-preferences". + */ +export interface PayloadPreference { + id: string; + user: { + relationTo: 'users'; + value: string | User; + }; + key?: string | null; + value?: + | { + [k: string]: unknown; + } + | unknown[] + | string + | number + | boolean + | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-migrations". + */ +export interface PayloadMigration { + id: string; + name?: string | null; + batch?: number | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "posts_select". + */ +export interface PostsSelect { + title?: T; + updatedAt?: T; + createdAt?: T; + _status?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "media_select". + */ +export interface MediaSelect { + updatedAt?: T; + createdAt?: T; + url?: T; + thumbnailURL?: T; + filename?: T; + mimeType?: T; + filesize?: T; + width?: T; + height?: T; + focalX?: T; + focalY?: T; + sizes?: + | T + | { + thumbnail?: + | T + | { + url?: T; + width?: T; + height?: T; + mimeType?: T; + filesize?: T; + filename?: T; + }; + medium?: + | T + | { + url?: T; + width?: T; + height?: T; + mimeType?: T; + filesize?: T; + filename?: T; + }; + large?: + | T + | { + url?: T; + width?: T; + height?: T; + mimeType?: T; + filesize?: T; + filename?: T; + }; + }; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "users_select". + */ +export interface UsersSelect { + updatedAt?: T; + createdAt?: T; + email?: T; + resetPasswordToken?: T; + resetPasswordExpiration?: T; + salt?: T; + hash?: T; + loginAttempts?: T; + lockUntil?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-locked-documents_select". + */ +export interface PayloadLockedDocumentsSelect { + document?: T; + globalSlug?: T; + user?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-preferences_select". + */ +export interface PayloadPreferencesSelect { + user?: T; + key?: T; + value?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-migrations_select". + */ +export interface PayloadMigrationsSelect { + name?: T; + batch?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "auth". + */ +export interface Auth { + [k: string]: unknown; +} + + +declare module 'payload' { + // @ts-ignore + export interface GeneratedTypes extends Config {} +} \ No newline at end of file diff --git a/test/admin-bar/tsconfig.eslint.json b/test/admin-bar/tsconfig.eslint.json new file mode 100644 index 000000000..b34cc7afb --- /dev/null +++ b/test/admin-bar/tsconfig.eslint.json @@ -0,0 +1,13 @@ +{ + // extend your base config to share compilerOptions, etc + //"extends": "./tsconfig.json", + "compilerOptions": { + // ensure that nobody can accidentally use this config for a build + "noEmit": true + }, + "include": [ + // whatever paths you intend to lint + "./**/*.ts", + "./**/*.tsx" + ] +} diff --git a/test/admin-bar/tsconfig.json b/test/admin-bar/tsconfig.json new file mode 100644 index 000000000..a83856816 --- /dev/null +++ b/test/admin-bar/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../tsconfig.json", + "include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} diff --git a/test/admin-bar/types.d.ts b/test/admin-bar/types.d.ts new file mode 100644 index 000000000..8d5bd7d65 --- /dev/null +++ b/test/admin-bar/types.d.ts @@ -0,0 +1,9 @@ +import type { RequestContext as OriginalRequestContext } from 'payload' + +declare module 'payload' { + // Create a new interface that merges your additional fields with the original one + export interface RequestContext extends OriginalRequestContext { + myObject?: string + // ... + } +} diff --git a/test/generateImportMap.ts b/test/generateImportMap.ts index 51fce1723..f21336cfd 100644 --- a/test/generateImportMap.ts +++ b/test/generateImportMap.ts @@ -23,8 +23,14 @@ async function run() { const config: SanitizedConfig = await (await import(pathWithConfig)).default let rootDir = '' - if (testConfigDir === 'live-preview' || testConfigDir === 'admin-root') { + + if ( + testConfigDir === 'live-preview' || + testConfigDir === 'admin-root' || + testConfigDir === 'admin-bar' + ) { rootDir = testDir + if (process.env.PAYLOAD_TEST_PROD === 'true') { // If in prod mode, there may be a testSuite/prod folder. If so, use that as the rootDir const prodDir = path.resolve(testDir, 'prod') diff --git a/test/package.json b/test/package.json index 456357d77..817077514 100644 --- a/test/package.json +++ b/test/package.json @@ -25,6 +25,7 @@ "@aws-sdk/client-s3": "^3.614.0", "@date-fns/tz": "1.2.0", "@next/env": "15.2.0", + "@payloadcms/admin-bar": "workspace:*", "@payloadcms/db-mongodb": "workspace:*", "@payloadcms/db-postgres": "workspace:*", "@payloadcms/db-sqlite": "workspace:*", diff --git a/test/setupProd.ts b/test/setupProd.ts index b90671567..ab6006fa0 100644 --- a/test/setupProd.ts +++ b/test/setupProd.ts @@ -7,6 +7,7 @@ const dirname = path.dirname(filename) export const tgzToPkgNameMap = { payload: 'payload-*', + '@payloadcms/admin-bar': 'payloadcms-admin-bar-*', '@payloadcms/db-mongodb': 'payloadcms-db-mongodb-*', '@payloadcms/db-postgres': 'payloadcms-db-postgres-*', '@payloadcms/db-vercel-postgres': 'payloadcms-db-vercel-postgres-*', diff --git a/test/tsconfig.typecheck.json b/test/tsconfig.typecheck.json index 1f059a791..4051bf080 100644 --- a/test/tsconfig.typecheck.json +++ b/test/tsconfig.typecheck.json @@ -12,6 +12,9 @@ // "../packages/**/src/**/*.tsx" ], "references": [ + { + "path": "../packages/admin-bar" + }, { "path": "../packages/create-payload-app" }, diff --git a/tools/releaser/src/lib/publishList.ts b/tools/releaser/src/lib/publishList.ts index 7bb869b5b..c0f6fbf01 100644 --- a/tools/releaser/src/lib/publishList.ts +++ b/tools/releaser/src/lib/publishList.ts @@ -9,6 +9,7 @@ export const packagePublishList = [ 'ui', 'next', 'graphql', + 'admin-bar', 'live-preview', 'live-preview-react', 'live-preview-vue', diff --git a/tsconfig.base.json b/tsconfig.base.json index 4b37de391..f8e3c3771 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -31,7 +31,8 @@ } ], "paths": { - "@payload-config": ["./test/plugin-import-export/config.ts"], + "@payload-config": ["./test/admin-bar/config.ts"], + "@payloadcms/admin-bar": ["./packages/admin-bar/src"], "@payloadcms/live-preview": ["./packages/live-preview/src"], "@payloadcms/live-preview-react": ["./packages/live-preview-react/src/index.ts"], "@payloadcms/live-preview-vue": ["./packages/live-preview-vue/src/index.ts"], @@ -71,11 +72,13 @@ "@payloadcms/plugin-multi-tenant": ["./packages/plugin-multi-tenant/src/index.ts"], "@payloadcms/next": ["./packages/next/src/exports/*"], "@payloadcms/storage-s3/client": ["./packages/storage-s3/src/exports/client.ts"], - "@payloadcms/storage-vercel-blob/client": ["./packages/storage-vercel-blob/src/exports/client.ts" + "@payloadcms/storage-vercel-blob/client": [ + "./packages/storage-vercel-blob/src/exports/client.ts" ], "@payloadcms/storage-gcs/client": ["./packages/storage-gcs/src/exports/client.ts"], "@payloadcms/storage-uploadthing/client": [ - "./packages/storage-uploadthing/src/exports/client.ts"] + "./packages/storage-uploadthing/src/exports/client.ts" + ] } }, "include": ["${configDir}/src"], diff --git a/tsconfig.json b/tsconfig.json index bcb2746e4..353ae6cb8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,9 +4,11 @@ "composite": false, "noEmit": true, "baseUrl": ".", - }, "references": [ + { + "path": "./packages/admin-bar" + }, { "path": "./packages/create-payload-app" },