diff --git a/package.json b/package.json index 542619de..7bc79262 100644 --- a/package.json +++ b/package.json @@ -64,10 +64,10 @@ "test-gen-openapi3": "rm -rf ./tmp && yarn build && ENTRYPOINT=https://demo.api-platform.com/docs.json FORMAT=openapi3 ./testgen.sh", "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", "test-gen-env": "rm -rf ./tmp && yarn build && API_PLATFORM_CREATE_CLIENT_ENTRYPOINT=https://demo.api-platform.com API_PLATFORM_CREATE_CLIENT_OUTPUT=./tmp ./lib/index.js", - "test-react-app": "rm -rf ./tmp/app && mkdir -p ./tmp/app && yarn create react-app --template typescript ./tmp/app/reactapp && yarn --cwd ./tmp/app/reactapp add react-router-dom react-hook-form && cp -R ./tmp/react/* ./tmp/app/reactapp/src && cp ./templates/react/index.tsx ./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'", + "test-react-app": "./testapp.sh react", "test-next-app": "./testapp.sh next", "test-vue-app": "./testapp.sh vue", - "test-nuxt-app": "rm -rf ./tmp/app && mkdir -p ./tmp/app && yarn create nuxt-app --answers \"'{\\\"name\\\":\\\"nuxt\\\",\\\"language\\\":\\\"js\\\",\\\"pm\\\":\\\"yarn\\\",\\\"ui\\\":\\\"vuetify\\\",\\\"template\\\":\\\"html\\\",\\\"features\\\":[],\\\"linter\\\":[],\\\"test\\\":\\\"none\\\",\\\"mode\\\":\\\"spa\\\",\\\"target\\\":\\\"static\\\",\\\"devTools\\\":[],\\\"vcs\\\":\\\"none\\\"}'\" ./tmp/app/nuxt && yarn --cwd ./tmp/app/nuxt add moment lodash vuelidate vuex-map-fields && cp -R ./tmp/nuxt/* ./tmp/app/nuxt && NUXT_TELEMETRY_DISABLED=1 yarn --cwd ./tmp/app/nuxt generate && start-server-and-test 'yarn --cwd ./tmp/app/nuxt start --hostname 127.0.0.1' http://127.0.0.1:3000/books/ 'yarn playwright test'" + "test-nuxt-app": "./testapp.sh nuxt" }, "lint-staged": { "src/**/*.js": "yarn lint --fix" diff --git a/src/generators/QuasarGenerator.js b/src/generators/QuasarGenerator.js index 17de8425..756876bc 100644 --- a/src/generators/QuasarGenerator.js +++ b/src/generators/QuasarGenerator.js @@ -1,7 +1,6 @@ import chalk from "chalk"; import handlebars from "handlebars"; import hbh_comparison from "handlebars-helpers/lib/comparison.js"; -import hbh_array from "handlebars-helpers/lib/array.js"; import hbh_string from "handlebars-helpers/lib/string.js"; import BaseGenerator from "./BaseGenerator.js"; @@ -9,117 +8,79 @@ export default class extends BaseGenerator { constructor(params) { super(params); - this.registerTemplates(`quasar/`, [ - // modules - "store/modules/foo/index.js", - "store/modules/foo/create/actions.js", - "store/modules/foo/create/getters.js", - "store/modules/foo/create/index.js", - "store/modules/foo/create/mutation_types.js", - "store/modules/foo/create/mutations.js", - "store/modules/foo/create/state.js", - "store/modules/foo/delete/actions.js", - "store/modules/foo/delete/getters.js", - "store/modules/foo/delete/index.js", - "store/modules/foo/delete/mutation_types.js", - "store/modules/foo/delete/mutations.js", - "store/modules/foo/delete/state.js", - "store/modules/foo/list/actions.js", - "store/modules/foo/list/getters.js", - "store/modules/foo/list/index.js", - "store/modules/foo/list/mutation_types.js", - "store/modules/foo/list/mutations.js", - "store/modules/foo/list/state.js", - "store/modules/foo/show/actions.js", - "store/modules/foo/show/getters.js", - "store/modules/foo/show/index.js", - "store/modules/foo/show/mutation_types.js", - "store/modules/foo/show/mutations.js", - "store/modules/foo/show/state.js", - "store/modules/foo/update/actions.js", - "store/modules/foo/update/getters.js", - "store/modules/foo/update/index.js", - "store/modules/foo/update/mutation_types.js", - "store/modules/foo/update/mutations.js", - "store/modules/foo/update/state.js", - - // common for modules - "common/store/mutation_types.js", - "common/store/create/actions.js", - "common/store/create/getters.js", - "common/store/create/mutation_types.js", - "common/store/create/mutations.js", - "common/store/create/state.js", - "common/store/delete/actions.js", - "common/store/delete/getters.js", - "common/store/delete/mutation_types.js", - "common/store/delete/mutations.js", - "common/store/delete/state.js", - "common/store/list/actions.js", - "common/store/list/getters.js", - "common/store/list/mutation_types.js", - "common/store/list/mutations.js", - "common/store/list/state.js", - "common/store/show/actions.js", - "common/store/show/getters.js", - "common/store/show/mutation_types.js", - "common/store/show/mutations.js", - "common/store/show/state.js", - "common/store/update/actions.js", - "common/store/update/getters.js", - "common/store/update/mutation_types.js", - "common/store/update/mutations.js", - "common/store/update/state.js", + this.registerTemplates("common/", [ + // types + "types/collection.ts", + "types/error.ts", + "types/foo.ts", + "types/item.ts", + "types/view.ts", - // components - "components/foo/Create.vue", - "components/foo/Filter.vue", - "components/foo/Form.vue", - "components/foo/List.vue", - "components/foo/Update.vue", - "components/foo/Show.vue", - - //common components - "common/components/index.js", - "common/components/ActionCell.vue", - "common/components/Breadcrumb.vue", - "common/components/ConfirmDelete.vue", - "common/components/DataFilter.vue", - "common/components/InputDate.vue", - "common/components/Loading.vue", - "common/components/Toolbar.vue", - - // components mixins - "common/mixins/CreateMixin.js", - "common/mixins/ListMixin.js", - "common/mixins/ShowMixin.js", - "common/mixins/UpdateMixin.js", - - // routes - "router/foo.js", + // utils + "utils/api.ts", + "utils/config.ts", + "utils/date.ts", + "utils/error.ts", + "utils/mercure.ts", + ]); - // error - "error/SubmissionError.js", + this.registerTemplates("vue-common/", [ + // composables + "composables/mercureItem.ts", + "composables/mercureList.ts", + ]); - // utils - "utils/fetch.js", - "utils/dates.js", - "utils/notify.js", - "utils/vuexer.js", + this.registerTemplates("quasar/", [ + // components + "components/foo/FooCreate.vue", + "components/foo/FooFilter.vue", + "components/foo/FooForm.vue", + "components/foo/FooList.vue", + "components/foo/FooShow.vue", + "components/foo/FooUpdate.vue", + + // common components + "components/common/CommonActionCell.vue", + "components/common/CommonBreadcrumb.vue", + "components/common/CommonConfirmDelete.vue", + "components/common/CommonDataFilter.vue", + "components/common/CommonFormRepeater.vue", + "components/common/CommonLoading.vue", + "components/common/CommonToolbar.vue", + + // composables + "composables/breadcrumb.ts", + "composables/errors.ts", + "composables/notifications.ts", // i18n - "i18n/index.js", + "i18n/foo.ts", + "i18n/common.ts", + + // pages + "pages/foo/PageCreate.vue", + "pages/foo/PageList.vue", + "pages/foo/PageShow.vue", + "pages/foo/PageUpdate.vue", + + // router + "router/foo.ts", + + // stores + "stores/foo/create.ts", + "stores/foo/delete.ts", + "stores/foo/list.ts", + "stores/foo/show.ts", + "stores/foo/update.ts", + + // types + "types/breadcrumb.ts", + "types/list.ts", ]); handlebars.registerHelper("compare", hbh_comparison.compare); - handlebars.registerHelper("ifEven", hbh_comparison.ifEven); - handlebars.registerHelper("ifOdd", hbh_comparison.ifOdd); - handlebars.registerHelper("inArray", hbh_array.inArray); - handlebars.registerHelper("forEach", hbh_array.forEach); handlebars.registerHelper("lowercase", hbh_string.lowercase); handlebars.registerHelper("capitalize", hbh_string.capitalize); - - this.registerSwitchHelper(); } help(resource) { @@ -134,122 +95,25 @@ export default class extends BaseGenerator { ); console.log( chalk.green(` -//Add to quasar.conf -// 1. in 'framework.components' - 'QTable', - 'QTh', - 'QTr', - 'QTd', - 'QBreadcrumbs', - 'QBreadcrumbsEl', - 'QSpace', - 'QInput', - 'QForm', - 'QSelect', - 'QMarkupTable', - 'QDate', - 'QTime', - 'QCheckbox', - 'QPopupProxy', - 'QSpinner', - 'QInnerLoading', - 'QCard', - 'QCardSection', - 'QCardActions', - 'QExpansionItem', - 'QDialog', - 'QAvatar', - -// 2. in 'framework.config', customize later -notify: { - position: 'top', - multiLine: true, - timeout: 0, -}, - -// 3. in 'framework.directives - 'ClosePopup' - -// 4. in 'framework.plugins - 'Notify' - -//import routes -import ${titleLc}Routes from '../router/${titleLc}'; - -// Add routes to VueRouter -const router = new VueRouter({ +// Import routes in src/router/routes.ts +import ${titleLc}Routes from './${titleLc}'; + +const routes: RouteRecordRaw[] = [ // ... - routes: [ - ...${titleLc}Routes, - ] -}); + ...${titleLc}Routes, +]; -// Add the modules in the store -import ${titleLc} from '../store/modules/${titleLc}/'; +// import translations in src/i18n/en-US/index.ts +import ${titleLc} from './${titleLc}'; -export const store = new Vuex.Store({ +export default { // ... - modules: { - ${titleLc} - } -}); + ${titleLc}, +} `) ); } - registerSwitchHelper() { - /* - https://github.com/wycats/handlebars.js/issues/927#issuecomment-318640459 - - {{#switch state}} - {{#case "page1" "page2"}}page 1 or 2{{/case}} - {{#case "page3"}}page3{{/case}} - {{#case "page4"}}page4{{/case}} - {{#case "page5"}} - {{#switch s}} - {{#case "3"}}s = 3{{/case}} - {{#case "2"}}s = 2{{/case}} - {{#case "1"}}s = 1{{/case}} - {{#default}}unknown{{/default}} - {{/switch}} - {{/case}} - {{#default}}page0{{/default}} - {{/switch}} - */ - handlebars.__switch_stack__ = []; - - handlebars.registerHelper("switch", function (value, options) { - handlebars.__switch_stack__.push({ - switch_match: false, - switch_value: value, - }); - let html = options.fn(this); - handlebars.__switch_stack__.pop(); - return html; - }); - handlebars.registerHelper("case", function (value, options) { - var args = Array.from(arguments); - options = args.pop(); - var caseValues = args; - var stack = - handlebars.__switch_stack__[handlebars.__switch_stack__.length - 1]; - - if (stack.switch_match || caseValues.indexOf(stack.switch_value) === -1) { - return ""; - } else { - stack.switch_match = true; - return options.fn(this); - } - }); - handlebars.registerHelper("default", function (options) { - var stack = - handlebars.__switch_stack__[handlebars.__switch_stack__.length - 1]; - if (!stack.switch_match) { - return options.fn(this); - } - }); - } - generate(api, resource, dir) { return resource .getParameters() @@ -300,44 +164,23 @@ export const store = new Vuex.Store({ return result; } - printObject(obj) { - var cache = []; - console.log( - JSON.stringify(obj, function (key, value) { - if (typeof value === "object" && value !== null) { - if (cache.includes(value)) { - // Duplicate reference found, discard key - return; - } - // Store value in our collection - cache.push(value); - } - return value; - }) - ); - cache = null; - } - generateFiles(api, resource, dir, params) { const lc = resource.title.toLowerCase(); const titleUcFirst = resource.title.charAt(0).toUpperCase() + resource.title.slice(1); - const formFields = this.buildFields(resource.writableFields); - - const dateTypes = ["time", "date", "dateTime"]; - const formContainsDate = formFields.some((e) => dateTypes.includes(e.type)); - - const fields = this.buildFields(resource.readableFields); - const listContainsDate = fields.some((e) => dateTypes.includes(e.type)); + const fields = this.parseFields(resource); + const formFields = this.buildFields(fields); + const hasIsRelations = fields.some((field) => field.isRelations); + const hasDateField = fields.some((field) => field.type === "dateTime"); const parameters = []; params.forEach((p) => { const paramIndex = fields.findIndex((field) => field.name === p.variable); if (paramIndex === -1) { if (p.variable.startsWith("order[")) { - var v = p.variable.slice(6, -1); - var found = fields.findIndex((field) => field.name === v); + let v = p.variable.slice(6, -1); + let found = fields.findIndex((field) => field.name === v); if (found !== -1) { fields[found].sortable = true; } @@ -345,8 +188,8 @@ export const store = new Vuex.Store({ } if (p.variable.startsWith("exists[")) { - var exists = p.variable.slice(7, -1); - var foundExistsFieldIndex = fields.findIndex( + let exists = p.variable.slice(7, -1); + let foundExistsFieldIndex = fields.findIndex( (field) => field.name === exists ); if (foundExistsFieldIndex !== -1) { @@ -361,13 +204,6 @@ export const store = new Vuex.Store({ } return; } - - if (!p.name) { - p = { ...p, name: p.variable }; - } - if (!p.sortable) { - parameters.push(p); - } } else { const param = fields[paramIndex]; param.multiple = p.multiple; @@ -375,214 +211,134 @@ export const store = new Vuex.Store({ } }); - const paramsHaveRefs = parameters.some( - (e) => e.type === "text" && e.reference - ); - const labels = this.commonLabelTexts(); - const hashEntry = this.hashCode(api.entrypoint); - const context = { - title: resource.title, name: resource.name, lc, - uc: resource.title.toUpperCase(), fields, - dateTypes, - listContainsDate, - paramsHaveRefs, + hasIsRelations, + hasDateField, parameters, formFields, - formContainsDate, hydraPrefix: this.hydraPrefix, titleUcFirst, labels, - hashEntry, }; // Create directories // These directories may already exist [ - `${dir}/config`, - `${dir}/error`, + `${dir}/components/common`, + `${dir}/composables`, + `${dir}/i18n`, + `${dir}/i18n/en-US`, `${dir}/router`, + `${dir}/types`, `${dir}/utils`, - `${dir}/i18n`, - `${dir}/i18n/en-us`, - - `${dir}/common`, - `${dir}/common/components`, - `${dir}/common/mixins`, - `${dir}/common/store`, - `${dir}/common/store/create`, - `${dir}/common/store/delete`, - `${dir}/common/store/list`, - `${dir}/common/store/show`, - `${dir}/common/store/update`, ].forEach((dir) => this.createDir(dir, false)); [ - `${dir}/store/modules/${lc}`, - `${dir}/store/modules/${lc}/create`, - `${dir}/store/modules/${lc}/delete`, - `${dir}/store/modules/${lc}/list`, - `${dir}/store/modules/${lc}/show`, - `${dir}/store/modules/${lc}/update`, - `${dir}/components/${lc}`, + `${dir}/pages/${lc}`, + `${dir}/stores/${lc}`, ].forEach((dir) => this.createDir(dir)); [ - "common/components/index.js", - "common/components/ActionCell.vue", - "common/components/Breadcrumb.vue", - "common/components/ConfirmDelete.vue", - "common/components/DataFilter.vue", - "common/components/InputDate.vue", - "common/components/Loading.vue", - "common/components/Toolbar.vue", - - "common/mixins/CreateMixin.js", - "common/mixins/ListMixin.js", - "common/mixins/ShowMixin.js", - "common/mixins/UpdateMixin.js", - - "common/store/mutation_types.js", - "common/store/create/actions.js", - "common/store/create/getters.js", - "common/store/create/mutation_types.js", - "common/store/create/mutations.js", - "common/store/create/state.js", - "common/store/delete/actions.js", - "common/store/delete/getters.js", - "common/store/delete/mutation_types.js", - "common/store/delete/mutations.js", - "common/store/delete/state.js", - "common/store/list/actions.js", - "common/store/list/getters.js", - "common/store/list/mutation_types.js", - "common/store/list/mutations.js", - "common/store/list/state.js", - "common/store/show/actions.js", - "common/store/show/getters.js", - "common/store/show/mutation_types.js", - "common/store/show/mutations.js", - "common/store/show/state.js", - "common/store/update/actions.js", - "common/store/update/getters.js", - "common/store/update/mutation_types.js", - "common/store/update/mutations.js", - "common/store/update/state.js", - - "utils/dates.js", - "utils/notify.js", - "utils/vuexer.js", + // common components + "components/common/CommonActionCell.vue", + "components/common/CommonBreadcrumb.vue", + "components/common/CommonConfirmDelete.vue", + "components/common/CommonDataFilter.vue", + "components/common/CommonFormRepeater.vue", + "components/common/CommonLoading.vue", + "components/common/CommonToolbar.vue", + + // composables + "composables/breadcrumb.ts", + "composables/errors.ts", + "composables/mercureItem.ts", + "composables/mercureList.ts", + "composables/notifications.ts", + + // types + "types/breadcrumb.ts", + "types/collection.ts", + "types/error.ts", + "types/item.ts", + "types/list.ts", + "types/view.ts", + + // utils + "utils/api.ts", + "utils/date.ts", + "utils/error.ts", + "utils/mercure.ts", ].forEach((common) => this.createFile(common, `${dir}/${common}`, context, false) ); [ - // modules - "store/modules/%s/index.js", - "store/modules/%s/create/actions.js", - "store/modules/%s/create/getters.js", - "store/modules/%s/create/index.js", - "store/modules/%s/create/mutation_types.js", - "store/modules/%s/create/mutations.js", - "store/modules/%s/create/state.js", - "store/modules/%s/delete/actions.js", - "store/modules/%s/delete/getters.js", - "store/modules/%s/delete/index.js", - "store/modules/%s/delete/mutation_types.js", - "store/modules/%s/delete/mutations.js", - "store/modules/%s/delete/state.js", - "store/modules/%s/list/actions.js", - "store/modules/%s/list/getters.js", - "store/modules/%s/list/index.js", - "store/modules/%s/list/mutation_types.js", - "store/modules/%s/list/mutations.js", - "store/modules/%s/list/state.js", - "store/modules/%s/show/actions.js", - "store/modules/%s/show/getters.js", - "store/modules/%s/show/index.js", - "store/modules/%s/show/mutation_types.js", - "store/modules/%s/show/mutations.js", - "store/modules/%s/show/state.js", - "store/modules/%s/update/actions.js", - "store/modules/%s/update/getters.js", - "store/modules/%s/update/index.js", - "store/modules/%s/update/mutation_types.js", - "store/modules/%s/update/mutations.js", - "store/modules/%s/update/state.js", - // components - "components/%s/Create.vue", - "components/%s/Filter.vue", - "components/%s/Form.vue", - "components/%s/List.vue", - "components/%s/Update.vue", - "components/%s/Show.vue", + "components/%s/%sCreate.vue", + "components/%s/%sFilter.vue", + "components/%s/%sForm.vue", + "components/%s/%sList.vue", + "components/%s/%sShow.vue", + "components/%s/%sUpdate.vue", + + // pages + "pages/%s/PageCreate.vue", + "pages/%s/PageList.vue", + "pages/%s/PageShow.vue", + "pages/%s/PageUpdate.vue", // routes - "router/%s.js", + "router/%s.ts", + + // stores + "stores/%s/create.ts", + "stores/%s/delete.ts", + "stores/%s/list.ts", + "stores/%s/show.ts", + "stores/%s/update.ts", + + // types + "types/%s.ts", ].forEach((pattern) => { if ( - pattern === "components/%s/Filter.vue" && + pattern === "components/%s/%sFilter.vue" && !context.parameters.length ) { return; } - this.createFileFromPattern(pattern, dir, [lc], context); + this.createFileFromPattern(pattern, dir, [lc, titleUcFirst], context); }); - // error - this.createFile( - "error/SubmissionError.js", - `${dir}/error/SubmissionError.js`, - context, - false - ); - - this.createEntrypoint( - api.entrypoint, - `${dir}/config/${hashEntry}_entrypoint.js` - ); - - this.createFile( - "utils/fetch.js", - `${dir}/utils/fetch.js`, - { hydraPrefix: this.hydraPrefix }, - false - ); + // config + this.createConfigFile(`${dir}/utils/config.ts`, { + entrypoint: api.entrypoint, + }); this.createFile( - "i18n/index.js", - `${dir}/i18n/en-us/index.js`, - { labels: Object.values(labels) }, + "i18n/common.ts", + `${dir}/i18n/en-US/common.ts`, + { labels }, false ); const contextLabels = { labels: this.contextLabelTexts(formFields, fields), }; + this.createFile( - "i18n/index.js", - `${dir}/i18n/en-us/${lc}.js`, + "i18n/foo.ts", + `${dir}/i18n/en-US/${lc}.ts`, contextLabels, false ); } - hashCode(s) { - return Math.abs( - Array.from(s).reduce( - (s, c) => (Math.imul(31, s) + c.charCodeAt(0)) | 0, - 0 - ) - ); - } - contextLabelTexts(formFields, fields) { let texts = []; formFields.forEach((x) => texts.push(x.name)); // forms @@ -611,8 +367,35 @@ export const store = new Vuex.Store({ stringValidation: "Please type something", required: "Field is required", recPerPage: "Records per page:", + id: "ID", + actions: "Actions", }; + } + + parseFields(resource) { + const fields = [ + ...resource.writableFields, + ...resource.readableFields, + ].reduce((list, field) => { + if (list[field.name]) { + return list; + } - // handlebars.registerPartial("myPartial", "{{name}}"); + const isReferences = field.reference && field.maxCardinality !== 1; + const isEmbeddeds = field.embedded && field.maxCardinality !== 1; + + return { + ...list, + [field.name]: { + ...field, + isReferences, + isEmbeddeds, + isRelation: field.reference || field.embedded, + isRelations: isEmbeddeds || isReferences, + }, + }; + }, {}); + + return Object.values(fields); } } diff --git a/src/generators/QuasarGenerator.test.js b/src/generators/QuasarGenerator.test.js index f159fc97..1dacd513 100644 --- a/src/generators/QuasarGenerator.test.js +++ b/src/generators/QuasarGenerator.test.js @@ -7,7 +7,7 @@ import QuasarGenerator from "./QuasarGenerator.js"; const dirname = path.dirname(fileURLToPath(import.meta.url)); -test("Generate a Quasar app", () => { +test("Generate a Quasar app", async () => { const generator = new QuasarGenerator({ hydraPrefix: "hydra:", templateDirectory: `${dirname}/../../templates`, @@ -21,6 +21,7 @@ test("Generate a Quasar app", () => { reference: null, required: true, description: "An URL", + type: "string", }), ]; const resource = new Resource("abc", "http://example.com/foos", { @@ -37,60 +38,62 @@ test("Generate a Quasar app", () => { title: "My API", resources: [resource], }); - generator - .generate(api, resource, tmpobj.name) - .then(() => { - expect(fs.existsSync(tmpobj.name + "/components/foo/Create.vue")).toBe( - true - ); - expect(fs.existsSync(tmpobj.name + "/components/foo/Form.vue")).toBe( - true - ); - expect(fs.existsSync(tmpobj.name + "/components/foo/List.vue")).toBe( - true - ); - expect(fs.existsSync(tmpobj.name + "/components/foo/Show.vue")).toBe( - true - ); - expect(fs.existsSync(tmpobj.name + "/components/foo/Update.vue")).toBe( - true - ); - expect(fs.existsSync(tmpobj.name + "/config/entrypoint.js")).toBe(true); + await generator.generate(api, resource, tmpobj.name, []); - expect(fs.existsSync(tmpobj.name + "/error/SubmissionError.js")).toBe( - true - ); + // common components + [ + "ActionCell", + "Breadcrumb", + "ConfirmDelete", + "DataFilter", + "FormRepeater", + "Loading", + "Toolbar", + ].forEach((name) => { + expect( + fs.existsSync(`${tmpobj.name}/components/common/Common${name}.vue`) + ).toBe(true); + }); + + // components + ["Create", "Form", "List", "Show", "Update"].forEach((name) => { + expect(fs.existsSync(`${tmpobj.name}/components/foo/Foo${name}.vue`)).toBe( + true + ); + }); + + // i18n + expect(fs.existsSync(`${tmpobj.name}/i18n/en-US/common.ts`)).toBe(true); + expect(fs.existsSync(`${tmpobj.name}/i18n/en-US/foo.ts`)).toBe(true); + + // pages + ["Create", "List", "Show", "Update"].forEach((name) => { + expect(fs.existsSync(`${tmpobj.name}/pages/foo/Page${name}.vue`)).toBe( + true + ); + }); + + // router + expect(fs.existsSync(`${tmpobj.name}/router/foo.ts`)).toBe(true); + + // stores + ["create", "delete", "list", "show", "update"].forEach((name) => { + expect(fs.existsSync(`${tmpobj.name}/stores/foo/${name}.ts`)).toBe(true); + }); - expect(fs.existsSync(tmpobj.name + "/router/foo.js")).toBe(true); + // types + ["breadcrumb", "collection", "error", "foo", "item", "list", "view"].forEach( + (name) => { + expect(fs.existsSync(`${tmpobj.name}/types/${name}.ts`)).toBe(true); + } + ); - expect(fs.existsSync(tmpobj.name + "/store/modules/foo/index.js")).toBe( - true - ); + // utils + expect(fs.existsSync(`${tmpobj.name}/utils/api.ts`)).toBe(true); + expect(fs.existsSync(`${tmpobj.name}/utils/config.ts`)).toBe(true); + expect(fs.existsSync(`${tmpobj.name}/utils/date.ts`)).toBe(true); + expect(fs.existsSync(`${tmpobj.name}/utils/error.ts`)).toBe(true); - ["create", "delete", "list", "show", "update"].forEach((action) => { - expect( - fs.existsSync(`${tmpobj.name}/store/modules/foo/${action}/actions.js`) - ).toBe(true); - expect( - fs.existsSync(`${tmpobj.name}/store/modules/foo/${action}/getters.js`) - ).toBe(true); - expect( - fs.existsSync(`${tmpobj.name}/store/modules/foo/${action}/index.js`) - ).toBe(true); - expect( - fs.existsSync( - `${tmpobj.name}/store/modules/foo/${action}/mutation_types.js` - ) - ).toBe(true); - expect( - fs.existsSync( - `${tmpobj.name}/store/modules/foo/${action}/mutations.js` - ) - ).toBe(true); - }); - expect(fs.existsSync(tmpobj.name + "/utils/fetch.js")).toBe(true); - tmpobj.removeCallback(); - }) - .catch(() => {}); + tmpobj.removeCallback(); }); diff --git a/src/generators/VueGenerator.js b/src/generators/VueGenerator.js index f0baa169..b99d66bd 100644 --- a/src/generators/VueGenerator.js +++ b/src/generators/VueGenerator.js @@ -17,11 +17,19 @@ export default class extends BaseGenerator { "types/view.ts", // utils + "utils/api.ts", "utils/config.ts", + "utils/date.ts", "utils/error.ts", "utils/mercure.ts", ]); + this.registerTemplates("vue-common/", [ + // composables + "composables/mercureItem.ts", + "composables/mercureList.ts", + ]); + this.registerTemplates(`vue/`, [ // components "components/foo/FooCreate.vue", @@ -33,10 +41,6 @@ export default class extends BaseGenerator { // common components "components/common/FormRepeater.vue", - // composables - "composables/mercureItem.ts", - "composables/mercureList.ts", - // routes "router/foo.ts", @@ -50,10 +54,6 @@ export default class extends BaseGenerator { // types "types/stores.ts", - // utils - "utils/api.ts", - "utils/date.ts", - // views "views/foo/ViewCreate.vue", "views/foo/ViewList.vue", diff --git a/templates/common/types/collection.ts b/templates/common/types/collection.ts index b5245962..f710e6fd 100644 --- a/templates/common/types/collection.ts +++ b/templates/common/types/collection.ts @@ -1,11 +1,11 @@ -import type { View } from "./view"; +import type { View } from './view'; export interface PagedCollection { - "@context"?: string; - "@id"?: string; - "@type"?: string; - "{{hydraPrefix}}member": T[]; - "{{hydraPrefix}}search"?: object; - "{{hydraPrefix}}totalItems"?: number; - "{{hydraPrefix}}view": View; + '@context'?: string; + '@id'?: string; + '@type'?: string; + '{{hydraPrefix}}member': T[]; + '{{hydraPrefix}}search'?: object; + '{{hydraPrefix}}totalItems'?: number; + '{{hydraPrefix}}view': View; } diff --git a/templates/common/types/foo.ts b/templates/common/types/foo.ts index 541c8454..220bfc66 100644 --- a/templates/common/types/foo.ts +++ b/templates/common/types/foo.ts @@ -2,6 +2,6 @@ import type { Item } from "./item"; export interface {{titleUcFirst}} extends Item { {{#each fields}} - {{#if readonly}}readonly{{/if}} {{{name}}}?: {{#if (compare type "==" "dateTime")}}string{{else if (compare type "==" "integer")}}number{{else if isRelation}}any{{else}}{{{type}}}{{/if}}; + {{#if readonly}}readonly{{/if}} {{name}}?: {{#if (compare type "==" "dateTime")}}string{{else if (compare type "==" "integer")}}number{{else if isRelation}}any{{else}}{{type}}{{/if}}; {{/each}} } diff --git a/templates/common/types/item.ts b/templates/common/types/item.ts index f8d95cdc..766cc0f1 100644 --- a/templates/common/types/item.ts +++ b/templates/common/types/item.ts @@ -1,3 +1,3 @@ export interface Item { - "@id"?: string; + '@id'?: string; } diff --git a/templates/common/types/view.ts b/templates/common/types/view.ts index 9a6bb10a..19cd75d1 100644 --- a/templates/common/types/view.ts +++ b/templates/common/types/view.ts @@ -1,7 +1,7 @@ export interface View { - "@id": string; - "{{hydraPrefix}}first": string; - "{{hydraPrefix}}last": string; - "{{hydraPrefix}}next": string; - "{{hydraPrefix}}previous": string; + '@id': string; + '{{hydraPrefix}}first': string; + '{{hydraPrefix}}last': string; + '{{hydraPrefix}}next': string; + '{{hydraPrefix}}previous': string; } diff --git a/templates/common/utils/api.ts b/templates/common/utils/api.ts new file mode 100644 index 00000000..83723914 --- /dev/null +++ b/templates/common/utils/api.ts @@ -0,0 +1,54 @@ +import qs from 'qs'; +import type { SubmissionErrors } from '../types/error'; +import { SubmissionError } from './error'; +import { ENTRYPOINT } from './config'; + +const MIME_TYPE = 'application/ld+json'; + +export default async function (id: string, options: any = {}) { + if (typeof options.headers === 'undefined') { + Object.assign(options, { headers: new Headers() }); + } + + if (options.headers.get('Accept') === null) { + options.headers.set('Accept', MIME_TYPE); + } + + if ( + options.body !== undefined && + !(options.body instanceof FormData) && + options.headers.get('Content-Type') === null + ) { + options.headers.set('Content-Type', MIME_TYPE); + } + + if (options.params) { + const queryString = qs.stringify(options.params); + id = `${id}?${queryString}`; + } + + // enable CORS for all requests + Object.assign(options, { + mode: 'cors', + // credentials: 'include', // when credentials needed + }); + + const response = await fetch(new URL(id, ENTRYPOINT), options); + + if (!response.ok) { + const data = await response.json(); + const error = data['{{hydraPrefix}}description'] || response.statusText; + if (!data.violations) throw Error(error); + + const errors: SubmissionErrors = { _error: error }; + data.violations.forEach( + (violation: { propertyPath: string; message: string }) => { + errors[violation.propertyPath] = violation.message; + } + ); + + throw new SubmissionError(errors); + } + + return response; +} diff --git a/templates/common/utils/date.ts b/templates/common/utils/date.ts new file mode 100644 index 00000000..5e346e2d --- /dev/null +++ b/templates/common/utils/date.ts @@ -0,0 +1,15 @@ +import dayjs from 'dayjs'; + +export function formatDateTime(date?: string): string | null { + if (!date) return null; + + return dayjs(date).format('DD/MM/YYYY'); +} + +export function formatDateInput(value?: string): string | undefined { + if (!value) { + return undefined; + } + + return dayjs(value).format('YYYY-MM-DD'); +} diff --git a/templates/common/utils/mercure.ts b/templates/common/utils/mercure.ts index f9e9263f..c3c70110 100644 --- a/templates/common/utils/mercure.ts +++ b/templates/common/utils/mercure.ts @@ -21,13 +21,13 @@ export const mercureSubscribe = ( return eventSource; }; -export const extractHubURL = (response: Response): URL | null => { +export const extractHubURL = (response: Response): URL | undefined => { const linkHeader = response.headers.get("Link"); - if (!linkHeader) return null; + if (!linkHeader) return undefined; const matches = linkHeader.match( /<([^>]+)>;\s+rel=(?:mercure|"[^"]*mercure[^"]*")/ ); - return matches && matches[1] ? new URL(matches[1], ENTRYPOINT) : null; + return matches && matches[1] ? new URL(matches[1], ENTRYPOINT) : undefined; }; diff --git a/templates/quasar/common/components/ActionCell.vue b/templates/quasar/common/components/ActionCell.vue deleted file mode 100644 index b65a0e76..00000000 --- a/templates/quasar/common/components/ActionCell.vue +++ /dev/null @@ -1,59 +0,0 @@ - - - diff --git a/templates/quasar/common/components/Breadcrumb.vue b/templates/quasar/common/components/Breadcrumb.vue deleted file mode 100644 index 47a57ebe..00000000 --- a/templates/quasar/common/components/Breadcrumb.vue +++ /dev/null @@ -1,32 +0,0 @@ - - - \ No newline at end of file diff --git a/templates/quasar/common/components/ConfirmDelete.vue b/templates/quasar/common/components/ConfirmDelete.vue deleted file mode 100644 index d05005d7..00000000 --- a/templates/quasar/common/components/ConfirmDelete.vue +++ /dev/null @@ -1,35 +0,0 @@ - - - diff --git a/templates/quasar/common/components/DataFilter.vue b/templates/quasar/common/components/DataFilter.vue deleted file mode 100644 index 066b38d2..00000000 --- a/templates/quasar/common/components/DataFilter.vue +++ /dev/null @@ -1,43 +0,0 @@ - - - diff --git a/templates/quasar/common/components/InputDate.vue b/templates/quasar/common/components/InputDate.vue deleted file mode 100644 index 1716f7e2..00000000 --- a/templates/quasar/common/components/InputDate.vue +++ /dev/null @@ -1,145 +0,0 @@ - - - - diff --git a/templates/quasar/common/components/Loading.vue b/templates/quasar/common/components/Loading.vue deleted file mode 100644 index 7c416bc4..00000000 --- a/templates/quasar/common/components/Loading.vue +++ /dev/null @@ -1,16 +0,0 @@ - - - diff --git a/templates/quasar/common/components/Toolbar.vue b/templates/quasar/common/components/Toolbar.vue deleted file mode 100644 index a552ad2c..00000000 --- a/templates/quasar/common/components/Toolbar.vue +++ /dev/null @@ -1,91 +0,0 @@ - - - diff --git a/templates/quasar/common/components/index.js b/templates/quasar/common/components/index.js deleted file mode 100644 index d93a4ccb..00000000 --- a/templates/quasar/common/components/index.js +++ /dev/null @@ -1,7 +0,0 @@ -export { default as ActionCell } from './ActionCell'; -export { default as Breadcrumb } from './Breadcrumb'; -export { default as ConfirmDelete } from './ConfirmDelete'; -export { default as DataFilter } from './DataFilter'; -export { default as InputDate } from './InputDate'; -export { default as Loading } from './Loading'; -export { default as Toolbar } from './Toolbar'; diff --git a/templates/quasar/common/mixins/CreateMixin.js b/templates/quasar/common/mixins/CreateMixin.js deleted file mode 100644 index 648530e8..00000000 --- a/templates/quasar/common/mixins/CreateMixin.js +++ /dev/null @@ -1,39 +0,0 @@ -import { error } from '../../utils/notify'; - -export default { - watch: { - created(created) { - this.onCreated(created); - }, - - error(message) { - this.onError(message); - }, - }, - - methods: { - onCreated(item) { - item && - this.$router.push({ - name: `${this.$options.servicePrefix}Update`, - params: { id: item['@id'] }, - }); - }, - - onError(message) { - message && error(message, this.$t('{{{labels.close}}}')); - }, - - onSendForm() { - this.$refs.createForm.$children[0].validate().then(success => { - if (success) { - this.create(this.item); - } - }); - }, - - resetForm() { - this.item = {}; - }, - }, -}; diff --git a/templates/quasar/common/mixins/ListMixin.js b/templates/quasar/common/mixins/ListMixin.js deleted file mode 100644 index a24a5faf..00000000 --- a/templates/quasar/common/mixins/ListMixin.js +++ /dev/null @@ -1,120 +0,0 @@ -import { error, success } from '../../utils/notify'; -import { extractDate } from '../../utils/dates'; - -export default { - created() { - this.onCreated(); - }, - - data() { - return { - pagination: { - sortBy: null, - descending: false, - page: 1, // page to be displayed - rowsPerPage: 3, // maximum displayed rows - rowsNumber: 10, // max number of rows - }, - nextPage: null, - filters: {}, - filtration: {}, - expandedFilter: false, - }; - }, - - watch: { - error(message) { - this.onListError(message); - }, - - items() { - this.pagination.page = this.nextPage; - this.pagination.rowsNumber = this.totalItems; - this.nextPage = null; - }, - - deletedItem(val) { - this.onDeletedItem(val); - }, - }, - - methods: { - onCreated() { - this.onRequest({ - pagination: this.pagination - }); - }, - - onListError(message) { - message && error(message, this.$t('{{{labels.close}}}')); - }, - - onDeletedItem(val) { - success(`${val['@id']} ${this.$t('{{{labels.deleted}}}')}.`, this.$t('{{{labels.close}}}')); - }, - - onRequest(props, init) { - const { - pagination: { page, rowsPerPage: itemsPerPage, sortBy, descending }, - } = props; - this.nextPage = page; - let params = { - ...this.filtration, - }; - if (itemsPerPage > 0) { - params = { ...params, itemsPerPage, page }; - } - if (sortBy) { - params[`order[${sortBy}]`] = descending ? 'DESC' : 'ASC'; - } - this.getPage({ params }).then(() => { - this.pagination.sortBy = sortBy; - this.pagination.descending = descending; - this.pagination.rowsPerPage = itemsPerPage; - if (!init) { - this.filters = { ...this.filtration }; - } - }); - }, - - formatDateTime(val, format) { - return val ? this.$d(extractDate(val), format) : ''; - }, - - onSendFilter() { - this.onRequest({ - pagination: this.pagination, - }); - }, - - resetFilter() { - this.filters = {}; - }, - - addHandler() { - this.$router.push({ name: `${this.$options.servicePrefix}Create` }); - }, - - showHandler(item) { - this.$router.push({ - name: `${this.$options.servicePrefix}Show`, - params: { id: item['@id'] } - }); - }, - - editHandler(item) { - this.$router.push({ - name: `${this.$options.servicePrefix}Update`, - params: { id: item['@id'] } - }); - }, - - deleteHandler(item) { - this.deleteItem(item).then(() => - this.onRequest({ - pagination: this.pagination, - }), - ); - }, - }, -}; diff --git a/templates/quasar/common/mixins/ShowMixin.js b/templates/quasar/common/mixins/ShowMixin.js deleted file mode 100644 index b3cf94b8..00000000 --- a/templates/quasar/common/mixins/ShowMixin.js +++ /dev/null @@ -1,61 +0,0 @@ -import { extractDate } from '../../utils/dates'; - -export default { - created() { - this.onCreated(); - }, - - beforeDestroy() { - this.onBeforeDestroy(); - }, - - watch: { - error(message) { - this.onShowError(message); - }, - - deleteError(message) { - this.onDeletedError(message); - }, - }, - - methods: { - onCreated() { - this.retrieve(decodeURIComponent(this.$route.params.id)); - }, - - onBeforeDestroy() { - this.reset(); - }, - - onShowError(message) { - message && - this.$q.notify({ - message, - color: 'red', - icon: 'error', - closeBtn: this.$t('{{{labels.close}}}'), - }); - }, - - onDeletedError(message) { - message && - this.$q.notify({ - message, - color: 'red', - icon: 'error', - closeBtn: this.$t('{{{labels.close}}}'), - }); - }, - - formatDateTime(val, format) { - return val ? this.$d(extractDate(val), format) : ''; - }, - - deleteItem() { - this.deleteItem(this.item).then(() => - this.$router.push({ name: `${this.$options.servicePrefix}List` }) - ); - }, - }, -}; diff --git a/templates/quasar/common/mixins/UpdateMixin.js b/templates/quasar/common/mixins/UpdateMixin.js deleted file mode 100644 index 948d50e0..00000000 --- a/templates/quasar/common/mixins/UpdateMixin.js +++ /dev/null @@ -1,83 +0,0 @@ -import { error, success } from '../../utils/notify'; - -export default { - data() { - return { - item: {}, - }; - }, - - created() { - this.onCreated(); - }, - - beforeDestroy() { - this.onBeforeDestroy(); - }, - - watch: { - error(message) { - this.onUpdateError(message); - }, - - deleteError(message) { - this.onDeleteError(message); - }, - - updated(val) { - this.onUpdated(val); - }, - - retrieved(val) { - this.item = { ...val }; - }, - }, - - methods: { - del() { - this.deleteItem(this.retrieved).then(() => - this.$router - .push({ name: `${this.$options.servicePrefix}List` }) - .catch(() => {}) - ); - }, - - reset() { - this.updateReset(); - this.delReset(); - this.createReset(); - }, - - onSendForm() { - this.$refs.updateForm.$children[0].validate().then(success => { - if (success) { - this.update(this.item); - } - }); - }, - - resetForm() { - this.item = { ...this.retrieved }; - }, - - onCreated() { - this.retrieve(decodeURIComponent(this.$route.params.id)); - }, - - onBeforeDestroy() { - this.reset(); - }, - - onUpdated(val) { - success(`${val['@id']} ${this.$t('{{{labels.updated}}}')}.`, this.$t('{{{labels.close}}}')); - }, - - onUpdateError(message) { - message && error(message, this.$t('{{{labels.close}}}')); - }, - - onDeleteError(message) { - message && error(message, this.$t('{{{labels.close}}}')); - }, - }, -}; diff --git a/templates/quasar/common/store/create/actions.js b/templates/quasar/common/store/create/actions.js deleted file mode 100644 index c5a6543a..00000000 --- a/templates/quasar/common/store/create/actions.js +++ /dev/null @@ -1,36 +0,0 @@ -import SubmissionError from '../../../error/SubmissionError'; -import fetch from '../../../utils/fetch'; - -export const createCommon = ({ commit }, { page, ep, values }, { types }) => { - commit(types.SET_ERROR, ''); - commit(types.TOGGLE_LOADING); - - return fetch( - { id: page, ep }, - { method: 'POST', body: JSON.stringify(values) } - ) - .then(response => { - commit(types.TOGGLE_LOADING); - - return response.json(); - }) - .then(data => { - commit(types.SET_CREATED, data); - }) - .catch(e => { - commit(types.TOGGLE_LOADING); - - if (e instanceof SubmissionError) { - commit(types.SET_VIOLATIONS, e.errors); - // eslint-disable-next-line - commit(types.SET_ERROR, e.errors._error); - return; - } - - commit(types.SET_ERROR, e.message); - }); -}; - -export const resetCommon = ({ commit }, { types }) => { - commit(types.RESET); -}; diff --git a/templates/quasar/common/store/create/getters.js b/templates/quasar/common/store/create/getters.js deleted file mode 100644 index df466e80..00000000 --- a/templates/quasar/common/store/create/getters.js +++ /dev/null @@ -1,4 +0,0 @@ -export const created = state => state.created; -export const error = state => state.error; -export const isLoading = state => state.isLoading; -export const violations = state => state.violations; diff --git a/templates/quasar/common/store/create/mutation_types.js b/templates/quasar/common/store/create/mutation_types.js deleted file mode 100644 index 4b80d5b9..00000000 --- a/templates/quasar/common/store/create/mutation_types.js +++ /dev/null @@ -1,5 +0,0 @@ -import { mutationTypes } from '../mutation_types'; - -const types = ['RESET', 'SET_CREATED', 'SET_ERROR', 'SET_VIOLATIONS', 'TOGGLE_LOADING']; - -export default m => mutationTypes(m, 'CREATE', types); diff --git a/templates/quasar/common/store/create/mutations.js b/templates/quasar/common/store/create/mutations.js deleted file mode 100644 index 15c2aaca..00000000 --- a/templates/quasar/common/store/create/mutations.js +++ /dev/null @@ -1,21 +0,0 @@ -export default (initState, types) => ({ - [types.SET_ERROR](state, error) { - Object.assign(state, { error }); - }, - - [types.TOGGLE_LOADING](state) { - Object.assign(state, { isLoading: !state.isLoading }); - }, - - [types.SET_CREATED](state, created) { - Object.assign(state, { created }); - }, - - [types.SET_VIOLATIONS](state, violations) { - Object.assign(state, { violations }); - }, - - [types.RESET](state) { - Object.assign(state, initState); - }, -}); diff --git a/templates/quasar/common/store/create/state.js b/templates/quasar/common/store/create/state.js deleted file mode 100644 index 558b8d1f..00000000 --- a/templates/quasar/common/store/create/state.js +++ /dev/null @@ -1,6 +0,0 @@ -export default () => ({ - isLoading: false, - error: '', - created: null, - violations: null, -}); diff --git a/templates/quasar/common/store/delete/actions.js b/templates/quasar/common/store/delete/actions.js deleted file mode 100644 index 22eb84d2..00000000 --- a/templates/quasar/common/store/delete/actions.js +++ /dev/null @@ -1,19 +0,0 @@ -import fetch from '../../../utils/fetch'; - -export const delCommon = ({ commit }, { item, ep }, { types }) => { - commit(types.TOGGLE_LOADING); - - return fetch({ id: item['@id'], ep }, { method: 'DELETE' }) - .then(() => { - commit(types.TOGGLE_LOADING); - commit(types.SET_DELETED, item); - }) - .catch(e => { - commit(types.TOGGLE_LOADING); - commit(types.SET_ERROR, e.message); - }); -}; - -export const resetCommon = ({ commit }, { types }) => { - commit(types.RESET); -}; diff --git a/templates/quasar/common/store/delete/getters.js b/templates/quasar/common/store/delete/getters.js deleted file mode 100644 index 5d0feed2..00000000 --- a/templates/quasar/common/store/delete/getters.js +++ /dev/null @@ -1,3 +0,0 @@ -export const deleted = state => state.deleted; -export const error = state => state.error; -export const isLoading = state => state.isLoading; diff --git a/templates/quasar/common/store/delete/mutation_types.js b/templates/quasar/common/store/delete/mutation_types.js deleted file mode 100644 index e12dd9e3..00000000 --- a/templates/quasar/common/store/delete/mutation_types.js +++ /dev/null @@ -1,5 +0,0 @@ -import { mutationTypes } from '../mutation_types'; - -const types = ['RESET', 'SET_ERROR', 'SET_DELETED', 'TOGGLE_LOADING']; - -export default m => mutationTypes(m, 'DELETE', types); diff --git a/templates/quasar/common/store/delete/mutations.js b/templates/quasar/common/store/delete/mutations.js deleted file mode 100644 index 1e1fd8fc..00000000 --- a/templates/quasar/common/store/delete/mutations.js +++ /dev/null @@ -1,17 +0,0 @@ -export default (initState, types) => ({ - [types.SET_DELETED](state, deleted) { - Object.assign(state, { deleted }); - }, - - [types.SET_ERROR](state, error) { - Object.assign(state, { error }); - }, - - [types.TOGGLE_LOADING](state) { - Object.assign(state, { isLoading: !state.isLoading }); - }, - - [types.RESET](state) { - Object.assign(state, initState); - }, -}); diff --git a/templates/quasar/common/store/delete/state.js b/templates/quasar/common/store/delete/state.js deleted file mode 100644 index 1499de79..00000000 --- a/templates/quasar/common/store/delete/state.js +++ /dev/null @@ -1,5 +0,0 @@ -export default () => ({ - isLoading: false, - error: '', - deleted: null, -}); diff --git a/templates/quasar/common/store/list/actions.js b/templates/quasar/common/store/list/actions.js deleted file mode 100644 index 76b03c6f..00000000 --- a/templates/quasar/common/store/list/actions.js +++ /dev/null @@ -1,39 +0,0 @@ -import fetch from '../../../utils/fetch'; - -export const getItemsCommon = ( - { commit }, - { page, ep, params }, - { types, hydraPrefix } -) => { - commit(types.TOGGLE_LOADING); - return fetch({ id: page, ep }, { params }) - .then(response => response.json()) - .then(data => { - commit(types.TOGGLE_LOADING); - commit(types.SET_ITEMS, data[`${hydraPrefix}member`]); - commit(types.SET_VIEW, data[`${hydraPrefix}view`]); - commit(types.SET_TOTALITEMS, data[`${hydraPrefix}totalItems`]); - }) - .catch(e => { - commit(types.TOGGLE_LOADING); - commit(types.SET_ERROR, e.message); - }); -}; - -export const getSelectItemsCommon = ( - { commit }, - { page, ep, params }, - { types, hydraPrefix } -) => { - commit(types.TOGGLE_LOADING); - return fetch({ id: page, ep }, { params }) - .then(response => response.json()) - .then(data => { - commit(types.TOGGLE_LOADING); - commit(types.SET_SELECT_ITEMS, data[`${hydraPrefix}member`]); - }) - .catch(e => { - commit(types.TOGGLE_LOADING); - commit(types.SET_ERROR, e.message); - }); -}; diff --git a/templates/quasar/common/store/list/getters.js b/templates/quasar/common/store/list/getters.js deleted file mode 100644 index 5bdb4d7a..00000000 --- a/templates/quasar/common/store/list/getters.js +++ /dev/null @@ -1,7 +0,0 @@ -export const error = state => state.error; -export const isLoading = state => state.isLoading; -export const items = state => state.items; -export const selectItems = state => state.selectItems; -export const selectItemsTemplate = state => state.selectItemsTemplate; -export const view = state => state.view; -export const totalItems = state => state.totalItems; diff --git a/templates/quasar/common/store/list/mutation_types.js b/templates/quasar/common/store/list/mutation_types.js deleted file mode 100644 index a375a54d..00000000 --- a/templates/quasar/common/store/list/mutation_types.js +++ /dev/null @@ -1,14 +0,0 @@ -import { mutationTypes } from '../mutation_types'; - -const types = [ - 'RESET', - 'SET_ITEMS', - 'SET_SELECT_ITEMS', - 'SET_SELECT_ITEMS_TEMPLATE', - 'SET_ERROR', - 'SET_VIEW', - 'TOGGLE_LOADING', - 'SET_TOTALITEMS', -]; - -export default m => mutationTypes(m, 'LIST', types); diff --git a/templates/quasar/common/store/list/mutations.js b/templates/quasar/common/store/list/mutations.js deleted file mode 100644 index 24541874..00000000 --- a/templates/quasar/common/store/list/mutations.js +++ /dev/null @@ -1,33 +0,0 @@ -export default (initState, types) => ({ - [types.RESET](state) { - Object.assign(state, initState); - }, - - [types.SET_ERROR](state, error) { - Object.assign(state, { error }); - }, - - [types.SET_ITEMS](state, items) { - Object.assign(state, { items }); - }, - - [types.SET_SELECT_ITEMS](state, selectItems) { - Object.assign(state, { selectItems }); - }, - - [types.SET_SELECT_ITEMS_TEMPLATE](state, selectItemsTemplate) { - Object.assign(state, { selectItemsTemplate }); - }, - - [types.TOGGLE_LOADING](state) { - Object.assign(state, { isLoading: !state.isLoading }); - }, - - [types.SET_VIEW](state, view) { - Object.assign(state, { view }); - }, - - [types.SET_TOTALITEMS](state, totalItems) { - Object.assign(state, { totalItems }); - }, -}); diff --git a/templates/quasar/common/store/list/state.js b/templates/quasar/common/store/list/state.js deleted file mode 100644 index 7148e84d..00000000 --- a/templates/quasar/common/store/list/state.js +++ /dev/null @@ -1,9 +0,0 @@ -export default () => ({ - error: '', - isLoading: false, - items: [], - view: [], - totalItems: 10, - selectItems: null, - selectItemsTemplate: '', -}); diff --git a/templates/quasar/common/store/mutation_types.js b/templates/quasar/common/store/mutation_types.js deleted file mode 100644 index 2f9352df..00000000 --- a/templates/quasar/common/store/mutation_types.js +++ /dev/null @@ -1,5 +0,0 @@ -export const mutationTypes = (m, area, todoTypes) => { - let types = {}; - todoTypes.forEach(item => (types[`${item}`] = `${m}_${area}_${item}`)); - return types; -}; diff --git a/templates/quasar/common/store/show/actions.js b/templates/quasar/common/store/show/actions.js deleted file mode 100644 index f64224a9..00000000 --- a/templates/quasar/common/store/show/actions.js +++ /dev/null @@ -1,20 +0,0 @@ -import fetch from '../../../utils/fetch'; - -export const retrieveCommon = ({ commit }, id, { types }) => { - commit(types.TOGGLE_LOADING); - - return fetch(id) - .then(response => response.json()) - .then(data => { - commit(types.TOGGLE_LOADING); - commit(types.SET_RETRIEVED, data); - }) - .catch(e => { - commit(types.TOGGLE_LOADING); - commit(types.SET_ERROR, e.message); - }); -}; - -export const resetCommon = ({ commit }, { types }) => { - commit(types.RESET); -}; diff --git a/templates/quasar/common/store/show/getters.js b/templates/quasar/common/store/show/getters.js deleted file mode 100644 index 5c5ac951..00000000 --- a/templates/quasar/common/store/show/getters.js +++ /dev/null @@ -1,3 +0,0 @@ -export const error = state => state.error; -export const isLoading = state => state.isLoading; -export const retrieved = state => state.retrieved; diff --git a/templates/quasar/common/store/show/mutation_types.js b/templates/quasar/common/store/show/mutation_types.js deleted file mode 100644 index a1e5d706..00000000 --- a/templates/quasar/common/store/show/mutation_types.js +++ /dev/null @@ -1,5 +0,0 @@ -import { mutationTypes } from '../mutation_types'; - -const types = ['RESET', 'SET_ERROR', 'SET_RETRIEVED', 'TOGGLE_LOADING']; - -export default m => mutationTypes(m, 'SHOW', types); diff --git a/templates/quasar/common/store/show/mutations.js b/templates/quasar/common/store/show/mutations.js deleted file mode 100644 index 69fcdc94..00000000 --- a/templates/quasar/common/store/show/mutations.js +++ /dev/null @@ -1,17 +0,0 @@ -export default (initState, types) => ({ - [types.RESET](state) { - Object.assign(state, initState); - }, - - [types.SET_ERROR](state, error) { - Object.assign(state, { error }); - }, - - [types.SET_RETRIEVED](state, retrieved) { - Object.assign(state, { retrieved }); - }, - - [types.TOGGLE_LOADING](state) { - Object.assign(state, { isLoading: !state.isLoading }); - }, -}); diff --git a/templates/quasar/common/store/show/state.js b/templates/quasar/common/store/show/state.js deleted file mode 100644 index 3560e8fd..00000000 --- a/templates/quasar/common/store/show/state.js +++ /dev/null @@ -1,5 +0,0 @@ -export default () => ({ - error: '', - isLoading: false, - retrieved: null, -}); diff --git a/templates/quasar/common/store/update/actions.js b/templates/quasar/common/store/update/actions.js deleted file mode 100644 index 25ed1a54..00000000 --- a/templates/quasar/common/store/update/actions.js +++ /dev/null @@ -1,54 +0,0 @@ -import SubmissionError from '../../../error/SubmissionError'; -import fetch from '../../../utils/fetch'; - -export const resetCommon = ({ commit }, { types }) => { - commit(types.RESET); -}; - -export const retrieveCommon = ({ commit }, dest, { types }) => { - commit(types.TOGGLE_LOADING); - - return fetch(dest) - .then(response => response.json()) - .then(data => { - commit(types.TOGGLE_LOADING); - commit(types.SET_RETRIEVED, data); - }) - .catch(e => { - commit(types.TOGGLE_LOADING); - commit(types.SET_ERROR, e.message); - }); -}; - -export const updateCommon = ({ commit, state }, { values, ep }, { types }) => { - commit(types.SET_ERROR, ''); - commit(types.TOGGLE_LOADING); - - return fetch( - { id: (state.retrieved && state.retrieved['@id']) || values['@id'], ep }, - { - method: 'PUT', - headers: new Headers({ 'Content-Type': 'application/ld+json' }), - body: JSON.stringify(values), - } - ) - .then(response => response.json()) - .then(data => { - commit(types.TOGGLE_LOADING); - commit(types.SET_UPDATED, data); - }) - .catch(e => { - commit(types.TOGGLE_LOADING); - - if (e instanceof SubmissionError) { - commit(types.SET_VIOLATIONS, e.errors); - // eslint-disable-next-line - commit(types.SET_ERROR, e.errors._error); - - return; - } - - // eslint-disable-next-line - commit(types.SET_ERROR, e.message); - }); -}; diff --git a/templates/quasar/common/store/update/getters.js b/templates/quasar/common/store/update/getters.js deleted file mode 100644 index 80690026..00000000 --- a/templates/quasar/common/store/update/getters.js +++ /dev/null @@ -1,5 +0,0 @@ -export const error = state => state.error; -export const isLoading = state => state.isLoading; -export const retrieved = state => state.retrieved; -export const updated = state => state.updated; -export const violations = state => state.violations; diff --git a/templates/quasar/common/store/update/mutation_types.js b/templates/quasar/common/store/update/mutation_types.js deleted file mode 100644 index ec0244c1..00000000 --- a/templates/quasar/common/store/update/mutation_types.js +++ /dev/null @@ -1,12 +0,0 @@ -import { mutationTypes } from '../mutation_types'; - -const types = [ - 'RESET', - 'SET_ERROR', - 'SET_RETRIEVED', - 'SET_UPDATED', - 'SET_VIOLATIONS', - 'TOGGLE_LOADING', -]; - -export default m => mutationTypes(m, 'UPDATE', types); diff --git a/templates/quasar/common/store/update/mutations.js b/templates/quasar/common/store/update/mutations.js deleted file mode 100644 index 42eab2fe..00000000 --- a/templates/quasar/common/store/update/mutations.js +++ /dev/null @@ -1,25 +0,0 @@ -export default (initState, types) => ({ - [types.RESET](state) { - Object.assign(state, initState); - }, - - [types.SET_ERROR](state, error) { - Object.assign(state, { error }); - }, - - [types.TOGGLE_LOADING](state) { - Object.assign(state, { isLoading: !state.isLoading }); - }, - - [types.SET_RETRIEVED](state, retrieved) { - Object.assign(state, { retrieved }); - }, - - [types.SET_UPDATED](state, updated) { - Object.assign(state, { error: '', updated, violations: null }); - }, - - [types.SET_VIOLATIONS](state, violations) { - Object.assign(state, { violations }); - }, -}); diff --git a/templates/quasar/common/store/update/state.js b/templates/quasar/common/store/update/state.js deleted file mode 100644 index 718ce69c..00000000 --- a/templates/quasar/common/store/update/state.js +++ /dev/null @@ -1,7 +0,0 @@ -export default () => ({ - error: '', - isLoading: false, - retrieved: null, - updated: null, - violations: null, -}); diff --git a/templates/quasar/components/common/CommonActionCell.vue b/templates/quasar/components/common/CommonActionCell.vue new file mode 100644 index 00000000..a2c6b593 --- /dev/null +++ b/templates/quasar/components/common/CommonActionCell.vue @@ -0,0 +1,75 @@ + + + diff --git a/templates/quasar/components/common/CommonBreadcrumb.vue b/templates/quasar/components/common/CommonBreadcrumb.vue new file mode 100644 index 00000000..e3ca889e --- /dev/null +++ b/templates/quasar/components/common/CommonBreadcrumb.vue @@ -0,0 +1,27 @@ + + + diff --git a/templates/quasar/components/common/CommonConfirmDelete.vue b/templates/quasar/components/common/CommonConfirmDelete.vue new file mode 100644 index 00000000..441d81da --- /dev/null +++ b/templates/quasar/components/common/CommonConfirmDelete.vue @@ -0,0 +1,54 @@ + + + diff --git a/templates/quasar/components/common/CommonDataFilter.vue b/templates/quasar/components/common/CommonDataFilter.vue new file mode 100644 index 00000000..0aeed752 --- /dev/null +++ b/templates/quasar/components/common/CommonDataFilter.vue @@ -0,0 +1,44 @@ + + + diff --git a/templates/quasar/components/common/CommonFormRepeater.vue b/templates/quasar/components/common/CommonFormRepeater.vue new file mode 100644 index 00000000..ab6f6db4 --- /dev/null +++ b/templates/quasar/components/common/CommonFormRepeater.vue @@ -0,0 +1,72 @@ + + + diff --git a/templates/quasar/components/common/CommonLoading.vue b/templates/quasar/components/common/CommonLoading.vue new file mode 100644 index 00000000..8d3d38a8 --- /dev/null +++ b/templates/quasar/components/common/CommonLoading.vue @@ -0,0 +1,11 @@ + + + diff --git a/templates/quasar/components/common/CommonToolbar.vue b/templates/quasar/components/common/CommonToolbar.vue new file mode 100644 index 00000000..a4f5d033 --- /dev/null +++ b/templates/quasar/components/common/CommonToolbar.vue @@ -0,0 +1,93 @@ + + + diff --git a/templates/quasar/components/foo/Create.vue b/templates/quasar/components/foo/Create.vue deleted file mode 100644 index d4d26df7..00000000 --- a/templates/quasar/components/foo/Create.vue +++ /dev/null @@ -1,56 +0,0 @@ - - - diff --git a/templates/quasar/components/foo/Filter.vue b/templates/quasar/components/foo/Filter.vue deleted file mode 100644 index 79caa479..00000000 --- a/templates/quasar/components/foo/Filter.vue +++ /dev/null @@ -1,191 +0,0 @@ - - - diff --git a/templates/quasar/components/foo/FooCreate.vue b/templates/quasar/components/foo/FooCreate.vue new file mode 100644 index 00000000..e782e53a --- /dev/null +++ b/templates/quasar/components/foo/FooCreate.vue @@ -0,0 +1,42 @@ + + + diff --git a/templates/quasar/components/foo/FooFilter.vue b/templates/quasar/components/foo/FooFilter.vue new file mode 100644 index 00000000..8ad251c1 --- /dev/null +++ b/templates/quasar/components/foo/FooFilter.vue @@ -0,0 +1,31 @@ + + + diff --git a/templates/quasar/components/foo/FooForm.vue b/templates/quasar/components/foo/FooForm.vue new file mode 100644 index 00000000..b2d98f79 --- /dev/null +++ b/templates/quasar/components/foo/FooForm.vue @@ -0,0 +1,103 @@ + + + diff --git a/templates/quasar/components/foo/FooList.vue b/templates/quasar/components/foo/FooList.vue new file mode 100644 index 00000000..7942090f --- /dev/null +++ b/templates/quasar/components/foo/FooList.vue @@ -0,0 +1,304 @@ + + + diff --git a/templates/quasar/components/foo/FooShow.vue b/templates/quasar/components/foo/FooShow.vue new file mode 100644 index 00000000..ed13cd21 --- /dev/null +++ b/templates/quasar/components/foo/FooShow.vue @@ -0,0 +1,157 @@ + + + diff --git a/templates/quasar/components/foo/FooUpdate.vue b/templates/quasar/components/foo/FooUpdate.vue new file mode 100644 index 00000000..5c6b9f4a --- /dev/null +++ b/templates/quasar/components/foo/FooUpdate.vue @@ -0,0 +1,86 @@ + + + diff --git a/templates/quasar/components/foo/Form.vue b/templates/quasar/components/foo/Form.vue deleted file mode 100644 index 4c361744..00000000 --- a/templates/quasar/components/foo/Form.vue +++ /dev/null @@ -1,228 +0,0 @@ - - - diff --git a/templates/quasar/components/foo/List.vue b/templates/quasar/components/foo/List.vue deleted file mode 100644 index a42e99fd..00000000 --- a/templates/quasar/components/foo/List.vue +++ /dev/null @@ -1,132 +0,0 @@ - - - diff --git a/templates/quasar/components/foo/Show.vue b/templates/quasar/components/foo/Show.vue deleted file mode 100644 index a8ad2f59..00000000 --- a/templates/quasar/components/foo/Show.vue +++ /dev/null @@ -1,73 +0,0 @@ - - - diff --git a/templates/quasar/components/foo/Update.vue b/templates/quasar/components/foo/Update.vue deleted file mode 100644 index 4f04665b..00000000 --- a/templates/quasar/components/foo/Update.vue +++ /dev/null @@ -1,39 +0,0 @@ - - - diff --git a/templates/quasar/composables/breadcrumb.ts b/templates/quasar/composables/breadcrumb.ts new file mode 100644 index 00000000..ea776382 --- /dev/null +++ b/templates/quasar/composables/breadcrumb.ts @@ -0,0 +1,9 @@ +import { useRoute } from 'vue-router'; +import type { BreadcrumbValue } from 'src/types/breadcrumb'; + +export function useBreadcrumb() { + const route = useRoute(); + const breadcrumb = route.meta.breadcrumb as BreadcrumbValue[]; + + return breadcrumb; +} diff --git a/templates/quasar/composables/errors.ts b/templates/quasar/composables/errors.ts new file mode 100644 index 00000000..2ed28288 --- /dev/null +++ b/templates/quasar/composables/errors.ts @@ -0,0 +1,18 @@ +import { Ref, watch } from 'vue'; +import { useNotifications } from './notifications'; + +export function useWatchErrors( + errors: (Ref | undefined)[] +) { + const { displayErrorNotification } = useNotifications(); + + watch(errors, (newErrors) => { + newErrors.forEach((newError) => { + if (!newError?.value) { + return; + } + + displayErrorNotification(newError.value); + }); + }); +} diff --git a/templates/quasar/composables/notifications.ts b/templates/quasar/composables/notifications.ts new file mode 100644 index 00000000..7eb075ff --- /dev/null +++ b/templates/quasar/composables/notifications.ts @@ -0,0 +1,30 @@ +import { useQuasar } from 'quasar'; +import { useI18n } from 'vue-i18n'; + +export function useNotifications() { + const $q = useQuasar(); + const { t } = useI18n(); + + const displayErrorNotification = (message: string) => { + $q.notify({ + message, + color: 'red', + icon: 'error', + closeBtn: t('close'), + }); + }; + + const displaySuccessNotification = (message: string) => { + $q.notify({ + message, + color: 'green', + icon: 'tag_faces', + closeBtn: t('close'), + }); + }; + + return { + displayErrorNotification, + displaySuccessNotification, + }; +} diff --git a/templates/quasar/error/SubmissionError.js b/templates/quasar/error/SubmissionError.js deleted file mode 100644 index fbbdfafa..00000000 --- a/templates/quasar/error/SubmissionError.js +++ /dev/null @@ -1,9 +0,0 @@ -export default class SubmissionError extends Error { - constructor(errors) { - super('Submit Validation Failed'); - this.errors = errors; - Error.captureStackTrace(this, this.constructor); - this.name = this.constructor.name; - return this; - } -} diff --git a/templates/quasar/i18n/common.ts b/templates/quasar/i18n/common.ts new file mode 100644 index 00000000..68e60200 --- /dev/null +++ b/templates/quasar/i18n/common.ts @@ -0,0 +1,5 @@ +export default { + {{#each labels}} + {{@key}}: '{{this}}', + {{/each }} +}; diff --git a/templates/quasar/i18n/foo.ts b/templates/quasar/i18n/foo.ts new file mode 100644 index 00000000..2e380185 --- /dev/null +++ b/templates/quasar/i18n/foo.ts @@ -0,0 +1,5 @@ +export default { + {{#each labels}} + {{this}}: '{{capitalize this}}', + {{/each }} +}; diff --git a/templates/quasar/i18n/index.js b/templates/quasar/i18n/index.js deleted file mode 100644 index 5d50295e..00000000 --- a/templates/quasar/i18n/index.js +++ /dev/null @@ -1,5 +0,0 @@ -export default { - {{#each labels as |label|}} - '{{{capitalize label}}}': '{{{capitalize label}}}', - {{/each }} -}; diff --git a/templates/quasar/pages/foo/PageCreate.vue b/templates/quasar/pages/foo/PageCreate.vue new file mode 100644 index 00000000..373f99ec --- /dev/null +++ b/templates/quasar/pages/foo/PageCreate.vue @@ -0,0 +1,11 @@ + + + diff --git a/templates/quasar/pages/foo/PageList.vue b/templates/quasar/pages/foo/PageList.vue new file mode 100644 index 00000000..346fe490 --- /dev/null +++ b/templates/quasar/pages/foo/PageList.vue @@ -0,0 +1,11 @@ + + + diff --git a/templates/quasar/pages/foo/PageShow.vue b/templates/quasar/pages/foo/PageShow.vue new file mode 100644 index 00000000..b1346509 --- /dev/null +++ b/templates/quasar/pages/foo/PageShow.vue @@ -0,0 +1,11 @@ + + + diff --git a/templates/quasar/pages/foo/PageUpdate.vue b/templates/quasar/pages/foo/PageUpdate.vue new file mode 100644 index 00000000..0ab67aa0 --- /dev/null +++ b/templates/quasar/pages/foo/PageUpdate.vue @@ -0,0 +1,11 @@ + + + diff --git a/templates/quasar/router/foo.js b/templates/quasar/router/foo.js deleted file mode 100644 index 19547cbe..00000000 --- a/templates/quasar/router/foo.js +++ /dev/null @@ -1,65 +0,0 @@ -import {{{titleUcFirst}}}List from '../components/{{{lc}}}/List'; -import {{{titleUcFirst}}}Create from '../components/{{{lc}}}/Create'; -import {{{titleUcFirst}}}Update from '../components/{{{lc}}}/Update'; -import {{{titleUcFirst}}}Show from '../components/{{{lc}}}/Show'; - -const list = { - label: '{{{ titleUcFirst }}}List', - icon: 'whatshot', -}; -const create = { - label: '{{{ titleUcFirst }}}Create', - icon: 'whatshot', -}; -const update = { - label: '{{{ titleUcFirst }}}Update', - icon: 'whatshot', -}; -const show = { - label: '{{{ titleUcFirst }}}Show', - icon: 'whatshot', -}; - -export default [ - { - name: list['label'], - path: '/{{{name}}}/', - component: {{{ titleUcFirst }}}List, - meta: { - breadcrumb: [list], - }, - }, - { - name: create['label'], - path: '/{{{name}}}/create', - component: {{{ titleUcFirst }}}Create, - meta: { - breadcrumb: [ - { ...list , to: { name: list['label'] } }, - create, - ], - }, - }, - { - name: update['label'], - path: '/{{{name}}}/edit/:id', - component: {{{ titleUcFirst }}}Update, - meta: { - breadcrumb: [ - { ...list , to: { name: list['label'] } }, - update, - ], - }, - }, - { - name: show['label'], - path: '/{{{name}}}/show/:id', - component: {{{ titleUcFirst }}}Show, - meta: { - breadcrumb: [ - { ...list , to: { name: list['label'] } }, - show, - ], - }, - }, -]; diff --git a/templates/quasar/router/foo.ts b/templates/quasar/router/foo.ts new file mode 100644 index 00000000..76d3eab2 --- /dev/null +++ b/templates/quasar/router/foo.ts @@ -0,0 +1,53 @@ +import type { BreadcrumbValue } from 'types/breadcrumb'; + +const list: BreadcrumbValue = { + label: '{{titleUcFirst}}List', + icon: 'whatshot', +}; +const create: BreadcrumbValue = { + label: '{{titleUcFirst}}Create', + icon: 'whatshot', +}; +const update: BreadcrumbValue = { + label: '{{titleUcFirst}}Update', + icon: 'whatshot', +}; +const show: BreadcrumbValue = { + label: '{{titleUcFirst}}Show', + icon: 'whatshot', +}; + +export default [ + { + name: list.label, + path: '/{{name}}/', + component: () => import('pages/{{lc}}/PageList.vue'), + meta: { + breadcrumb: [list], + }, + }, + { + name: create.label, + path: '/{{name}}/create', + component: () => import('pages/{{lc}}/PageCreate.vue'), + meta: { + breadcrumb: [{ ...list, to: { name: list.label } }, create], + }, + }, + { + name: update.label, + path: '/{{name}}/edit/:id', + component: () => import('pages/{{lc}}/PageUpdate.vue'), + meta: { + breadcrumb: [{ ...list, to: { name: list.label } }, update], + }, + }, + { + name: show.label, + path: '/{{name}}/show/:id', + component: () => import('pages/{{lc}}/PageShow.vue'), + meta: { + breadcrumb: [{ ...list, to: { name: list.label } }, show], + }, + }, +]; diff --git a/templates/quasar/store/modules/foo/create/actions.js b/templates/quasar/store/modules/foo/create/actions.js deleted file mode 100644 index 22b767d6..00000000 --- a/templates/quasar/store/modules/foo/create/actions.js +++ /dev/null @@ -1,13 +0,0 @@ -import { createCommon, resetCommon } from '../../../../common/store/create/actions'; -import { ENTRYPOINT } from "../../../../config/{{{hashEntry}}}_entrypoint"; - -const page = '{{{name}}}'; - -export default function(types) { - const create = (context, values) => - createCommon(context, { page, values, ep: ENTRYPOINT }, { types }); - - const reset = context => resetCommon(context, { types }); - - return { create, reset }; -} diff --git a/templates/quasar/store/modules/foo/create/getters.js b/templates/quasar/store/modules/foo/create/getters.js deleted file mode 100644 index 5580e943..00000000 --- a/templates/quasar/store/modules/foo/create/getters.js +++ /dev/null @@ -1 +0,0 @@ -export * from "../../../../common/store/create/getters"; diff --git a/templates/quasar/store/modules/foo/create/index.js b/templates/quasar/store/modules/foo/create/index.js deleted file mode 100644 index 70c23968..00000000 --- a/templates/quasar/store/modules/foo/create/index.js +++ /dev/null @@ -1,13 +0,0 @@ -import actions from './actions'; -import * as getters from './getters'; -import mutations from './mutations'; -import state from './state'; -import types from "./mutation_types"; - -export default { - namespaced: true, - state, - actions: actions(types), - getters, - mutations: mutations(state, types) -}; diff --git a/templates/quasar/store/modules/foo/create/mutation_types.js b/templates/quasar/store/modules/foo/create/mutation_types.js deleted file mode 100644 index 5154b1cd..00000000 --- a/templates/quasar/store/modules/foo/create/mutation_types.js +++ /dev/null @@ -1,2 +0,0 @@ -import makeTypes from '../../../../common/store/create/mutation_types'; -export default makeTypes('{{{uc}}}'); diff --git a/templates/quasar/store/modules/foo/create/mutations.js b/templates/quasar/store/modules/foo/create/mutations.js deleted file mode 100644 index eeffa4c8..00000000 --- a/templates/quasar/store/modules/foo/create/mutations.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "../../../../common/store/create/mutations"; diff --git a/templates/quasar/store/modules/foo/create/state.js b/templates/quasar/store/modules/foo/create/state.js deleted file mode 100644 index 3830ddc5..00000000 --- a/templates/quasar/store/modules/foo/create/state.js +++ /dev/null @@ -1,2 +0,0 @@ -import makeState from '../../../../common/store/create/state'; -export default makeState(); diff --git a/templates/quasar/store/modules/foo/delete/actions.js b/templates/quasar/store/modules/foo/delete/actions.js deleted file mode 100644 index 616a158c..00000000 --- a/templates/quasar/store/modules/foo/delete/actions.js +++ /dev/null @@ -1,11 +0,0 @@ -import { delCommon, resetCommon } from '../../../../common/store/delete/actions'; -import { ENTRYPOINT } from "../../../../config/{{{hashEntry}}}_entrypoint"; - -export default function(types) { - const del = (context, item) => delCommon(context, { item, ep: ENTRYPOINT }, { types }); - const reset = context => { - resetCommon(context, { types }); - }; - - return { del, reset }; -} diff --git a/templates/quasar/store/modules/foo/delete/getters.js b/templates/quasar/store/modules/foo/delete/getters.js deleted file mode 100644 index 85deab48..00000000 --- a/templates/quasar/store/modules/foo/delete/getters.js +++ /dev/null @@ -1 +0,0 @@ -export * from "../../../../common/store/delete/getters"; diff --git a/templates/quasar/store/modules/foo/delete/index.js b/templates/quasar/store/modules/foo/delete/index.js deleted file mode 100644 index 70c23968..00000000 --- a/templates/quasar/store/modules/foo/delete/index.js +++ /dev/null @@ -1,13 +0,0 @@ -import actions from './actions'; -import * as getters from './getters'; -import mutations from './mutations'; -import state from './state'; -import types from "./mutation_types"; - -export default { - namespaced: true, - state, - actions: actions(types), - getters, - mutations: mutations(state, types) -}; diff --git a/templates/quasar/store/modules/foo/delete/mutation_types.js b/templates/quasar/store/modules/foo/delete/mutation_types.js deleted file mode 100644 index 1079fc4c..00000000 --- a/templates/quasar/store/modules/foo/delete/mutation_types.js +++ /dev/null @@ -1,2 +0,0 @@ -import makeTypes from '../../../../common/store/delete/mutation_types'; -export default makeTypes("{{{uc}}}"); diff --git a/templates/quasar/store/modules/foo/delete/mutations.js b/templates/quasar/store/modules/foo/delete/mutations.js deleted file mode 100644 index 6dda4cf5..00000000 --- a/templates/quasar/store/modules/foo/delete/mutations.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "../../../../common/store/delete/mutations"; diff --git a/templates/quasar/store/modules/foo/delete/state.js b/templates/quasar/store/modules/foo/delete/state.js deleted file mode 100644 index f29a97a8..00000000 --- a/templates/quasar/store/modules/foo/delete/state.js +++ /dev/null @@ -1,2 +0,0 @@ -import makeState from '../../../../common/store/delete/state'; -export default makeState(); diff --git a/templates/quasar/store/modules/foo/index.js b/templates/quasar/store/modules/foo/index.js deleted file mode 100644 index c76b015f..00000000 --- a/templates/quasar/store/modules/foo/index.js +++ /dev/null @@ -1,16 +0,0 @@ -import list from './list'; -import create from './create'; -import update from './update'; -import show from './show'; -import del from './delete'; - -export default { - namespaced: true, - modules: { - list, - create, - update, - show, - del, - }, -}; diff --git a/templates/quasar/store/modules/foo/list/actions.js b/templates/quasar/store/modules/foo/list/actions.js deleted file mode 100644 index fc05ffc0..00000000 --- a/templates/quasar/store/modules/foo/list/actions.js +++ /dev/null @@ -1,26 +0,0 @@ -import { - getItemsCommon, - getSelectItemsCommon -} from '../../../../common/store/list/actions'; -import { ENTRYPOINT } from "../../../../config/{{{hashEntry}}}_entrypoint"; - -const hydraPrefix = '{{{hydraPrefix}}}'; -const page = '{{{name}}}'; - -export default function(types) { - const getItems = (context, options) => - getItemsCommon( - context, - { ...{ page, ep: ENTRYPOINT, params: {} }, ...options }, - { types, hydraPrefix }, - ); - - const getSelectItems = (context, options) => - getSelectItemsCommon( - context, - { ...{ page, ep: ENTRYPOINT, params: { properties: ['id', 'name'] } }, ...options }, - { types, hydraPrefix }, - ); - - return { getItems, getSelectItems }; -} diff --git a/templates/quasar/store/modules/foo/list/getters.js b/templates/quasar/store/modules/foo/list/getters.js deleted file mode 100644 index 956e50bd..00000000 --- a/templates/quasar/store/modules/foo/list/getters.js +++ /dev/null @@ -1 +0,0 @@ -export * from "../../../../common/store/list/getters"; diff --git a/templates/quasar/store/modules/foo/list/index.js b/templates/quasar/store/modules/foo/list/index.js deleted file mode 100644 index a71c9bae..00000000 --- a/templates/quasar/store/modules/foo/list/index.js +++ /dev/null @@ -1,13 +0,0 @@ -import actions from "./actions"; -import * as getters from "./getters"; -import mutations from "./mutations"; -import state from "./state"; -import types from "./mutation_types"; - -export default { - namespaced: true, - state, - actions: actions(types), - getters, - mutations: mutations(state, types) -}; diff --git a/templates/quasar/store/modules/foo/list/mutation_types.js b/templates/quasar/store/modules/foo/list/mutation_types.js deleted file mode 100644 index b57f3002..00000000 --- a/templates/quasar/store/modules/foo/list/mutation_types.js +++ /dev/null @@ -1,2 +0,0 @@ -import makeTypes from '../../../../common/store/list/mutation_types'; -export default makeTypes('{{{uc}}}'); diff --git a/templates/quasar/store/modules/foo/list/mutations.js b/templates/quasar/store/modules/foo/list/mutations.js deleted file mode 100644 index 59c22030..00000000 --- a/templates/quasar/store/modules/foo/list/mutations.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "../../../../common/store/list/mutations"; diff --git a/templates/quasar/store/modules/foo/list/state.js b/templates/quasar/store/modules/foo/list/state.js deleted file mode 100644 index ff95b484..00000000 --- a/templates/quasar/store/modules/foo/list/state.js +++ /dev/null @@ -1,2 +0,0 @@ -import makeState from "../../../../common/store/list/state"; -export default makeState(); diff --git a/templates/quasar/store/modules/foo/show/actions.js b/templates/quasar/store/modules/foo/show/actions.js deleted file mode 100644 index ec545b0c..00000000 --- a/templates/quasar/store/modules/foo/show/actions.js +++ /dev/null @@ -1,12 +0,0 @@ -import { retrieveCommon, resetCommon } from '../../../../common/store/show/actions'; -import { ENTRYPOINT } from "../../../../config/{{{hashEntry}}}_entrypoint"; - -export default function(types) { - const retrieve = (context, id) => retrieveCommon(context, { id, ep: ENTRYPOINT }, { types }); - - const reset = context => { - resetCommon(context, { types }); - }; - - return { retrieve, reset }; -} diff --git a/templates/quasar/store/modules/foo/show/getters.js b/templates/quasar/store/modules/foo/show/getters.js deleted file mode 100644 index dc7aea78..00000000 --- a/templates/quasar/store/modules/foo/show/getters.js +++ /dev/null @@ -1 +0,0 @@ -export * from "../../../../common/store/show/getters"; diff --git a/templates/quasar/store/modules/foo/show/index.js b/templates/quasar/store/modules/foo/show/index.js deleted file mode 100644 index 70c23968..00000000 --- a/templates/quasar/store/modules/foo/show/index.js +++ /dev/null @@ -1,13 +0,0 @@ -import actions from './actions'; -import * as getters from './getters'; -import mutations from './mutations'; -import state from './state'; -import types from "./mutation_types"; - -export default { - namespaced: true, - state, - actions: actions(types), - getters, - mutations: mutations(state, types) -}; diff --git a/templates/quasar/store/modules/foo/show/mutation_types.js b/templates/quasar/store/modules/foo/show/mutation_types.js deleted file mode 100644 index 1628ae4f..00000000 --- a/templates/quasar/store/modules/foo/show/mutation_types.js +++ /dev/null @@ -1,2 +0,0 @@ -import makeTypes from '../../../../common/store/show/mutation_types'; -export default makeTypes('{{{uc}}}'); diff --git a/templates/quasar/store/modules/foo/show/mutations.js b/templates/quasar/store/modules/foo/show/mutations.js deleted file mode 100644 index 47ab3091..00000000 --- a/templates/quasar/store/modules/foo/show/mutations.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "../../../../common/store/show/mutations"; diff --git a/templates/quasar/store/modules/foo/show/state.js b/templates/quasar/store/modules/foo/show/state.js deleted file mode 100644 index 2b014b9f..00000000 --- a/templates/quasar/store/modules/foo/show/state.js +++ /dev/null @@ -1,2 +0,0 @@ -import makeState from '../../../../common/store/show/state'; -export default makeState(); diff --git a/templates/quasar/store/modules/foo/update/actions.js b/templates/quasar/store/modules/foo/update/actions.js deleted file mode 100644 index 8edad5ec..00000000 --- a/templates/quasar/store/modules/foo/update/actions.js +++ /dev/null @@ -1,15 +0,0 @@ -import { resetCommon, retrieveCommon, updateCommon } from '../../../../common/store/update/actions'; -import { ENTRYPOINT } from "../../../../config/{{{hashEntry}}}_entrypoint"; - -export default function(types) { - const reset = context => { - resetCommon(context, { types }); - }; - - const retrieve = (context, id) => - retrieveCommon(context, { id, ep: ENTRYPOINT }, { types }); - const update = (context, values) => - updateCommon(context, { values, ep: ENTRYPOINT }, { types }); - - return { reset, retrieve, update }; -} diff --git a/templates/quasar/store/modules/foo/update/getters.js b/templates/quasar/store/modules/foo/update/getters.js deleted file mode 100644 index dca50409..00000000 --- a/templates/quasar/store/modules/foo/update/getters.js +++ /dev/null @@ -1 +0,0 @@ -export * from "../../../../common/store/update/getters"; diff --git a/templates/quasar/store/modules/foo/update/index.js b/templates/quasar/store/modules/foo/update/index.js deleted file mode 100644 index a71c9bae..00000000 --- a/templates/quasar/store/modules/foo/update/index.js +++ /dev/null @@ -1,13 +0,0 @@ -import actions from "./actions"; -import * as getters from "./getters"; -import mutations from "./mutations"; -import state from "./state"; -import types from "./mutation_types"; - -export default { - namespaced: true, - state, - actions: actions(types), - getters, - mutations: mutations(state, types) -}; diff --git a/templates/quasar/store/modules/foo/update/mutation_types.js b/templates/quasar/store/modules/foo/update/mutation_types.js deleted file mode 100644 index cc885f48..00000000 --- a/templates/quasar/store/modules/foo/update/mutation_types.js +++ /dev/null @@ -1,2 +0,0 @@ -import makeTypes from '../../../../common/store/update/mutation_types'; -export default makeTypes('{{{uc}}}'); diff --git a/templates/quasar/store/modules/foo/update/mutations.js b/templates/quasar/store/modules/foo/update/mutations.js deleted file mode 100644 index eb3de174..00000000 --- a/templates/quasar/store/modules/foo/update/mutations.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "../../../../common/store/update/mutations"; diff --git a/templates/quasar/store/modules/foo/update/state.js b/templates/quasar/store/modules/foo/update/state.js deleted file mode 100644 index fa8e51fe..00000000 --- a/templates/quasar/store/modules/foo/update/state.js +++ /dev/null @@ -1,2 +0,0 @@ -import makeState from '../../../../common/store/update/state'; -export default makeState(); diff --git a/templates/quasar/stores/foo/create.ts b/templates/quasar/stores/foo/create.ts new file mode 100644 index 00000000..1a003999 --- /dev/null +++ b/templates/quasar/stores/foo/create.ts @@ -0,0 +1,68 @@ +import { defineStore } from 'pinia'; +import { SubmissionError } from 'src/utils/error'; +import api from 'src/utils/api'; +import type { {{titleUcFirst}} } from 'src/types/{{lc}}'; +import type { SubmissionErrors } from 'src/types/error'; + +interface State { + created?: {{titleUcFirst}}; + isLoading: boolean; + error?: string; + violations?: SubmissionErrors; +} + +export const use{{titleUcFirst}}CreateStore = defineStore('{{lc}}Create', { + state: (): State => ({ + created: undefined, + isLoading: false, + error: undefined, + violations: undefined, + }), + + actions: { + async create(payload: {{titleUcFirst}}) { + this.setError(undefined); + this.setViolations(undefined); + this.toggleLoading(); + + try { + const response = await api('{{name}}', { + method: 'POST', + body: JSON.stringify(payload), + }); + const data: {{titleUcFirst}} = await response.json(); + + this.toggleLoading(); + this.setCreated(data); + } catch (error) { + this.toggleLoading(); + + if (error instanceof SubmissionError) { + this.setViolations(error.errors); + this.setError(error.errors._error); + return; + } + + if (error instanceof Error) { + this.setError(error.message); + } + } + }, + + setCreated(created: {{titleUcFirst}}) { + this.created = created; + }, + + toggleLoading() { + this.isLoading = !this.isLoading; + }, + + setError(error: string | undefined) { + this.error = error; + }, + + setViolations(violations: SubmissionErrors | undefined) { + this.violations = violations; + }, + }, +}); diff --git a/templates/quasar/stores/foo/delete.ts b/templates/quasar/stores/foo/delete.ts new file mode 100644 index 00000000..8fd3aab8 --- /dev/null +++ b/templates/quasar/stores/foo/delete.ts @@ -0,0 +1,60 @@ +import { defineStore } from 'pinia'; +import api from 'src/utils/api'; +import type { {{titleUcFirst}} } from 'src/types/{{lc}}'; + +interface State { + deleted?: {{titleUcFirst}}; + mercureDeleted?: {{titleUcFirst}}; + isLoading: boolean; + error?: string; +} + +export const use{{titleUcFirst}}DeleteStore = defineStore('{{lc}}Delete', { + state: (): State => ({ + deleted: undefined, + mercureDeleted: undefined, + isLoading: false, + error: undefined, + }), + + actions: { + async deleteItem(item: {{titleUcFirst}}) { + this.toggleLoading(); + + if (!item?.['@id']) { + this.setError('No {{lc}} found. Please reload'); + return; + } + + try { + await api(item['@id'], { method: 'DELETE' }); + + this.toggleLoading(); + this.setDeleted(item); + this.setMercureDeleted(undefined); + } catch (error) { + this.toggleLoading(); + + if (error instanceof Error) { + this.setError(error.message); + } + } + }, + + toggleLoading() { + this.isLoading = !this.isLoading; + }, + + setDeleted(deleted: {{titleUcFirst}}) { + this.deleted = deleted; + }, + + setMercureDeleted(mercureDeleted?: {{titleUcFirst}}) { + this.mercureDeleted = mercureDeleted; + }, + + setError(error: string) { + this.error = error; + }, + }, +}); diff --git a/templates/quasar/stores/foo/list.ts b/templates/quasar/stores/foo/list.ts new file mode 100644 index 00000000..a77f077b --- /dev/null +++ b/templates/quasar/stores/foo/list.ts @@ -0,0 +1,96 @@ +import { defineStore } from 'pinia'; +import api from 'src/utils/api'; +import { extractHubURL } from 'src/utils/mercure'; +import type { PagedCollection } from 'src/types/collection'; +import type { ListParams } from 'src/types/list'; +import type { {{titleUcFirst}} } from 'src/types/{{lc}}'; +import type { View } from 'src/types/view'; + +interface State { + items: {{titleUcFirst}}[]; + totalItems: number; + hubUrl?: URL; + isLoading: boolean; + view?: View; + error?: string; +} + +export const use{{titleUcFirst}}ListStore = defineStore('{{lc}}List', { + state: (): State => ({ + items: [], + totalItems: 0, + hubUrl: undefined, + isLoading: false, + view: undefined, + error: undefined, + }), + + actions: { + async getItems(page: string, params: ListParams) { + this.toggleLoading(); + + try { + const path = page ? `{{name}}?page=${page}` : '{{name}}'; + const response = await api(path, { params }); + const data: PagedCollection<{{titleUcFirst}}> = await response.json(); + const hubUrl = extractHubURL(response); + + this.toggleLoading(); + + this.setItems(data['{{hydraPrefix}}member']); + this.setTotalItems(data['{{hydraPrefix}}totalItems'] ?? 0); + this.setView(data['{{hydraPrefix}}view']); + + if (hubUrl) { + this.setHubUrl(hubUrl); + } + } catch (error) { + this.toggleLoading(); + + if (error instanceof Error) { + this.setError(error.message); + } + } + }, + + toggleLoading() { + this.isLoading = !this.isLoading; + }, + + setItems(items: {{titleUcFirst}}[]) { + this.items = items; + }, + + setTotalItems(totalItems: number) { + this.totalItems = totalItems; + }, + + setHubUrl(hubUrl: URL) { + this.hubUrl = hubUrl; + }, + + setView(view: View) { + this.view = view; + }, + + setError(error: string) { + this.error = error; + }, + + updateItem(updatedItem: {{titleUcFirst}}) { + const item: {{titleUcFirst}} | undefined = this.items.find( + (i) => i['@id'] === updatedItem['@id'] + ); + + if (!item) return; + + Object.assign(item, updatedItem); + }, + + deleteItem(deletedItem: {{titleUcFirst}}) { + this.items = this.items.filter((item) => { + return item['@id'] !== deletedItem['@id']; + }); + }, + }, +}); diff --git a/templates/quasar/stores/foo/show.ts b/templates/quasar/stores/foo/show.ts new file mode 100644 index 00000000..5a74c30e --- /dev/null +++ b/templates/quasar/stores/foo/show.ts @@ -0,0 +1,61 @@ +import { defineStore } from 'pinia'; +import api from 'src/utils/api'; +import { extractHubURL } from 'src/utils/mercure'; +import type { {{titleUcFirst}} } from 'src/types/{{lc}}'; + +interface State { + retrieved?: {{titleUcFirst}}; + hubUrl?: URL; + isLoading: boolean; + error?: string; +} + +export const use{{titleUcFirst}}ShowStore = defineStore('{{lc}}Show', { + state: (): State => ({ + retrieved: undefined, + hubUrl: undefined, + isLoading: false, + error: undefined, + }), + + actions: { + async retrieve(id: string) { + this.toggleLoading(); + + try { + const response = await api(id); + const data: {{titleUcFirst}} = await response.json(); + const hubUrl = extractHubURL(response); + + this.toggleLoading(); + this.setRetrieved(data); + + if (hubUrl) { + this.setHubUrl(hubUrl); + } + } catch (error) { + this.toggleLoading(); + + if (error instanceof Error) { + this.setError(error.message); + } + } + }, + + toggleLoading() { + this.isLoading = !this.isLoading; + }, + + setRetrieved(retrieved: {{titleUcFirst}}) { + this.retrieved = retrieved; + }, + + setHubUrl(hubUrl: URL) { + this.hubUrl = hubUrl; + }, + + setError(error: string) { + this.error = error; + }, + }, +}); diff --git a/templates/quasar/stores/foo/update.ts b/templates/quasar/stores/foo/update.ts new file mode 100644 index 00000000..13655651 --- /dev/null +++ b/templates/quasar/stores/foo/update.ts @@ -0,0 +1,117 @@ +import { defineStore } from 'pinia'; +import { SubmissionError } from 'src/utils/error'; +import api from 'src/utils/api'; +import { extractHubURL } from 'src/utils/mercure'; +import type { {{titleUcFirst}} } from 'src/types/{{lc}}'; +import type { SubmissionErrors } from 'src/types/error'; + +interface State { + retrieved?: {{titleUcFirst}}; + updated?: {{titleUcFirst}}; + hubUrl?: URL; + isLoading: boolean; + error?: string; + violations?: SubmissionErrors; +} + +export const use{{titleUcFirst}}UpdateStore = defineStore('{{lc}}Update', { + state: (): State => ({ + retrieved: undefined, + updated: undefined, + hubUrl: undefined, + isLoading: false, + error: undefined, + violations: undefined, + }), + + actions: { + async retrieve(id: string) { + this.toggleLoading(); + + try { + const response = await api(id); + const data: {{titleUcFirst}} = await response.json(); + const hubUrl = extractHubURL(response); + + this.toggleLoading(); + this.setRetrieved(data); + + if (hubUrl) { + this.setHubUrl(hubUrl); + } + } catch (error) { + this.toggleLoading(); + + if (error instanceof Error) { + this.setError(error.message); + } + } + }, + + async update(payload: {{titleUcFirst}}) { + this.setError(undefined); + this.toggleLoading(); + + if (!this.retrieved) { + this.setError('No {{lc}} found. Please reload'); + return; + } + + try { + const response = await api( + this.retrieved['@id'] ?? payload['@id'] ?? '', + { + method: 'PUT', + headers: new Headers({ 'Content-Type': 'application/ld+json' }), + body: JSON.stringify(payload), + } + ); + const data: {{titleUcFirst}} = await response.json(); + + this.toggleLoading(); + this.setUpdated(data); + } catch (error) { + this.toggleLoading(); + + if (error instanceof SubmissionError) { + this.setViolations(error.errors); + this.setError(error.errors._error); + return; + } + + if (error instanceof Error) { + this.setError(error.message); + } + } + }, + + setRetrieved(retrieved: {{titleUcFirst}}) { + this.retrieved = retrieved; + }, + + setUpdated(updated: {{titleUcFirst}}) { + this.updated = updated; + }, + + setHubUrl(hubUrl: URL) { + this.hubUrl = hubUrl; + }, + + toggleLoading() { + this.isLoading = !this.isLoading; + }, + + setError(error?: string) { + this.error = error; + }, + + setViolations(violations?: SubmissionErrors) { + this.violations = violations; + }, + + resetErrors() { + this.setError(undefined); + this.setViolations(undefined); + }, + }, +}); diff --git a/templates/quasar/types/breadcrumb.ts b/templates/quasar/types/breadcrumb.ts new file mode 100644 index 00000000..07132ad2 --- /dev/null +++ b/templates/quasar/types/breadcrumb.ts @@ -0,0 +1,7 @@ +import { RouteLocation } from 'vue-router'; + +export interface BreadcrumbValue { + label: string; + icon: string; + to?: RouteLocation; +} diff --git a/templates/quasar/types/list.ts b/templates/quasar/types/list.ts new file mode 100644 index 00000000..eca0b425 --- /dev/null +++ b/templates/quasar/types/list.ts @@ -0,0 +1,16 @@ +export interface Pagination { + sortBy?: string; + descending: boolean; + page: number; + rowsPerPage: number; + rowsNumber: number; +} + +export interface Filters { + [key: string]: string; +} + +export interface ListParams { + pagination?: Pagination; + filters?: Filters; +} diff --git a/templates/quasar/utils/dates.js b/templates/quasar/utils/dates.js deleted file mode 100644 index 5d8b4513..00000000 --- a/templates/quasar/utils/dates.js +++ /dev/null @@ -1,5 +0,0 @@ -import { date } from 'quasar'; - -const extractDate = value => date.extractDate(value, 'YYYY-MM-DDTHH:mm:ssZ'); - -export { extractDate }; diff --git a/templates/quasar/utils/fetch.js b/templates/quasar/utils/fetch.js deleted file mode 100644 index 823ac623..00000000 --- a/templates/quasar/utils/fetch.js +++ /dev/null @@ -1,57 +0,0 @@ -import SubmissionError from '../error/SubmissionError'; - -const MIME_TYPE = 'application/ld+json'; - -// make query string array of values -const makeParamArray = (key, arr) => arr.map(val => `${key}[]=${val}`).join('&'); - -export default function({ id, ep }, options = {}) { - if (typeof options.headers === 'undefined') Object.assign(options, { headers: new Headers() }); - - if (options.headers.get('Accept') === null) options.headers.set('Accept', MIME_TYPE); - - if ( - options.body !== undefined && - !(options.body instanceof FormData) && - options.headers.get('Content-Type') === null - ) { - options.headers.set('Content-Type', MIME_TYPE); - } - - if (options.params) { - var queryString = Object.keys(options.params) - .map(key => - Array.isArray(options.params[key]) - ? makeParamArray(key, options.params[key]) - : `${key}=${options.params[key]}`, - ) - .join('&'); - id = `${id}?${queryString}`; - } - - // enable CORS for all requests - Object.assign(options, { - mode: 'cors', - // credentials: 'include', // when credentials needed - }); - - const entryPoint = ep + (ep.endsWith('/') ? '' : '/'); - - return fetch(new URL(id, entryPoint), options).then(response => { - if (response.ok) return response; - - return response.json().then(json => { - const error = json['{{{hydraPrefix}}}description'] - ? json['{{{hydraPrefix}}}description'] - : response.statusText; - if (!json.violations) throw Error(error); - - const errors = { _error: error }; - json.violations.map(violation => - Object.assign(errors, { [violation.propertyPath]: violation.message }), - ); - - throw new SubmissionError(errors); - }); - }); -} diff --git a/templates/quasar/utils/notify.js b/templates/quasar/utils/notify.js deleted file mode 100644 index de4ed26e..00000000 --- a/templates/quasar/utils/notify.js +++ /dev/null @@ -1,31 +0,0 @@ -import { Notify } from 'quasar'; - -const error = (message, closeLabel) => - Notify.create({ - message, - color: 'red', - icon: 'error', - closeBtn: closeLabel, - }); - -const success = (message, closeLabel) => - Notify.create({ - message, - color: 'green', - icon: 'tag_faces', - closeBtn: closeLabel, - }); - -const warning = (message, closeLabel) => - Notify.create({ - message, - color: 'yellow', - icon: 'warning', - closeBtn: closeLabel, - }); - -export { - error, - success, - warning, -}; diff --git a/templates/quasar/utils/vuexer.js b/templates/quasar/utils/vuexer.js deleted file mode 100644 index 3047bc80..00000000 --- a/templates/quasar/utils/vuexer.js +++ /dev/null @@ -1,85 +0,0 @@ -import { mapActions, mapGetters, mapMutations, createNamespacedHelpers } from 'vuex'; - -export const create = module => { - const lowmod = module.toLowerCase(); - const { mapGetters, mapActions } = createNamespacedHelpers(`${lowmod}/create`); - const getters = mapGetters(['error', 'isLoading', 'created', 'violations']); - const actions = mapActions(['create']); - return { getters, actions }; -}; - -export const list = module => { - const lowmod = module.toLowerCase(); - const getters = mapGetters({ - deletedItem: `${lowmod}/del/deleted`, - error: `${lowmod}/list/error`, - items: `${lowmod}/list/items`, - isLoading: `${lowmod}/list/isLoading`, - view: `${lowmod}/list/view`, - totalItems: `${lowmod}/list/totalItems`, - }); - const actions = mapActions({ - getPage: `${lowmod}/list/getItems`, - deleteItem: `${lowmod}/del/del`, - }); - return { getters, actions }; -}; - -export const show = module => { - const lowmod = module.toLowerCase(); - const getters = mapGetters({ - deleteError: `${lowmod}/del/error`, - error: `${lowmod}/show/error`, - isLoading: `${lowmod}/show/isLoading`, - item: `${lowmod}/show/retrieved`, - }); - const actions = mapActions({ - del: `${lowmod}/del/del`, - reset: `${lowmod}/show/reset`, - retrieve: `${lowmod}/show/retrieve`, - }); - return { getters, actions }; -}; - -export const update = module => { - const lowmod = module.toLowerCase(); - const getters = mapGetters({ - isLoading: `${lowmod}/update/isLoading`, - error: `${lowmod}/update/error`, - deleteError: `${lowmod}/del/error`, - deleteLoading: `${lowmod}/del/isLoading`, - deleted: `${lowmod}/del/deleted`, - retrieved: `${lowmod}/update/retrieved`, - updated: `${lowmod}/update/updated`, - violations: `${lowmod}/update/violations`, - }); - const actions = mapActions({ - createReset: `${lowmod}/create/reset`, - deleteItem: `${lowmod}/del/del`, - delReset: `${lowmod}/del/reset`, - retrieve: `${lowmod}/update/retrieve`, - updateReset: `${lowmod}/update/reset`, - update: `${lowmod}/update/update`, - }); - return { getters, actions }; -}; - -export const form = modules => { - let getters = {}, - actions = {}, - mutations = {}; - modules.forEach(({ name, module }) => { - const lowmod = module.toLowerCase(); - getters[`${name}SelectItems`] = `${lowmod}/list/selectItems`; - getters[`${name}SelectItemsTemplate`] = `${lowmod}/list/selectItemsTemplate`; - actions[`${name}GetSelectItems`] = `${lowmod}/list/getSelectItems`; - mutations[ - `${name}SetSelectItemsTemplate` - ] = `${lowmod}/list/${module.toUpperCase()}_LIST_SET_SELECT_ITEMS_TEMPLATE`; - }); - return { - getters: mapGetters(getters), - actions: mapActions(actions), - mutations: mapMutations(mutations), - }; -}; diff --git a/templates/vue/composables/mercureItem.ts b/templates/vue-common/composables/mercureItem.ts similarity index 91% rename from templates/vue/composables/mercureItem.ts rename to templates/vue-common/composables/mercureItem.ts index 68191d9f..546a941b 100644 --- a/templates/vue/composables/mercureItem.ts +++ b/templates/vue-common/composables/mercureItem.ts @@ -1,8 +1,8 @@ import { onBeforeUnmount } from "vue"; import { useRouter } from "vue-router"; -import { mercureSubscribe } from "@/utils/mercure"; import type { StoreGeneric } from "pinia"; -import type { Item } from "@/types/item"; +import { mercureSubscribe } from "../utils/mercure"; +import type { Item } from "../types/item"; export function useMercureItem({ store, diff --git a/templates/vue/composables/mercureList.ts b/templates/vue-common/composables/mercureList.ts similarity index 90% rename from templates/vue/composables/mercureList.ts rename to templates/vue-common/composables/mercureList.ts index 83e106d5..fd9b515a 100644 --- a/templates/vue/composables/mercureList.ts +++ b/templates/vue-common/composables/mercureList.ts @@ -1,7 +1,7 @@ import { onBeforeUnmount } from "vue"; -import { mercureSubscribe } from "@/utils/mercure"; import type { StoreGeneric } from "pinia"; -import type { Item } from "@/types/item"; +import { mercureSubscribe } from "../utils/mercure"; +import type { Item } from "../types/item"; export function useMercureList({ store, diff --git a/templates/vue/utils/api.ts b/templates/vue/utils/api.ts deleted file mode 100644 index c1098d64..00000000 --- a/templates/vue/utils/api.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { isArray, isObject, isUndefined, forEach } from "lodash"; -import { ENTRYPOINT } from "@/utils/config"; -import { SubmissionError } from "@/utils/error"; -import type { SubmissionErrors } from "@/types/error"; - -const MIME_TYPE = "application/ld+json"; - -const transformRelationToIri = (payload: any) => { - forEach(payload, (value, property) => { - if ((isObject(value) as any) && !isUndefined(value["@id"])) { - payload[property] = value["@id"]; - } - - if (isArray(value)) payload[property] = transformRelationToIri(value); - }); - - return payload; -}; - -export default async function (id: string, options: any = {}) { - if (options.headers !== "undefined") { - options.headers = new Headers(); - } - - if (options.headers.get("Accept") === null) { - options.headers.set("Accept", MIME_TYPE); - options.headers.set("Content-Type", MIME_TYPE); - } - - if ( - options.body !== "undefined" && - !(options.body instanceof FormData) && - options.headers.get("Content-Type" === null) - ) { - options.headers.set("Content-Type", MIME_TYPE); - } - - const payload: any = options.body && JSON.parse(options.body); - if ((isObject(payload) as any) && payload["@id"]) { - options.body = JSON.stringify(transformRelationToIri(payload)); - } - - const response = await fetch(new URL(id, ENTRYPOINT), options); - - if (!response.ok) { - const data = await response.json(); - const error = data["{{hydraPrefix}}description"] || response.statusText; - if (!data.violations) throw Error(error); - - const errors: SubmissionErrors = { _error: error }; - data.violations.forEach( - (violation: { propertyPath: string; message: string }) => { - errors[violation.propertyPath] = violation.message; - } - ); - - throw new SubmissionError(errors); - } - - return response; -} diff --git a/templates/vue/utils/date.ts b/templates/vue/utils/date.ts deleted file mode 100644 index 36589faa..00000000 --- a/templates/vue/utils/date.ts +++ /dev/null @@ -1,15 +0,0 @@ -import dayjs from "dayjs"; - -const formatDateTime = (date?: string): string | null => { - if (!date) return null; - - return dayjs(date).format("DD/MM/YYYY"); -}; - -const formatDateInput = (date?: string): string | undefined => { - if (!date) return undefined; - - return dayjs(date).format("YYYY-MM-DD"); -}; - -export { formatDateTime, formatDateInput }; diff --git a/testapp.sh b/testapp.sh index 67d8642c..62c52119 100755 --- a/testapp.sh +++ b/testapp.sh @@ -24,12 +24,30 @@ if [ "$1" = "next" ]; then start-server-and-test 'yarn --cwd ./tmp/app/next start' http://127.0.0.1:3000/books/ 'yarn playwright test' fi +if [ "$1" = "react" ]; then + yarn create react-app --template typescript ./tmp/app/reactapp + yarn --cwd ./tmp/app/reactapp add react-router-dom react-hook-form + + cp -R ./tmp/react/* ./tmp/app/reactapp/src + cp ./templates/react/index.tsx ./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' +fi + +if [ "$1" = "nuxt" ]; then + yarn create nuxt-app --answers "'{\"name\":\"nuxt\",\"language\":\"js\",\"pm\":\"yarn\",\"ui\":\"vuetify\",\"template\":\"html\",\"features\":[],\"linter\":[],\"test\":\"none\",\"mode\":\"spa\",\"target\":\"static\",\"devTools\":[],\"vcs\":\"none\"}'" ./tmp/app/nuxt + yarn --cwd ./tmp/app/nuxt add moment lodash vuelidate vuex-map-fields + + cp -R ./tmp/nuxt/* ./tmp/app/nuxt + NUXT_TELEMETRY_DISABLED=1 yarn --cwd ./tmp/app/nuxt generate + start-server-and-test 'yarn --cwd ./tmp/app/nuxt start --hostname 127.0.0.1' http://127.0.0.1:3000/books/ 'yarn playwright test' +fi + if [ "$1" = "vue" ]; then cd ./tmp/app npm init vue@3 -- --typescript --router --pinia --eslint-with-prettier vue cd ../.. yarn --cwd ./tmp/app/vue install - yarn --cwd ./tmp/app/vue add lodash @types/lodash dayjs + yarn --cwd ./tmp/app/vue add qs @types/qs dayjs # Tailwind yarn --cwd ./tmp/app/vue add tailwindcss postcss autoprefixer