Skip to content

Commit 26fba58

Browse files
authored
feat: add mercure to vue.js template (#313)
1 parent b9555f7 commit 26fba58

35 files changed

+348
-83
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ jobs:
2727
- run: yarn test-gen
2828
- run: yarn test-next-app
2929
- run: yarn test-react-app
30+
- run: yarn test-vue-app
3031
- run: yarn test-gen-env
3132
- run: yarn test-gen-openapi3
3233
- run: yarn check

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@
6565
"test-gen-custom": "rm -rf ./tmp && yarn build && babel src/generators/ReactGenerator.js src/generators/BaseGenerator.js -d ./tmp/gens && cp -r ./templates/react ./templates/react-common ./templates/entrypoint.js ./tmp/gens && ./lib/index.js https://demo.api-platform.com ./tmp/react-custom -g \"$(pwd)/tmp/gens/ReactGenerator.js\" -t ./tmp/gens",
6666
"test-gen-env": "rm -rf ./tmp && yarn build && API_PLATFORM_CLIENT_GENERATOR_ENTRYPOINT=https://demo.api-platform.com API_PLATFORM_CLIENT_GENERATOR_OUTPUT=./tmp ./lib/index.js",
6767
"test-react-app": "rm -rf ./tmp/app && mkdir -p ./tmp/app && yarn create react-app ./tmp/app/reactapp && yarn --cwd ./tmp/app/reactapp add react-router-dom@5 redux redux-thunk react-redux redux-form connected-react-router && cp -R ./tmp/react/* ./tmp/app/reactapp/src && cp ./templates/react/index.js ./tmp/app/reactapp/src && start-server-and-test 'BROWSER=none yarn --cwd ./tmp/app/reactapp start' http://127.0.0.1:3000/books/ 'yarn playwright test'",
68-
"test-next-app": "rm -rf ./tmp/app && mkdir -p ./tmp/app && yarn create next-app --typescript ./tmp/app/next && yarn --cwd ./tmp/app/next add isomorphic-unfetch formik react-query && cp -R ./tmp/next/* ./tmp/app/next && rm ./tmp/app/next/pages/index.tsx && rm -rf ./tmp/app/next/pages/api && yarn --cwd ./tmp/app/next build && start-server-and-test 'yarn --cwd ./tmp/app/next start' http://127.0.0.1:3000/books/ 'yarn playwright test'"
68+
"test-next-app": "rm -rf ./tmp/app && mkdir -p ./tmp/app && yarn create next-app --typescript ./tmp/app/next && yarn --cwd ./tmp/app/next add isomorphic-unfetch formik react-query && cp -R ./tmp/next/* ./tmp/app/next && rm ./tmp/app/next/pages/index.tsx && rm -rf ./tmp/app/next/pages/api && yarn --cwd ./tmp/app/next build && start-server-and-test 'yarn --cwd ./tmp/app/next start' http://127.0.0.1:3000/books/ 'yarn playwright test'",
69+
"test-vue-app": "rm -rf ./tmp/app && mkdir -p ./tmp/app && cd ./tmp/app && npm init -y vue@2 -- --router vue && cd ../.. && yarn --cwd ./tmp/app/vue add vuex@3 vuex-map-fields lodash && cp -R ./tmp/vue/* ./tmp/app/vue/src && cp ./templates/vue/main.js ./tmp/app/vue/src && yarn --cwd ./tmp/app/vue build && start-server-and-test 'yarn --cwd ./tmp/app/vue vite preview --host 127.0.0.1 --port 3000' http://127.0.0.1:3000/books/ 'yarn playwright test'"
6970
},
7071
"lint-staged": {
7172
"src/**/*.js": "yarn lint --fix"

src/generators/ReactGenerator.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ export default class extends BaseGenerator {
55
constructor(params) {
66
super(params);
77

8+
this.registerTemplates("common/", [
9+
// utils
10+
"utils/mercure.js",
11+
]);
12+
813
this.registerTemplates("react-common/", [
914
// actions
1015
"actions/foo/create.js",
@@ -130,6 +135,7 @@ combineReducers({ ${titleLc},/* ... */ }),
130135
context,
131136
false
132137
);
138+
this.createFile("utils/mercure.js", `${dir}/utils/mercure.js`);
133139

134140
this.createEntrypoint(api.entrypoint, `${dir}/config/entrypoint.js`);
135141
}

src/generators/ReactNativeGenerator.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ export default class extends BaseGenerator {
1313
return options.inverse(this);
1414
});
1515

16+
this.registerTemplates("common/", [
17+
// utils
18+
"utils/mercure.js",
19+
]);
20+
1621
this.registerTemplates(`react-common/`, [
1722
// actions
1823
"actions/foo/create.js",
@@ -133,6 +138,7 @@ combineReducers({ ${titleLc}, /* ... */ }),
133138

134139
[
135140
"utils/dataAccess.js",
141+
"utils/mercure.js",
136142
"utils/helpers.js",
137143
"components/Spinner.js",
138144
"components/Confirm.js",

src/generators/VueGenerator.js

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ export default class extends BaseGenerator {
55
constructor(params) {
66
super(params);
77

8+
this.registerTemplates("common/", [
9+
// utils
10+
"utils/mercure.js",
11+
]);
12+
813
this.registerTemplates(`vue/`, [
914
// modules
1015
"store/modules/foo/index.js",
@@ -36,6 +41,10 @@ export default class extends BaseGenerator {
3641
"components/foo/Update.vue",
3742
"components/foo/Show.vue",
3843

44+
// mixins
45+
"mixins/ItemWatcher.js",
46+
"mixins/ListWatcher.js",
47+
3948
// routes
4049
"router/foo.js",
4150

@@ -102,9 +111,13 @@ export const store = new Vuex.Store({
102111

103112
// Create directories
104113
// These directories may already exist
105-
[`${dir}/config`, `${dir}/error`, `${dir}/router`, `${dir}/utils`].forEach(
106-
(dir) => this.createDir(dir, false)
107-
);
114+
[
115+
`${dir}/config`,
116+
`${dir}/error`,
117+
`${dir}/mixins`,
118+
`${dir}/router`,
119+
`${dir}/utils`,
120+
].forEach((dir) => this.createDir(dir, false));
108121

109122
[
110123
`${dir}/store/modules/${lc}`,
@@ -153,6 +166,10 @@ export const store = new Vuex.Store({
153166
this.createFileFromPattern(pattern, dir, lc, context)
154167
);
155168

169+
for (const file of ["mixins/ItemWatcher.js", "mixins/ListWatcher.js"]) {
170+
this.createFile(file, `${dir}/${file}`);
171+
}
172+
156173
// error
157174
this.createFile(
158175
"error/SubmissionError.js",
@@ -174,5 +191,6 @@ export const store = new Vuex.Store({
174191
{ hydraPrefix: this.hydraPrefix },
175192
false
176193
);
194+
this.createFile("utils/mercure.js", `${dir}/utils/mercure.js`);
177195
}
178196
}

templates/common/utils/mercure.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { ENTRYPOINT } from "../config/entrypoint";
2+
3+
export const mercureSubscribe = (hubURL, topics, setData) => {
4+
const url = new URL(hubURL, ENTRYPOINT);
5+
topics.forEach(topic =>
6+
url.searchParams.append("topic", (new URL(topic, ENTRYPOINT)).toString())
7+
);
8+
const eventSource = new EventSource(url.toString());
9+
eventSource.addEventListener("message", (event) => setData(JSON.parse(event.data)));
10+
11+
return eventSource;
12+
}
13+
14+
export const extractHubURL = (response) => {
15+
const linkHeader = response.headers.get('Link');
16+
if (!linkHeader) return null;
17+
18+
const matches = linkHeader.match(
19+
/<([^>]+)>;\s+rel=(?:mercure|"[^"]*mercure[^"]*")/
20+
);
21+
22+
return matches && matches[1] ? new URL(matches[1], ENTRYPOINT) : null;
23+
}

templates/react-common/actions/foo/list.js

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
1-
import {
2-
fetch,
3-
normalize,
4-
extractHubURL,
5-
mercureSubscribe as subscribe
6-
} from '../../utils/dataAccess';
1+
import { fetch, normalize } from '../../utils/dataAccess';
2+
import { extractHubURL, mercureSubscribe as subscribe } from "../../utils/mercure";
73
import { success as deleteSuccess } from './delete';
84

95
export function error(error) {
@@ -61,11 +57,9 @@ export function reset(eventSource) {
6157

6258
export function mercureSubscribe(hubURL, topics) {
6359
return dispatch => {
64-
const eventSource = subscribe(hubURL, topics);
60+
const eventSource = subscribe(hubURL, topics, data =>
61+
dispatch(mercureMessage(normalize(data))));
6562
dispatch(mercureOpen(eventSource));
66-
eventSource.addEventListener('message', event =>
67-
dispatch(mercureMessage(normalize(JSON.parse(event.data))))
68-
);
6963
};
7064
}
7165

templates/react-common/actions/foo/show.js

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
1-
import {
2-
fetch,
3-
extractHubURL,
4-
normalize,
5-
mercureSubscribe as subscribe
6-
} from '../../utils/dataAccess';
1+
import { fetch, normalize } from '../../utils/dataAccess';
2+
import { extractHubURL, mercureSubscribe as subscribe } from "../../utils/mercure";
73

84
export function error(error) {
95
return { type: '{{{uc}}}_SHOW_ERROR', error };
@@ -54,11 +50,9 @@ export function reset(eventSource) {
5450

5551
export function mercureSubscribe(hubURL, topic) {
5652
return dispatch => {
57-
const eventSource = subscribe(hubURL, [topic]);
53+
const eventSource = subscribe(hubURL, [topic], data =>
54+
dispatch(mercureMessage(normalize(data))));
5855
dispatch(mercureOpen(eventSource));
59-
eventSource.addEventListener('message', event =>
60-
dispatch(mercureMessage(normalize(JSON.parse(event.data))))
61-
);
6256
};
6357
}
6458

templates/react-common/actions/foo/update.js

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
import { SubmissionError } from 'redux-form';
2-
import {
3-
fetch,
4-
extractHubURL,
5-
normalize,
6-
mercureSubscribe as subscribe
7-
} from '../../utils/dataAccess';
2+
import { fetch, normalize } from '../../utils/dataAccess';
3+
import { extractHubURL, mercureSubscribe as subscribe } from "../../utils/mercure";
84
import { success as createSuccess } from './create';
95
import { loading, error } from './delete';
106

@@ -107,11 +103,9 @@ export function reset(eventSource) {
107103

108104
export function mercureSubscribe(hubURL, topic) {
109105
return dispatch => {
110-
const eventSource = subscribe(hubURL, [topic]);
106+
const eventSource = subscribe(hubURL, [topic], data =>
107+
dispatch(mercureMessage(normalize(data))));
111108
dispatch(mercureOpen(eventSource));
112-
eventSource.addEventListener('message', event =>
113-
dispatch(mercureMessage(normalize(JSON.parse(event.data))))
114-
);
115109
};
116110
}
117111

templates/react-common/utils/dataAccess.js

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,6 @@ export function fetch(id, options = {}) {
4646
});
4747
}
4848

49-
export function mercureSubscribe(url, topics) {
50-
topics.forEach(topic =>
51-
url.searchParams.append('topic', new URL(topic, ENTRYPOINT))
52-
);
53-
54-
return new EventSource(url.toString());
55-
}
56-
5749
export function normalize(data) {
5850
if (has(data, 'hydra:member')) {
5951
// Normalize items in collections
@@ -70,14 +62,3 @@ export function normalize(data) {
7062
: get(value, '@id', value)
7163
);
7264
}
73-
74-
export function extractHubURL(response) {
75-
const linkHeader = response.headers.get('Link');
76-
if (!linkHeader) return null;
77-
78-
const matches = linkHeader.match(
79-
/<([^>]+)>;\s+rel=(?:mercure|"[^"]*mercure[^"]*")/
80-
);
81-
82-
return matches && matches[1] ? new URL(matches[1], ENTRYPOINT) : null;
83-
}

templates/vue/components/foo/Create.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<div>
3-
<h1>New {{{title}}}</h1>
3+
<h1>Create {{{title}}}</h1>
44

55
<div
66
v-if="isLoading"
@@ -29,7 +29,7 @@
2929
<script>
3030
import { createHelpers } from 'vuex-map-fields';
3131
import { mapActions } from 'vuex';
32-
import {{{titleUcFirst}}}Form from './Form';
32+
import {{{titleUcFirst}}}Form from './Form.vue';
3333
3434
const { mapFields } = createHelpers({
3535
getterType: '{{{lc}}}/create/getField',

templates/vue/components/foo/List.vue

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
<div
99
v-if="deletedItem"
1010
class="alert alert-success">\{{ deletedItem['@id'] }} deleted.</div>
11+
<div
12+
v-if="mercureDeletedItem"
13+
class="alert alert-success">\{{ mercureDeletedItem['@id'] }} deleted by another user.</div>
1114
<div
1215
v-if="error"
1316
class="alert alert-danger">\{{ error }}</div>
@@ -21,7 +24,7 @@
2124
<table class="table table-responsive table-striped table-hover">
2225
<thead>
2326
<tr>
24-
<th>Id</th>
27+
<th>id</th>
2528
{{#each fields}}
2629
<th>{{name}}</th>
2730
{{/each }}
@@ -119,18 +122,27 @@
119122
<script>
120123
import { mapActions } from 'vuex';
121124
import { mapFields } from 'vuex-map-fields';
125+
import ListWatcher from '../../mixins/ListWatcher';
126+
import * as types from '../../store/modules/{{{lc}}}/list/mutation_types'
127+
import * as delTypes from '../../store/modules/{{{lc}}}/delete/mutation_types';
122128
123129
export default {
130+
mixins: [ListWatcher],
124131
computed: {
125132
...mapFields('{{{lc}}}/del', {
126133
deletedItem: 'deleted',
134+
mercureDeletedItem: 'mercureDeleted',
127135
}),
128136
...mapFields('{{{lc}}}/list', {
129137
error: 'error',
130138
items: 'items',
139+
hubUrl: 'hubUrl',
131140
isLoading: 'isLoading',
132141
view: 'view',
133142
}),
143+
itemUpdateMutation: () => `{{{lc}}}/list/${types.UPDATE_ITEM}`,
144+
itemDeleteMutation: () => `{{{lc}}}/list/${types.DELETE_ITEM}`,
145+
itemMercureDeletedMutation: () => `{{{lc}}}/del/${delTypes.{{{uc}}}_DELETE_MERCURE_SET_DELETED}`,
134146
},
135147
136148
mounted() {

templates/vue/components/foo/Show.vue

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<div>
3-
<h1>Show \{{ item && item['@id'] }}</h1>
3+
<h1>Show Book \{{ item && item['@id'] }}</h1>
44

55
<div
66
v-if="isLoading"
@@ -56,24 +56,52 @@
5656
</router-link>
5757
<button
5858
class="btn btn-danger"
59-
@click="deleteItem(item)">Delete</button>
59+
@click="del">Delete</button>
6060
</div>
6161
</template>
6262

6363
<script>
6464
import { mapActions } from 'vuex';
6565
import { mapFields } from 'vuex-map-fields';
66+
import ItemWatcher from '../../mixins/ItemWatcher';
67+
import * as types from '../../store/modules/{{{lc}}}/show/mutation_types';
68+
import * as delTypes from '../../store/modules/{{{lc}}}/delete/mutation_types';
6669
6770
export default {
71+
mixins: [ItemWatcher],
6872
computed: {
6973
...mapFields('{{{lc}}}/del', {
7074
deleteError: 'error',
75+
deleted: 'deleted',
76+
mercureDeleted: 'mercureDeleted',
7177
}),
7278
...mapFields('{{{lc}}}/show', {
7379
error: 'error',
7480
isLoading: 'isLoading',
7581
item: 'retrieved',
82+
hubUrl: 'hubUrl',
7683
}),
84+
itemUpdateMutation: () =>`{{{lc}}}/show/${types.{{{uc}}}_SHOW_SET_RETRIEVED}`,
85+
itemMercureDeletedMutation: () => `{{{lc}}}/del/${delTypes.{{{uc}}}_DELETE_MERCURE_SET_DELETED}`,
86+
},
87+
88+
watch: {
89+
// eslint-disable-next-line object-shorthand,func-names
90+
deleted: function(deleted) {
91+
if (!deleted) {
92+
return;
93+
}
94+
95+
this.$router.push({ name: '{{{titleUcFirst}}}List' });
96+
},
97+
// eslint-disable-next-line object-shorthand,func-names
98+
mercureDeleted: function(deleted) {
99+
if (!deleted) {
100+
return;
101+
}
102+
103+
this.$router.push({ name: '{{{titleUcFirst}}}List' });
104+
},
77105
},
78106
79107
beforeDestroy () {
@@ -86,14 +114,14 @@ export default {
86114
87115
methods: {
88116
...mapActions({
89-
del: '{{{lc}}}/del/del',
117+
deleteItem: '{{{lc}}}/del/del',
90118
reset: '{{{lc}}}/show/reset',
91119
retrieve: '{{{lc}}}/show/retrieve',
92120
}),
93121
94-
deleteItem (item) {
95-
if (window.confirm('Are you sure you want to delete this item?')) {
96-
this.del(item).then(() => this.$router.push({ name: '{{{titleUcFirst}}}List' }));
122+
del() {
123+
if (window.confirm('Are you sure you want to delete this {{{lc}}}?')) {
124+
this.deleteItem(this.item);
97125
}
98126
},
99127
},

0 commit comments

Comments
 (0)