diff --git a/examples/custom-admin-ui-logo/app/(admin)/.admin/index.tsx b/examples/custom-admin-ui-logo/app/(admin)/.admin/index.tsx new file mode 100644 index 00000000000..5dd11446daf --- /dev/null +++ b/examples/custom-admin-ui-logo/app/(admin)/.admin/index.tsx @@ -0,0 +1,18 @@ +/* eslint-disable */ +import * as view0 from '@keystone-6/core/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view' +import * as view1 from '@keystone-6/core/fields/types/text/views' +import * as view2 from '@keystone-6/core/fields/types/select/views' +import * as view3 from '@keystone-6/core/fields/types/checkbox/views' +import * as view4 from '@keystone-6/core/fields/types/relationship/views' +import * as view5 from '@keystone-6/core/fields/types/timestamp/views' + +import * as adminConfig from '../config' + +export const config = { + lazyMetadataQuery: {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"keystone","loc":{"start":22,"end":30}},"arguments":[],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"adminMeta","loc":{"start":39,"end":48}},"arguments":[],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"lists","loc":{"start":59,"end":64}},"arguments":[],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"key","loc":{"start":77,"end":80}},"arguments":[],"directives":[],"loc":{"start":77,"end":80}},{"kind":"Field","name":{"kind":"Name","value":"isHidden","loc":{"start":91,"end":99}},"arguments":[],"directives":[],"loc":{"start":91,"end":99}},{"kind":"Field","name":{"kind":"Name","value":"fields","loc":{"start":110,"end":116}},"arguments":[],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"path","loc":{"start":131,"end":135}},"arguments":[],"directives":[],"loc":{"start":131,"end":135}},{"kind":"Field","name":{"kind":"Name","value":"createView","loc":{"start":148,"end":158}},"arguments":[],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"fieldMode","loc":{"start":175,"end":184}},"arguments":[],"directives":[],"loc":{"start":175,"end":184}}],"loc":{"start":159,"end":198}},"loc":{"start":148,"end":198}}],"loc":{"start":117,"end":210}},"loc":{"start":110,"end":210}}],"loc":{"start":65,"end":220}},"loc":{"start":59,"end":220}}],"loc":{"start":49,"end":228}},"loc":{"start":39,"end":228}}],"loc":{"start":31,"end":234}},"loc":{"start":22,"end":234}}]}}]}, + fieldViews: [view0,view1,view2,view3,view4,view5], + adminMetaHash: '1mrsjib', + adminConfig, + apiPath: '/api/graphql', + adminPath: '', +}; diff --git a/examples/custom-admin-ui-logo/app/(admin)/[listKey]/[id]/page.tsx b/examples/custom-admin-ui-logo/app/(admin)/[listKey]/[id]/page.tsx new file mode 100644 index 00000000000..c5d7ea2be62 --- /dev/null +++ b/examples/custom-admin-ui-logo/app/(admin)/[listKey]/[id]/page.tsx @@ -0,0 +1,4 @@ +'use client' +import { ItemPage } from '@keystone-6/core/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage' + +export default ItemPage diff --git a/examples/custom-admin-ui-logo/app/(admin)/[listKey]/create/page.tsx b/examples/custom-admin-ui-logo/app/(admin)/[listKey]/create/page.tsx new file mode 100644 index 00000000000..d6042acaa96 --- /dev/null +++ b/examples/custom-admin-ui-logo/app/(admin)/[listKey]/create/page.tsx @@ -0,0 +1,4 @@ +'use client' +import { CreateItemPage } from '@keystone-6/core/___internal-do-not-use-will-break-in-patch/admin-ui/pages/CreateItemPage' + +export default CreateItemPage diff --git a/examples/custom-admin-ui-logo/app/(admin)/[listKey]/page.tsx b/examples/custom-admin-ui-logo/app/(admin)/[listKey]/page.tsx new file mode 100644 index 00000000000..f6e75f8cfab --- /dev/null +++ b/examples/custom-admin-ui-logo/app/(admin)/[listKey]/page.tsx @@ -0,0 +1,4 @@ +'use client' +import { ListPage } from '@keystone-6/core/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage' + +export default ListPage diff --git a/examples/custom-admin-ui-logo/app/(admin)/config.tsx b/examples/custom-admin-ui-logo/app/(admin)/config.tsx new file mode 100644 index 00000000000..53be6083334 --- /dev/null +++ b/examples/custom-admin-ui-logo/app/(admin)/config.tsx @@ -0,0 +1 @@ +export { components } from '../admin/config' \ No newline at end of file diff --git a/examples/custom-admin-ui-logo/app/(admin)/layout.tsx b/examples/custom-admin-ui-logo/app/(admin)/layout.tsx new file mode 100644 index 00000000000..abb5a0f3b2c --- /dev/null +++ b/examples/custom-admin-ui-logo/app/(admin)/layout.tsx @@ -0,0 +1,16 @@ +'use client' +import { Layout } from '@keystone-6/core/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App' +import { config } from './.admin' + + +export default function AdminLayout ({ + children, +}: { + children: React.ReactNode +}) { + return ( + + {children} + + ) +} \ No newline at end of file diff --git a/examples/custom-admin-ui-logo/app/(admin)/no-access/page.tsx b/examples/custom-admin-ui-logo/app/(admin)/no-access/page.tsx new file mode 100644 index 00000000000..70877231fee --- /dev/null +++ b/examples/custom-admin-ui-logo/app/(admin)/no-access/page.tsx @@ -0,0 +1,4 @@ +'use client' +import { getNoAccessPage } from '@keystone-6/core/___internal-do-not-use-will-break-in-patch/admin-ui/pages/NoAccessPage' + +export default getNoAccessPage({ sessionsEnabled: false }) diff --git a/examples/custom-admin-ui-logo/app/(admin)/page.tsx b/examples/custom-admin-ui-logo/app/(admin)/page.tsx new file mode 100644 index 00000000000..5c268390b0f --- /dev/null +++ b/examples/custom-admin-ui-logo/app/(admin)/page.tsx @@ -0,0 +1,2 @@ +'use client' +export { HomePage as default } from '@keystone-6/core/___internal-do-not-use-will-break-in-patch/admin-ui/pages/HomePage' diff --git a/examples/custom-admin-ui-logo/admin/components/CustomLogo.tsx b/examples/custom-admin-ui-logo/app/admin/components/CustomLogo.tsx similarity index 100% rename from examples/custom-admin-ui-logo/admin/components/CustomLogo.tsx rename to examples/custom-admin-ui-logo/app/admin/components/CustomLogo.tsx diff --git a/examples/custom-admin-ui-logo/admin/config.tsx b/examples/custom-admin-ui-logo/app/admin/config.tsx similarity index 100% rename from examples/custom-admin-ui-logo/admin/config.tsx rename to examples/custom-admin-ui-logo/app/admin/config.tsx diff --git a/examples/custom-admin-ui-logo/app/layout.tsx b/examples/custom-admin-ui-logo/app/layout.tsx new file mode 100644 index 00000000000..38a4853e3a5 --- /dev/null +++ b/examples/custom-admin-ui-logo/app/layout.tsx @@ -0,0 +1,11 @@ +export default function RootLayout ({ + children, +}: { + children: React.ReactNode +}) { + return ( + + {children} + + ) +} diff --git a/examples/custom-admin-ui-logo/next-env.d.ts b/examples/custom-admin-ui-logo/next-env.d.ts new file mode 100644 index 00000000000..4f11a03dc6c --- /dev/null +++ b/examples/custom-admin-ui-logo/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/examples/custom-admin-ui-logo/next.config.mjs b/examples/custom-admin-ui-logo/next.config.mjs new file mode 100644 index 00000000000..bec106de70d --- /dev/null +++ b/examples/custom-admin-ui-logo/next.config.mjs @@ -0,0 +1,14 @@ +// you don't need this if you're building something outside of the Keystone repo + +export default { + experimental: { + // without this, 'Error: Expected Upload to be a GraphQL nullable type.' + serverComponentsExternalPackages: ['graphql'], + }, + eslint: { + ignoreDuringBuilds: true, + }, + typescript: { + ignoreBuildErrors: true, + }, +} diff --git a/examples/custom-admin-ui-logo/tsconfig.json b/examples/custom-admin-ui-logo/tsconfig.json new file mode 100644 index 00000000000..ccb2ed95d83 --- /dev/null +++ b/examples/custom-admin-ui-logo/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "strict": false, + "noEmit": true, + "incremental": true, + "module": "esnext", + "esModuleInterop": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "plugins": [ + { + "name": "next" + } + ] + }, + "include": [ + "next-env.d.ts", + ".next/types/**/*.ts", + "**/*.ts", + "**/*.tsx" + ], + "exclude": [ + "node_modules" + ] +} diff --git a/packages/core/src/admin-ui/system/generateAdminUI.ts b/packages/core/src/admin-ui/system/generateAdminUI.ts index bbe21cdd403..2c45c93a297 100644 --- a/packages/core/src/admin-ui/system/generateAdminUI.ts +++ b/packages/core/src/admin-ui/system/generateAdminUI.ts @@ -29,6 +29,12 @@ function getDoesAdminConfigExist (adminPath: string) { export async function writeAdminFile (file: AdminFileToWrite, projectAdminPath: string) { const outputFilename = Path.join(projectAdminPath, file.outputPath) + const overwrite = file.overwrite || !(await fse.exists(outputFilename)) + + if (!overwrite) { + return Path.normalize(outputFilename) + } + if (file.mode === 'copy') { if (!Path.isAbsolute(file.inputPath)) { throw new Error( @@ -36,10 +42,8 @@ export async function writeAdminFile (file: AdminFileToWrite, projectAdminPath: ) } await fse.ensureDir(Path.dirname(outputFilename)) - if (file.overwrite && !(await fse.exists(outputFilename))) { - // TODO: should we use copyFile or copy? - await fs.copyFile(file.inputPath, outputFilename) - } + // TODO: should we use copyFile or copy? + await fs.copyFile(file.inputPath, outputFilename) } let content: undefined | string try { @@ -86,22 +90,22 @@ export async function generateAdminUI ( // this won't clear out empty directories, this is fine since: // - they won't create pages in Admin UI which is really what this deleting is about avoiding // - we'll remove them when the user restarts the process - if (isLiveReload) { - const ignoredDir = Path.resolve(projectAdminPath, '.next') - const ignoredFiles = new Set( - [ - ...adminFiles.map(x => x.outputPath), - ...uniqueFiles, - 'next-env.d.ts', - 'pages/api/__keystone_api_build.js', - ].map(x => Path.resolve(projectAdminPath, x)) - ) + // if (isLiveReload) { + // const ignoredDir = Path.resolve(projectAdminPath, '.next') + // const ignoredFiles = new Set( + // [ + // ...adminFiles.map(x => x.outputPath), + // ...uniqueFiles, + // 'next-env.d.ts', + // 'pages/api/__keystone_api_build.js', + // ].map(x => Path.resolve(projectAdminPath, x)) + // ) - const entries = await walk(projectAdminPath, { - deepFilter: entry => entry.path !== ignoredDir, - entryFilter: entry => entry.dirent.isFile() && !ignoredFiles.has(entry.path), - }) + // const entries = await walk(projectAdminPath, { + // deepFilter: entry => entry.path !== ignoredDir, + // entryFilter: entry => entry.dirent.isFile() && !ignoredFiles.has(entry.path), + // }) - await Promise.all(entries.map(entry => fs.rm(entry.path, { recursive: true }))) - } + // await Promise.all(entries.map(entry => fs.rm(entry.path, { recursive: true }))) + // } } diff --git a/packages/core/src/scripts/cli.ts b/packages/core/src/scripts/cli.ts index 45920da7a6b..035fb6c5dea 100644 --- a/packages/core/src/scripts/cli.ts +++ b/packages/core/src/scripts/cli.ts @@ -15,6 +15,7 @@ export type Flags = { server: boolean ui: boolean withMigrations: boolean + resetAdmin: boolean } function defaultFlags (flags: Partial, defaults: Partial) { @@ -66,6 +67,9 @@ export async function cli (cwd: string, argv: string[]) { --no-db-push (dev) don't push any updates of your Prisma schema to your database + + --reset-admin (dev) + reset generated admin files --no-prisma (build, dev) don't build or validate the prisma schema @@ -87,7 +91,7 @@ export async function cli (cwd: string, argv: string[]) { const command = input.join(' ') || 'dev' if (command === 'dev') { - return dev(cwd, defaultFlags(flags, { dbPush: true, prisma: true, server: true, ui: true })) + return dev(cwd, defaultFlags(flags, { dbPush: true, prisma: true, server: true, ui: true, resetAdmin: false })) } if (command === 'migrate create') { diff --git a/packages/core/src/scripts/dev.ts b/packages/core/src/scripts/dev.ts index ccddf69881f..1d472bc65b9 100644 --- a/packages/core/src/scripts/dev.ts +++ b/packages/core/src/scripts/dev.ts @@ -56,7 +56,7 @@ function resolvablePromise () { export async function dev ( cwd: string, - { dbPush, prisma, server, ui }: Pick + { dbPush, prisma, server, ui, resetAdmin }: Pick ) { console.log('✨ Starting Keystone') let lastPromise = resolvablePromise>() @@ -264,7 +264,9 @@ export async function dev ( let nextApp if (!system.config.ui?.isDisabled && ui) { const paths = system.getPaths(cwd) - await fsp.rm(paths.admin, { recursive: true, force: true }) + if (resetAdmin) { + await fsp.rm(paths.admin, { recursive: true, force: true }) + } console.log('✨ Generating Admin UI code') await generateAdminUI(system.config, system.graphQLSchema, system.adminMeta, paths.admin, false)