Skip to content

Instantly share code, notes, and snippets.

@xavxyz
Last active January 13, 2017 05:31
Show Gist options
  • Save xavxyz/65cb4869f709fbf95fd09c66c118b775 to your computer and use it in GitHub Desktop.
Save xavxyz/65cb4869f709fbf95fd09c66c118b775 to your computer and use it in GitHub Desktop.
Over-engineered experiment, yet interesting, on Nova forms and data loading with GraphQL
// custom field on Categories, querying a list of Categories
{
fieldName: 'attachedTeams',
fieldSchema: {
type: [String],
control: Components.CategoriesAttachedTeams,
optional: true,
insertableBy: ['admins'],
editableBy: ['admins'],
viewableBy: ['members'],
resolveAs: 'attachedTeams: [Category]', // I want to access these data
}
},
// ......
// CategoriesEditForm.jsx
<SmartForm
collection={Categories}
documentId={props.category._id}
successCallback={category => {
props.closeCallback();
props.flash(context.intl.formatMessage({id: 'categories.edit_success'}, {name: category.name}), "success");
}}
removeSuccessCallback={({documentId, documentTitle}) => {
props.closeCallback();
props.flash(context.intl.formatMessage({id: 'categories.delete_success'}, {name: documentTitle}), "success");
// context.events.track("category deleted", {_id: documentId});
}}
showRemove={true}
/**
* I want to have the ability to query my custom resolvers here
*/
/>
// ....
// current state of FormWrapper.jsx
// see https://github.com/TelescopeJS/Telescope/blob/devel/packages/nova-forms/lib/FormWrapper.jsx#L67-L80
// fields with resolvers that contain "[" should be treated as arrays of _ids
// TODO: find a cleaner way to handle this
relevantFields = relevantFields.map(fieldName => {
const resolveAs = this.getSchema()[fieldName].resolveAs;
return resolveAs && resolveAs.indexOf('[') > -1 ? `${fieldName}{_id}` : fieldName;
});
// generate fragment based on the fields that can be edited. Note: always add _id.
const queryFragment = gql`
fragment ${fragmentName} on ${this.props.collection.typeName} {
_id
${relevantFields.join('\n')}
}
`
// CategoriesEditForm.jsx modifications
<SmartForm
collection={Categories}
// ...
queryCustomResolverFields={{
attachedTeams: ['name', 'image', 'slug'],
}}
/>
// .......
// FormWrapper.jsx modifications
relevantFields = relevantFields.map(fieldName => {
const resolveAs = this.getSchema()[fieldName].resolveAs;
if (resolveAs && resolveAs.includes('[')) {
let baseFields = ['_id'];
const additionalFields = this.props.queryCustomResolverFields && this.props.queryCustomResolverFields[fieldName] || [];
return `${fieldName}{ ${[...baseFields, ...additionalFields].join(' ')} }`;
} else {
return fieldName;
}
});
// conclusion: it works, but asking for the data is lame:
//
// queryCustomResolverFields={{
// attachedTeams: ['name', 'image', 'slug'],
// }}
// CategoriesEditForm.jsx modifications
<SmartForm
collection={Categories}
// ...
additionnalFragments={{
// youhou 🎉 I'm using directly a gql fragment that I could import from somewhere else!
attachedTeams: gql`
fragment attachedTeams on Category {
_id
name
slug
image
}
`
}}
/>
// FormWrapper.jsx modifications
// fields with resolvers that contain "[" should be treated as arrays of _ids by default, or queried with an additional fragment supplied as a prop
relevantFields = relevantFields.map(fieldName => {
const resolveAs = this.getSchema()[fieldName].resolveAs;
if (resolveAs && resolveAs.includes('[')) {
const additionalFragment = this.props.additionnalFragments && this.props.additionnalFragments[fieldName];
// no additional fragment supplied for this field
if (!additionalFragment) {
return `${fieldName} { _id }`;
}
// there is a fragment supplied, add it to the final query sent
const additionalFragmentBody = additionalFragment.loc.source.body;
additionalFragmentsList.push(additionalFragmentBody);
// add the field name + fragment name to the query sent
const additionalFragmentName = additionalFragment.definitions[0].name.value;
return `${fieldName} { ...${additionalFragmentName} }`;
} else {
return fieldName;
}
});
// generate fragment based on the fields that can be edited. Note: always add _id.
const queryFragment = gql`
fragment ${fragmentName} on ${this.props.collection.typeName} {
_id
${relevantFields.join('\n')}
}
${additionalFragmentsList.join('\n')}
`
// conclusion: it's overcomplicated. let's just add an option to pass a custom query to the form. 🎩
// generate fragment based on the fields that can be edited. Note: always add _id.
const generatedFragment = gql`
fragment ${fragmentName} on ${this.props.collection.typeName} {
_id
${relevantFields.join('\n')}
}
`
// get query & mutation fragment from props or else default to generatedFragment
const queryFragment = this.props.fragment || generatedFragment;
const mutationFragment = this.props.fragment || generatedFragment;
// 🤙
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment