Skip to content
Merged
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
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"chalk": "^2.1.0",
"commander": "^2.9.0",
"handlebars": "^4.0.6",
"handlebars-helpers": "^0.9.8",
"isomorphic-fetch": "^2.2.1",
"mkdirp": "^0.5.1",
"sprintf-js": "^1.1.1"
Expand All @@ -44,7 +45,7 @@
"lint": "eslint src",
"build": "babel src -d lib --ignore '*.test.js'",
"watch": "babel --watch src -d lib --ignore '*.test.js'",
"test-gen": "rm -rf ./tmp && npm run build && ./lib/index.js https://demo.api-platform.com ./tmp/react && ./lib/index.js https://demo.api-platform.com ./tmp/react-native -g react-native && ./lib/index.js https://demo.api-platform.com ./tmp/vue -g vue",
"test-gen": "rm -rf ./tmp && npm run build && ./lib/index.js https://demo.api-platform.com ./tmp/react && ./lib/index.js https://demo.api-platform.com ./tmp/react-native -g react-native && ./lib/index.js https://demo.api-platform.com ./tmp/vue -g vue && ./lib/index.js https://demo.api-platform.com ./tmp/admin-on-rest -g admin-on-rest",
"test-gen-env": "rm -rf ./tmp && npm run build && API_PLATFORM_CLIENT_GENERATOR_ENTRYPOINT=https://demo.api-platform.com API_PLATFORM_CLIENT_GENERATOR_OUTPUT=./tmp ./lib/index.js"
},
"bin": {
Expand Down
2 changes: 2 additions & 0 deletions resource.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import React from 'react'
import { Resource, Delete } from 'admin-on-rest'
3 changes: 3 additions & 0 deletions src/generators.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import AdminOnRestGenerator from './generators/AdminOnRestGenerator';
import ReactGenerator from './generators/ReactGenerator';
import ReactNativeGenerator from './generators/ReactNativeGenerator';
import TypescriptInterfaceGenerator from './generators/TypescriptInterfaceGenerator';
Expand All @@ -9,6 +10,8 @@ function wrap (cl) {

export default function generators (generator = 'react') {
switch (generator) {
case 'admin-on-rest':
return wrap(AdminOnRestGenerator);
case 'react':
return wrap(ReactGenerator);
case 'react-native':
Expand Down
61 changes: 61 additions & 0 deletions src/generators/AdminOnRestGenerator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import fs from 'fs';
import BaseGenerator from './BaseGenerator';
import handlebars from 'handlebars';
import hbh_comparison from 'handlebars-helpers/lib/comparison';

export default class extends BaseGenerator {
constructor(params) {
super(params);

this.registerTemplates(`admin-on-rest/`, [
'components/foo.js',
'config/foo.js',
'resources/foo.js',
'resource-import.js',
]);

handlebars.registerHelper('compare', hbh_comparison.compare);
}

help(resource) {
console.log('Code for the "%s" resource type has been generated!', resource.title);
}

appendFile(template, dest, context = {}) {
fs.appendFileSync(dest, this.templates[template](context));
}

generate(api, resource, dir) {
const lc = resource.title.toLowerCase();
const titleUcFirst = resource.title.charAt(0).toUpperCase() + resource.title.slice(1);

const context = {
title: resource.title,
name: resource.name,
lc,
uc: resource.title.toUpperCase(),
fields: resource.readableFields,
formFields: this.buildFields(resource.writableFields),
hydraPrefix: this.hydraPrefix,
titleUcFirst,
};

// Create directories
// These directories may already exist
for (let dir of [`${dir}/config`, `${dir}/resources`, `${dir}/components/`]) {
this.createDir(dir, false);
}

for (let pattern of [
'components/%s.js',
'config/%s.js',
'resources/%s.js',
]) {
this.createFileFromPattern(pattern, dir, lc, context)
}

this.appendFile('resource-import.js', `${dir}/resource-import.js`, context);

this.createEntrypoint(api.entrypoint, `${dir}/config/_entrypoint.js`)
}
}
44 changes: 44 additions & 0 deletions src/generators/AdminOnRestGenerator.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import Api from '@api-platform/api-doc-parser/lib/Api';
import Resource from '@api-platform/api-doc-parser/lib/Resource';
import Field from '@api-platform/api-doc-parser/lib/Field';
import fs from 'fs';
import tmp from 'tmp';
import AdminOnRestGenerator from './AdminOnRestGenerator';


test('Generate a Admin On Rest app', () => {
const generator = new AdminOnRestGenerator({hydraPrefix: 'hydra:', templateDirectory: `${__dirname}/../../templates`});
const tmpobj = tmp.dirSync({unsafeCleanup: true});

const fields = [new Field('bar', {
id: 'http://schema.org/url',
range: 'http://www.w3.org/2001/XMLSchema#string',
reference: null,
required: true,
description: 'An URL'
})];
const resource = new Resource('abc', 'http://example.com/foos', {
id: 'foo',
title: 'Foo',
readableFields: fields,
writableFields: fields
});
const api = new Api('http://example.com', {
entrypoint: 'http://example.com:8080',
title: 'My API',
resources: [resource]
});
generator.generate(api, resource, tmpobj.name);

expect(fs.existsSync(tmpobj.name+'/config/_entrypoint.js'), true);

expect(fs.existsSync(tmpobj.name+'/components/abc.js'), true);

expect(fs.existsSync(tmpobj.name+'/config/abc.js'), true);

expect(fs.existsSync(tmpobj.name+'/resources/abc.js'), true);

expect(fs.existsSync(tmpobj.name+'/resource-import.js'), true);

tmpobj.removeCallback();
});
3 changes: 3 additions & 0 deletions src/generators/BaseGenerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ export default class {
case 'http://www.w3.org/2001/XMLSchema#time':
return {type: 'time'};

case 'http://www.w3.org/2001/XMLSchema#dateTime':
return {type: 'dateTime'};

default:
return {type: 'text'};
}
Expand Down
2 changes: 1 addition & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ program
.usage('entrypoint outputDirectory')
.option('-r, --resource [resourceName]', 'Generate CRUD for the given resource')
.option('-p, --hydra-prefix [hydraPrefix]', 'The hydra prefix used by the API', 'hydra:')
.option('-g, --generator [generator]', 'The generator to use, one of "react", "react-native", "vue"', 'react')
.option('-g, --generator [generator]', 'The generator to use, one of "react", "react-native", "vue", "admin-on-rest"', 'react')
.option('-t, --template-directory [templateDirectory]', 'The templates directory base to use. Final directory will be ${templateDirectory}/${generator}', `${__dirname}/../templates/`)
.parse(process.argv);

Expand Down
106 changes: 106 additions & 0 deletions templates/admin-on-rest/components/foo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import React from 'react';
import {CardActions} from 'material-ui/Card';
import {
List, Datagrid, Edit, Create, Show, SimpleShowLayout, SimpleForm,
DateField, TextField,
TextInput, DateInput,
EditButton,ShowButton, DeleteButton, RefreshButton, ListButton, CreateButton
} from 'admin-on-rest';
import {configList, configEdit, configCreate, configShow} from '../config/{{{lc}}}';

export const {{title}}List = (props) => (
<List
actions={<{{title}}ListActions/>}
{...props}
>
<Datagrid>
{{#each fields}}
{configList.{{name}} && <TextField source="{{{name}}}" />}
{{/each}}
{configList.buttons.show && <ShowButton />}
{configList.buttons.edit && <EditButton />}
{configList.buttons.delete && <DeleteButton />}
</Datagrid>
</List>
);

const {{title}}Title = ({record}) => {
return <span>{{title}} {record && record.id ? ` : ${record.id}` : ''}</span>;
};

export const {{title}}Edit = (props) => (
<Edit
actions={<{{title}}EditActions/>}
title={<{{title}}Title />}
{...props}
>
<SimpleForm>
{{#each formFields}}
{{#compare type "==" "dateTime" }}
{configEdit.{{name}} && <DateInput source="{{{name}}}" />}
{{else}}
{configEdit.{{name}} && <TextInput source="{{{name}}}" />}
{{/compare}}
{{/each}}
</SimpleForm>
</Edit>
);

export const {{title}}Create = (props) => (
<Create title='Create a {{{title}}}' {...props}>
<SimpleForm>
{{#each formFields}}
{{#compare type "==" "dateTime" }}
{configCreate.{{name}} && <DateField source="{{{name}}}" />}
{{else}}
{configCreate.{{name}} && <TextInput source="{{{name}}}" />}
{{/compare}}
{{/each}}
</SimpleForm>
</Create>
);

export const {{title}}Show = (props) => (
<Show
actions={<{{title}}ShowActions/>}
title={<{{title}}Title />}
{...props}
>
<SimpleShowLayout>
{{#each fields}}
{configShow.{{name}} && <TextField source="{{{name}}}" />}
{{/each}}
</SimpleShowLayout>
</Show>
);

const cardActionStyle = {
zIndex: 2,
display: 'inline-block',
float: 'right',
};

const {{title}}ListActions = ({basePath, data}) => (
<CardActions style={cardActionStyle}>
{configList.buttons.create && <CreateButton basePath={basePath} />}
{configList.buttons.refresh && <RefreshButton basePath={basePath} record={data} />}
</CardActions>
);

const {{title}}ShowActions = ({basePath, data}) => (
<CardActions style={cardActionStyle}>
{configShow.buttons.edit && <EditButton basePath={basePath} record={data}/>}
{configShow.buttons.list && <ListButton basePath={basePath}/>}
{configShow.buttons.delete && <DeleteButton basePath={basePath} record={data}/>}
{configShow.buttons.refresh && <RefreshButton basePath={basePath} record={data}/>}
</CardActions>
);

const {{title}}EditActions = ({basePath, data}) => (
<CardActions style={cardActionStyle}>
{configShow.buttons.show && <ShowButton basePath={basePath} record={data}/>}
{configShow.buttons.list && <ListButton basePath={basePath}/>}
{configShow.buttons.delete && <DeleteButton basePath={basePath} record={data}/>}
{configShow.buttons.refresh && <RefreshButton basePath={basePath} record={data}/>}
</CardActions>
);
49 changes: 49 additions & 0 deletions templates/admin-on-rest/config/foo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
export const configList = {
'@id': true,
{{#each fields}}
{{{ name }}}: true,
{{/each}}
buttons: {
show: true,
edit: true,
create: true,
refresh: true,
delete: true,
}
}

export const configEdit = {
'@id': true,
{{#each fields}}
{{{ name }}}: true,
{{/each}}
buttons: {
show: true,
list: true,
delete: true,
refresh: true,
}
}

export const configCreate = {
'@id': true,
{{#each fields}}
{{{ name }}}: true,
{{/each}}
buttons: {
list: true,
}
}

export const configShow = {
'@id': true,
{{#each fields}}
{{{ name }}}: true,
{{/each}}
buttons: {
edit: true,
list: true,
delete: true,
refresh: true,
}
}
1 change: 1 addition & 0 deletions templates/admin-on-rest/resource-import.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as {{lc}} } from './resources/{{{lc}}}';
15 changes: 15 additions & 0 deletions templates/admin-on-rest/resources/foo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react'
import { Resource, Delete } from 'admin-on-rest'
import { {{title}}Create, {{title}}Edit, {{title}}List, {{title}}Show } from '../components/{{{lc}}}';

export default (
<Resource
key='{{{name}}}'
name='{{{name}}}'
list={ {{title}}List }
create={ {{title}}Create }
edit={ {{title}}Edit }
show={ {{title}}Show }
remove={ Delete }
/>
);
Loading