Giter Club home page Giter Club logo

keystone's Introduction

Keystone: The superpowered CMS for developers



Keystone helps you build faster and scale further than any other CMS or App Framework. Describe your schema, and get a powerful GraphQL API & beautiful Management UI for your content and data.

No boilerplate or bootstrapping – just elegant APIs to help you ship the code that matters without sacrificing the flexibility or power of a bespoke back-end.

Contents

Usage & Documentation

Keystone 6 is published to npm under the @keystone-6/* namespace.

You can find our extended documentation on our website, but some quick links that might be helpful:

  • Read Why Keystone to learn about our vision and what's in the box.
  • Getting Started walks you through first steps with the create-keystone-app CLI.
  • Our Examples contain a growing collection of projects you can run locally to learn more about a Keystone feature.
  • An API Reference contains the details on Keystone's foundational building blocks.
  • Some Guides offer practical walkthroughs on how to build with those blocks.

💡 While our API Reference is generally complete, we are are still working hard on increasing the fidelity of our guides and examples. If you have an example you'd like see, please open a GitHub discussion!

Our @keystone-6/* packages are written for the Node Maintenance and Active LTS versions of Node; and our continuous integration seamlessly tracks that. You may have success with Node versions that are Pending or End-of-Life, but you may have problems too.

Looking for Keystone 5?

The Keystone 5 codebase is now in maintenance mode and lives at keystonejs/keystone-5. For more information read Keystone 5 and beyond.

Enjoying Keystone?

Interested in what's new?

For a birds-eye view of what the Keystone project is working towards, check out our Roadmap.

Feedback

Share your thoughts and feature requests on Slack (preferred) or Twitter. Bugfixes and issues always welcome.

Versioning

Keystone follows semver.

Code of Conduct

Keystone adheres to the Contributor Covenant Code of Conduct.

Security

For vulnerability reporting, please refer to our security policy.

License

Thinkmill

Copyright (c) 2023 Thinkmill Labs Pty Ltd. Licensed under the MIT License.

keystone's People

Contributors

allcontributors[bot] avatar bartduisters avatar bladey avatar borisno2 avatar dcousens avatar dependabot[bot] avatar dominikwilkowski avatar emmatown avatar gautamsi avatar github-actions[bot] avatar gwyneplaine avatar jedwatson avatar jesstelford avatar jordanoverbye avatar jossmac avatar keystonejs-release-bot avatar madebymike avatar mikehazell avatar molomby avatar nathsimpson avatar noviny avatar raveling avatar renovate[bot] avatar sarneaud avatar seandoylegit avatar simonswiss avatar singharmani avatar ticidesign avatar timleslie avatar vultraz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

keystone's Issues

Add deploy hooks to ci

Happy to pick setting up a CI process for this.

What are some of the things we'd like?

  • Run linting
  • Make some tests? ;P (Jest / Ava?)

Super nice to haves

  • Deploy the frontend somewhere
    • Maybe have all static front ends point to a the same demo backend? Maybe that wont work because we really need to be generating most of that...
  • deploy backend preview to heroku?

Feel free to suggest more things and I'll pick it up soon

Big Ideas

Just wanted to put down a list of the things that we never did / could get around to in Keystone 4 and earlier, that it would be good to tackle up front in Keystone 5 and make sure we've got the right architecture and ideas to deliver them.

Relationships: Negation of filter

See keystonejs/keystone-5#81 for context

Could we support a negative version of the nested filter clause? (i.e "items that aren't linked to { conditions }")

We could do, eg; user_not: WhereUserInput. Would that be the same as negating the nested fields?

allPosts(where: { author: { name_contains: 'Je', awesomeness_gt: 10 } })

is equivalent to...

allPosts(where: { author_not: { name_not_contains: 'Je', awesomeness_lte: 10 } })

Add support for custom pages / views in the Admin UI

@lukebatchelor thought this one might interest you.

I've been thinking we should make it so you can plug in custom routes/pages/views into the Admin UI. While there's a bit to design / spec for this, a good place to start would be moving the new style-guide that @jossmac has been working on in the Admin UI into the test-project as a proof of concept.

As a really draft idea (feel free to challenge / iterate on this):

const admin = new AdminUI(keystone, {
  views: [
    {
      route: '/style-guide' // ends up being mounted at /admin/style-guide
      label: 'Style Guide', // label in the top nav bar
      view: './admin/views/StyleGuide', // path to the React component that we inject
    }
  ]
});

Another thing to consider would be how we can plug in custom pieces of UI into existing views, like the Home Page / Items List / Item Details. Ideally, we could add a button to the homepage linking to the style guide... not sure the best way to design the plugin API for that yet though. Maybe some "slots" concept...

In any case the API could change pretty easily, getting something in place that integrates with the build process is a good first step.

More pagination options

We currently support two pagination options on List queries:

  • first: Int (limits the number of items returned)
  • skip: Int (skips that many items from the start, based on the sort criteria)

In addition, if we're hoping to get close to API-compatible with graph.cool / Prisma we should add support for additional pagination options in the List GraphQL APIs:

  • last: Int (reverse of first)
  • after: ID (alternative to skip, starts after the provided ID based on sort criteria)
  • before: ID (reverse of after)

I'm not sure if these are easy/possible to implement with MongoDB so it may be a Postgres-adapter specific thing.

Add a WYSIWYG HTML field

This would be fun to add early on, even though behind the scenes it's just another Text field.

We should try and create a really great content authoring experience for Keystone 5, and I've been looking at Slate as the basis for our rich content editor.

It's also a good use of our new ability to have independent field packages.

So this task is to:

  • Create a new package for @keystonejs/field-html-wysiwyg (we shouldn't bundle it by default, because the choice of editor is opinionated, and if you don't need it then let's not add the weight)
  • Get a good default setup of Slate running in the Field UI Component
  • Keep the Implementation of the field simple, separately we'll start extracting common functionality for basic data type fields into shareable packages so we don't keep repeating the code for queries / logic / etc

Relationships: Allow filtering by fields nested more than 1 level deep

See keystonejs/keystone-5#81 for context

Eg, this works:

{
  allCompanies(where: {
    teams: {
      department_contains: 'r&d'
    }
  }) {
    name
    teams {
      department
    }
  }
}

but this is currently an error:

{
  allCompanies(where: {
    teams: {
      members: { name_contains: 'Je' }
    }
  }) {
    name
    teams {
      members {
        name
      }
    }
  }
}

Some things to consider:

  • How well does Mongo support nesting aggregate queries?
  • What's the performance penalty on nesting deeply? Is there an arbitrary / sanity limit we should set?
  • How do we handle infinite recursion?
  • Is the effort worth the payoff? Who actually needs this feature, and can they work around it by doing a multi-step query?

Write Cypress Tests for the Twitter OAuth flow

This might be impossible to make it portable? Who do we login as? What Twitter app do we log into?

Ideally, we'd be able to mock out the Twitter URL and act as an OAuth provider in between... Or something.

Linking IDs for related items when using createItems

Following from #138 and the discussion in #135

I think we should support inserting data directly into relationship fields if the IDs of the items to be related can be known ahead of time. e.g

const category = await keystone.lists.Category.model.findOne({ name: 'Keystone' });
const jed = await keystone.lists.User.model.findOne({ name: 'Jed Watson' });

keystone.createItems({
  Post: [
    { title: 'Keystone 5 Annnouncement', categories: [category.id], author: jed.id  }
  ]
});

Arguably this is possible with the where syntax, but:

If we can do this in the initial phase (i.e don't separate out relationship fields when they contain simple values) then it enables a workaround if the relationship fields are required in the schema.

Add CSRF for Admin UI

We did a lot of work on CSRF in Keystone 4; we should consider that in terms of Keystone 5, GraphQL, and current best practice.

Add custom Views for field type rendering in List view

i.e

{
  type: 'Text',
  implementation: Text,
  views: {
    Field: path.resolve(__dirname, './views/Field'),
    Cell: path.resolve(__dirname, './views/Cell'),
  },
}
  • Password should render in fixed-width font (will receive "*****" from the back-end soon)
  • Text fields should support a linkTo prop, which would cause them to render a react-router link
  • Select fields should look up the label of their value in the options meta and render that instead of the value

Make Admin UI mount path customisable

There are currently a bunch of hard-coded paths that assume the Admin UI is mounted at /admin. The WebServer already takes an adminPath config, but a lot of the UI was scaffolded before meta was being injected by Webpack so it's only implemented on the server.

Acceptance criteria:

  • Set the config adminPath: '/keystone' in the test project, the Admin UI navigation should work as expected but use /keystone/... in all the URLs and links instead of /admin/...

Enforce standardisation of values returned from adapter methods (aka: No more ObjectId)?

The mongoose adapter is currently returning the results directly from mongoose. This includes some mongo-specific data on the object, as well as things like:

{
  id: ObjectId("abc123"),
}

Which makes doing equality checks difficult.

Should we standardise the way data is returned from the adapter methods, so we can get something like this?

{
  id: "abc123",
}

There may be other places where this is an issue, but this is the only one I've seen so far.

Gaps in types

Here is the SDL for a project I'm going to port to Keystone 5:

type Group @model {
  id: ID! @isUnique
  createdAt: DateTime!
  updatedAt: DateTime!

  events: [Event!]! @relation(name: "GroupEvents")
  name: String!
  owners: [User!]! @relation(name: "OwnedGroups")
  about: String @defaultValue(value: "")
  cfps: [CFP!]! @relation(name: "GroupCFPs")
}

type Event @model {
  id: ID! @isUnique
  createdAt: DateTime!
  updatedAt: DateTime!

  group: Group @relation(name: "GroupEvents")
  owners: [User!]! @relation(name: "OwnedEvents")
  name: String!
  details: String!
  startTime: DateTime!
  cfps: [CFP!]! @relation(name: "EventCFPs")
}

type User @model {
  id: ID! @isUnique
  createdAt: DateTime!
  updatedAt: DateTime!

  email: String @isUnique
  password: String

  # NOTE: Not a relation as there can be multiple (past) logins,
  # but we only care about the most recent one for the user
  twitter: TwitterLogin

  name: String @defaultValue(value: "")
  displayName: String @isUnique
  avatar: Upload @relation(name: "UserAvatar")
  bio: String @defaultValue(value: "")

  ownedGroups: [Group!]! @relation(name: "OwnedGroups")
  ownedEvents: [Event!]! @relation(name: "OwnedEvents")
  presentations: [Presentation!]! @relation(name: "UserPresentations")
}

type TwitterLogin @model {
  id: ID! @isUnique
  createdAt: DateTime!
  updatedAt: DateTime!

  accessToken: String
  twitterId: String!
  username: String!

  # NOTE: Not a relation as there can be multiple (past) logins,
  # but we only care about the most recent one for the user
  user: User!
}

type CFP @model {
  id: ID! @isUnique
  createdAt: DateTime!
  updatedAt: DateTime!

  group: Group! @relation(name: "GroupCFPs")
  event: Event @relation(name: "EventCFPs")

  acceptedAt: DateTime
  rejectedAt: DateTime

  presentation: Presentation! @relation(name: "PresentationCFPs")
}

type Presentation @model {
  id: ID! @isUnique
  createdAt: DateTime!
  updatedAt: DateTime!

  cfps: [CFP!]! @relation(name: "PresentationCFPs")
  title: String!
  pitch: String
  description: String
  user: User! @relation(name: "UserPresentations")
}

Add "Create" button + UI to the Item View

We have a generic Create Item modal, which has been integrated into the List View.

We need to add it to the Item view as well to making creating multiple new items easier, since when you create an item it automatically navigates you to the item details view.

The button should be bold and green, and go to the right of the header (where it says {list.label}: {item.name} so that it's placed similarly to the List screen.

Should be as simple as plugging the modal in and adding showCreateModal state + some handlers to the ItemDetails class.

Set up tests

@timleslie assigned this one to you, but feel free to pass it on if you want.

From the top of my head, the test processes we'll want to add are:

  • ESLint
  • Unit Tests (functional, per package)
    • Cover things like creating a new Keystone instance, adding Lists, retrieving meta and GraphQL config
    • Creating a new Admin UI and WebServer
  • Field Type Unit Tests (based on what was set up for Keystone 4)
    • Any functional tests against a field type (e.g. formatting, validation, etc)
    • Seed a generated list with data colocated with the field code, spin up a GraphQL endpoint and assert filters work as expected
  • Integration Tests (initialise test project w/ seed database, use cypress to test against it)
    • Should run through basic nav, check all views load
    • Search, add columns, etc. in the List view
    • Add / edit / delete an Item

We should probably also add some tests for the UI package - maybe Jest based? cc/ @jossmac lmk what you think would be helpful here

While things are in a really prototypey stage I don't think we should be aiming for comprehensive test coverage, but getting all the infrastructure in place would be really useful so we can add tests for different areas as they stabilise, and having smoke tests asap would be really valuable because we're starting to get quite a bit of surface area and manual testing in the Admin UI can easily miss stuff.

Refactor List page into separate components

... it's getting a bit out of control in a single file.

No established pattern for how to do this, feel free to suggest something you think is easy and intuitive but will scale well.

Bug: 400 Network error on /posts page

Not sure what the exact root cause is as once it happens things seem to become a little unpredictable, but the shortest path to reproduction seems to be:

  • run bolt start
  • open admin ui
  • click users
  • search for something: "d"
  • click posts/

I get a 400 error every time from here. Clicking around after that I'll get a mix of responses though, loading screens, 400's or sometimes the actual page.

Nest Filters in GraphQL List queries

Field-specific filters are currently on the top level of the listQuery. They should be nested under a filter key (like graph.cool) or where (like Prisma) key, with a {List}FilterInput type that defines them.

This will require updates to the GraphQL generation code for lists in the core package and the Queries in the admin-ui package.

Relationship support in `createItems`

Ie; this is currently impossible:

keystone.createItems({
  Users: [{
    name: 'Jess',
  }],
  Posts: [{
    title: 'Hello world',
    author: ??? // How do I relate to the user?
  }],
});

Add some order to the cypress tests

I'd like to break off some tests into files so the names are a bit more descriptive.
from:

.
├── fixtures
├── integration
│   ├── adding-data_spec.js
│   ├── load-users-list_spec.js
│   ├── test_project_spec.js
│   └── update-user-attachment_spec.js
├── mock
├── plugins
├── screenshots
├── support
└── videos

to:

.
├── fixtures
├── integration
│   ├── homepage-create-buttons_spec.js
│   ├── local-file-upload_spec.js
│   ├── nav-bar_spec.js
│   ├── saving-text_spec.js
│   └── welcome-message_spec.js
├── mock
├── plugins
├── screenshots
├── support
└── videos

Retain state of pagination, visible columns and filters in the List view route

Right now, it's a pretty poor user experience navigating back to the list view from an item if you had selected columns, applied search or filters, or traversed pages because it completely forgets where you were.

We need to lift that state out of the List Page component into the route query string

Not sure the best approach to serialising filters - that can get ugly pretty quick, but it's probably fine to just JSONify the filter state for a first pass. More complex solutions could involve localStorage and hashing the filter set, but that breaks our ability to bookmark / share URLs so require more thought.

OTOH we don't have filters until #94 lands; implementing pagination, column selection and search value should be fairly straight-forward so we can get that in first. Filters are in now! so that's fair game too 😁

Offline Support

We should be able to support, at least, read-only lists and items.

Flaky UI tests on Cypress

There are failing tests and flaky tests on circle CI, particularly related to Cypress.

The flaky tests are currently providing negative value, as time is being wasted during review trying to work out whether the failures are valid on each branch.

This task will investigate the recent failures and disable those tests which are not currently providing positive value.

Add Date / DateTime / Timestamp Fields

We need to add three fields for managing dates to Keystone:

  • Date - just a date, no time or timezone information stored. Good for birthdays / etc. We should probably store this as a string in the YYYY-MM-DD format.
  • DateTime - a date with time and timezone information embedded. Needs more discussion on how to store / etc.
  • Timestamp - a date stored in Epoch time.

The full DateTime field would ideally suit JavaScript + MongoDB + Postgres + GraphQL. The Admin UI should explicitly surface all three parts and let you modify them independently.

Not 100% sure that all three add value, in that DateTime and Timestamp kind of store the same thing, except (I believe) that storing dates in Epoch time strips them of their timezone.

Over to @molomby / @jesstelford / @dominikwilkowski / @timleslie to discuss.

On the client-side, we'll need a few new components:

  • Date Input
  • Time Input
  • Field components for all three

In terms of client-side libraries, I'd like to use date-fns unless there's a compelling reason to use something else.

Filter tests for built in types

  • Text
  • Select - In progress (branch select-filter-tests)
  • Relationship
  • Password
  • File
  • CloudinaryImage (this will be moving out of core)

Implement defaultColumns and defaultSort for Lists

As per Keystone 4, lists should support customising a default set of columns and a default field to sort by in the Admin UI.

These would be specified in the List config:

keystone.createList('User', {
  fields: {
    // ...
  },
  defaultColumns: 'name, email, company',
  defaultSort: 'name',
});

Add all core field types

Capturing this information here from a discussion around it. There is a set of field-types that are basic enough that we would want to build them as part of a base set, before starting to look at more complex field types. This list should be seen as a starting point:

  • Boolean (checkbox): See issue #146 @mikehazell
  • Date
  • Date-time
  • date-time-timezone
  • Number (double, integer, decimal, likely want them all)
  • Id (relationship)
  • Password
  • Select
  • Text

Other types that were brought up:

  • list type (nested lists)
  • text-area
  • geo

List filter UI

Needs:

  • popout with fields --> filter
    • CloudinaryImage
    • File
    • Password
    • Relationship
    • Select
    • Text
  • config for available filters on a given field type
  • ui device for displaying the applied filters
  • query to respect the applied filters

Design System / @arch-ui components

What do we want to achieve with this project?

  • Support Keystone's needs, with an open API that can be easily used elsewhere
  • Reinvigorate the community, and promote contribution

Components

Fields

  • input
  • textarea (?input multiline=true)
  • checkbox
  • radio
  • ?toggle/switch
  • ?range/slider

Layout

  • container
  • fluid group
  • contiguous group (for inputs and buttons)

Modal

  • dialog
  • dropdown menu
  • popover (for selecting filters, columns, etc.)
  • tooltip

Navigation

  • breadcrumbs (item view)
  • pagination (list view)
  • slides (complex intention with limited space)
  • ?tabs

Misc

  • badge
  • button
  • lozenge
  • pill/tag/chip (selected filters from keystone list view)
  • ?segmented control

Progress

  • loading spinner (page load, busy button, etc.)
  • progress bar (image uploading)

Alert

  • message ("saved successfully", "error fetching data")
  • ?toast

Ability to set default columns for list view

As a user I would love to be bale to customize the columns that are shown be default in the admin ui listing as some of the elements it shows on default are not relevant for that specific list.

Update many items modal

We need to build the UI & mutation to update many items from the List view's Manage mode.

@jossmac if you can put the modal UI together then bounce this back to me, I'll take it from there.

Should basically prompt users with a Select full of the fields in the list; when a field is selected, add it to the form so the value can be set.

Audit Relationship fields implementation

To finish implementing Relationships, we need to:

  • Nest the related list type in the GraphQL Schema
  • Implement the resolver for relationship types in the GraphQL Resolvers
  • Update the client-side query that loads relationships for the item and list views so they request the id of relationship field values, and don't just expecting a string
  • Add a custom renderer for Relationship fields in the List view that renders the name and links to the item, for the first 3 items in a relationship (then "... x more")

The last task will rely on having the ability to implement custom cell components ("views") for field types that are used by the List view in the Admin UI, which is technically possible but hasn't been done yet.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.