Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Templates for Relay frontend #43

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file modified packages/create-graphql/bin/create-graphql
100644 → 100755
Empty file.
68 changes: 68 additions & 0 deletions packages/create-graphql/src/commands/frontend.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import spawn from 'cross-spawn-promise';

function parseOptions(opts) {
const availableOptions = ['add', 'edit', 'list', 'view'];

// Check if any commands was provided
const anyCommandsProvided = Object.keys(opts).some(option =>
availableOptions.indexOf(option) !== -1,
);

let options = opts;

// If not, use the default options
if (!anyCommandsProvided) {
options = {
add: true,
edit: true,
list: true,
view: true,
...options,
};
}

const {
add,
edit,
list,
view,
schema,
} = options;

return {
add: add || false,
edit: edit || false,
list: list || false,
view: view || false,
schema: schema || false,
};
}

function generate(name, options) {
// Parse all arguments
const parsedOptions = parseOptions(options);
// Get only the chose arguments
const chosenOptions = Object.keys(parsedOptions).filter(opt => !!parsedOptions[opt]);

// Check if schema argument has been passed
const schemaIndex = chosenOptions.indexOf('schema');
chosenOptions.forEach(async (option) => {
const payload = [`graphql:${option}`, name];

// If argument schema exists
if (schemaIndex !== -1) {
// Remove the next running option because the schema must be used along with this command
chosenOptions.splice(schemaIndex, 1);

// Push schema to the arguments to send to yeoman
payload.push(parsedOptions.schema);
}

await spawn('yo', payload, {
shell: true,
stdio: 'inherit',
});
});
}

export default generate;
1 change: 1 addition & 0 deletions packages/create-graphql/src/commands/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export init from './init';
export generate from './generate';
export frontend from './frontend';
16 changes: 16 additions & 0 deletions packages/create-graphql/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import pkg from '../package.json';
import {
init,
generate,
frontend,
} from './commands';
import { verifyYeoman } from './utils';

Expand Down Expand Up @@ -37,6 +38,21 @@ program
generate(name, options);
});

program
.command('frontend <name>')
.alias('f')
.option('-a, --add', 'Generate a new Add Form screen')
.option('-e, --edit', 'Generate a new Edit Form screen')
.option('-l, --list', 'Generate a new List screen')
.option('-v, --view', 'Generate a new View for an ObjectType')
.option('--schema <schema.json Path>', 'Generate from a schema.json')
.description('Generate a new frontend file (Add, Edit, List, View)')
.action(async (name, options) => {
await verifyYeoman();

frontend(name, options);
});

program.parse(process.argv);

if (process.argv.length <= 2) {
Expand Down
4 changes: 4 additions & 0 deletions packages/generator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
"generators/mutation",
"generators/test",
"generators/utils.js",
"generators/frontend/add",
"generators/frontend/edit",
"generators/frontend/list",
"generators/frontend/view",
"generators/graphql-logo.js",
"generators/graphqlrc.json"
],
Expand Down
30 changes: 30 additions & 0 deletions packages/generator/src/add/__tests__/AddGenerator.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import helper from 'yeoman-test';
import assert from 'yeoman-assert';
import path from 'path';

import {
getFileContent,
} from '../../../test/helpers';

import { getConfigDir } from '../../utils';

const addGenerator = path.join(__dirname, '..');

it('generate add and add mutation files', async () => {
const folder = await helper.run(addGenerator)
.withArguments('Example')
.toPromise();

const destinationDir = getConfigDir('add');

assert.file([
`${destinationDir}/ExampleAdd.js`, `${destinationDir}/ExampleAddMutation.js`,
]);

const files = {
add: getFileContent(`${folder}/${destinationDir}/ExampleAdd.js`),
addMutation: getFileContent(`${folder}/${destinationDir}/ExampleAddMutation.js`),
};

expect(files).toMatchSnapshot();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`generate add and add mutation files 1`] = `
Object {
"add": "import React, { Component, PropTypes } from 'react';
import Relay from 'react-relay';
import RelayStore from '../../RelayStore';
import { withRouter } from 'react-router';

import ExampleAddMutation from './ExampleAddMutation';

import Form from '../common/Form';

class ExampleAdd extends Component {
static contextTypes = {
showSnackbar: PropTypes.func,
};

fields = [
{
name: 'id',
placeholder: 'ID',
required: true,
},
// TODO - add ObjectType fields here
];

onSubmit = (data) => {
const mutation = new ExampleAddMutation({
viewer: this.props.viewer,
...data,
});

RelayStore.commitUpdate(mutation, {
onSuccess: ({ ExampleAdd }) => {
this.context.showSnackbar({
message: 'Example created successfully!',
});

this.props.router.push(\`/examples/view/\${ExampleAdd.exampleEdge.node.id}\`);
},
onFailure: (failureResponse) => {
this.context.showSnackbar({
message: 'There was an error while trying to create a Example.',
});

console.log('FAIL', failureResponse);
},
});
};

render() {
return (
<div>
<h1 style={styles.title}>
New Example
</h1>
<Form
fields={this.fields}
onSubmit={this.onSubmit}
/>
</div>
);
}
}

const styles = {
form: {
backgroundColor: 'white',
boxShadow: 'rgba(0, 0, 0, 0.056863) 0px 7px 8px, rgba(0, 0, 0, 0.227451) 0px 0px 0px',
borderWidth: 1,
borderStyle: 'solid',
borderColor: '#E7ECEA',
padding: 20,
paddingTop: 50,
},
formContainer: {
display: 'flex',
flexWrap: 'wrap',
},
title: {
fontSize: 25,
fontWeight: 300,
},
actionsContainer: {
display: 'flex',
justifyContent: 'flex-end',
marginTop: 5,
paddingRight: 8,
borderTopStyle: 'solid',
borderTopWidth: 1,
paddingTop: 15,
borderColor: '#ECECEC',
},
formField: {
marginRight: 10,
flex: '1 0 47%',
},
selectField: {
marginRight: 10,
flex: '1 0 48%',
},
};

export default Relay.createContainer(withRouter(ExampleAdd), {
fragments: {
viewer: () => Relay.QL\`
fragment on Viewer {
\${ExampleAddMutation.getFragment('viewer')}
}
\`,
},
});
",
"addMutation": "import Relay from 'react-relay';

export default class ExampleAddMutation extends Relay.Mutation {
static fragments = {
viewer: () => Relay.QL\`
fragment on Viewer {
id
}
\`,
};

getMutation() {
return Relay.QL\`mutation {
ExampleAdd
}\`;
}

getVariables() {
const {
id
// TODO - add mutation input fields here
} = this.props;

return {
id
// TODO - add mutation input fields here
};
}

getFatQuery() {
return Relay.QL\`
fragment on ExampleAddPayload {
exampleEdge
viewer {
examples
}
}
\`;
}

getConfigs() {
return [
{
type: 'RANGE_ADD',
parentName: 'viewer',
parentID: this.props.viewer.id,
connectionName: 'Examples',
edgeName: 'ExampleEdge',
rangeBehaviors: {
'': 'prepend',
},
},
{
type: 'REQUIRED_CHILDREN',
children: [Relay.QL\`
fragment on ExampleAddPayload {
exampleEdge
}
\`],
},
];
}
}
",
}
`;
Loading