diff --git a/src/boot/quasar.js b/src/boot/quasar.js index 01fe68d8bcd..a1991d9a4de 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 9b0393489cb..6f8377d96f0 100644 --- a/src/components/NavBar.vue +++ b/src/components/NavBar.vue @@ -1,6 +1,7 @@ <script setup> import { onMounted, ref } from 'vue'; import { useI18n } from 'vue-i18n'; +import { useRoute } from 'vue-router'; import { useState } from 'src/composables/useState'; import { useStateStore } from 'stores/useStateStore'; import { useStateQueryStore } from 'src/stores/useStateQueryStore'; @@ -17,8 +18,10 @@ const stateQuery = useStateQueryStore(); const state = useState(); const user = state.getUser(); const appName = 'Lilium'; - -onMounted(() => stateStore.setMounted()); +onMounted(() => { + stateStore.setMounted(); + stateQuery.add(useRoute()); +}); const pinnedModulesRef = ref(); </script> diff --git a/src/composables/useNotify.js b/src/composables/useNotify.js index 2f0e1c25704..309156d2af9 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 76c3f4f28ed..4438ad11d0b 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 10186d92a82..7feaa990a6e 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 66b5efd525d..be1e25ca852 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 d25dbb92156..9893d32644d 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, }; });