keystone icon indicating copy to clipboard operation
keystone copied to clipboard

[RFC] Full Next.Js support and UI upgrades

Open gautamsi opened this issue 1 year ago • 8 comments

Full Next.JS support

Currently the frontend is hidden away in .keystone/admin folder and generates multiple pages for each list routes. This is not very continent and makes customization very difficult. To overcome this I have proposed use of full Next.Js integration.

Some initial poc done in #9181 .

Goals

  • [ ] Leverage full Next.Js integration instead of isolated instance
  • [ ] Upgrade Next.Js to use App Router with server actions
  • [ ] Code split custom field views instead of bundling them together
  • [ ] Frontend to have less dependency on GraphQL for Administration, this also opens up additional features
  • [ ] upgrade @keystone-ui to be ssr friendly
  • [ ] Decouple Admin-UI and frontend logic to allow use of other frameworks like Remix
  • [ ] Allow selection of relationship fields in UI
  • [ ] Nested filters in UI
  • [ ] Add support for UI Hooks/Extensions
  • [ ] ....TBD (waiting for community feedback)

Using App router will allow theming and customization easily with the Layouts.

Kudos to @junaid33 for initial Next.Js 14 work done in https://github.com/openshiporg/openfront

gautamsi avatar Jun 24 '24 01:06 gautamsi

This looks so good! And adding themes should be a lot easier with this.

I think it would be really powerful if Keystone took the Shadcn/ui approach and let people "copy and paste" the whole Admin UI thru a CLI (or using a simple frontend). They could choose a theme, point to their schema, add an adminPath, and the CLI could build the app pages and layout pages. Then people could really hack away at that code and change almost everything.

I started doing this for Openship 3 and reusing the Fields component instead of building forms all over again is saving me so much time. The props passed to Fields can easily be manipulated to hide certain fields and error handling and validation are all built-in. I even built a EditItemDrawer that makes it easy to edit items on the fly .

Maybe down the line, Apollo client and Prisma can be decoupled and people can plug in React-Query or Drizzle instead thru the CLI and they still get the Admin-UI.

junaid33 avatar Jun 26 '24 08:06 junaid33

Hey @gautamsi and @junaid33 Firstly, thanks for pushing this conversation forward. I haven't had much opportunity to play around with the inner workings of Keystone in a while, but I did get the chance to over the weekend and started playing with this concept of NextJS app directory. I also had a few things in mind, namely:

  • Get a cut-down version of Keystone Context - without NextJS React, Apollo etc etc
  • Have a simplified Admin UI that doesn't require a separate app
  • Upgrade to NextJS 15
  • Ideally not require a GraphQL endpoint to get the AdminUI to work
  • have a composable UI - be able to import forms onto custom pages

I made some decent progress separating Keystone into three packages:

  • Core
  • AdminUI
  • CLI (You can find my branch here: https://github.com/OpenSaasAU/keystone/tree/ks-core-lite)

I took a slightly different approach to the AdminUI - I can see the benefits of generating the whole UI files, but I also think this could be daunting for a new-comer or could get unwieldy with large projects especially when it comes to breaking changes that might require some file regeneration.

What I have been trying out is using NextJS dynamic routes (you can also use getStaticPaths so they are prerendered at build time) this means all the developer needs is a ./app/admin/[[...admin]]/page.tsx and layout.tsx (see https://github.com/OpenSaasAU/keystone/blob/89111eb4f8e441822f6fbc25c582d4e9a471de55/examples/framework-nextjs-app-directory/src/app/(admin)/admin/%5B%5B...adminUI%5D%5D/layout.tsx) - ideally you would pass a keystone context into the page.tsx and do away with Apollo

It would be good to have a progressive customisation. For example, a developer could import a page to a custom route or import a form component into a custom page.

borisno2 avatar Nov 11 '24 10:11 borisno2

I tried running this @borisno2 but could not run, seems like scrip files missing from cli.

gautamsi avatar Nov 12 '24 01:11 gautamsi

Is that in the postinstall for each package? I haven't updated all the examples to use the cli package, just the nextjs-app-directory one.

Also make sure pnpm preconstruct dev runs correctly

borisno2 avatar Nov 12 '24 02:11 borisno2

Hey @gautamsi - did you get my branch working? Did you have any thoughts on the alternative approach?

Keen on hearing @dcousens thoughts on the approach here.

borisno2 avatar Dec 25 '24 20:12 borisno2

@borisno2 unfortunately I could not fix them to run properly. It is good approach though, isolating admin pages under wildcard route is good idea but we have to provide them composable admin pages.

I would prefer to give full flexibility.

gautamsi avatar Dec 25 '24 22:12 gautamsi

I agree composable admin pages are ideal for offering full flexibility.

ie it would be awesome to do things like...

For a custom create/update form in a page

// some/custom/create/page.tsx
import { getSessionContext } from 'keystone/context'
import CustomHeader from 'src/components/CustomHeader'
import CustomHeaderTitle from 'src/components/CustomHeaderTitle'
import CreateForm from '@keystone-6/admin-ui/components/CreateForm'

export default function MyCustomCreatePage() {
  const context = getSessionContext()
  return (
  <>
      <CustomHeader>
        <CustomHeaderTitle>Create Item</CustomHeaderTitle>
      </CustomHeader>
      <CreateForm list="Item" context={context} />
  </>
  )
}

Or for a list:

import { getSessionContext } from 'keystone/context'
import CustomHeader from 'src/components/CustomHeader'
import CustomHeaderTitle from 'src/components/CustomHeaderTitle'
import List from '@keystone-6/admin-ui/components/CreateForm'

export default function MyCustomCreatePage() {
  const context = getSessionContext()
  return (
    <>
      <CustomHeader>
        <CustomHeaderTitle>Create Item</CustomHeaderTitle>
      </CustomHeader>
      <List list="Item" context={context} />
    </>
  )
}

But I think it is also important to offer a progressive customisation approach for easy onboarding. ie you might start with the wildcard route approach to give a full default admin ui. but maybe use the Form approach above to replace certain pages or for more non-admin type pages.

borisno2 avatar Dec 26 '24 01:12 borisno2

I am all for wildcard route, but need @dcousens to weigh in, also this could be next step after my PR is merged.

One other things I noticed that with #9253 and keystar ui we are also getting rid of statically generated admin meta, which will also change some approach with full Next 15 SSR.

gautamsi avatar Dec 26 '24 04:12 gautamsi

I have searched for information regarding this, and this is the closest thread I found related to my question. I am creating custom pages and want to import data into them, but get context or session don't work there. Is there a way to do it. I find strange that custom pages wouldn't allow import data into them. Would be grateful if someone could clarify that.

jj-matos avatar Nov 06 '25 21:11 jj-matos

if you are creating custom pages with the keystone released version you have to look into app router example

gautamsi avatar Nov 07 '25 17:11 gautamsi