diff --git a/examples/document-field/next-env.d copy.ts b/examples/document-field/next-env.d copy.ts deleted file mode 100644 index 4f11a03dc6c..00000000000 --- a/examples/document-field/next-env.d copy.ts +++ /dev/null @@ -1,5 +0,0 @@ -/// -/// - -// NOTE: This file should not be edited -// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/examples/document-field/next.config.js b/examples/document-field/next.config.js deleted file mode 100644 index 00184d61daa..00000000000 --- a/examples/document-field/next.config.js +++ /dev/null @@ -1,5 +0,0 @@ -// you don't need this if you're building something outside of the Keystone repo - -const withPreconstruct = require('@preconstruct/next') - -module.exports = withPreconstruct() diff --git a/examples/document-field/next.config.mjs b/examples/document-field/next.config.mjs new file mode 100644 index 00000000000..da3eee2060e --- /dev/null +++ b/examples/document-field/next.config.mjs @@ -0,0 +1,16 @@ +export default { + experimental: { + // Experimental ESM Externals + // https://nextjs.org/docs/messages/import-esm-externals + // required to fix build admin ui issues related to "react-day-picker" and "date-fn" + esmExternals: 'loose', + // without this, 'Error: Expected Upload to be a GraphQL nullable type.' + serverComponentsExternalPackages: ['graphql'], + }, + typescript: { + ignoreBuildErrors: true, + }, + eslint: { + ignoreDuringBuilds: true, + }, +} diff --git a/examples/document-field/src/app/(admin)/author/[id]/page.tsx b/examples/document-field/src/app/(admin)/author/[id]/page.tsx index 8b44a9869f5..86b4d126459 100644 --- a/examples/document-field/src/app/(admin)/author/[id]/page.tsx +++ b/examples/document-field/src/app/(admin)/author/[id]/page.tsx @@ -41,16 +41,17 @@ const author = data?.author ) } -export async function getStaticPaths (): Promise { - const data = await fetchGraphQL(gql` - query { - authors { - id - } - } - `) - return { - paths: data.authors.map((post: any) => ({ params: { id: post.id } })), - fallback: 'blocking', - } -} +// TODO - CAN NOT use this in app router properly +// export async function getStaticPaths (): Promise { +// const data = await fetchGraphQL(gql` +// query { +// authors { +// id +// } +// } +// `) +// return { +// paths: data.authors.map((post: any) => ({ params: { id: post.id } })), +// fallback: 'blocking', +// } +// } diff --git a/examples/document-field/src/app/(admin)/post/[slug]/page.tsx b/examples/document-field/src/app/(admin)/post/[slug]/page.tsx index ab476cde41d..f132603ad6f 100644 --- a/examples/document-field/src/app/(admin)/post/[slug]/page.tsx +++ b/examples/document-field/src/app/(admin)/post/[slug]/page.tsx @@ -79,16 +79,17 @@ export default async function Post ({ params }: { params: any }) { ) } -export async function getStaticPaths (): Promise { - const data = await fetchGraphQL(gql` - query { - posts { - slug - } - } - `) - return { - paths: data.posts.map((post: any) => ({ params: { slug: post.slug } })), - fallback: 'blocking', - } -} +// TODO - CAN NOT use this in app router properly +// export async function getStaticPaths (): Promise { +// const data = await fetchGraphQL(gql` +// query { +// posts { +// slug +// } +// } +// `) +// return { +// paths: data.posts.map((post: any) => ({ params: { slug: post.slug } })), +// fallback: 'blocking', +// } +// } diff --git a/packages/core/src/admin-ui/context.tsx b/packages/core/src/admin-ui/context.tsx index cf0df247597..eff7cff037c 100644 --- a/packages/core/src/admin-ui/context.tsx +++ b/packages/core/src/admin-ui/context.tsx @@ -1,3 +1,4 @@ +import { notFound } from 'next/navigation' import React, { type ReactNode, createContext, useContext, useMemo } from 'react' import { Center } from '@keystone-ui/core' import { ToastProvider } from '@keystone-ui/toast' @@ -164,6 +165,6 @@ export const useList = (key: string) => { if (lists[key]) { return lists[key] } else { - throw new Error(`Invalid list key provided to useList: ${key}`) + return notFound() } } diff --git a/packages/core/src/admin-ui/system/generateAdminUI.ts b/packages/core/src/admin-ui/system/generateAdminUI.ts index 3ce9d4c074a..9d9984b06f7 100644 --- a/packages/core/src/admin-ui/system/generateAdminUI.ts +++ b/packages/core/src/admin-ui/system/generateAdminUI.ts @@ -64,6 +64,7 @@ export async function generateAdminUI ( graphQLSchema: GraphQLSchema, adminMeta: AdminMetaRootVal, projectAdminPath: string, + hasSrc: boolean, isLiveReload: boolean ) { // Write out the files configured by the user @@ -76,7 +77,7 @@ export async function generateAdminUI ( // Write out the built-in admin UI files. Don't overwrite any user-defined pages. const configFileExists = getDoesAdminConfigExist(projectAdminPath) - let adminFiles = writeAdminFiles(config, graphQLSchema, adminMeta, configFileExists) + let adminFiles = writeAdminFiles(config, graphQLSchema, adminMeta, configFileExists, hasSrc) adminFiles = adminFiles.filter( x => !uniqueFiles.has(Path.normalize(Path.join(projectAdminPath, x.outputPath))) diff --git a/packages/core/src/admin-ui/templates/index.ts b/packages/core/src/admin-ui/templates/index.ts index cdf8e2ce5b2..4a64ce87688 100644 --- a/packages/core/src/admin-ui/templates/index.ts +++ b/packages/core/src/admin-ui/templates/index.ts @@ -16,14 +16,15 @@ export const writeAdminFiles = ( config: __ResolvedKeystoneConfig, graphQLSchema: GraphQLSchema, adminMeta: AdminMetaRootVal, - configFileExists: boolean + configFileExists: boolean, + srcExists: boolean, ): AdminFileToWrite[] => { const ext = config.ui?.tsx ? 'tsx' : 'js' return [ { mode: 'write', - src: nextConfigTemplate(config.ui?.basePath), - outputPath: '../../next.config.mjs', + src: nextConfigTemplate(), + outputPath: `${srcExists ? '../' : ''}../../next.config.mjs`, }, { mode: 'write', src: noAccessTemplate(config.session), outputPath: `no-access/page.${ext}` }, { mode: 'write', src: adminLayoutTemplate(), outputPath: `layout.${ext}` }, diff --git a/packages/core/src/admin-ui/templates/next-config.ts b/packages/core/src/admin-ui/templates/next-config.ts index 8d098b72858..054f1b39c63 100644 --- a/packages/core/src/admin-ui/templates/next-config.ts +++ b/packages/core/src/admin-ui/templates/next-config.ts @@ -1,4 +1,4 @@ -export const nextConfigTemplate = (basePath?: string) => +export const nextConfigTemplate = () => `export default { experimental: { // Experimental ESM Externals diff --git a/packages/core/src/lib/createSystem.ts b/packages/core/src/lib/createSystem.ts index 789d92a3b03..b4e2ac7a748 100644 --- a/packages/core/src/lib/createSystem.ts +++ b/packages/core/src/lib/createSystem.ts @@ -68,6 +68,7 @@ export function getSystemPaths (cwd: string, config: KeystoneConfig | __Resolved prisma: builtPrismaPath, graphql: builtGraphqlPath, }, + hasSrc, } } diff --git a/packages/core/src/scripts/build.ts b/packages/core/src/scripts/build.ts index d32f5d8312e..850546c6398 100644 --- a/packages/core/src/scripts/build.ts +++ b/packages/core/src/scripts/build.ts @@ -39,7 +39,7 @@ export async function build ( console.log('✨ Generating Admin UI code') const paths = system.getPaths(cwd) - await generateAdminUI(system.config, system.graphQLSchema, system.adminMeta, paths.admin, false) + await generateAdminUI(system.config, system.graphQLSchema, system.adminMeta, paths.admin, paths.hasSrc, false) console.log('✨ Building Admin UI') await nextBuild( diff --git a/packages/core/src/scripts/dev.ts b/packages/core/src/scripts/dev.ts index 1d472bc65b9..75b75e52e9a 100644 --- a/packages/core/src/scripts/dev.ts +++ b/packages/core/src/scripts/dev.ts @@ -269,7 +269,7 @@ export async function dev ( } console.log('✨ Generating Admin UI code') - await generateAdminUI(system.config, system.graphQLSchema, system.adminMeta, paths.admin, false) + await generateAdminUI(system.config, system.graphQLSchema, system.adminMeta, paths.admin, paths.hasSrc, false) console.log('✨ Preparing Admin UI app') nextApp = next({ dev: true, dir: cwd }) @@ -338,7 +338,7 @@ export async function dev ( } await generateTypes(cwd, newSystem) - await generateAdminUI(newSystem.config, newSystem.graphQLSchema, newSystem.adminMeta, paths.admin, true) + await generateAdminUI(newSystem.config, newSystem.graphQLSchema, newSystem.adminMeta, paths.admin, paths.hasSrc, true) if (prismaClientModule) { if (server && lastApolloServer) { const { context: newContext } = newSystem.getKeystone(prismaClientModule) diff --git a/tests/admin-ui-tests/live-reloading.test.ts b/tests/admin-ui-tests/live-reloading.test.ts index 7b98a5147f1..92c5534e085 100644 --- a/tests/admin-ui-tests/live-reloading.test.ts +++ b/tests/admin-ui-tests/live-reloading.test.ts @@ -21,6 +21,8 @@ let ksProcess: ExecaChildProcess = undefined as any let page: Page = undefined as any let browser: Browser = undefined as any +jest.setTimeout(300000) // testing why this one fail + test('start keystone', async () => { // just in case a previous failing test run messed things up, let's reset it await replaceSchema('initial.ts'); @@ -54,7 +56,7 @@ test('Creating an item with the GraphQL API and navigating to the item page for expect(value).toBe('blah') }) -test('api routes written with getAdditionalFiles containing [...rest] work', async () => { +test.only('api routes written with getAdditionalFiles containing [...rest] work', async () => { expect( await fetch('http://localhost:3000/api/blah/asdasdas/das/da/sdad').then(x => x.text()) ).toEqual('something') diff --git a/tests/test-projects/live-reloading/keystone.ts b/tests/test-projects/live-reloading/keystone.ts index 62b86624edb..43b9d02523e 100644 --- a/tests/test-projects/live-reloading/keystone.ts +++ b/tests/test-projects/live-reloading/keystone.ts @@ -19,8 +19,9 @@ export default config({ () => [ { mode: 'write', - src: "export default function(req,res) {res.send('something')}", - outputPath: 'pages/api/blah/[...rest].js', + src: "export async function GET() { return new Response('something')}", + overwrite: true, + outputPath: 'api/blah/[...rest]/route.js', }, ], ],