diff --git a/design-system/website/components/Navigation.tsx b/design-system/website/components/Navigation.tsx index f93a7e9ea14..c8e52158799 100644 --- a/design-system/website/components/Navigation.tsx +++ b/design-system/website/components/Navigation.tsx @@ -4,7 +4,7 @@ import { Fragment, type ReactNode } from 'react' import { jsx, useTheme } from '@keystone-ui/core' import Link from 'next/link' -import { useRouter } from 'next/router' +import { usePathname } from 'next/navigation' const Brand = () => { const { palette } = useTheme() @@ -37,8 +37,8 @@ const Section = ({ label, children }: SectionProps) => { type NavItemProps = { href: string, children: ReactNode } const NavItem = ({ href, children }: NavItemProps) => { const { palette, radii, spacing } = useTheme() - const router = useRouter() - const isSelected = router.pathname === href + const pathname = usePathname() + const isSelected = pathname === href return (
  • + {children} + + ) +} \ No newline at end of file diff --git a/examples/auth/app/(admin)/no-access/page.tsx b/examples/auth/app/(admin)/no-access/page.tsx new file mode 100644 index 00000000000..00571f2f9b3 --- /dev/null +++ b/examples/auth/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: true }) diff --git a/examples/auth/app/(admin)/page.tsx b/examples/auth/app/(admin)/page.tsx new file mode 100644 index 00000000000..5c268390b0f --- /dev/null +++ b/examples/auth/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/auth/app/(admin)/signin/page.tsx b/examples/auth/app/(admin)/signin/page.tsx new file mode 100644 index 00000000000..ef30e38dcac --- /dev/null +++ b/examples/auth/app/(admin)/signin/page.tsx @@ -0,0 +1,5 @@ +'use client' +/* eslint-disable */ +import { getSigninPage } from '@keystone-6/auth/pages/SigninPage' + +export default getSigninPage({"identityField":"name","secretField":"password","mutationName":"authenticateUserWithPassword","successTypename":"UserAuthenticationWithPasswordSuccess","failureTypename":"UserAuthenticationWithPasswordFailure"}) diff --git a/examples/auth/app/layout.tsx b/examples/auth/app/layout.tsx new file mode 100644 index 00000000000..38a4853e3a5 --- /dev/null +++ b/examples/auth/app/layout.tsx @@ -0,0 +1,11 @@ +export default function RootLayout ({ + children, +}: { + children: React.ReactNode +}) { + return ( + + {children} + + ) +} diff --git a/examples/auth/keystone.ts b/examples/auth/keystone.ts index 88f7606d0a1..fb1b868a49b 100644 --- a/examples/auth/keystone.ts +++ b/examples/auth/keystone.ts @@ -71,5 +71,5 @@ export default withAuth>( // the session secret is used to encrypt cookie data secret: sessionSecret, }), - }) + }) as any ) diff --git a/examples/nextjs-keystone-two-servers/nextjs-frontend/next-env.d.ts b/examples/auth/next-env.d.ts similarity index 100% rename from examples/nextjs-keystone-two-servers/nextjs-frontend/next-env.d.ts rename to examples/auth/next-env.d.ts diff --git a/examples/auth/next.config.mjs b/examples/auth/next.config.mjs new file mode 100644 index 00000000000..8f06b183bdf --- /dev/null +++ b/examples/auth/next.config.mjs @@ -0,0 +1,10 @@ +// you don't need this if you're building something outside of the Keystone repo + +export default { + eslint: { + ignoreDuringBuilds: true, + }, + typescript: { + ignoreBuildErrors: true, + }, +} diff --git a/examples/auth/package.json b/examples/auth/package.json index 0e3f415f09d..4f733d35ec2 100644 --- a/examples/auth/package.json +++ b/examples/auth/package.json @@ -12,7 +12,8 @@ "dependencies": { "@keystone-6/auth": "^8.0.0", "@keystone-6/core": "^6.2.0", - "@prisma/client": "5.17.0" + "@prisma/client": "5.17.0", + "next": "^14.2.0" }, "devDependencies": { "prisma": "5.17.0", diff --git a/examples/auth/schema.graphql b/examples/auth/schema.graphql index c2ded0eb201..d6ddcb6aa87 100644 --- a/examples/auth/schema.graphql +++ b/examples/auth/schema.graphql @@ -67,6 +67,380 @@ input UserCreateInput { isAdmin: Boolean } +type Project { + id: ID! + slug: String + name: String + createdAt: DateTime + updatedAt: DateTime + deletedAt: DateTime + taskRuns(where: TaskRunWhereInput! = {}, orderBy: [TaskRunOrderByInput!]! = [], take: Int, skip: Int! = 0, cursor: TaskRunWhereUniqueInput): [TaskRun!] + taskRunsCount(where: TaskRunWhereInput! = {}): Int +} + +scalar DateTime @specifiedBy(url: "https://datatracker.ietf.org/doc/html/rfc3339#section-5.6") + +input ProjectWhereUniqueInput { + id: ID + slug: String +} + +input ProjectWhereInput { + AND: [ProjectWhereInput!] + OR: [ProjectWhereInput!] + NOT: [ProjectWhereInput!] + id: IDFilter + slug: StringFilter + name: StringFilter + createdAt: DateTimeNullableFilter + updatedAt: DateTimeNullableFilter + deletedAt: DateTimeNullableFilter + taskRuns: TaskRunManyRelationFilter +} + +input StringFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringFilter +} + +input NestedStringFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringFilter +} + +input DateTimeNullableFilter { + equals: DateTime + in: [DateTime!] + notIn: [DateTime!] + lt: DateTime + lte: DateTime + gt: DateTime + gte: DateTime + not: DateTimeNullableFilter +} + +input TaskRunManyRelationFilter { + every: TaskRunWhereInput + some: TaskRunWhereInput + none: TaskRunWhereInput +} + +input ProjectOrderByInput { + id: OrderDirection + slug: OrderDirection + name: OrderDirection + createdAt: OrderDirection + updatedAt: OrderDirection + deletedAt: OrderDirection +} + +input ProjectUpdateInput { + slug: String + name: String + createdAt: DateTime + updatedAt: DateTime + deletedAt: DateTime + taskRuns: TaskRunRelateToManyForUpdateInput +} + +input TaskRunRelateToManyForUpdateInput { + disconnect: [TaskRunWhereUniqueInput!] + set: [TaskRunWhereUniqueInput!] + create: [TaskRunCreateInput!] + connect: [TaskRunWhereUniqueInput!] +} + +input ProjectUpdateArgs { + where: ProjectWhereUniqueInput! + data: ProjectUpdateInput! +} + +input ProjectCreateInput { + slug: String + name: String + createdAt: DateTime + updatedAt: DateTime + deletedAt: DateTime + taskRuns: TaskRunRelateToManyForCreateInput +} + +input TaskRunRelateToManyForCreateInput { + create: [TaskRunCreateInput!] + connect: [TaskRunWhereUniqueInput!] +} + +type TaskRun { + id: ID! + number: Int + friendlyId: String + status: String + taskIdentifier: String + isTest: Boolean + payload: String + payloadType: String + context: JSON + traceId: String + spanId: String + project: Project + createdAt: DateTime + updatedAt: DateTime + attempts(where: TaskRunAttemptWhereInput! = {}, orderBy: [TaskRunAttemptOrderByInput!]! = [], take: Int, skip: Int! = 0, cursor: TaskRunAttemptWhereUniqueInput): [TaskRunAttempt!] + attemptsCount(where: TaskRunAttemptWhereInput! = {}): Int + startedAt: DateTime + completedAt: DateTime +} + +input TaskRunWhereUniqueInput { + id: ID +} + +input TaskRunWhereInput { + AND: [TaskRunWhereInput!] + OR: [TaskRunWhereInput!] + NOT: [TaskRunWhereInput!] + id: IDFilter + number: IntNullableFilter + friendlyId: StringFilter + status: StringNullableFilter + taskIdentifier: StringFilter + isTest: BooleanFilter + payload: StringFilter + payloadType: StringFilter + traceId: StringFilter + spanId: StringFilter + project: ProjectWhereInput + createdAt: DateTimeNullableFilter + updatedAt: DateTimeNullableFilter + attempts: TaskRunAttemptManyRelationFilter + startedAt: DateTimeNullableFilter + completedAt: DateTimeNullableFilter +} + +input IntNullableFilter { + equals: Int + in: [Int!] + notIn: [Int!] + lt: Int + lte: Int + gt: Int + gte: Int + not: IntNullableFilter +} + +input StringNullableFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: StringNullableFilter +} + +input TaskRunAttemptManyRelationFilter { + every: TaskRunAttemptWhereInput + some: TaskRunAttemptWhereInput + none: TaskRunAttemptWhereInput +} + +input TaskRunOrderByInput { + id: OrderDirection + number: OrderDirection + friendlyId: OrderDirection + status: OrderDirection + taskIdentifier: OrderDirection + isTest: OrderDirection + payload: OrderDirection + payloadType: OrderDirection + traceId: OrderDirection + spanId: OrderDirection + createdAt: OrderDirection + updatedAt: OrderDirection + startedAt: OrderDirection + completedAt: OrderDirection +} + +input TaskRunUpdateInput { + number: Int + friendlyId: String + status: String + taskIdentifier: String + isTest: Boolean + payload: String + payloadType: String + context: JSON + traceId: String + spanId: String + project: ProjectRelateToOneForUpdateInput + createdAt: DateTime + updatedAt: DateTime + attempts: TaskRunAttemptRelateToManyForUpdateInput + startedAt: DateTime + completedAt: DateTime +} + +input ProjectRelateToOneForUpdateInput { + create: ProjectCreateInput + connect: ProjectWhereUniqueInput + disconnect: Boolean +} + +input TaskRunAttemptRelateToManyForUpdateInput { + disconnect: [TaskRunAttemptWhereUniqueInput!] + set: [TaskRunAttemptWhereUniqueInput!] + create: [TaskRunAttemptCreateInput!] + connect: [TaskRunAttemptWhereUniqueInput!] +} + +input TaskRunUpdateArgs { + where: TaskRunWhereUniqueInput! + data: TaskRunUpdateInput! +} + +input TaskRunCreateInput { + number: Int + friendlyId: String + status: String + taskIdentifier: String + isTest: Boolean + payload: String + payloadType: String + context: JSON + traceId: String + spanId: String + project: ProjectRelateToOneForCreateInput + createdAt: DateTime + updatedAt: DateTime + attempts: TaskRunAttemptRelateToManyForCreateInput + startedAt: DateTime + completedAt: DateTime +} + +input ProjectRelateToOneForCreateInput { + create: ProjectCreateInput + connect: ProjectWhereUniqueInput +} + +input TaskRunAttemptRelateToManyForCreateInput { + create: [TaskRunAttemptCreateInput!] + connect: [TaskRunAttemptWhereUniqueInput!] +} + +type TaskRunAttempt { + id: ID! + number: Int + friendlyId: String + taskRun: TaskRun + status: String + createdAt: DateTime + updatedAt: DateTime + startedAt: DateTime + completedAt: DateTime + error: JSON + output: String + outputType: String +} + +input TaskRunAttemptWhereUniqueInput { + id: ID +} + +input TaskRunAttemptWhereInput { + AND: [TaskRunAttemptWhereInput!] + OR: [TaskRunAttemptWhereInput!] + NOT: [TaskRunAttemptWhereInput!] + id: IDFilter + number: IntNullableFilter + friendlyId: StringFilter + taskRun: TaskRunWhereInput + status: StringNullableFilter + createdAt: DateTimeNullableFilter + updatedAt: DateTimeNullableFilter + startedAt: DateTimeNullableFilter + completedAt: DateTimeNullableFilter + output: StringFilter + outputType: StringFilter +} + +input TaskRunAttemptOrderByInput { + id: OrderDirection + number: OrderDirection + friendlyId: OrderDirection + status: OrderDirection + createdAt: OrderDirection + updatedAt: OrderDirection + startedAt: OrderDirection + completedAt: OrderDirection + output: OrderDirection + outputType: OrderDirection +} + +input TaskRunAttemptUpdateInput { + number: Int + friendlyId: String + taskRun: TaskRunRelateToOneForUpdateInput + status: String + createdAt: DateTime + updatedAt: DateTime + startedAt: DateTime + completedAt: DateTime + error: JSON + output: String + outputType: String +} + +input TaskRunRelateToOneForUpdateInput { + create: TaskRunCreateInput + connect: TaskRunWhereUniqueInput + disconnect: Boolean +} + +input TaskRunAttemptUpdateArgs { + where: TaskRunAttemptWhereUniqueInput! + data: TaskRunAttemptUpdateInput! +} + +input TaskRunAttemptCreateInput { + number: Int + friendlyId: String + taskRun: TaskRunRelateToOneForCreateInput + status: String + createdAt: DateTime + updatedAt: DateTime + startedAt: DateTime + completedAt: DateTime + error: JSON + output: String + outputType: String +} + +input TaskRunRelateToOneForCreateInput { + create: TaskRunCreateInput + connect: TaskRunWhereUniqueInput +} + """ The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). """ @@ -79,6 +453,24 @@ type Mutation { updateUsers(data: [UserUpdateArgs!]!): [User] deleteUser(where: UserWhereUniqueInput!): User deleteUsers(where: [UserWhereUniqueInput!]!): [User] + createProject(data: ProjectCreateInput!): Project + createProjects(data: [ProjectCreateInput!]!): [Project] + updateProject(where: ProjectWhereUniqueInput!, data: ProjectUpdateInput!): Project + updateProjects(data: [ProjectUpdateArgs!]!): [Project] + deleteProject(where: ProjectWhereUniqueInput!): Project + deleteProjects(where: [ProjectWhereUniqueInput!]!): [Project] + createTaskRun(data: TaskRunCreateInput!): TaskRun + createTaskRuns(data: [TaskRunCreateInput!]!): [TaskRun] + updateTaskRun(where: TaskRunWhereUniqueInput!, data: TaskRunUpdateInput!): TaskRun + updateTaskRuns(data: [TaskRunUpdateArgs!]!): [TaskRun] + deleteTaskRun(where: TaskRunWhereUniqueInput!): TaskRun + deleteTaskRuns(where: [TaskRunWhereUniqueInput!]!): [TaskRun] + createTaskRunAttempt(data: TaskRunAttemptCreateInput!): TaskRunAttempt + createTaskRunAttempts(data: [TaskRunAttemptCreateInput!]!): [TaskRunAttempt] + updateTaskRunAttempt(where: TaskRunAttemptWhereUniqueInput!, data: TaskRunAttemptUpdateInput!): TaskRunAttempt + updateTaskRunAttempts(data: [TaskRunAttemptUpdateArgs!]!): [TaskRunAttempt] + deleteTaskRunAttempt(where: TaskRunAttemptWhereUniqueInput!): TaskRunAttempt + deleteTaskRunAttempts(where: [TaskRunAttemptWhereUniqueInput!]!): [TaskRunAttempt] endSession: Boolean! authenticateUserWithPassword(name: String!, password: String!): UserAuthenticationWithPasswordResult createInitialUser(data: CreateInitialUserInput!): UserAuthenticationWithPasswordSuccess! @@ -104,6 +496,15 @@ type Query { user(where: UserWhereUniqueInput!): User users(where: UserWhereInput! = {}, orderBy: [UserOrderByInput!]! = [], take: Int, skip: Int! = 0, cursor: UserWhereUniqueInput): [User!] usersCount(where: UserWhereInput! = {}): Int + projects(where: ProjectWhereInput! = {}, orderBy: [ProjectOrderByInput!]! = [], take: Int, skip: Int! = 0, cursor: ProjectWhereUniqueInput): [Project!] + project(where: ProjectWhereUniqueInput!): Project + projectsCount(where: ProjectWhereInput! = {}): Int + taskRuns(where: TaskRunWhereInput! = {}, orderBy: [TaskRunOrderByInput!]! = [], take: Int, skip: Int! = 0, cursor: TaskRunWhereUniqueInput): [TaskRun!] + taskRun(where: TaskRunWhereUniqueInput!): TaskRun + taskRunsCount(where: TaskRunWhereInput! = {}): Int + taskRunAttempts(where: TaskRunAttemptWhereInput! = {}, orderBy: [TaskRunAttemptOrderByInput!]! = [], take: Int, skip: Int! = 0, cursor: TaskRunAttemptWhereUniqueInput): [TaskRunAttempt!] + taskRunAttempt(where: TaskRunAttemptWhereUniqueInput!): TaskRunAttempt + taskRunAttemptsCount(where: TaskRunAttemptWhereInput! = {}): Int keystone: KeystoneMeta! authenticatedItem: AuthenticatedItem } diff --git a/examples/auth/schema.prisma b/examples/auth/schema.prisma index 9ae26a3cb1c..f58555439ca 100644 --- a/examples/auth/schema.prisma +++ b/examples/auth/schema.prisma @@ -18,3 +18,54 @@ model User { password String isAdmin Boolean @default(false) } + +model Project { + id String @id @default(cuid()) + slug String @unique @default("") + name String @default("") + createdAt DateTime? @default(now()) + updatedAt DateTime? @default(now()) @updatedAt + deletedAt DateTime? + taskRuns TaskRun[] @relation("TaskRun_project") +} + +model TaskRun { + id String @id @default(cuid()) + number Int? @default(0) + friendlyId String @default("") + status String? @default("pending") + taskIdentifier String @default("") + isTest Boolean @default(false) + payload String @default("") + payloadType String @default("application/json") + context String? + traceId String @default("") + spanId String @default("") + project Project? @relation("TaskRun_project", fields: [projectId], references: [id]) + projectId String? @map("project") + createdAt DateTime? @default(now()) + updatedAt DateTime? @default(now()) @updatedAt + attempts TaskRunAttempt[] @relation("TaskRunAttempt_taskRun") + startedAt DateTime? + completedAt DateTime? + + @@index([projectId]) +} + +model TaskRunAttempt { + id String @id @default(cuid()) + number Int? @default(0) + friendlyId String @default("") + taskRun TaskRun? @relation("TaskRunAttempt_taskRun", fields: [taskRunId], references: [id]) + taskRunId String? @map("taskRun") + status String? @default("pending") + createdAt DateTime? @default(now()) + updatedAt DateTime? @default(now()) @updatedAt + startedAt DateTime? + completedAt DateTime? + error String? + output String @default("") + outputType String @default("application/json") + + @@index([taskRunId]) +} diff --git a/examples/auth/schema.ts b/examples/auth/schema.ts index 2879ee9f407..a657f6863c2 100644 --- a/examples/auth/schema.ts +++ b/examples/auth/schema.ts @@ -1,6 +1,6 @@ import { list } from '@keystone-6/core' import { allowAll, denyAll } from '@keystone-6/core/access' -import { text, checkbox, password } from '@keystone-6/core/fields' +import { text, checkbox, password, timestamp, relationship, json, select, integer } from '@keystone-6/core/fields' import type { Lists } from '.keystone/types' // WARNING: this example is for demonstration purposes only @@ -153,4 +153,76 @@ export const lists = { }), }, }), + Project: list({ + access: allowAll, + + fields: { + slug: text({ isIndexed: 'unique' }), + name: text({ validation: { isRequired: true } }), + createdAt: timestamp({ defaultValue: { kind: 'now' } }), + updatedAt: timestamp({ defaultValue: { kind: 'now' }, db: { updatedAt: true } }), + deletedAt: timestamp({}), + taskRuns: relationship({ ref: 'TaskRun.project', many: true }), + } + }), + TaskRun: list({ + access: allowAll, + + fields: { + number: integer({ defaultValue: 0 }), + friendlyId: text({}), + status: select({ + options: [ + { label: 'Pending', value: 'pending' }, + { label: 'Executing', value: 'executing' }, + { label: 'Paused', value: 'paused' }, + { label: 'Canceled', value: 'canceled' }, + { label: 'Interrupted', value: 'interrupted' }, + { label: 'Completed Successfully', value: 'completed_successfully' }, + { label: 'Completed With Errors', value: 'completed_with_errors' }, + { label: 'System Failure', value: 'system_failure' }, + { label: 'Crashed', value: 'crashed' }], + defaultValue: 'pending' + }), + taskIdentifier: text({}), + isTest: checkbox({ defaultValue: false }), + payload: text({}), + payloadType: text({ defaultValue: 'application/json' }), + context: json({}), + traceId: text({}), + spanId: text({}), + project: relationship({ ref: 'Project.taskRuns' }), + createdAt: timestamp({ defaultValue: { kind: 'now' } }), + updatedAt: timestamp({ defaultValue: { kind: 'now' }, db: { updatedAt: true } }), + attempts: relationship({ ref: 'TaskRunAttempt.taskRun', many: true }), + startedAt: timestamp({}), + completedAt: timestamp({}), + } + }), + TaskRunAttempt: list({ + access: allowAll, + + fields: { + number: integer({ defaultValue: 0 }), + friendlyId: text({}), + taskRun: relationship({ ref: 'TaskRun.attempts' }), + status: select({ + options: [ + { label: 'Pending', value: 'pending' }, + { label: 'Executing', value: 'executing' }, + { label: 'Paused', value: 'paused' }, + { label: 'Failed', value: 'failed' }, + { label: 'Canceled', value: 'canceled' }, + { label: 'Completed', value: 'completed' }], + defaultValue: 'pending' + }), + createdAt: timestamp({ defaultValue: { kind: 'now' } }), + updatedAt: timestamp({ defaultValue: { kind: 'now' }, db: { updatedAt: true } }), + startedAt: timestamp({}), + completedAt: timestamp({}), + error: json({}), + output: text({}), + outputType: text({ defaultValue: 'application/json' }), + } + }) } satisfies Lists diff --git a/examples/auth/tsconfig.json b/examples/auth/tsconfig.json new file mode 100644 index 00000000000..ccb2ed95d83 --- /dev/null +++ b/examples/auth/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/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..f2b986e29ca --- /dev/null +++ b/examples/custom-admin-ui-logo/app/(admin)/config.tsx @@ -0,0 +1 @@ +export { components } from '../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/config/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/config/components/CustomLogo.tsx diff --git a/examples/custom-admin-ui-logo/admin/config.tsx b/examples/custom-admin-ui-logo/app/config/index.tsx similarity index 100% rename from examples/custom-admin-ui-logo/admin/config.tsx rename to examples/custom-admin-ui-logo/app/config/index.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/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/examples/custom-admin-ui-navigation/app/(admin)/.admin/index.tsx b/examples/custom-admin-ui-navigation/app/(admin)/.admin/index.tsx new file mode 100644 index 00000000000..283542749b0 --- /dev/null +++ b/examples/custom-admin-ui-navigation/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-navigation/app/(admin)/[listKey]/[id]/page.tsx b/examples/custom-admin-ui-navigation/app/(admin)/[listKey]/[id]/page.tsx new file mode 100644 index 00000000000..c5d7ea2be62 --- /dev/null +++ b/examples/custom-admin-ui-navigation/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-navigation/app/(admin)/[listKey]/create/page.tsx b/examples/custom-admin-ui-navigation/app/(admin)/[listKey]/create/page.tsx new file mode 100644 index 00000000000..d6042acaa96 --- /dev/null +++ b/examples/custom-admin-ui-navigation/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-navigation/app/(admin)/[listKey]/page.tsx b/examples/custom-admin-ui-navigation/app/(admin)/[listKey]/page.tsx new file mode 100644 index 00000000000..f6e75f8cfab --- /dev/null +++ b/examples/custom-admin-ui-navigation/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-navigation/app/(admin)/config.tsx b/examples/custom-admin-ui-navigation/app/(admin)/config.tsx new file mode 100644 index 00000000000..f2b986e29ca --- /dev/null +++ b/examples/custom-admin-ui-navigation/app/(admin)/config.tsx @@ -0,0 +1 @@ +export { components } from '../config' \ No newline at end of file diff --git a/examples/custom-admin-ui-navigation/app/(admin)/layout.tsx b/examples/custom-admin-ui-navigation/app/(admin)/layout.tsx new file mode 100644 index 00000000000..abb5a0f3b2c --- /dev/null +++ b/examples/custom-admin-ui-navigation/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-navigation/app/(admin)/no-access/page.tsx b/examples/custom-admin-ui-navigation/app/(admin)/no-access/page.tsx new file mode 100644 index 00000000000..70877231fee --- /dev/null +++ b/examples/custom-admin-ui-navigation/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-navigation/app/(admin)/page.tsx b/examples/custom-admin-ui-navigation/app/(admin)/page.tsx new file mode 100644 index 00000000000..5c268390b0f --- /dev/null +++ b/examples/custom-admin-ui-navigation/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-navigation/admin/components/CustomNavigation.tsx b/examples/custom-admin-ui-navigation/app/config/components/CustomNavigation.tsx similarity index 100% rename from examples/custom-admin-ui-navigation/admin/components/CustomNavigation.tsx rename to examples/custom-admin-ui-navigation/app/config/components/CustomNavigation.tsx diff --git a/examples/custom-admin-ui-navigation/admin/config.ts b/examples/custom-admin-ui-navigation/app/config/index.ts similarity index 100% rename from examples/custom-admin-ui-navigation/admin/config.ts rename to examples/custom-admin-ui-navigation/app/config/index.ts diff --git a/examples/custom-admin-ui-navigation/app/layout.tsx b/examples/custom-admin-ui-navigation/app/layout.tsx new file mode 100644 index 00000000000..38a4853e3a5 --- /dev/null +++ b/examples/custom-admin-ui-navigation/app/layout.tsx @@ -0,0 +1,11 @@ +export default function RootLayout ({ + children, +}: { + children: React.ReactNode +}) { + return ( + + {children} + + ) +} diff --git a/examples/custom-admin-ui-navigation/next-env.d.ts b/examples/custom-admin-ui-navigation/next-env.d.ts new file mode 100644 index 00000000000..4f11a03dc6c --- /dev/null +++ b/examples/custom-admin-ui-navigation/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-navigation/tsconfig.json b/examples/custom-admin-ui-navigation/tsconfig.json new file mode 100644 index 00000000000..ccb2ed95d83 --- /dev/null +++ b/examples/custom-admin-ui-navigation/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/examples/custom-admin-ui-pages/app/(admin)/.admin/index.tsx b/examples/custom-admin-ui-pages/app/(admin)/.admin/index.tsx new file mode 100644 index 00000000000..5dd11446daf --- /dev/null +++ b/examples/custom-admin-ui-pages/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-pages/app/(admin)/[listKey]/[id]/page.tsx b/examples/custom-admin-ui-pages/app/(admin)/[listKey]/[id]/page.tsx new file mode 100644 index 00000000000..c5d7ea2be62 --- /dev/null +++ b/examples/custom-admin-ui-pages/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-pages/app/(admin)/[listKey]/create/page.tsx b/examples/custom-admin-ui-pages/app/(admin)/[listKey]/create/page.tsx new file mode 100644 index 00000000000..d6042acaa96 --- /dev/null +++ b/examples/custom-admin-ui-pages/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-pages/app/(admin)/[listKey]/page.tsx b/examples/custom-admin-ui-pages/app/(admin)/[listKey]/page.tsx new file mode 100644 index 00000000000..f6e75f8cfab --- /dev/null +++ b/examples/custom-admin-ui-pages/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-pages/app/(admin)/config.tsx b/examples/custom-admin-ui-pages/app/(admin)/config.tsx new file mode 100644 index 00000000000..f2b986e29ca --- /dev/null +++ b/examples/custom-admin-ui-pages/app/(admin)/config.tsx @@ -0,0 +1 @@ +export { components } from '../config' \ No newline at end of file diff --git a/examples/custom-admin-ui-pages/admin/pages/custom-page.tsx b/examples/custom-admin-ui-pages/app/(admin)/custom-page/page.tsx similarity index 87% rename from examples/custom-admin-ui-pages/admin/pages/custom-page.tsx rename to examples/custom-admin-ui-pages/app/(admin)/custom-page/page.tsx index ccf76ad67aa..346ab365520 100644 --- a/examples/custom-admin-ui-pages/admin/pages/custom-page.tsx +++ b/examples/custom-admin-ui-pages/app/(admin)/custom-page/page.tsx @@ -1,8 +1,7 @@ -/** @jsxRuntime classic */ -/** @jsx jsx */ +'use client' import Link from 'next/link' import { PageContainer } from '@keystone-6/core/admin-ui/components' -import { jsx, Heading } from '@keystone-ui/core' +import { Heading } from '@keystone-ui/core' // Please note that while this capability is driven by Next.js's pages directory // We do not currently support any of the auxillary methods that Next.js provides i.e. `getStaticProps` // Presently the only export from the directory that is supported is the page component itself. @@ -10,7 +9,7 @@ export default function CustomPage () { return ( Custom Page}>

    diff --git a/examples/custom-admin-ui-pages/app/(admin)/layout.tsx b/examples/custom-admin-ui-pages/app/(admin)/layout.tsx new file mode 100644 index 00000000000..abb5a0f3b2c --- /dev/null +++ b/examples/custom-admin-ui-pages/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-pages/app/(admin)/no-access/page.tsx b/examples/custom-admin-ui-pages/app/(admin)/no-access/page.tsx new file mode 100644 index 00000000000..70877231fee --- /dev/null +++ b/examples/custom-admin-ui-pages/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-pages/app/(admin)/page.tsx b/examples/custom-admin-ui-pages/app/(admin)/page.tsx new file mode 100644 index 00000000000..5c268390b0f --- /dev/null +++ b/examples/custom-admin-ui-pages/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-pages/admin/components/CustomNavigation.tsx b/examples/custom-admin-ui-pages/app/config/components/CustomNavigation.tsx similarity index 100% rename from examples/custom-admin-ui-pages/admin/components/CustomNavigation.tsx rename to examples/custom-admin-ui-pages/app/config/components/CustomNavigation.tsx diff --git a/examples/custom-admin-ui-pages/admin/config.ts b/examples/custom-admin-ui-pages/app/config/index.ts similarity index 100% rename from examples/custom-admin-ui-pages/admin/config.ts rename to examples/custom-admin-ui-pages/app/config/index.ts diff --git a/examples/custom-admin-ui-pages/app/layout.tsx b/examples/custom-admin-ui-pages/app/layout.tsx new file mode 100644 index 00000000000..38a4853e3a5 --- /dev/null +++ b/examples/custom-admin-ui-pages/app/layout.tsx @@ -0,0 +1,11 @@ +export default function RootLayout ({ + children, +}: { + children: React.ReactNode +}) { + return ( + + {children} + + ) +} diff --git a/examples/custom-admin-ui-pages/next-env.d.ts b/examples/custom-admin-ui-pages/next-env.d.ts new file mode 100644 index 00000000000..4f11a03dc6c --- /dev/null +++ b/examples/custom-admin-ui-pages/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-pages/tsconfig.json b/examples/custom-admin-ui-pages/tsconfig.json new file mode 100644 index 00000000000..ccb2ed95d83 --- /dev/null +++ b/examples/custom-admin-ui-pages/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/examples/custom-field-view/app/(admin)/.admin/index.tsx b/examples/custom-field-view/app/(admin)/.admin/index.tsx new file mode 100644 index 00000000000..7c8948ac698 --- /dev/null +++ b/examples/custom-field-view/app/(admin)/.admin/index.tsx @@ -0,0 +1,21 @@ +/* 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 view6 from "@keystone-6/core/fields/types/json/views" +import * as view7 from "../../.././fields/related-links/components" +import * as view8 from "@/fields/related-links/components" + +const adminConfig = {} + +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,view6,view7,view8], + adminMetaHash: 'o10uod', + adminConfig, + apiPath: '/api/graphql', + adminPath: '', +}; diff --git a/examples/custom-field-view/app/(admin)/[listKey]/[id]/page.tsx b/examples/custom-field-view/app/(admin)/[listKey]/[id]/page.tsx new file mode 100644 index 00000000000..c5d7ea2be62 --- /dev/null +++ b/examples/custom-field-view/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-field-view/app/(admin)/[listKey]/create/page.tsx b/examples/custom-field-view/app/(admin)/[listKey]/create/page.tsx new file mode 100644 index 00000000000..d6042acaa96 --- /dev/null +++ b/examples/custom-field-view/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-field-view/app/(admin)/[listKey]/page.tsx b/examples/custom-field-view/app/(admin)/[listKey]/page.tsx new file mode 100644 index 00000000000..f6e75f8cfab --- /dev/null +++ b/examples/custom-field-view/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-field-view/app/(admin)/layout.tsx b/examples/custom-field-view/app/(admin)/layout.tsx new file mode 100644 index 00000000000..abb5a0f3b2c --- /dev/null +++ b/examples/custom-field-view/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-field-view/app/(admin)/no-access/page.tsx b/examples/custom-field-view/app/(admin)/no-access/page.tsx new file mode 100644 index 00000000000..70877231fee --- /dev/null +++ b/examples/custom-field-view/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-field-view/app/(admin)/page.tsx b/examples/custom-field-view/app/(admin)/page.tsx new file mode 100644 index 00000000000..5c268390b0f --- /dev/null +++ b/examples/custom-field-view/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-field-view/app/layout.tsx b/examples/custom-field-view/app/layout.tsx new file mode 100644 index 00000000000..38a4853e3a5 --- /dev/null +++ b/examples/custom-field-view/app/layout.tsx @@ -0,0 +1,11 @@ +export default function RootLayout ({ + children, +}: { + children: React.ReactNode +}) { + return ( + + {children} + + ) +} diff --git a/examples/custom-field-view/next-env.d.ts b/examples/custom-field-view/next-env.d.ts new file mode 100644 index 00000000000..4f11a03dc6c --- /dev/null +++ b/examples/custom-field-view/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-field-view/schema.graphql b/examples/custom-field-view/schema.graphql index a7743bbd7f6..20635a2b137 100644 --- a/examples/custom-field-view/schema.graphql +++ b/examples/custom-field-view/schema.graphql @@ -9,6 +9,7 @@ type Task { assignedTo: Person finishBy: DateTime relatedLinks: JSON + moreLinks: JSON } enum TaskPriorityType { @@ -117,6 +118,7 @@ input TaskUpdateInput { assignedTo: PersonRelateToOneForUpdateInput finishBy: DateTime relatedLinks: JSON + moreLinks: JSON } input PersonRelateToOneForUpdateInput { @@ -137,6 +139,7 @@ input TaskCreateInput { assignedTo: PersonRelateToOneForCreateInput finishBy: DateTime relatedLinks: JSON + moreLinks: JSON } input PersonRelateToOneForCreateInput { diff --git a/examples/custom-field-view/schema.prisma b/examples/custom-field-view/schema.prisma index 32e04e70c82..fb3278a7169 100644 --- a/examples/custom-field-view/schema.prisma +++ b/examples/custom-field-view/schema.prisma @@ -21,6 +21,7 @@ model Task { assignedToId String? @map("assignedTo") finishBy DateTime? relatedLinks String? + moreLinks String? @@index([assignedToId]) } diff --git a/examples/custom-field-view/schema.ts b/examples/custom-field-view/schema.ts index 8a6516cd78d..ed877eee26f 100644 --- a/examples/custom-field-view/schema.ts +++ b/examples/custom-field-view/schema.ts @@ -30,6 +30,14 @@ export const lists = { itemView: { fieldMode: 'edit' }, }, }), + moreLinks: json({ + ui: { + views: '@/fields/related-links/components', + createView: { fieldMode: 'edit' }, + listView: { fieldMode: 'hidden' }, + itemView: { fieldMode: 'edit' }, + }, + }), }, }), Person: list({ diff --git a/examples/custom-field-view/tsconfig.json b/examples/custom-field-view/tsconfig.json new file mode 100644 index 00000000000..3b0afd8f406 --- /dev/null +++ b/examples/custom-field-view/tsconfig.json @@ -0,0 +1,37 @@ +{ + "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", + "paths": { + "@/fields/*": ["./fields/*"] + }, + "plugins": [ + { + "name": "next" + } + ] + }, + "include": [ + "next-env.d.ts", + ".next/types/**/*.ts", + "**/*.ts", + "**/*.tsx" + ], + "exclude": [ + "node_modules" + ] +} diff --git a/examples/custom-field/app/(admin)/.admin/index.tsx b/examples/custom-field/app/(admin)/.admin/index.tsx new file mode 100644 index 00000000000..ca1a2d962a6 --- /dev/null +++ b/examples/custom-field/app/(admin)/.admin/index.tsx @@ -0,0 +1,19 @@ +/* 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 "../../.././1-text-field/views" +import * as view2 from "../../.././2-stars-field/views" +import * as view3 from "../../.././4-conditional-field/views" +import * as view4 from "../../.././3-pair-field/views" +import * as view5 from "../../.././3-pair-field-nested/views" +import * as view6 from "../../.././3-pair-field-json/views" + +const adminConfig = {} + +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,view6], + adminMetaHash: 'fhppxz', + adminConfig, + apiPath: '/api/graphql', + adminPath: '', +}; diff --git a/examples/custom-field/app/(admin)/[listKey]/[id]/page.tsx b/examples/custom-field/app/(admin)/[listKey]/[id]/page.tsx new file mode 100644 index 00000000000..c5d7ea2be62 --- /dev/null +++ b/examples/custom-field/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-field/app/(admin)/[listKey]/create/page.tsx b/examples/custom-field/app/(admin)/[listKey]/create/page.tsx new file mode 100644 index 00000000000..d6042acaa96 --- /dev/null +++ b/examples/custom-field/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-field/app/(admin)/[listKey]/page.tsx b/examples/custom-field/app/(admin)/[listKey]/page.tsx new file mode 100644 index 00000000000..f6e75f8cfab --- /dev/null +++ b/examples/custom-field/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-field/app/(admin)/layout.tsx b/examples/custom-field/app/(admin)/layout.tsx new file mode 100644 index 00000000000..abb5a0f3b2c --- /dev/null +++ b/examples/custom-field/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-field/app/(admin)/no-access/page.tsx b/examples/custom-field/app/(admin)/no-access/page.tsx new file mode 100644 index 00000000000..70877231fee --- /dev/null +++ b/examples/custom-field/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-field/app/(admin)/page.tsx b/examples/custom-field/app/(admin)/page.tsx new file mode 100644 index 00000000000..5c268390b0f --- /dev/null +++ b/examples/custom-field/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-field/app/layout.tsx b/examples/custom-field/app/layout.tsx new file mode 100644 index 00000000000..38a4853e3a5 --- /dev/null +++ b/examples/custom-field/app/layout.tsx @@ -0,0 +1,11 @@ +export default function RootLayout ({ + children, +}: { + children: React.ReactNode +}) { + return ( + + {children} + + ) +} diff --git a/examples/custom-field/next-env.d.ts b/examples/custom-field/next-env.d.ts new file mode 100644 index 00000000000..4f11a03dc6c --- /dev/null +++ b/examples/custom-field/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-field/tsconfig.json b/examples/custom-field/tsconfig.json new file mode 100644 index 00000000000..3b0afd8f406 --- /dev/null +++ b/examples/custom-field/tsconfig.json @@ -0,0 +1,37 @@ +{ + "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", + "paths": { + "@/fields/*": ["./fields/*"] + }, + "plugins": [ + { + "name": "next" + } + ] + }, + "include": [ + "next-env.d.ts", + ".next/types/**/*.ts", + "**/*.ts", + "**/*.tsx" + ], + "exclude": [ + "node_modules" + ] +} diff --git a/examples/document-field/README.md b/examples/document-field/README.md index ffd84eb8744..8712f661bda 100644 --- a/examples/document-field/README.md +++ b/examples/document-field/README.md @@ -1,6 +1,6 @@ ## Feature Example - Document Field -This project demonstrates how to configure [document fields](https://keystonejs.com/docs/guides/document-fields) in your Keystone system and render their data in a frontend application. +This project demonstrates how to configure [document fields](https://keystonejs.com/docs/guides/document-fields) in your Keystone system and render their data in a frontend. It builds on the [Blog](../blog) starter project. ## Instructions @@ -16,13 +16,7 @@ You can use the Admin UI to create items in your database. You can also access a GraphQL Playground at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. -In a separate terminal, start the frontend dev server: - -``` -pnpm dev:site -``` - -This will start the frontend at [localhost:3001](http://localhost:3001). +Go to url [localhost:3000/site](http://localhost:3000/site) tp see the page rendering document field content. ## Configuring fields diff --git a/examples/document-field/next-env.d.ts b/examples/document-field/next-env.d.ts index 7b7aa2c7727..4f11a03dc6c 100644 --- a/examples/document-field/next-env.d.ts +++ b/examples/document-field/next-env.d.ts @@ -1,2 +1,5 @@ /// -/// +/// + +// 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/package.json b/examples/document-field/package.json index cde0ce07419..a5094fbfa2a 100644 --- a/examples/document-field/package.json +++ b/examples/document-field/package.json @@ -5,7 +5,6 @@ "license": "MIT", "scripts": { "dev": "keystone dev", - "dev:site": "next dev -p 3001", "start": "keystone start", "build": "keystone build", "postinstall": "keystone postinstall" diff --git a/examples/document-field/src/app/(admin)/.admin/index.tsx b/examples/document-field/src/app/(admin)/.admin/index.tsx new file mode 100644 index 00000000000..e53104746f4 --- /dev/null +++ b/examples/document-field/src/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/fields-document/views" +import * as view4 from "@keystone-6/core/fields/types/timestamp/views" +import * as view5 from "@keystone-6/core/fields/types/relationship/views" + +const adminConfig = {} + +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: '1oos0js', + adminConfig, + apiPath: '/api/graphql', + adminPath: '', +}; diff --git a/examples/document-field/src/app/(admin)/[listKey]/[id]/page.tsx b/examples/document-field/src/app/(admin)/[listKey]/[id]/page.tsx new file mode 100644 index 00000000000..c5d7ea2be62 --- /dev/null +++ b/examples/document-field/src/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/document-field/src/app/(admin)/[listKey]/create/page.tsx b/examples/document-field/src/app/(admin)/[listKey]/create/page.tsx new file mode 100644 index 00000000000..d6042acaa96 --- /dev/null +++ b/examples/document-field/src/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/document-field/src/app/(admin)/[listKey]/page.tsx b/examples/document-field/src/app/(admin)/[listKey]/page.tsx new file mode 100644 index 00000000000..f6e75f8cfab --- /dev/null +++ b/examples/document-field/src/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/document-field/src/app/(admin)/author/[id]/page.tsx b/examples/document-field/src/app/(admin)/author/[id]/page.tsx new file mode 100644 index 00000000000..59d033be780 --- /dev/null +++ b/examples/document-field/src/app/(admin)/author/[id]/page.tsx @@ -0,0 +1,57 @@ +import { type GetStaticPathsResult, type GetStaticPropsContext } from 'next' +import Link from 'next/link' +import React from 'react' +import { DocumentRenderer } from '@keystone-6/document-renderer' +import { fetchGraphQL, gql } from "../../../utils"; + +export default async function Post ({ params }: any) { +const data = await fetchGraphQL( + gql` + query ($id: ID!) { + author(where: { id: $id }) { + name + bio { + document + } + posts(where: { status: { equals: published } }, orderBy: { publishDate: desc }) { + id + title + slug + } + } + } + `, + { id: params!.id } +) +const author = data?.author + return ( +

    +

    {author.name}

    + +

    Bio

    + {author.bio?.document && } + +

    Posts

    + {author.posts.map((post: any) => ( +
  • + {post.title} +
  • + ))} +
    + ) +} + +// 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)/layout.tsx b/examples/document-field/src/app/(admin)/layout.tsx new file mode 100644 index 00000000000..abb5a0f3b2c --- /dev/null +++ b/examples/document-field/src/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/document-field/src/app/(admin)/no-access/page.tsx b/examples/document-field/src/app/(admin)/no-access/page.tsx new file mode 100644 index 00000000000..70877231fee --- /dev/null +++ b/examples/document-field/src/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/document-field/src/app/(admin)/page.tsx b/examples/document-field/src/app/(admin)/page.tsx new file mode 100644 index 00000000000..5c268390b0f --- /dev/null +++ b/examples/document-field/src/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/document-field/src/pages/post/[slug].tsx b/examples/document-field/src/app/(admin)/post/[slug]/page.tsx similarity index 80% rename from examples/document-field/src/pages/post/[slug].tsx rename to examples/document-field/src/app/(admin)/post/[slug]/page.tsx index eaf941ad802..05edeb0631f 100644 --- a/examples/document-field/src/pages/post/[slug].tsx +++ b/examples/document-field/src/app/(admin)/post/[slug]/page.tsx @@ -2,7 +2,7 @@ import { type GetStaticPathsResult, type GetStaticPropsContext } from 'next' import Link from 'next/link' import React from 'react' import { DocumentRenderer, type DocumentRendererProps } from '@keystone-6/document-renderer' -import { fetchGraphQL, gql } from '../../utils' +import { fetchGraphQL, gql } from "../../../utils"; // By default the DocumentRenderer will render unstyled html elements. // We're customising how headings are rendered here but you can customise @@ -39,7 +39,26 @@ const renderers: DocumentRendererProps['renderers'] = { }, } -export default function Post ({ post }: { post: any }) { +export default async function Post ({ params }: { params: any }) { + const data = await fetchGraphQL( + gql` + query ($slug: String!) { + post(where: { slug: $slug }) { + title + content { + document(hydrateRelationships: true) + } + publishDate + author { + id + name + } + } + } + `, + { slug: params!.slug } + ) + const post = data?.post return (

    {post.title}

    @@ -60,40 +79,17 @@ export default function Post ({ post }: { post: 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', - } -} - -export async function getStaticProps ({ params }: GetStaticPropsContext) { - // We use (hydrateRelationships: true) to ensure we have the data we need - // to render the inline relationships. - const data = await fetchGraphQL( - gql` - query ($slug: String!) { - post(where: { slug: $slug }) { - title - content { - document(hydrateRelationships: true) - } - publishDate - author { - id - name - } - } - } - `, - { slug: params!.slug } - ) - return { props: { post: data.post }, revalidate: 60 } -} +// 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/examples/document-field/src/app/layout.tsx b/examples/document-field/src/app/layout.tsx new file mode 100644 index 00000000000..38a4853e3a5 --- /dev/null +++ b/examples/document-field/src/app/layout.tsx @@ -0,0 +1,11 @@ +export default function RootLayout ({ + children, +}: { + children: React.ReactNode +}) { + return ( + + {children} + + ) +} diff --git a/examples/document-field/src/pages/index.tsx b/examples/document-field/src/app/site/page.tsx similarity index 58% rename from examples/document-field/src/pages/index.tsx rename to examples/document-field/src/app/site/page.tsx index 737a083edb8..5af491efde4 100644 --- a/examples/document-field/src/pages/index.tsx +++ b/examples/document-field/src/app/site/page.tsx @@ -1,21 +1,44 @@ import Link from 'next/link' import React from 'react' -import { fetchGraphQL, gql } from '../utils' +import { fetchGraphQL, gql } from "../utils"; -type Author = { id: string, name: string, posts: { id: string, slug: string, title: string }[] } +type Author = { + id: string + name: string + posts: { id: string, slug: string, title: string }[] +} + +export default async function Index () { + const data = await fetchGraphQL(gql` + query { + authors { + id + name + posts( + where: { status: { equals: published } } + orderBy: { publishDate: desc } + ) { + id + slug + title + } + } + } + `) + + const authors: Author[] = data?.authors || [] -export default function Index ({ authors }: { authors: Author[] }) { return ( <>

    Keystone Blog Project - Home

      - {authors.map(author => ( + {authors.map((author) => (
    • {author.name}

        - {author.posts.map(post => ( + {author.posts.map((post) => (
      • {post.title}
      • @@ -27,20 +50,3 @@ export default function Index ({ authors }: { authors: Author[] }) { ) } - -export async function getStaticProps () { - const data = await fetchGraphQL(gql` - query { - authors { - id - name - posts(where: { status: { equals: published } }, orderBy: { publishDate: desc }) { - id - slug - title - } - } - } - `) - return { props: { authors: data.authors }, revalidate: 30 } -} diff --git a/examples/document-field/src/utils.tsx b/examples/document-field/src/app/utils.tsx similarity index 100% rename from examples/document-field/src/utils.tsx rename to examples/document-field/src/app/utils.tsx diff --git a/examples/document-field/src/pages/author/[id].tsx b/examples/document-field/src/pages/author/[id].tsx deleted file mode 100644 index f3aa3dbdf80..00000000000 --- a/examples/document-field/src/pages/author/[id].tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { type GetStaticPathsResult, type GetStaticPropsContext } from 'next' -import Link from 'next/link' -import React from 'react' -import { DocumentRenderer } from '@keystone-6/document-renderer' -import { fetchGraphQL, gql } from '../../utils' - -export default function Post ({ author }: { author: any }) { - return ( -
        -

        {author.name}

        - -

        Bio

        - {author.bio?.document && } - -

        Posts

        - {author.posts.map((post: any) => ( -
      • - {post.title} -
      • - ))} -
        - ) -} - -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', - } -} - -export async function getStaticProps ({ params }: GetStaticPropsContext) { - const data = await fetchGraphQL( - gql` - query ($id: ID!) { - author(where: { id: $id }) { - name - bio { - document - } - posts(where: { status: { equals: published } }, orderBy: { publishDate: desc }) { - id - title - slug - } - } - } - `, - { id: params!.id } - ) - return { props: { author: data.author }, revalidate: 60 } -} diff --git a/examples/document-field/tsconfig.json b/examples/document-field/tsconfig.json index 1ed5fb820cb..64857dc28d3 100644 --- a/examples/document-field/tsconfig.json +++ b/examples/document-field/tsconfig.json @@ -1,7 +1,11 @@ { "compilerOptions": { "target": "esnext", - "lib": ["dom", "dom.iterable", "esnext"], + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], "allowJs": false, "skipLibCheck": false, "strict": true, @@ -12,8 +16,21 @@ "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve" + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ] }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], - "exclude": ["node_modules"] + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts" + ], + "exclude": [ + "node_modules" + ] } diff --git a/packages/auth/src/index.ts b/packages/auth/src/index.ts index 68448486a4c..3929bd4a9a0 100644 --- a/packages/auth/src/index.ts +++ b/packages/auth/src/index.ts @@ -99,19 +99,20 @@ export function createAuth ({ * * The signin page is always included, and the init page is included when initFirstItem is set */ - const authGetAdditionalFiles = () => { + const authGetAdditionalFiles = ({ tsx }: { tsx: boolean }) => { + const ext = tsx ? 'tsx' : 'js' const filesToWrite: AdminFileToWrite[] = [ { mode: 'write', src: signinTemplate({ gqlNames, identityField, secretField }), - outputPath: 'pages/signin.js', + outputPath: `signin/page.${ext}`, }, ] if (initFirstItem) { filesToWrite.push({ mode: 'write', src: initTemplate({ listKey, initFirstItem }), - outputPath: 'pages/init.js', + outputPath: `init/page.${ext}`, }) } return filesToWrite @@ -215,7 +216,6 @@ export function createAuth ({ }): Promise<{ kind: 'redirect', to: string } | void> { const { req } = context const { pathname } = new URL(req!.url!, 'http://_') - // redirect to init if initFirstItem conditions are met if (pathname !== `${basePath}/init` && (await hasInitFirstItemConditions(context))) { return { kind: 'redirect', to: `${basePath}/init` } @@ -262,7 +262,7 @@ export function createAuth ({ ui = { ...ui, publicPages: [...publicPages, ...authPublicPages], - getAdditionalFiles: [...getAdditionalFiles, authGetAdditionalFiles], + getAdditionalFiles: [...getAdditionalFiles, () => authGetAdditionalFiles({ tsx: ui?.tsx ?? true })], isAccessAllowed: async (context: KeystoneContext) => { if (await hasInitFirstItemConditions(context)) return true diff --git a/packages/auth/src/lib/useFromRedirect.ts b/packages/auth/src/lib/useFromRedirect.ts deleted file mode 100644 index 6b0828e2c4f..00000000000 --- a/packages/auth/src/lib/useFromRedirect.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { useMemo } from 'react' - -// TODO: remove or fix -export function useRedirect () { - return useMemo(() => '/', []) -} diff --git a/packages/auth/src/pages/InitPage.tsx b/packages/auth/src/pages/InitPage.tsx index cc92c2ee987..75d6ef791f2 100644 --- a/packages/auth/src/pages/InitPage.tsx +++ b/packages/auth/src/pages/InitPage.tsx @@ -22,7 +22,6 @@ import { import { guessEmailFromValue, validEmail } from '../lib/emailHeuristics' import { IconTwitter, IconGithub } from '../components/Icons' import { SigninContainer } from '../components/SigninContainer' -import { useRedirect } from '../lib/useFromRedirect' const signupURL = 'https://signup.keystonejs.cloud/api/newsletter-signup' @@ -31,6 +30,7 @@ function Welcome ({ value, onContinue }: { value: any, onContinue: () => void }) const [email, setEmail] = useState(guessEmailFromValue(value)) const [error, setError] = useState(null) const [loading, setLoading] = useState(false) + const { adminPath } = useKeystone() const onSubmit = async (event: React.FormEvent) => { event.preventDefault() @@ -138,7 +138,7 @@ function Welcome ({ value, onContinue }: { value: any, onContinue: () => void }) {error ? 'Try again' : 'Continue'} {error && ( - )} @@ -157,7 +157,7 @@ function InitPage ({ fieldPaths: string[] enableWelcome: boolean }) { - const { adminMeta } = useKeystone() + const { adminMeta, adminPath } = useKeystone() const fields = useMemo(() => { const fields: Record = {} fieldPaths.forEach(fieldPath => { @@ -190,7 +190,6 @@ function InitPage ({ }`) const reinitContext = useReinitContext() const router = useRouter() - const redirect = useRedirect() const onSubmit = async (event: React.FormEvent) => { event.preventDefault() @@ -229,11 +228,11 @@ function InitPage ({ await reinitContext() if (enableWelcome) return setMode('welcome') - router.push(redirect) + router.push(adminPath || '/') } const onComplete = () => { - router.push(redirect) + router.push(adminPath || '/') } return mode === 'init' ? ( diff --git a/packages/auth/src/pages/SigninPage.tsx b/packages/auth/src/pages/SigninPage.tsx index d0b5b7536d7..9772c33971d 100644 --- a/packages/auth/src/pages/SigninPage.tsx +++ b/packages/auth/src/pages/SigninPage.tsx @@ -12,7 +12,6 @@ import { useMutation, gql } from '@keystone-6/core/admin-ui/apollo' import { useRawKeystone, useReinitContext } from '@keystone-6/core/admin-ui/context' import { useRouter } from '@keystone-6/core/admin-ui/router' import { SigninContainer } from '../components/SigninContainer' -import { useRedirect } from '../lib/useFromRedirect' type SigninPageProps = { identityField: string @@ -59,15 +58,14 @@ export function SigninPage ({ const reinitContext = useReinitContext() const router = useRouter() const rawKeystone = useRawKeystone() - const redirect = useRedirect() - + const { adminPath } = useRawKeystone() // if we are signed in, redirect immediately useEffect(() => { if (submitted) return if (rawKeystone.authenticatedItem.state === 'authenticated') { - router.push(redirect) + router.push(adminPath || '/') } - }, [rawKeystone.authenticatedItem, router, redirect, submitted]) + }, [rawKeystone.authenticatedItem, router, adminPath, submitted]) useEffect(() => { if (!submitted) return @@ -79,8 +77,8 @@ export function SigninPage ({ return } - router.push(redirect) - }, [rawKeystone.adminMeta, router, redirect, submitted]) + router.push(adminPath || '/') + }, [rawKeystone.adminMeta, router, adminPath, submitted]) const onSubmit = async (event: FormEvent) => { event.preventDefault() diff --git a/packages/auth/src/templates/init.ts b/packages/auth/src/templates/init.ts index 03e69aa977d..3cbe4f9b624 100644 --- a/packages/auth/src/templates/init.ts +++ b/packages/auth/src/templates/init.ts @@ -8,15 +8,17 @@ type InitTemplateArgs = { export const initTemplate = ({ listKey, initFirstItem }: InitTemplateArgs) => { // -- TEMPLATE START - return `import { getInitPage } from '@keystone-6/auth/pages/InitPage'; + return `'use client' +/* eslint-disable */ +import { getInitPage } from '@keystone-6/auth/pages/InitPage' -const fieldPaths = ${JSON.stringify(initFirstItem.fields)}; +const fieldPaths = ${JSON.stringify(initFirstItem.fields)} export default getInitPage(${JSON.stringify({ listKey, fieldPaths: initFirstItem.fields, enableWelcome: !initFirstItem.skipKeystoneWelcome, - })}); + })}) ` // -- TEMPLATE END } diff --git a/packages/auth/src/templates/signin.ts b/packages/auth/src/templates/signin.ts index 6e333babc59..25542dc9ac3 100644 --- a/packages/auth/src/templates/signin.ts +++ b/packages/auth/src/templates/signin.ts @@ -10,7 +10,9 @@ export const signinTemplate = ({ secretField: string }) => { // -- TEMPLATE START - return `import { getSigninPage } from '@keystone-6/auth/pages/SigninPage' + return `'use client' +/* eslint-disable */ +import { getSigninPage } from '@keystone-6/auth/pages/SigninPage' export default getSigninPage(${JSON.stringify({ identityField: identityField, @@ -18,7 +20,7 @@ export default getSigninPage(${JSON.stringify({ mutationName: gqlNames.authenticateItemWithPassword, successTypename: gqlNames.ItemAuthenticationWithPasswordSuccess, failureTypename: gqlNames.ItemAuthenticationWithPasswordFailure, - })}); + })}) ` // -- TEMPLATE END } diff --git a/packages/core/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/index.tsx b/packages/core/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/index.tsx index 49d0da8982c..a4ee5924f3f 100644 --- a/packages/core/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/index.tsx +++ b/packages/core/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/App/index.tsx @@ -1,27 +1,30 @@ import React from 'react' import { Core } from '@keystone-ui/core' -import { type AppProps } from 'next/app' import { type DocumentNode } from 'graphql' import { type AdminConfig, type FieldViews } from '../../../../types' import { ErrorBoundary } from '../../../../admin-ui/components' import { KeystoneProvider } from '../../../../admin-ui/context' +type AdminProps = { + children: React.ReactNode + config: AppConfig +} + type AppConfig = { adminConfig: AdminConfig adminMetaHash: string fieldViews: FieldViews lazyMetadataQuery: DocumentNode apiPath: string + adminPath: string } -export const getApp = - (props: AppConfig) => - ({ Component, pageProps }: AppProps) => { - return ( +export function Layout ({ children, config }: AdminProps) { + return ( - + - + {children} diff --git a/packages/core/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/CreateItemPage/index.tsx b/packages/core/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/CreateItemPage/index.tsx index e437e65af8f..4721bd9d1d8 100644 --- a/packages/core/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/CreateItemPage/index.tsx +++ b/packages/core/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/CreateItemPage/index.tsx @@ -4,7 +4,6 @@ import { Box, jsx } from '@keystone-ui/core' import { LoadingDots } from '@keystone-ui/loading' import { Button } from '@keystone-ui/button' -import { useRouter } from 'next/router' import { Fields } from '../../../../admin-ui/utils' import { PageContainer } from '../../../../admin-ui/components/PageContainer' import { useKeystone, useList } from '../../../../admin-ui' @@ -12,10 +11,12 @@ import { GraphQLErrorNotice } from '../../../../admin-ui/components' import { type ListMeta } from '../../../../types' import { useCreateItem } from '../../../../admin-ui/utils/useCreateItem' import { BaseToolbar, ColumnLayout, ItemPageHeader } from '../ItemPage/common' +import { useRouter } from '../../../../admin-ui/router' function CreatePageForm (props: { list: ListMeta }) { const createItem = useCreateItem(props.list) const router = useRouter() + const { adminPath } = useKeystone() return ( {createItem.error && ( @@ -34,7 +35,7 @@ function CreatePageForm (props: { list: ListMeta }) { onClick={async () => { const item = await createItem.create() if (item) { - router.push(`/${props.list.path}/${item.id}`) + router.push(`${adminPath}/${props.list.path}/${item.id}`) } }} > @@ -45,14 +46,11 @@ function CreatePageForm (props: { list: ListMeta }) { ) } -type CreateItemPageProps = { listKey: string } +type CreateItemPageProps = { params: { listKey: string } } -export const getCreateItemPage = (props: CreateItemPageProps) => () => - - -function CreateItemPage (props: CreateItemPageProps) { - const list = useList(props.listKey) - const { createViewFieldModes } = useKeystone() +export function CreateItemPage ({ params }: CreateItemPageProps) { + const { createViewFieldModes, listsKeyByPath } = useKeystone() + const list = useList(listsKeyByPath[params.listKey]) return ( {hideCreate === false && !list.isSingleton && ( - + Create {list.singular} @@ -158,10 +159,11 @@ export function HomePage () { ) } return Object.keys(lists).map(key => { - if (!visibleLists.lists.has(key)) { + const list = lists[key] + if (!visibleLists.lists.has(list.key)) { return null } - const result = dataGetter.get(key) + const result = dataGetter.get(list.key) return ( - + {props.list.label} diff --git a/packages/core/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.tsx b/packages/core/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.tsx index b5f3d46cd42..cdf4a1206e1 100644 --- a/packages/core/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.tsx +++ b/packages/core/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.tsx @@ -2,7 +2,6 @@ /** @jsx jsx */ import copyToClipboard from 'clipboard-copy' -import { useRouter } from 'next/router' import { Fragment, type HTMLAttributes, @@ -37,15 +36,19 @@ import { } from '../../../../admin-ui/utils' import { gql, useMutation, useQuery } from '../../../../admin-ui/apollo' -import { useList } from '../../../../admin-ui/context' +import { useKeystone, useList } from '../../../../admin-ui/context' import { PageContainer, HEADER_HEIGHT } from '../../../../admin-ui/components/PageContainer' import { GraphQLErrorNotice } from '../../../../admin-ui/components/GraphQLErrorNotice' import { usePreventNavigation } from '../../../../admin-ui/utils/usePreventNavigation' import { CreateButtonLink } from '../../../../admin-ui/components/CreateButtonLink' import { BaseToolbar, ColumnLayout, ItemPageHeader } from './common' +import { useRouter } from '../../../../admin-ui/router' type ItemPageProps = { - listKey: string + params: { + id: string + listKey: string + } } function useEventCallback any>(callback: Func): Func { @@ -267,6 +270,7 @@ function DeleteButton ({ itemId: string list: ListMeta }) { + const { adminPath } = useKeystone() const toasts = useToasts() const [deleteItem, { loading }] = useMutation( gql`mutation ($id: ID!) { @@ -307,7 +311,7 @@ function DeleteButton ({ tone: 'negative', }) } - router.push(list.isSingleton ? '/' : `/${list.path}`) + router.push(`${adminPath}/${list.isSingleton ? '' : `${list.path}`}`) return toasts.addToast({ title: itemLabel, message: `Deleted ${list.singular} item successfully`, @@ -330,11 +334,11 @@ function DeleteButton ({ ) } -export const getItemPage = (props: ItemPageProps) => () => - -function ItemPage ({ listKey }: ItemPageProps) { +export function ItemPage ({ params }: ItemPageProps) { + const { listsKeyByPath } = useKeystone() + const listKey = listsKeyByPath[params.listKey] const list = useList(listKey) - const id = useRouter().query.id as string + const id = params.id as string const { query, selectedFields } = useMemo(() => { const selectedFields = Object.entries(list.fields) diff --git a/packages/core/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/FieldSelection.tsx b/packages/core/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/FieldSelection.tsx index fcfd317dfba..edbd33fb6f0 100644 --- a/packages/core/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/FieldSelection.tsx +++ b/packages/core/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/FieldSelection.tsx @@ -5,9 +5,9 @@ import { Box, jsx } from '@keystone-ui/core' import { ChevronDownIcon } from '@keystone-ui/icons/icons/ChevronDownIcon' import { Options, OptionPrimitive, CheckMark } from '@keystone-ui/options' import { Popover } from '@keystone-ui/popover' -import { useRouter } from 'next/router' import { type ListMeta } from '../../../../types' import { useSelectedFields } from './useSelectedFields' +import { useRouter } from '../../../../admin-ui/router' function isArrayEqual (arrA: string[], arrB: string[]) { if (arrA.length !== arrB.length) return false diff --git a/packages/core/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.tsx b/packages/core/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.tsx index 78578e317c4..5e1133dab4f 100644 --- a/packages/core/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.tsx +++ b/packages/core/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.tsx @@ -23,7 +23,7 @@ import { gql, type TypedDocumentNode, useMutation, useQuery } from '../../../../ import { CellLink } from '../../../../admin-ui/components' import { PageContainer, HEADER_HEIGHT } from '../../../../admin-ui/components/PageContainer' import { Pagination, PaginationLabel, usePaginationParams } from '../../../../admin-ui/components/Pagination' -import { useList } from '../../../../admin-ui/context' +import { useKeystone, useList } from '../../../../admin-ui/context' import { GraphQLErrorNotice } from '../../../../admin-ui/components/GraphQLErrorNotice' import { Link, useRouter } from '../../../../admin-ui/router' import { useFilter } from '../../../../fields/types/relationship/views/RelationshipSelect' @@ -36,7 +36,7 @@ import { useFilters } from './useFilters' import { useSelectedFields } from './useSelectedFields' import { useSort } from './useSort' -type ListPageProps = { listKey: string } +type ListPageProps = { params: { listKey: string } } type FetchedFieldMeta = { path: string @@ -98,7 +98,7 @@ function useQueryParamsFromLocalStorage (listKey: string) { return x.startsWith('!') || storeableQueries.includes(x) }) - if (!hasSomeQueryParamsWhichAreAboutListPage && router.isReady) { + if (!hasSomeQueryParamsWhichAreAboutListPage) { const queryParamsFromLocalStorage = localStorage.getItem(localStorageKey) let parsed try { @@ -109,7 +109,7 @@ function useQueryParamsFromLocalStorage (listKey: string) { } } }, - [localStorageKey, router.isReady] + [localStorageKey] ) useEffect(() => { let queryParamsToSerialize: Record = {} @@ -128,9 +128,9 @@ function useQueryParamsFromLocalStorage (listKey: string) { return { resetToDefaults } } -export const getListPage = (props: ListPageProps) => () => - -function ListPage ({ listKey }: ListPageProps) { +export function ListPage ({ params }: ListPageProps) { + const { listsKeyByPath } = useKeystone() + const listKey = listsKeyByPath[params.listKey] const list = useList(listKey) const { query, push } = useRouter() @@ -575,6 +575,7 @@ function ListTable ({ orderableFields: Set }) { const list = useList(listKey) + const { adminPath } = useKeystone() const { query } = useRouter() const shouldShowLinkIcon = !list.fields[selectedFields.keys().next().value].views.Cell.supportsLinkTo @@ -697,8 +698,8 @@ function ListTable ({ alignItems: 'center', justifyContent: 'center', }} - href={`/${list.path}/[id]`} - as={`/${list.path}/${encodeURIComponent(itemId)}`} + href={`${adminPath}/${list.path}/[id]`} + as={`${adminPath}/${list.path}/${encodeURIComponent(itemId)}`} > @@ -718,8 +719,8 @@ function ListTable ({ {i === 0 && Cell.supportsLinkTo ? ( {errorMessage} @@ -740,8 +741,8 @@ function ListTable ({ linkTo={ i === 0 && Cell.supportsLinkTo ? { - href: `/${list.path}/[id]`, - as: `/${list.path}/${encodeURIComponent(itemId)}`, + href: `${adminPath}/${list.path}/[id]`, + as: `${adminPath}/${list.path}/${encodeURIComponent(itemId)}`, } : undefined } diff --git a/packages/core/src/admin-ui/components/CreateButtonLink.tsx b/packages/core/src/admin-ui/components/CreateButtonLink.tsx index f3a7c2e1ef8..10fe9165ef1 100644 --- a/packages/core/src/admin-ui/components/CreateButtonLink.tsx +++ b/packages/core/src/admin-ui/components/CreateButtonLink.tsx @@ -4,8 +4,10 @@ import { Button } from '@keystone-ui/button' import { jsx } from '@keystone-ui/core' import type { ListMeta } from '../../types' import { Link } from '../router' +import { useKeystone } from '../context' export function CreateButtonLink (props: { list: ListMeta }) { + const { adminPath } = useKeystone() return ( diff --git a/packages/core/src/fields/types/relationship/views/index.tsx b/packages/core/src/fields/types/relationship/views/index.tsx index e094d555905..ef1c6bc8dba 100644 --- a/packages/core/src/fields/types/relationship/views/index.tsx +++ b/packages/core/src/fields/types/relationship/views/index.tsx @@ -34,6 +34,7 @@ function LinkToRelatedItems ({ list: ListMeta refFieldKey?: string }) { + const { adminPath } = useKeystone() function constructQuery ({ refFieldKey, itemId, @@ -60,14 +61,14 @@ function LinkToRelatedItems ({ if (value.kind === 'many') { const query = constructQuery({ refFieldKey, value, itemId }) return ( - ) } return ( - ) @@ -249,7 +250,7 @@ export const Field = ({ export const Cell: CellComponent = ({ field, item }) => { const list = useList(field.refListKey) const { colors } = useTheme() - + const { adminPath } = useKeystone() if (field.display === 'count') { const count = item[`${field.path}Count`] ?? 0 return ( @@ -277,7 +278,7 @@ export const Cell: CellComponent = ({ field, item }) => { {displayItems.map((item, index) => ( {!!index ? ', ' : ''} - + {item.label || item.id} @@ -288,6 +289,7 @@ export const Cell: CellComponent = ({ field, item }) => { } export const CardValue: CardValueComponent = ({ field, item }) => { + const { adminPath } = useKeystone() const list = useList(field.refListKey) const data = item[field.path] return ( @@ -298,7 +300,7 @@ export const CardValue: CardValueComponent = ({ field, item } .map((item, index) => ( {!!index ? ', ' : ''} - + {item.label || item.id} diff --git a/packages/core/src/lib/createAdminUIMiddleware.ts b/packages/core/src/lib/createAdminUIMiddleware.ts index 151136791ec..728d198c139 100644 --- a/packages/core/src/lib/createAdminUIMiddleware.ts +++ b/packages/core/src/lib/createAdminUIMiddleware.ts @@ -31,7 +31,7 @@ export function createAdminUIMiddlewareWithNextApp ( return async (req: express.Request, res: express.Response) => { const { pathname } = url.parse(req.url) - if (pathname?.startsWith(`${basePath}/_next`) || pathname?.startsWith(`${basePath}/__next`)) { + if (pathname?.startsWith(`/_next`) || pathname?.startsWith(`/__next`)) { return handle(req, res) } diff --git a/packages/core/src/lib/createSystem.ts b/packages/core/src/lib/createSystem.ts index 78b039d8627..fd6c16da3e0 100644 --- a/packages/core/src/lib/createSystem.ts +++ b/packages/core/src/lib/createSystem.ts @@ -1,4 +1,5 @@ import path from 'node:path' +import fs from 'node:fs' import { randomBytes } from 'node:crypto' import { type KeystoneConfig, @@ -49,9 +50,15 @@ export function getSystemPaths (cwd: string, config: KeystoneConfig | __Resolved ? path.join(cwd, config.graphql.schemaPath) // TODO: enforce initConfig before getSystemPaths : path.join(cwd, 'schema.graphql') + const srcPath = path.join(cwd, 'src') + const hasSrc = fs.existsSync(srcPath) + // remove leading `/` if present + const basePath = config.ui?.basePath?.replace(/^\//, '') ?? '' + const adminPath = path.join(cwd, hasSrc ? 'src' : '', `app/${basePath || '(admin)'}`) + return { config: getBuiltKeystoneConfigurationPath(cwd), - admin: path.join(cwd, '.keystone/admin'), + admin: adminPath, prisma: prismaClientPath ?? '@prisma/client', types: { relativePrismaPath, @@ -61,6 +68,7 @@ export function getSystemPaths (cwd: string, config: KeystoneConfig | __Resolved prisma: builtPrismaPath, graphql: builtGraphqlPath, }, + hasSrc, } } @@ -201,7 +209,7 @@ function formatUrl (provider: __ResolvedKeystoneConfig['db']['provider'], url: s } export function createSystem (config_: KeystoneConfig) { - const config = resolveDefaults(config_) + const config = resolveDefaults(config_, true) const lists = initialiseLists(config) const adminMeta = createAdminMeta(config, lists) const graphQLSchema = createGraphQLSchema(config, lists, adminMeta, false) diff --git a/packages/core/src/lib/defaults.ts b/packages/core/src/lib/defaults.ts index 8ca6b760f6f..b93982d5290 100644 --- a/packages/core/src/lib/defaults.ts +++ b/packages/core/src/lib/defaults.ts @@ -59,7 +59,7 @@ function defaultIsAccessAllowed ({ session, sessionStrategy }: KeystoneContext) async function noop () {} function identity (x: T) { return x } -export function resolveDefaults (config: KeystoneConfig): __ResolvedKeystoneConfig { +export function resolveDefaults (config: KeystoneConfig, inject = false): __ResolvedKeystoneConfig { if (!['postgresql', 'sqlite', 'mysql'].includes(config.db.provider)) { throw new TypeError(`"db.provider" only supports "sqlite", "postgresql" or "mysql"`) } @@ -109,7 +109,7 @@ export function resolveDefaults (config: schemaPath: config.graphql?.schemaPath ?? 'schema.graphql', extendGraphqlSchema: config.graphql?.extendGraphqlSchema ?? ((s) => s), }, - lists: injectDefaults(config, defaultIdField), + lists: inject ? injectDefaults(config, defaultIdField) : config.lists, server: { maxFileSize: 200 * 1024 * 1024, // 200 MiB extendExpressApp: config.server?.extendExpressApp ?? noop, @@ -130,6 +130,7 @@ export function resolveDefaults (config: getAdditionalFiles: config.ui?.getAdditionalFiles ?? [], pageMiddleware: config.ui?.pageMiddleware ?? noop, publicPages:config.ui?.publicPages ?? [], + tsx: config.ui?.tsx ?? true, }, } } diff --git a/packages/core/src/lib/id-field.ts b/packages/core/src/lib/id-field.ts index 0ea90ddcaae..5522c0eefc9 100644 --- a/packages/core/src/lib/id-field.ts +++ b/packages/core/src/lib/id-field.ts @@ -6,7 +6,8 @@ import { fieldType, orderDirectionEnum, } from '../types' -import { graphql } from '..' +import { graphql } from '../types/schema' + import { userInputError } from './core/graphql-errors' type IDType = string | number | null diff --git a/packages/core/src/schema.ts b/packages/core/src/schema.ts index 4d4fba24148..2117692bfbb 100644 --- a/packages/core/src/schema.ts +++ b/packages/core/src/schema.ts @@ -1,3 +1,4 @@ +import { resolveDefaults } from './lib/defaults' import { type BaseFields, type BaseKeystoneTypeInfo, @@ -7,7 +8,7 @@ import { } from './types' export function config (config: KeystoneConfig) { - return config + return resolveDefaults(config) } let i = 0 diff --git a/packages/core/src/scripts/build.ts b/packages/core/src/scripts/build.ts index 14ddbb1f990..46ed9e1df99 100644 --- a/packages/core/src/scripts/build.ts +++ b/packages/core/src/scripts/build.ts @@ -39,11 +39,11 @@ 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( - paths.admin, + cwd, undefined, undefined, undefined, diff --git a/packages/core/src/scripts/cli.ts b/packages/core/src/scripts/cli.ts index 8bda144b5ed..b08afdf8c51 100644 --- a/packages/core/src/scripts/cli.ts +++ b/packages/core/src/scripts/cli.ts @@ -14,6 +14,7 @@ export type Flags = { server: boolean ui: boolean withMigrations: boolean + resetAdmin: boolean } function defaultFlags (flags: Partial, defaults: Partial) { @@ -62,6 +63,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 @@ -83,7 +87,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 74c03b3c71f..07ab5e2ea3d 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>() @@ -267,11 +267,13 @@ export async function dev ( console.log('✨ Generating Admin UI code') const paths = system.getPaths(cwd) - await fsp.rm(paths.admin, { recursive: true, force: true }) - await generateAdminUI(system.config, system.graphQLSchema, system.adminMeta, paths.admin, false) + if (resetAdmin) { + await fsp.rm(paths.admin, { recursive: true, force: true }) + } + await generateAdminUI(system.config, system.graphQLSchema, system.adminMeta, paths.admin, paths.hasSrc, false) console.log('✨ Preparing Admin UI') - nextApp = next({ dev: true, dir: paths.admin }) + nextApp = next({ dev: true, dir: cwd }) await nextApp.prepare() expressServer.use(createAdminUIMiddlewareWithNextApp(system.config, context, nextApp)) console.log(`✅ Admin UI ready`) @@ -334,7 +336,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/packages/core/src/scripts/start.ts b/packages/core/src/scripts/start.ts index 8e9ccdca72f..dc3a50fb9ed 100644 --- a/packages/core/src/scripts/start.ts +++ b/packages/core/src/scripts/start.ts @@ -35,8 +35,8 @@ export async function start ( console.log(`✅ GraphQL API ready`) if (!system.config.ui?.isDisabled && ui) { - console.log('✨ Preparing Admin UI') - const nextApp = next({ dev: false, dir: paths.admin }) + console.log('✨ Preparing Admin UI Next.js') + const nextApp = next({ dev: false, dir: cwd }) await nextApp.prepare() expressServer.use(await createAdminUIMiddlewareWithNextApp(system.config, keystone.context, nextApp)) console.log(`✅ Admin UI ready`) diff --git a/packages/core/src/types/config/index.ts b/packages/core/src/types/config/index.ts index 0e08f70241d..c18ca0441b8 100644 --- a/packages/core/src/types/config/index.ts +++ b/packages/core/src/types/config/index.ts @@ -248,6 +248,8 @@ export type KeystoneConfig MaybePromise<{ kind: 'redirect', to: string } | void> + /** Generate .tsx files instead of .js */ + tsx?: boolean } } @@ -277,8 +279,8 @@ export type __ResolvedKeystoneConfig=0.6.0', teleport: '>=0.2.0'} deprecated: |- You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other. - (For a CapTP with native promises, see @endo/eventual-send and @endo/captp) qs@6.11.0: @@ -14576,14 +14578,14 @@ snapshots: '@graphql-tools/optimize@1.4.0(graphql@16.9.0)': dependencies: graphql: 16.9.0 - tslib: 2.4.1 + tslib: 2.6.3 '@graphql-tools/relay-operation-optimizer@6.5.18(graphql@16.9.0)': dependencies: '@ardatan/relay-compiler': 12.0.0(graphql@16.9.0) '@graphql-tools/utils': 9.2.1(graphql@16.9.0) graphql: 16.9.0 - tslib: 2.4.1 + tslib: 2.6.3 transitivePeerDependencies: - encoding - supports-color @@ -14599,7 +14601,7 @@ snapshots: '@graphql-tools/utils@8.13.1(graphql@16.9.0)': dependencies: graphql: 16.9.0 - tslib: 2.4.1 + tslib: 2.6.3 '@graphql-tools/utils@9.2.1(graphql@16.9.0)': dependencies: @@ -18352,7 +18354,7 @@ snapshots: camel-case@4.1.2: dependencies: pascal-case: 3.1.2 - tslib: 2.4.1 + tslib: 2.6.3 camelcase-keys@6.2.2: dependencies: @@ -18373,7 +18375,7 @@ snapshots: capital-case@1.0.4: dependencies: no-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.3 upper-case-first: 2.0.2 capture-exit@2.0.0: @@ -18436,7 +18438,7 @@ snapshots: path-case: 3.0.4 sentence-case: 3.0.4 snake-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.3 char-regex@1.0.2: {} @@ -18644,7 +18646,7 @@ snapshots: constant-case@3.0.4: dependencies: no-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.3 upper-case: 2.0.2 content-disposition@0.5.4: @@ -20125,7 +20127,7 @@ snapshots: header-case@2.0.4: dependencies: capital-case: 1.0.4 - tslib: 2.4.1 + tslib: 2.6.3 hex-rgb@4.3.0: {} @@ -20440,7 +20442,7 @@ snapshots: is-lower-case@2.0.2: dependencies: - tslib: 2.4.1 + tslib: 2.6.3 is-module@1.0.0: {} @@ -20512,7 +20514,7 @@ snapshots: is-upper-case@2.0.2: dependencies: - tslib: 2.4.1 + tslib: 2.6.3 is-windows@1.0.2: {} @@ -21177,11 +21179,11 @@ snapshots: lower-case-first@2.0.2: dependencies: - tslib: 2.4.1 + tslib: 2.6.3 lower-case@2.0.2: dependencies: - tslib: 2.4.1 + tslib: 2.6.3 lowercase-keys@2.0.0: {} @@ -22584,7 +22586,7 @@ snapshots: param-case@3.0.4: dependencies: dot-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.3 parent-module@1.0.1: dependencies: @@ -22659,7 +22661,7 @@ snapshots: pascal-case@3.1.2: dependencies: no-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.3 pascalcase@0.1.1: {} @@ -22686,7 +22688,7 @@ snapshots: path-case@3.0.4: dependencies: dot-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.3 path-exists@3.0.0: {} @@ -23603,7 +23605,7 @@ snapshots: sentence-case@3.0.4: dependencies: no-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.3 upper-case-first: 2.0.2 serve-static@1.15.0: @@ -23888,7 +23890,7 @@ snapshots: sponge-case@1.0.1: dependencies: - tslib: 2.4.1 + tslib: 2.6.3 sprintf-js@1.0.3: {} @@ -24067,7 +24069,7 @@ snapshots: swap-case@2.0.2: dependencies: - tslib: 2.4.1 + tslib: 2.6.3 symbol-observable@4.0.0: {} @@ -24142,7 +24144,7 @@ snapshots: title-case@3.0.3: dependencies: - tslib: 2.4.1 + tslib: 2.6.3 tmp@0.0.33: dependencies: @@ -24466,11 +24468,11 @@ snapshots: upper-case-first@2.0.2: dependencies: - tslib: 2.4.1 + tslib: 2.6.3 upper-case@2.0.2: dependencies: - tslib: 2.4.1 + tslib: 2.6.3 uri-js@4.4.1: dependencies: diff --git a/tests/admin-ui-tests/live-reloading.test.ts b/tests/admin-ui-tests/live-reloading.test.ts index 597bb509f47..b1c075cc2a6 100644 --- a/tests/admin-ui-tests/live-reloading.test.ts +++ b/tests/admin-ui-tests/live-reloading.test.ts @@ -29,6 +29,8 @@ let ksProcess = 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') @@ -60,7 +62,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/api-tests/fields/types/relationship.test.ts b/tests/api-tests/fields/types/relationship.test.ts index f42a137b089..cad4393ad0c 100644 --- a/tests/api-tests/fields/types/relationship.test.ts +++ b/tests/api-tests/fields/types/relationship.test.ts @@ -24,7 +24,7 @@ function getSchema (field: { }, }), }, - }) + }) as any ).graphQLSchema } @@ -140,7 +140,7 @@ describe('Reference errors', () => { config({ db: { url: 'file:./thing.db', provider: 'sqlite' }, lists, - }) + }) as any ).graphQLSchema } 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', }, ], ],