forked from gosignal/keystone
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add computed field * Make field non-filterable or sortable * Fix test * Add isOrderable * Change computed to virtual * Add test * Item never used * Merge remote * Remove filter methods from controller
- Loading branch information
1 parent
640cbd9
commit 6a348b9
Showing
13 changed files
with
297 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
'@keystonejs/app-admin-ui': minor | ||
'@keystonejs/fields': minor | ||
'@keystonejs/keystone': minor | ||
--- | ||
|
||
Added a new field type 'Computed'. This allows creation of fields that return data computed from other field values or outside Keystone. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { Implementation } from '../../Implementation'; | ||
import { MongooseFieldAdapter } from '@keystonejs/adapter-mongoose'; | ||
import { KnexFieldAdapter } from '@keystonejs/adapter-knex'; | ||
import { parseFieldAccess } from '@keystonejs/access-control'; | ||
|
||
export class Virtual extends Implementation { | ||
constructor() { | ||
super(...arguments); | ||
} | ||
|
||
gqlOutputFields() { | ||
return [`${this.path}: ${this.config.graphQLReturnType || `String`}`]; | ||
} | ||
getGqlAuxTypes() { | ||
return this.config.extendGraphQLTypes || []; | ||
} | ||
gqlOutputFieldResolvers() { | ||
return { [`${this.path}`]: this.config.resolver }; | ||
} | ||
gqlQueryInputFields() { | ||
return []; | ||
} | ||
extendAdminMeta(meta) { | ||
return { | ||
...meta, | ||
isOrderable: false, | ||
graphQLSelection: this.config.graphQLReturnFragment || '', | ||
isReadOnly: true, | ||
}; | ||
} | ||
|
||
parseFieldAccess(args) { | ||
const parsedAccess = parseFieldAccess(args); | ||
const fieldDefaults = { create: false, update: false, delete: false }; | ||
return Object.keys(parsedAccess).reduce((prev, schemaName) => { | ||
prev[schemaName] = { ...fieldDefaults, read: parsedAccess[schemaName].read }; | ||
return prev; | ||
}, {}); | ||
} | ||
} | ||
|
||
const CommonTextInterface = superclass => | ||
class extends superclass { | ||
getQueryConditions() { | ||
return {}; | ||
} | ||
}; | ||
|
||
export class MongoVirtualInterface extends CommonTextInterface(MongooseFieldAdapter) { | ||
addToMongooseSchema() {} | ||
} | ||
|
||
export class KnexVirtualInterface extends CommonTextInterface(KnexFieldAdapter) { | ||
constructor() { | ||
super(...arguments); | ||
} | ||
addToTableSchema() {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
<!--[meta] | ||
section: api | ||
subSection: field-types | ||
title: Virtual | ||
[meta]--> | ||
|
||
# Virtual | ||
|
||
## Usage | ||
|
||
If the resolver is a function that returns a string you don't need to define a return type. | ||
|
||
```js | ||
keystone.createList('Example', { | ||
fields: { | ||
firstName: { type: Text }, | ||
lastName: { type: Text }, | ||
name: { | ||
type: Virtual, | ||
resolver: item => (`${item.firstName} ${item.lastName}`) | ||
}; | ||
}, | ||
}, | ||
}); | ||
``` | ||
|
||
If the return type is not a string define a `graphQLReturnType`. | ||
|
||
```js | ||
keystone.createList('Example', { | ||
fields: { | ||
fortyTwo: { | ||
type: Virtual, | ||
graphQLReturnType: `Int`, | ||
resolver: () => 42, | ||
}, | ||
}, | ||
}); | ||
``` | ||
|
||
For more complex types you can define a `graphQLReturnFragment` as well as `extendGraphQLTypes`. Resolver functions can be `async` so you can even fetch data from the file system or an external API: | ||
|
||
```js | ||
keystone.createList('Example', { | ||
fields: { | ||
movies: { | ||
type: Virtual, | ||
extendGraphQLTypes: [`type Movie { title: String, rating: Int }`], | ||
graphQLReturnType: `[Movie]`, | ||
graphQLReturnFragment: `{ | ||
title | ||
rating | ||
}`, | ||
resolver: async () => { | ||
const response = await fetch('http://example.com/api/movies/'); | ||
const data = await response.json(); | ||
return data.map(({ title, rating }) => ({ title, rating })); | ||
}, | ||
}, | ||
}, | ||
}); | ||
``` | ||
|
||
### Config | ||
|
||
| Option | Type | Default | Description | | ||
| ----------------------- | ---------- | ---------- | ----------------------------------------------------------- | | ||
| `resolver` | `Function` | (required) | | | ||
| `graphQLReturnType` | `String` | 'String' | A GraphQL Type String | | ||
| `graphQLReturnFragment` | `String` | '' | A GraphQL Fragment String -required for nested return types | | ||
| `extendGraphQLTypes` | `Array` | [] | An array of custom GraphQL type definitions | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { Virtual, MongoVirtualInterface, KnexVirtualInterface } from './Implementation'; | ||
import { importView } from '@keystonejs/build-field-types'; | ||
|
||
export default { | ||
type: 'Virtual', | ||
implementation: Virtual, | ||
views: { | ||
Controller: importView('./views/Controller'), | ||
Cell: importView('./views/Cell'), | ||
Field: importView('./views/Field'), | ||
Filter: importView('./views/Filter'), | ||
}, | ||
adapters: { | ||
mongoose: MongoVirtualInterface, | ||
knex: KnexVirtualInterface, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import React from 'react'; | ||
|
||
// We don't know what type of data we're getting back from a Virtual-field | ||
// but I'd like to present it as best as possible. | ||
// ToDo: Better presentation for more types of data | ||
|
||
const stringify = data => { | ||
const omitTypename = (key, value) => (key === '__typename' ? undefined : value); | ||
const dataWitoutTypename = JSON.parse(JSON.stringify(data), omitTypename); | ||
return JSON.stringify(dataWitoutTypename, null, 2); | ||
}; | ||
export default ({ data }) => { | ||
if (!data) return null; | ||
|
||
let prettyData = ''; | ||
if (typeof data === 'string') prettyData = data; | ||
else if (typeof data === 'number') prettyData = data; | ||
else if (typeof data === 'object') { | ||
prettyData = <pre>{stringify(data)}</pre>; | ||
} else { | ||
prettyData = <pre>{stringify(data)}</pre>; | ||
} | ||
|
||
return prettyData; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import React from 'react'; | ||
import PrettyData from '../prettyData'; | ||
|
||
export default ({ data }) => { | ||
return <PrettyData data={data} />; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import FieldController from '../../../Controller'; | ||
export default class VirtualController extends FieldController { | ||
getQueryFragment = () => { | ||
return `${this.path}${this.config.graphQLSelection}`; | ||
}; | ||
|
||
getFilterTypes = () => []; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/** @jsx jsx */ | ||
|
||
import { jsx } from '@emotion/core'; | ||
import { Component } from 'react'; | ||
|
||
import { colors, gridSize } from '@arch-ui/theme'; | ||
import { ShieldIcon } from '@arch-ui/icons'; | ||
|
||
import { FieldContainer } from '@arch-ui/fields'; | ||
import PrettyData from '../prettyData'; | ||
|
||
export const FieldLabel = props => { | ||
const accessError = (props.errors || []).find( | ||
error => error instanceof Error && error.name === 'AccessDeniedError' | ||
); | ||
return ( | ||
<span | ||
css={{ | ||
color: colors.N60, | ||
fontSize: '0.9rem', | ||
fontWeight: 500, | ||
paddingBottom: gridSize, | ||
display: 'flex', | ||
flexDirection: 'row', | ||
justifyContent: 'space-between', | ||
}} | ||
htmlFor={props.htmlFor} | ||
> | ||
{props.field.label} | ||
{accessError ? ( | ||
<ShieldIcon title={accessError.message} css={{ color: colors.N20, marginRight: '1em' }} /> | ||
) : null} | ||
</span> | ||
); | ||
}; | ||
|
||
export default class VirtualField extends Component { | ||
onChange = event => { | ||
this.props.onChange(event.target.value); | ||
}; | ||
|
||
render() { | ||
const { field, errors, value: serverValue } = this.props; | ||
const value = serverValue || ''; | ||
const canRead = errors.every( | ||
error => !(error instanceof Error && error.name === 'AccessDeniedError') | ||
); | ||
|
||
return ( | ||
<FieldContainer> | ||
<FieldLabel field={field} errors={errors} /> | ||
<PrettyData data={canRead ? value : undefined} /> | ||
</FieldContainer> | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// @flow | ||
|
||
import React, { Component } from 'react'; | ||
import { Input } from '@arch-ui/input'; | ||
import type { FilterProps } from '../../../types'; | ||
|
||
type Props = FilterProps<string>; | ||
|
||
export default class VirtualFilterView extends Component<Props> { | ||
handleChange = ({ target: { value } }: Object) => { | ||
this.props.onChange(value); | ||
}; | ||
|
||
render() { | ||
const { filter, field, innerRef, value } = this.props; | ||
|
||
if (!filter) return null; | ||
|
||
const placeholder = field.getFilterLabel(filter); | ||
|
||
return ( | ||
<Input onChange={this.handleChange} ref={innerRef} placeholder={placeholder} value={value} /> | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
Some important content 0.100393664270916 | ||
Some important content 0.42365754562902613 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters