diff --git a/src/boot/quasar.js b/src/boot/quasar.js
index d375c2f69..547517682 100644
--- a/src/boot/quasar.js
+++ b/src/boot/quasar.js
@@ -1,20 +1,18 @@
+import axios from 'axios';
import { boot } from 'quasar/wrappers';
import qFormMixin from './qformMixin';
import keyShortcut from './keyShortcut';
-import useNotify from 'src/composables/useNotify.js';
-import { CanceledError } from 'axios';
import { QForm } from 'quasar';
import { QLayout } from 'quasar';
import mainShortcutMixin from './mainShortcutMixin';
-
-const { notify } = useNotify();
+import { useCau } from 'src/composables/useCau';
export default boot(({ app }) => {
QForm.mixins = [qFormMixin];
QLayout.mixins = [mainShortcutMixin];
app.directive('shortcut', keyShortcut);
- app.config.errorHandler = (error) => {
+ app.config.errorHandler = async (error) => {
let message;
const response = error.response;
const responseData = response?.data;
@@ -45,12 +43,12 @@ 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';
}
- notify(message ?? 'globals.error', 'negative', 'error');
+ await useCau(response, message);
};
});
diff --git a/src/composables/useCau.js b/src/composables/useCau.js
new file mode 100644
index 000000000..29319bd9a
--- /dev/null
+++ b/src/composables/useCau.js
@@ -0,0 +1,73 @@
+import VnInput from 'src/components/common/VnInput.vue';
+import { useVnConfirm } from 'src/composables/useVnConfirm';
+import axios from 'axios';
+import { ref } from 'vue';
+import { i18n } from 'src/boot/i18n';
+import useNotify from 'src/composables/useNotify.js';
+
+export async function useCau(res, message) {
+ const { notify } = useNotify();
+ const { openConfirmationModal } = useVnConfirm();
+ const { config, headers, request, status, statusText, data } = res || {};
+ const { params, url, method, signal, headers: confHeaders } = config || {};
+ const { message: resMessage, code, name } = data?.error || {};
+
+ const additionalData = {
+ path: location.hash,
+ message: resMessage,
+ code,
+ request: request?.responseURL,
+ status,
+ name,
+ statusText: statusText,
+ config: {
+ url,
+ method,
+ params,
+ headers: confHeaders,
+ aborted: signal?.aborted,
+ version: headers?.['salix-version'],
+ },
+ };
+ const opts = {
+ actions: [
+ {
+ icon: 'support_agent',
+ color: 'primary',
+ dense: true,
+ flat: false,
+ round: true,
+ handler: async () => {
+ const locale = i18n.global.t;
+ const reason = ref(
+ code == 'ACCESS_DENIED' ? locale('cau.askPrivileges') : ''
+ );
+ openConfirmationModal(
+ locale('cau.title'),
+ locale('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: locale('cau.inputLabel'),
+ class: 'full-width',
+ required: true,
+ autofocus: true,
+ },
+ }
+ );
+ },
+ },
+ ],
+ };
+
+ notify(message ?? 'globals.error', 'negative', 'error', opts);
+}
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 7c0fcf5ee..e4924d3c1 100644
--- a/src/i18n/locale/en.yml
+++ b/src/i18n/locale/en.yml
@@ -370,6 +370,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 efa25473d..1a0adb2f3 100644
--- a/src/i18n/locale/es.yml
+++ b/src/i18n/locale/es.yml
@@ -372,6 +372,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
diff --git a/src/pages/Ticket/Card/TicketDescriptorMenu.vue b/src/pages/Ticket/Card/TicketDescriptorMenu.vue
index 60a703f84..38e2af612 100644
--- a/src/pages/Ticket/Card/TicketDescriptorMenu.vue
+++ b/src/pages/Ticket/Card/TicketDescriptorMenu.vue
@@ -1,6 +1,6 @@
{{ t('Show Proforma') }}
+
+
+
+
+ {{ t('Restore ticket') }}
+
diff --git a/test/cypress/integration/zone/zoneBasicData.spec.js b/test/cypress/integration/zone/zoneBasicData.spec.js
index de85dac94..6229039b7 100644
--- a/test/cypress/integration/zone/zoneBasicData.spec.js
+++ b/test/cypress/integration/zone/zoneBasicData.spec.js
@@ -1,5 +1,6 @@
describe('ZoneBasicData', () => {
const notification = '.q-notification__message';
+ const priceBasicData = '[data-cy="Price_input"]';
beforeEach(() => {
cy.viewport(1280, 720);
@@ -13,9 +14,15 @@ describe('ZoneBasicData', () => {
cy.get(notification).should('contains.text', "can't be blank");
});
+ it('should throw an error if the price is empty', () => {
+ cy.get(priceBasicData).clear();
+ cy.get('.q-btn-group > .q-btn--standard').click();
+ cy.get(notification).should('contains.text', 'cannot be blank');
+ });
+
it("should edit the basicData's zone", () => {
cy.get('.q-card > :nth-child(1)').type(' modified');
cy.get('.q-btn-group > .q-btn--standard').click();
- cy.get(notification).should('contains.text', 'Data saved');
+ cy.checkNotification('Data saved');
});
});