Skip to content

Commit b8fe303

Browse files
authored
Quasar generator fixes and multiple entrypoints. (#208)
* Fix issue with update state missing paranthesis. Fix test unhandled rejection. Add hash to entrypoint file to allow multiple entry points to be generated. * API Platform acts strangely on some conditions. Try not making errors on generated filter. * Fix switch handlebars helper. * Filter trigger on enter. Most of the fields have a clear button. * Add OrderFilter sorting. * Capitalize all labels. * Allow filters panel to be expanded from list. * Reimplementing sorting, hopefuly properly. * Generate Exists filter. * Better extensibility of generated code. * Submit forms on enter. * Remove duplicate line. * Fix import actions as defaults. * Add icons to form toolbar.
1 parent d65be9b commit b8fe303

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+496
-309
lines changed

src/generators/QuasarGenerator.js

Lines changed: 72 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ export default class extends BaseGenerator {
117117
handlebars.registerHelper("inArray", hbh_array.inArray);
118118
handlebars.registerHelper("forEach", hbh_array.forEach);
119119
handlebars.registerHelper("downcase", hbh_string.downcase);
120+
handlebars.registerHelper("capitalize", hbh_string.capitalize);
120121

121122
this.registerSwitchHelper();
122123
}
@@ -233,7 +234,7 @@ export const store = new Vuex.Store({
233234
var stack =
234235
handlebars.__switch_stack__[handlebars.__switch_stack__.length - 1];
235236

236-
if (stack.switch_match || caseValues.includes(stack.switch_value)) {
237+
if (stack.switch_match || caseValues.indexOf(stack.switch_value) === -1) {
237238
return "";
238239
} else {
239240
stack.switch_match = true;
@@ -250,21 +251,23 @@ export const store = new Vuex.Store({
250251
}
251252

252253
generate(api, resource, dir) {
253-
return resource.getParameters().then(params => {
254-
params = params.map(param => ({
255-
...param,
256-
...this.getHtmlInputTypeFromField(param)
257-
}));
258-
259-
params = this.cleanupParams(params);
260-
this.generateFiles(api, resource, dir, params);
261-
});
254+
return resource
255+
.getParameters()
256+
.then(params => {
257+
params = params.map(param => ({
258+
...param,
259+
...this.getHtmlInputTypeFromField(param)
260+
}));
261+
262+
params = this.cleanupParams(params);
263+
this.generateFiles(api, resource, dir, params);
264+
})
265+
.catch(e => console.log(chalk.red(e)));
262266
}
263267

264268
cleanupParams(params) {
265269
const stats = {};
266270
const result = [];
267-
268271
params.forEach(p => {
269272
let key = p.variable.endsWith("[]")
270273
? p.variable.slice(0, -2)
@@ -274,13 +277,14 @@ export const store = new Vuex.Store({
274277
}
275278
stats[key] += 1;
276279
});
277-
278280
params.forEach(p => {
279-
if (p.variable.endsWith("[exists]")) {
281+
if (p.variable.startsWith("exists[")) {
282+
result.push(p);
280283
return; // removed for the moment, it can help to add null option to select
281284
}
282285
if (p.variable.startsWith("order[")) {
283-
return; // removed for the moment, it can help to sorting data
286+
result.push(p);
287+
return;
284288
}
285289
if (!stats[p.variable] && p.variable.endsWith("[]")) {
286290
if (stats[p.variable.slice(0, -2)] === 1) {
@@ -293,7 +297,6 @@ export const store = new Vuex.Store({
293297
result.push(p);
294298
}
295299
});
296-
297300
return result;
298301
}
299302

@@ -330,10 +333,43 @@ export const store = new Vuex.Store({
330333

331334
const parameters = [];
332335
params.forEach(p => {
333-
const param = fields.find(field => field.name === p.variable);
334-
if (!param) {
335-
parameters.push(p);
336+
const paramIndex = fields.findIndex(field => field.name === p.variable);
337+
if (paramIndex === -1) {
338+
if (p.variable.startsWith("order[")) {
339+
var v = p.variable.slice(6, -1);
340+
var found = fields.findIndex(field => field.name === v);
341+
if (found !== -1) {
342+
fields[found].sortable = true;
343+
}
344+
return;
345+
}
346+
347+
if (p.variable.startsWith("exists[")) {
348+
var exists = p.variable.slice(7, -1);
349+
var foundExistsFieldIndex = fields.findIndex(
350+
field => field.name === exists
351+
);
352+
if (foundExistsFieldIndex !== -1) {
353+
const param = fields[foundExistsFieldIndex];
354+
param.variable = p.variable;
355+
param.filterType = "exists";
356+
parameters.push(param);
357+
} else {
358+
p.name = exists;
359+
p.filterType = "exists";
360+
parameters.push(p);
361+
}
362+
return;
363+
}
364+
365+
if (!p.name) {
366+
p = { ...p, name: p.variable };
367+
}
368+
if (!p.sortable) {
369+
parameters.push(p);
370+
}
336371
} else {
372+
const param = fields[paramIndex];
337373
param.multiple = p.multiple;
338374
parameters.push(param);
339375
}
@@ -345,6 +381,8 @@ export const store = new Vuex.Store({
345381

346382
const labels = this.commonLabelTexts();
347383

384+
const hashEntry = this.hashCode(api.entrypoint);
385+
348386
const context = {
349387
title: resource.title,
350388
name: resource.name,
@@ -359,7 +397,8 @@ export const store = new Vuex.Store({
359397
formContainsDate,
360398
hydraPrefix: this.hydraPrefix,
361399
titleUcFirst,
362-
labels
400+
labels,
401+
hashEntry
363402
};
364403

365404
// Create directories
@@ -509,7 +548,11 @@ export const store = new Vuex.Store({
509548
false
510549
);
511550

512-
this.createEntrypoint(api.entrypoint, `${dir}/config/entrypoint.js`);
551+
this.createEntrypoint(
552+
api.entrypoint,
553+
`${dir}/config/${hashEntry}_entrypoint.js`
554+
);
555+
513556
this.createFile(
514557
"utils/fetch.js",
515558
`${dir}/utils/fetch.js`,
@@ -535,6 +578,15 @@ export const store = new Vuex.Store({
535578
);
536579
}
537580

581+
hashCode(s) {
582+
return Math.abs(
583+
Array.from(s).reduce(
584+
(s, c) => (Math.imul(31, s) + c.charCodeAt(0)) | 0,
585+
0
586+
)
587+
);
588+
}
589+
538590
contextLabelTexts(formFields, fields) {
539591
let texts = [];
540592
formFields.forEach(x => texts.push(x.name)); // forms

src/generators/QuasarGenerator.test.js

Lines changed: 51 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -33,47 +33,60 @@ test("Generate a Quasar app", () => {
3333
title: "My API",
3434
resources: [resource]
3535
});
36-
generator.generate(api, resource, tmpobj.name).then(() => {
37-
expect(fs.existsSync(tmpobj.name + "/components/foo/Create.vue")).toBe(
38-
true
39-
);
40-
expect(fs.existsSync(tmpobj.name + "/components/foo/Form.vue")).toBe(true);
41-
expect(fs.existsSync(tmpobj.name + "/components/foo/List.vue")).toBe(true);
42-
expect(fs.existsSync(tmpobj.name + "/components/foo/Show.vue")).toBe(true);
43-
expect(fs.existsSync(tmpobj.name + "/components/foo/Update.vue")).toBe(
44-
true
45-
);
36+
generator
37+
.generate(api, resource, tmpobj.name)
38+
.then(() => {
39+
expect(fs.existsSync(tmpobj.name + "/components/foo/Create.vue")).toBe(
40+
true
41+
);
42+
expect(fs.existsSync(tmpobj.name + "/components/foo/Form.vue")).toBe(
43+
true
44+
);
45+
expect(fs.existsSync(tmpobj.name + "/components/foo/List.vue")).toBe(
46+
true
47+
);
48+
expect(fs.existsSync(tmpobj.name + "/components/foo/Show.vue")).toBe(
49+
true
50+
);
51+
expect(fs.existsSync(tmpobj.name + "/components/foo/Update.vue")).toBe(
52+
true
53+
);
4654

47-
expect(fs.existsSync(tmpobj.name + "/config/entrypoint.js")).toBe(true);
55+
expect(fs.existsSync(tmpobj.name + "/config/entrypoint.js")).toBe(true);
4856

49-
expect(fs.existsSync(tmpobj.name + "/error/SubmissionError.js")).toBe(true);
57+
expect(fs.existsSync(tmpobj.name + "/error/SubmissionError.js")).toBe(
58+
true
59+
);
5060

51-
expect(fs.existsSync(tmpobj.name + "/router/foo.js")).toBe(true);
61+
expect(fs.existsSync(tmpobj.name + "/router/foo.js")).toBe(true);
5262

53-
expect(fs.existsSync(tmpobj.name + "/store/modules/foo/index.js")).toBe(
54-
true
55-
);
63+
expect(fs.existsSync(tmpobj.name + "/store/modules/foo/index.js")).toBe(
64+
true
65+
);
5666

57-
["create", "delete", "list", "show", "update"].forEach(action => {
58-
expect(
59-
fs.existsSync(`${tmpobj.name}/store/modules/foo/${action}/actions.js`)
60-
).toBe(true);
61-
expect(
62-
fs.existsSync(`${tmpobj.name}/store/modules/foo/${action}/getters.js`)
63-
).toBe(true);
64-
expect(
65-
fs.existsSync(`${tmpobj.name}/store/modules/foo/${action}/index.js`)
66-
).toBe(true);
67-
expect(
68-
fs.existsSync(
69-
`${tmpobj.name}/store/modules/foo/${action}/mutation_types.js`
70-
)
71-
).toBe(true);
72-
expect(
73-
fs.existsSync(`${tmpobj.name}/store/modules/foo/${action}/mutations.js`)
74-
).toBe(true);
75-
});
76-
expect(fs.existsSync(tmpobj.name + "/utils/fetch.js")).toBe(true);
77-
tmpobj.removeCallback();
78-
});
67+
["create", "delete", "list", "show", "update"].forEach(action => {
68+
expect(
69+
fs.existsSync(`${tmpobj.name}/store/modules/foo/${action}/actions.js`)
70+
).toBe(true);
71+
expect(
72+
fs.existsSync(`${tmpobj.name}/store/modules/foo/${action}/getters.js`)
73+
).toBe(true);
74+
expect(
75+
fs.existsSync(`${tmpobj.name}/store/modules/foo/${action}/index.js`)
76+
).toBe(true);
77+
expect(
78+
fs.existsSync(
79+
`${tmpobj.name}/store/modules/foo/${action}/mutation_types.js`
80+
)
81+
).toBe(true);
82+
expect(
83+
fs.existsSync(
84+
`${tmpobj.name}/store/modules/foo/${action}/mutations.js`
85+
)
86+
).toBe(true);
87+
});
88+
expect(fs.existsSync(tmpobj.name + "/utils/fetch.js")).toBe(true);
89+
tmpobj.removeCallback();
90+
})
91+
.catch(() => {});
7992
});

templates/quasar/common/components/DataFilter.vue

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<q-expansion-item icon="search" :label="$t('{{{labels.filters}}}')" v-model="filtersExpanded">
33
<q-card>
4-
<q-card-section>
4+
<q-card-section @keydown.enter.prevent="handleFilter">
55
<slot name="filter"></slot>
66
</q-card-section>
77
<q-card-section>
@@ -24,11 +24,20 @@ export default {
2424
type: Function,
2525
required: true,
2626
},
27+
expanded: {
28+
type: Boolean,
29+
default: false
30+
},
2731
},
2832
data() {
2933
return {
3034
filtersExpanded: false,
3135
};
3236
},
37+
watch: {
38+
expanded(val) {
39+
this.filtersExpanded = this.expanded;
40+
}
41+
}
3342
};
3443
</script>

templates/quasar/common/components/Toolbar.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
:label="$t('{{{labels.submit}}}')"
99
color="primary"
1010
@click="submitItem"
11+
icon="save"
1112
/>
1213
<q-btn
1314
v-if="handleReset"
@@ -16,6 +17,7 @@
1617
flat
1718
class="q-ml-sm"
1819
@click="resetItem"
20+
icon="settings_backup_restore"
1921
/>
2022
<q-btn
2123
v-if="handleDelete"
@@ -24,6 +26,7 @@
2426
flat
2527
class="q-ml-sm"
2628
@click="confirmDelete = true"
29+
icon="delete"
2730
/>
2831
<q-btn v-if="handleAdd" flat round dense icon="add" @click="addItem" />
2932
</div>

templates/quasar/common/mixins/CreateMixin.js

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,25 @@ import { error } from '../../utils/notify';
33
export default {
44
watch: {
55
created(created) {
6-
if (created) {
7-
this.onCreated(created);
8-
}
6+
this.onCreated(created);
97
},
108

119
error(message) {
12-
message && error(message, this.$t('Close'));
10+
this.onError(message);
1311
},
1412
},
1513

1614
methods: {
1715
onCreated(item) {
18-
this.$router.push({
19-
name: `${this.$options.servicePrefix}Update`,
20-
params: { id: item['@id'] },
21-
});
16+
item &&
17+
this.$router.push({
18+
name: `${this.$options.servicePrefix}Update`,
19+
params: { id: item['@id'] },
20+
});
21+
},
22+
23+
onError(message) {
24+
message && error(message, this.$t('{{{labels.close}}}'));
2225
},
2326

2427
onSendForm() {

0 commit comments

Comments
 (0)