First pass at /callbacks dashboard

This commit is contained in:
Sacha Greif 2017-10-21 15:58:02 +09:00
parent 59ec044d04
commit 50943f01de
10 changed files with 365 additions and 104 deletions

View file

@ -4,10 +4,15 @@ Default mutations
*/
import { newMutation, editMutation, removeMutation, Utils } from 'meteor/vulcan:lib';
import { registerCallback, newMutation, editMutation, removeMutation, Utils } from 'meteor/vulcan:lib';
import Users from 'meteor/vulcan:users';
export const getDefaultMutations = (collectionName, options = {}) => ({
export const getDefaultMutations = (collectionName, options = {}) => {
// register callbacks for documentation purposes
registerCollectionCallbacks(collectionName);
return {
// mutation for inserting a new document
@ -120,5 +125,92 @@ export const getDefaultMutations = (collectionName, options = {}) => ({
},
},
}
};
const registerCollectionCallbacks = collectionName => {
collectionName = collectionName.toLowerCase();
registerCallback({
name: `${collectionName}.new.validate`,
arguments: [{document: 'The document being inserted'}, {currentUser: 'The current user'}, {validationErrors: 'An object that can be used to accumulate validation errors'}],
runs: 'sync',
returns: 'document',
description: `Validate a document before insertion (can be skipped when inserting directly on server).`
});
registerCallback({
name: `${collectionName}.new.before`,
arguments: [{document: 'The document being inserted'}, {currentUser: 'The current user'}],
runs: 'sync',
returns: 'document',
description: `Perform operations on a new document before it's inserted in the database.`
});
registerCallback({
name: `${collectionName}.new.after`,
arguments: [{document: 'The document being inserted'}, {currentUser: 'The current user'}],
runs: 'sync',
returns: 'document',
description: `Perform operations on a new document after it's inserted in the database but *before* the mutation returns it.`
});
registerCallback({
name: `${collectionName}.new.async`,
arguments: [{document: 'The document being inserted'}, {currentUser: 'The current user'}, {collection: 'The collection the document belongs to'}],
runs: 'async',
returns: null,
description: `Perform operations on a new document after it's inserted in the database asynchronously.`
});
registerCallback({
name: `${collectionName}.edit.validate`,
arguments: [{modifier: 'The MongoDB modifier'}, {document: 'The document being inserted'}, {currentUser: 'The current user'}, {validationErrors: 'An object that can be used to accumulate validation errors'}],
runs: 'sync',
returns: 'modifier',
description: `Validate a document before update (can be skipped when updating directly on server).`
});
registerCallback({
name: `${collectionName}.edit.before`,
arguments: [{modifier: 'The MongoDB modifier'}, {document: 'The document being inserted'}, {currentUser: 'The current user'}],
runs: 'sync',
returns: 'modifier',
description: `Perform operations on a document before it's updated in the database.`
});
registerCallback({
name: `${collectionName}.edit.after`,
arguments: [{document: 'The document being inserted'}, {currentUser: 'The current user'}],
runs: 'sync',
returns: 'document',
description: `Perform operations on a document after it's updated in the database but *before* the mutation returns it.`
});
registerCallback({
name: `${collectionName}.edit.async`,
arguments: [{document: 'The document being updated'}, {currentUser: 'The current user'}, {collection: 'The collection the document belongs to'}],
runs: 'async',
returns: null,
description: `Perform operations on a document after it's updated in the database asynchronously.`
});
registerCallback({
name: `${collectionName}.remove.validate`,
arguments: [{document: 'The document being removed'}, {currentUser: 'The current user'}, {validationErrors: 'An object that can be used to accumulate validation errors'}],
runs: 'sync',
returns: 'document',
description: `Validate a document before removal (can be skipped when removing directly on server).`
});
registerCallback({
name: `${collectionName}.remove.before`,
arguments: [{document: 'The document being removed'}, {currentUser: 'The current user'}],
runs: 'sync',
returns: null,
description: `Perform operations on a document before it's removed from the database.`
});
registerCallback({
name: `${collectionName}.new.async`,
arguments: [{document: 'The document being removed'}, {currentUser: 'The current user'}, {collection: 'The collection the document belongs to'}],
runs: 'async',
returns: null,
description: `Perform operations on a document after it's removed from the database asynchronously.`
});
}

View file

@ -0,0 +1,31 @@
import React from 'react';
import { FormattedMessage } from 'meteor/vulcan:i18n';
import { registerComponent, Components } from 'meteor/vulcan:lib';
import Callbacks from '../modules/callbacks/collection.js';
const CallbacksName = ({ document }) =>
<strong>{document.name}</strong>
const CallbacksDashboard = props =>
<div className="settings">
<Components.Datatable
showSearch={false}
showEdit={false}
collection={Callbacks}
options={{
fragmentName: 'CallbacksFragment'
}}
columns={[
{ name: 'name', component: CallbacksName },
'arguments',
'returns',
'runs',
'description',
'hooks',
]}
/>
</div>
registerComponent('Callbacks', CallbacksDashboard);
export default Callbacks;

View file

@ -0,0 +1,19 @@
import { createCollection } from 'meteor/vulcan:lib';
import schema from './schema.js';
import resolvers from './resolvers.js';
import './fragments.js';
const Callbacks = createCollection({
collectionName: 'Callbacks',
typeName: 'Callback',
schema,
resolvers,
});
export default Callbacks;

View file

@ -0,0 +1,12 @@
import { registerFragment } from 'meteor/vulcan:lib';
registerFragment(`
fragment CallbacksFragment on Callback {
name
arguments
runs
returns
description
hooks
}
`);

View file

@ -0,0 +1,26 @@
import { CallbackHooks } from 'meteor/vulcan:lib';
const resolvers = {
list: {
name: 'CallbacksList',
resolver(root, {terms = {}}, context, info) {
return CallbackHooks;
},
},
total: {
name: 'CallbacksTotal',
resolver(root, {terms = {}}, context) {
return CallbackHooks.length;
},
}
};
export default resolvers;

View file

@ -0,0 +1,63 @@
import { Callbacks } from 'meteor/vulcan:lib';
const schema = {
name: {
label: 'Name',
type: String,
viewableBy: ['admins'],
},
arguments: {
label: 'Arguments',
type: Array,
viewableBy: ['admins'],
},
'arguments.$': {
type: Object,
viewableBy: ['admins'],
},
runs: {
label: 'Runs',
type: String,
viewableBy: ['admins'],
},
returns: {
label: 'Should Return',
type: String,
viewableBy: ['admins'],
},
description: {
label: 'Description',
type: String,
viewableBy: ['admins'],
},
hooks: {
label: 'Hooks',
type: Array,
viewableBy: ['admins'],
resolveAs: {
type: '[String]',
resolver: (callback) => {
console.log('// callback')
console.log(callback)
console.log(Callbacks[callback.name])
if (Callbacks[callback.name]) {
const callbacks = Callbacks[callback.name].map(f => f.name);
console.log(callbacks)
return callbacks;
} else {
return [];
}
}
}
}
};
export default schema;

View file

@ -2,3 +2,4 @@
import '../components/Emails.jsx';
import '../components/Groups.jsx';
import '../components/Settings.jsx';
import '../components/Callbacks.jsx';

View file

@ -4,6 +4,7 @@ addRoute([
// {name: 'cheatsheet', path: '/cheatsheet', component: import('./components/Cheatsheet.jsx')},
{name: 'groups', path: '/groups', component: () => getDynamicComponent(import('../components/Groups.jsx'))},
{name: 'settings', path: '/settings', componentName: 'Settings'},
{name: 'settings', path: '/callbacks', componentName: 'Callbacks'},
// {name: 'emails', path: '/emails', component: () => getDynamicComponent(import('./components/Emails.jsx'))},
{name: 'emails', path: '/emails', componentName: 'Emails'},
]);

View file

@ -1,11 +1,26 @@
import { debug } from './debug.js';
/**
* @summary A list of all registered callback hooks
*/
export const CallbackHooks = [];
/**
* @summary Callback hooks provide an easy way to add extra steps to common operations.
* @namespace Callbacks
*/
export const Callbacks = {};
/**
* @summary Register a callback
* @param {String} hook - The name of the hook
* @param {Function} callback - The callback function
*/
export const registerCallback = function (callback) {
CallbackHooks.push(callback);
};
/**
* @summary Add a callback function to a hook
* @param {String} hook - The name of the hook

View file

@ -220,6 +220,7 @@ export const removeMutation = async ({ collection, documentId, currentUser, vali
}
}
await runCallbacks(`${collectionName}.remove.before`, document, currentUser);
await runCallbacks(`${collectionName}.remove.sync`, document, currentUser);
collection.remove(documentId);