From 8817fd7c5582934a91b2ec9d852c46e0517122a5 Mon Sep 17 00:00:00 2001 From: jorgep Date: Wed, 30 Oct 2024 13:55:51 +0100 Subject: [PATCH 1/8] feat: add support service wip --- src/boot/quasar.js | 58 ++++++++++++++++++++++++++++++-- src/components/NavBar.vue | 7 ++-- src/composables/useNotify.js | 3 +- src/composables/useVnConfirm.js | 31 ++++++++++------- src/i18n/locale/en.yml | 2 ++ src/i18n/locale/es.yml | 3 ++ src/stores/useStateQueryStore.js | 5 ++- 7 files changed, 90 insertions(+), 19 deletions(-) diff --git a/src/boot/quasar.js b/src/boot/quasar.js index 01fe68d8b..a1991d9a4 100644 --- a/src/boot/quasar.js +++ b/src/boot/quasar.js @@ -1,10 +1,17 @@ +import { ref } from 'vue'; +import axios from 'axios'; import { boot } from 'quasar/wrappers'; import qFormMixin from './qformMixin'; import keyShortcut from './keyShortcut'; +import { i18n } from './i18n'; import useNotify from 'src/composables/useNotify.js'; -import { CanceledError } from 'axios'; +import { useStateQueryStore } from 'src/stores/useStateQueryStore'; +import VnInput from 'src/components/common/VnInput.vue'; +import { useVnConfirm } from 'src/composables/useVnConfirm'; const { notify } = useNotify(); +const stateQuery = useStateQueryStore(); +const { openConfirmationModal } = useVnConfirm(); export default boot(({ app }) => { app.mixin(qFormMixin); @@ -40,12 +47,57 @@ export default boot(({ app }) => { } console.error(error); - if (error instanceof CanceledError) { + if (error instanceof axios.CanceledError) { const env = process.env.NODE_ENV; if (env && env !== 'development') return; message = 'Duplicate request'; } + // Convey to Alex or Juan... + const additionalData = { + frontPath: stateQuery.route.name, + backError: { + config: error.config, + data: error, + }, + httpRequest: error.request.response, + }; - notify(message ?? 'globals.error', 'negative', 'error'); + const opts = { + actions: [ + { + icon: 'support_agent', + color: 'primary', + dense: true, + flat: false, + round: true, + noDismiss: true, + handler: async () => { + const reason = ref(); + openConfirmationModal( + i18n.global.t('globals.sendCau'), + false, + async () => { + await axios.post('OsTickets/send-to-support', { + reason: reason.value, + additionalData, + }); + }, + null, + { + component: VnInput, + props: { + modelValue: reason, + 'onUpdate:modelValue': (val) => (reason.value = val), + label: i18n.global.t('globals.ExplainReason'), + class: 'full-width', + required: true, + }, + } + ); + }, + }, + ], + }; + notify(message ?? 'globals.error', 'negative', 'error', opts); }; }); diff --git a/src/components/NavBar.vue b/src/components/NavBar.vue index 9b0393489..6f8377d96 100644 --- a/src/components/NavBar.vue +++ b/src/components/NavBar.vue @@ -1,6 +1,7 @@ diff --git a/src/composables/useNotify.js b/src/composables/useNotify.js index 2f0e1c257..309156d2a 100644 --- a/src/composables/useNotify.js +++ b/src/composables/useNotify.js @@ -2,7 +2,7 @@ import { Notify } from 'quasar'; import { i18n } from 'src/boot/i18n'; export default function useNotify() { - const notify = (message, type, icon) => { + const notify = (message, type, icon, opts = {}) => { const defaultIcons = { warning: 'warning', negative: 'error', @@ -13,6 +13,7 @@ export default function useNotify() { message: i18n.global.t(message), type: type, icon: icon ? icon : defaultIcons[type], + ...opts, }); }; diff --git a/src/composables/useVnConfirm.js b/src/composables/useVnConfirm.js index 76c3f4f28..4438ad11d 100644 --- a/src/composables/useVnConfirm.js +++ b/src/composables/useVnConfirm.js @@ -1,22 +1,29 @@ +import { h } from 'vue'; +import { Dialog } from 'quasar'; import VnConfirm from 'components/ui/VnConfirm.vue'; -import { useQuasar } from 'quasar'; export function useVnConfirm() { - const quasar = useQuasar(); - - const openConfirmationModal = (title, message, promise, successFn) => { - quasar - .dialog({ - component: VnConfirm, - componentProps: { + const openConfirmationModal = ( + title, + message, + promise, + successFn, + customHTML = {} + ) => { + const { component, props } = customHTML; + Dialog.create({ + component: h( + VnConfirm, + { title: title, message: message, promise: promise, }, - }) - .onOk(async () => { - if (successFn) successFn(); - }); + { customHTML: () => h(component, props) } + ), + }).onOk(async () => { + if (successFn) successFn(); + }); }; return { openConfirmationModal }; diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml index 10186d92a..7feaa990a 100644 --- a/src/i18n/locale/en.yml +++ b/src/i18n/locale/en.yml @@ -314,6 +314,8 @@ globals: deleteConfirmTitle: Delete selected elements changeState: Change state raid: 'Raid {daysInForward} days' + sendCau: Send cau + ExplainReason: Explain why this error should not appear errors: statusUnauthorized: Access denied statusInternalServerError: An internal server error has ocurred diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml index 66b5efd52..be1e25ca8 100644 --- a/src/i18n/locale/es.yml +++ b/src/i18n/locale/es.yml @@ -318,6 +318,9 @@ globals: deleteConfirmTitle: Eliminar los elementos seleccionados changeState: Cambiar estado raid: 'Redada {daysInForward} días' + sendCau: Enviar cau + ExplainReason: Explique el motivo por el que no deberia aparecer este fallo + By sending this ticket, all the data related to the error, the section, the user, etc., are already sent.: Al enviar este cau ya se envían todos los datos relacionados con el error, la sección, el usuario, etc errors: statusUnauthorized: Acceso denegado statusInternalServerError: Ha ocurrido un error interno del servidor diff --git a/src/stores/useStateQueryStore.js b/src/stores/useStateQueryStore.js index d25dbb921..9893d3264 100644 --- a/src/stores/useStateQueryStore.js +++ b/src/stores/useStateQueryStore.js @@ -3,7 +3,9 @@ import { defineStore } from 'pinia'; export const useStateQueryStore = defineStore('stateQueryStore', () => { const queries = ref(new Set()); - + const route = computed(() => + Array.from(queries.value).find((query) => query?.fullPath) + ); function add(query) { queries.value.add(query); return query; @@ -27,5 +29,6 @@ export const useStateQueryStore = defineStore('stateQueryStore', () => { remove, queries, reset, + route, }; }); -- 2.40.1 From f6d200405ce236e88dcbc63152247b3d3a0766a2 Mon Sep 17 00:00:00 2001 From: jorgep Date: Tue, 5 Nov 2024 09:33:16 +0100 Subject: [PATCH 2/8] feat: message to grant access --- src/boot/quasar.js | 52 ++++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/src/boot/quasar.js b/src/boot/quasar.js index a1991d9a4..b3fb62ee7 100644 --- a/src/boot/quasar.js +++ b/src/boot/quasar.js @@ -62,6 +62,8 @@ export default boot(({ app }) => { httpRequest: error.request.response, }; + const isErrorPrivaleges = response?.code == 'ACCESS_DENIED'; + const opts = { actions: [ { @@ -70,30 +72,36 @@ export default boot(({ app }) => { dense: true, flat: false, round: true, - noDismiss: true, + noDismiss: isErrorPrivaleges, handler: async () => { - const reason = ref(); - openConfirmationModal( - i18n.global.t('globals.sendCau'), - false, - async () => { - await axios.post('OsTickets/send-to-support', { - reason: reason.value, - additionalData, - }); - }, - null, - { - component: VnInput, - props: { - modelValue: reason, - 'onUpdate:modelValue': (val) => (reason.value = val), - label: i18n.global.t('globals.ExplainReason'), - class: 'full-width', - required: true, + if (isErrorPrivaleges) { + // Create message and send to support + console.log('QUIERO ACCEDER!!!'); + } else { + const reason = ref(); + openConfirmationModal( + i18n.global.t('globals.sendCau'), + false, + async () => { + await axios.post('OsTickets/send-to-support', { + reason: reason.value, + additionalData, + }); }, - } - ); + null, + { + component: VnInput, + props: { + modelValue: reason, + 'onUpdate:modelValue': (val) => + (reason.value = val), + label: i18n.global.t('globals.ExplainReason'), + class: 'full-width', + required: true, + }, + } + ); + } }, }, ], -- 2.40.1 From 0c476725ae5672cf3bef59d32255797e6e1d6116 Mon Sep 17 00:00:00 2001 From: jorgep Date: Wed, 13 Nov 2024 13:11:02 +0100 Subject: [PATCH 3/8] refactor: use locale keys --- src/boot/quasar.js | 56 +++++++++++++++++++----------------------- src/i18n/locale/en.yml | 7 ++++-- src/i18n/locale/es.yml | 8 +++--- 3 files changed, 35 insertions(+), 36 deletions(-) diff --git a/src/boot/quasar.js b/src/boot/quasar.js index b3fb62ee7..5e10bacf1 100644 --- a/src/boot/quasar.js +++ b/src/boot/quasar.js @@ -61,9 +61,6 @@ export default boot(({ app }) => { }, httpRequest: error.request.response, }; - - const isErrorPrivaleges = response?.code == 'ACCESS_DENIED'; - const opts = { actions: [ { @@ -72,36 +69,33 @@ export default boot(({ app }) => { dense: true, flat: false, round: true, - noDismiss: isErrorPrivaleges, handler: async () => { - if (isErrorPrivaleges) { - // Create message and send to support - console.log('QUIERO ACCEDER!!!'); - } else { - const reason = ref(); - openConfirmationModal( - i18n.global.t('globals.sendCau'), - false, - async () => { - await axios.post('OsTickets/send-to-support', { - reason: reason.value, - additionalData, - }); + const reason = ref( + response.data.error.code == 'ACCESS_DENIED' + ? i18n.global.t('cau.askPrivileges') + : '' + ); + openConfirmationModal( + i18n.global.t('cau.title'), + i18n.global.t('cau.subtitle'), + async () => { + await axios.post('OsTickets/send-to-support', { + reason: reason.value, + additionalData, + }); + }, + null, + { + component: VnInput, + props: { + modelValue: reason, + 'onUpdate:modelValue': (val) => (reason.value = val), + label: i18n.global.t('cau.inputLabel'), + class: 'full-width', + required: true, }, - null, - { - component: VnInput, - props: { - modelValue: reason, - 'onUpdate:modelValue': (val) => - (reason.value = val), - label: i18n.global.t('globals.ExplainReason'), - class: 'full-width', - required: true, - }, - } - ); - } + } + ); }, }, ], diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml index e0d35d7e7..2eda4ddce 100644 --- a/src/i18n/locale/en.yml +++ b/src/i18n/locale/en.yml @@ -317,8 +317,6 @@ globals: deleteConfirmTitle: Delete selected elements changeState: Change state raid: 'Raid {daysInForward} days' - sendCau: Send cau - ExplainReason: Explain why this error should not appear errors: statusUnauthorized: Access denied statusInternalServerError: An internal server error has ocurred @@ -356,6 +354,11 @@ resetPassword: repeatPassword: Repeat password passwordNotMatch: Passwords don't match passwordChanged: Password changed +cau: + title: Send cau + subtitle: By sending this ticket, all the data related to the error, the section, the user, etc., are already sent. + inputLabel: Explain why this error should not appear + askPrivileges: Ask for privileges entry: list: newEntry: New entry diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml index ce8a8bf01..af475d27d 100644 --- a/src/i18n/locale/es.yml +++ b/src/i18n/locale/es.yml @@ -321,9 +321,6 @@ globals: deleteConfirmTitle: Eliminar los elementos seleccionados changeState: Cambiar estado raid: 'Redada {daysInForward} días' - sendCau: Enviar cau - ExplainReason: Explique el motivo por el que no deberia aparecer este fallo - By sending this ticket, all the data related to the error, the section, the user, etc., are already sent.: Al enviar este cau ya se envían todos los datos relacionados con el error, la sección, el usuario, etc errors: statusUnauthorized: Acceso denegado statusInternalServerError: Ha ocurrido un error interno del servidor @@ -359,6 +356,11 @@ resetPassword: repeatPassword: Repetir contraseña passwordNotMatch: Las contraseñas no coinciden passwordChanged: Contraseña cambiada +cau: + title: Enviar cau + subtitle: Al enviar este cau ya se envían todos los datos relacionados con el error, la sección, el usuario, etc + inputLabel: Explique el motivo por el que no deberia aparecer este fallo + askPrivileges: Solicitar permisos entry: list: newEntry: Nueva entrada -- 2.40.1 From 34df9cf2543fe0eb2783966897bd2dfd77416020 Mon Sep 17 00:00:00 2001 From: jorgep Date: Wed, 13 Nov 2024 15:33:41 +0100 Subject: [PATCH 4/8] fix: rollback --- src/boot/quasar.js | 13 +++++++------ src/components/NavBar.vue | 7 ++----- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/boot/quasar.js b/src/boot/quasar.js index 5e10bacf1..103b4812e 100644 --- a/src/boot/quasar.js +++ b/src/boot/quasar.js @@ -52,9 +52,9 @@ export default boot(({ app }) => { if (env && env !== 'development') return; message = 'Duplicate request'; } - // Convey to Alex or Juan... + const additionalData = { - frontPath: stateQuery.route.name, + frontPath: '', backError: { config: error.config, data: error, @@ -70,14 +70,15 @@ export default boot(({ app }) => { flat: false, round: true, handler: async () => { + const locale = i18n.global.t; const reason = ref( response.data.error.code == 'ACCESS_DENIED' - ? i18n.global.t('cau.askPrivileges') + ? locale('cau.askPrivileges') : '' ); openConfirmationModal( - i18n.global.t('cau.title'), - i18n.global.t('cau.subtitle'), + locale('cau.title'), + locale('cau.subtitle'), async () => { await axios.post('OsTickets/send-to-support', { reason: reason.value, @@ -90,7 +91,7 @@ export default boot(({ app }) => { props: { modelValue: reason, 'onUpdate:modelValue': (val) => (reason.value = val), - label: i18n.global.t('cau.inputLabel'), + label: locale('cau.inputLabel'), class: 'full-width', required: true, }, diff --git a/src/components/NavBar.vue b/src/components/NavBar.vue index 6f8377d96..9b0393489 100644 --- a/src/components/NavBar.vue +++ b/src/components/NavBar.vue @@ -1,7 +1,6 @@ -- 2.40.1 From a5d032f0224f4184bcf619762ff569656765bc0c Mon Sep 17 00:00:00 2001 From: jorgep Date: Wed, 13 Nov 2024 17:29:19 +0100 Subject: [PATCH 5/8] feat: make additional data object --- src/boot/quasar.js | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/boot/quasar.js b/src/boot/quasar.js index 103b4812e..a018eede7 100644 --- a/src/boot/quasar.js +++ b/src/boot/quasar.js @@ -5,12 +5,10 @@ import qFormMixin from './qformMixin'; import keyShortcut from './keyShortcut'; import { i18n } from './i18n'; import useNotify from 'src/composables/useNotify.js'; -import { useStateQueryStore } from 'src/stores/useStateQueryStore'; import VnInput from 'src/components/common/VnInput.vue'; import { useVnConfirm } from 'src/composables/useVnConfirm'; const { notify } = useNotify(); -const stateQuery = useStateQueryStore(); const { openConfirmationModal } = useVnConfirm(); export default boot(({ app }) => { @@ -53,13 +51,25 @@ export default boot(({ app }) => { message = 'Duplicate request'; } + const { config, headers, request, status, statusText, data } = response || {}; + const { params, url, method, signal, headers: confHeaders } = config || {}; + const { message: resMessage, code, name } = data?.error || {}; const additionalData = { - frontPath: '', - backError: { - config: error.config, - data: error, + path: location.href, + message: resMessage, + code, + request: request?.responseURL, + status, + name, + statusText: statusText, + config: { + url, + method, + params, + headers: confHeaders, + aborted: signal.aborted, + version: headers?.['salix-version'], }, - httpRequest: error.request.response, }; const opts = { actions: [ @@ -72,9 +82,7 @@ export default boot(({ app }) => { handler: async () => { const locale = i18n.global.t; const reason = ref( - response.data.error.code == 'ACCESS_DENIED' - ? locale('cau.askPrivileges') - : '' + code == 'ACCESS_DENIED' ? locale('cau.askPrivileges') : '' ); openConfirmationModal( locale('cau.title'), -- 2.40.1 From 81f1c447ad4152dfaf1eb03da686ebf8cb1f3b31 Mon Sep 17 00:00:00 2001 From: jorgep Date: Wed, 13 Nov 2024 17:45:02 +0100 Subject: [PATCH 6/8] fix: rollback --- src/stores/useStateQueryStore.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/stores/useStateQueryStore.js b/src/stores/useStateQueryStore.js index 9893d3264..d25dbb921 100644 --- a/src/stores/useStateQueryStore.js +++ b/src/stores/useStateQueryStore.js @@ -3,9 +3,7 @@ import { defineStore } from 'pinia'; export const useStateQueryStore = defineStore('stateQueryStore', () => { const queries = ref(new Set()); - const route = computed(() => - Array.from(queries.value).find((query) => query?.fullPath) - ); + function add(query) { queries.value.add(query); return query; @@ -29,6 +27,5 @@ export const useStateQueryStore = defineStore('stateQueryStore', () => { remove, queries, reset, - route, }; }); -- 2.40.1 From fa43f270ca0bc266c1f9644e15a19209f7bb7e30 Mon Sep 17 00:00:00 2001 From: jorgep Date: Thu, 14 Nov 2024 12:02:40 +0100 Subject: [PATCH 7/8] fix: prevent null --- src/boot/quasar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/boot/quasar.js b/src/boot/quasar.js index a018eede7..720fc29de 100644 --- a/src/boot/quasar.js +++ b/src/boot/quasar.js @@ -67,7 +67,7 @@ export default boot(({ app }) => { method, params, headers: confHeaders, - aborted: signal.aborted, + aborted: signal?.aborted, version: headers?.['salix-version'], }, }; -- 2.40.1 From 0fe740e415f3f15666fba18b4857adf8dd447de5 Mon Sep 17 00:00:00 2001 From: jorgep Date: Thu, 14 Nov 2024 13:20:23 +0100 Subject: [PATCH 8/8] fix: e2e --- src/pages/Worker/WorkerList.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Worker/WorkerList.vue b/src/pages/Worker/WorkerList.vue index 02bea0231..81b231710 100644 --- a/src/pages/Worker/WorkerList.vue +++ b/src/pages/Worker/WorkerList.vue @@ -306,7 +306,7 @@ async function autofillBic(worker) {