keystonejs / keystone Goto Github PK
View Code? Open in Web Editor NEWThe most powerful headless CMS for Node.js — built with GraphQL and React
Home Page: https://keystonejs.com
License: MIT License
The most powerful headless CMS for Node.js — built with GraphQL and React
Home Page: https://keystonejs.com
License: MIT License
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")
}
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
Cypress has been updated to 3.1, we're on 2.1
Changelog: https://docs.cypress.io/guides/references/changelog.html#3-0-0
@timleslie / @dominikwilkowski either of you interested in picking this up?
WIP: Details to come
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.
The GraphQL endpoints do this validation for us. Here, we are circumventing those checks and blindly pushing data into the database. We should be more strict about validating it before we do.
See https://github.com/opencrud/opencrud
... it looks like the Prisma team have turned their API (which we have loosely been following anyway) into a complete open spec - seems like a great idea for Keystone to implement it 👍
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',
});
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.
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 } })
select-filter-tests
)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:
@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)Field
UI ComponentWe did a lot of work on CSRF in Keystone 4; we should consider that in terms of Keystone 5, GraphQL, and current best practice.
@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:
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.
Related to #135.
The v4 implementation [...] did some nice stats collection too, which we logged out to the console when it was executed as part of an upgrade script: https://github.com/keystonejs/keystone-classic/blob/0caf792a89e46853aeffb5e23444f436423cf2f3/lib/core/createItems.js#L326
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 😁
Needs:
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:
Other types that were brought up:
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.
... 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.
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:
In terms of client-side libraries, I'd like to use date-fns unless there's a compelling reason to use something else.
i.e
{
type: 'Text',
implementation: Text,
views: {
Field: path.resolve(__dirname, './views/Field'),
Cell: path.resolve(__dirname, './views/Cell'),
},
}
"*****"
from the back-end soon)linkTo
prop, which would cause them to render a react-router linkoptions
meta and render that instead of the value
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.
Happy to pick setting up a CI process for this.
What are some of the things we'd like?
Super nice to haves
Feel free to suggest more things and I'll pick it up soon
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.
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.
See keystonejs/keystone-5#81 for context
@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.
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.
Setting fetchPolicy="cache-and-network"
fixes it in the short run here: https://github.com/keystonejs/keystone-5/blob/master/packages/fields/types/Relationship/views/Field.js#L43
Pressing enter won't submit the changes
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.
I assume at this point its the cloudinary field not knowing any of its secrets. Will add them as env vars to circle and go from there.
The error is not very helpful: https://circleci.com/gh/keystonejs/keystone-5/434
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:
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/...
Ie; this is currently impossible:
keystone.createItems({
Users: [{
name: 'Jess',
}],
Posts: [{
title: 'Hello world',
author: ??? // How do I relate to the user?
}],
});
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:
We should be able to support, at least, read-only lists and items.
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.
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:
bolt start
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.
To finish implementing Relationships, we need to:
id
of relationship field values, and don't just expecting a stringThe 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.
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.
See keystonejs/keystone-5#81 for context
AND
/OR
filtering: keystonejs/keystone-5#224A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.