From 197ebed39ddc38b9b89a63bc0c61e1aaab49fcc0 Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 15 Apr 2025 11:47:47 +0200 Subject: [PATCH 01/74] feat: refs #8224 add context menu forVnTable --- src/components/VnTable/VnContextMenu.vue | 90 ++++++++++++++++++++++++ src/components/VnTable/VnTable.vue | 12 +++- 2 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 src/components/VnTable/VnContextMenu.vue diff --git a/src/components/VnTable/VnContextMenu.vue b/src/components/VnTable/VnContextMenu.vue new file mode 100644 index 000000000..f9922538e --- /dev/null +++ b/src/components/VnTable/VnContextMenu.vue @@ -0,0 +1,90 @@ + + + +es: + Filter by selection: Filtro por selección + Exclude selection: Excluir selección + Remove filter: Quitar filtro por selección + Remove all filters: Eliminar todos los filtros + Copy value: Copiar valor + diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue index 29a9200f0..7353c3726 100644 --- a/src/components/VnTable/VnTable.vue +++ b/src/components/VnTable/VnTable.vue @@ -33,6 +33,7 @@ import VnTableOrder from 'src/components/VnTable/VnOrder.vue'; import VnTableFilter from './VnTableFilter.vue'; import { getColAlign } from 'src/composables/getColAlign'; import RightMenu from '../common/RightMenu.vue'; +import VnContextMenu from './VnContextMenu.vue'; const arrayData = useArrayData(useAttrs()['data-key']); const $props = defineProps({ @@ -169,8 +170,9 @@ const orders = ref(useFilterParams($attrs['data-key']).orders); const app = inject('app'); const tableHeight = useTableHeight(); -const editingRow = ref(null); -const editingField = ref(null); +const editingRow = ref(); +const editingField = ref(); +const contextMenuRef = ref({}); const isTableMode = computed(() => mode.value == TABLE_MODE); const selectRegex = /select/; const emit = defineEmits(['onFetch', 'update:selected', 'saveChanges']); @@ -195,6 +197,10 @@ onBeforeMount(() => { }); onMounted(async () => { + document.addEventListener('contextmenu', (event) => { + event.preventDefault(); + contextMenuRef.value.handler(event); + }); if ($props.isEditable) document.addEventListener('click', clickHandler); mode.value = quasar.platform.is.mobile && !$props.disableOption?.card @@ -777,6 +783,7 @@ const rowCtrlClickFunction = computed(() => { ]" :data-row-index="rowIndex" :data-col-field="col?.name" + :data-col-value="row?.[col?.name]" >
{ + en: From b25bd19bb5b21d0fd6ee42c63d5dcbc5ac8e21e5 Mon Sep 17 00:00:00 2001 From: jtubau Date: Tue, 15 Apr 2025 14:59:41 +0200 Subject: [PATCH 02/74] feat: refs #7385 add delivery forecast and delivered fields to route summary and descriptor --- src/pages/Route/Card/RouteDescriptor.vue | 13 +++++++++++++ src/pages/Route/Card/RouteSummary.vue | 14 ++++++++++++++ src/pages/Route/locale/en.yml | 2 ++ src/pages/Route/locale/es.yml | 2 ++ 4 files changed, 31 insertions(+) diff --git a/src/pages/Route/Card/RouteDescriptor.vue b/src/pages/Route/Card/RouteDescriptor.vue index ee42d8e76..67bc88fec 100644 --- a/src/pages/Route/Card/RouteDescriptor.vue +++ b/src/pages/Route/Card/RouteDescriptor.vue @@ -68,6 +68,19 @@ onMounted(async () => { + diff --git a/src/pages/Route/Card/RouteSummary.vue b/src/pages/Route/Card/RouteSummary.vue index 86bdbb5c5..435385f34 100644 --- a/src/pages/Route/Card/RouteSummary.vue +++ b/src/pages/Route/Card/RouteSummary.vue @@ -80,6 +80,20 @@ const ticketColumns = ref([ sortable: false, align: 'left', }, + { + name: 'dated', + label: t('route.delivered'), + field: (row) => dashIfEmpty(toDate(row?.landed)), + sortable: false, + align: 'center', + }, + { + name: 'prevision', + label: t('route.forecast'), + field: (row) => dashIfEmpty(toDate(row?.eta)), + sortable: false, + align: 'center', + }, { name: 'packages', label: t('route.summary.packages'), diff --git a/src/pages/Route/locale/en.yml b/src/pages/Route/locale/en.yml index e7e2d691e..de7af53e8 100644 --- a/src/pages/Route/locale/en.yml +++ b/src/pages/Route/locale/en.yml @@ -70,6 +70,8 @@ route: searchInfo: You can search by route reference dated: Dated preview: Preview + delivered: Delivered + forecast: Forecast cmr: search: Search Cmr searchInfo: You can search Cmr by Id diff --git a/src/pages/Route/locale/es.yml b/src/pages/Route/locale/es.yml index 2785ded31..857bebc17 100644 --- a/src/pages/Route/locale/es.yml +++ b/src/pages/Route/locale/es.yml @@ -71,6 +71,8 @@ route: searchInfo: Puedes buscar por referencia de la ruta dated: Fecha preview: Vista previa + delivered: Entregado + forecast: Pronóstico cmr: list: results: resultados From 2f20abf388819b9754c5791d6556e6666a3fa23c Mon Sep 17 00:00:00 2001 From: jtubau Date: Tue, 15 Apr 2025 15:40:03 +0200 Subject: [PATCH 03/74] refactor: refs #7385 update ticket columns to use 'delivered' and 'forecast' fields in RouteSummary --- src/pages/Route/Card/RouteSummary.vue | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/Route/Card/RouteSummary.vue b/src/pages/Route/Card/RouteSummary.vue index 435385f34..17295905b 100644 --- a/src/pages/Route/Card/RouteSummary.vue +++ b/src/pages/Route/Card/RouteSummary.vue @@ -81,16 +81,16 @@ const ticketColumns = ref([ align: 'left', }, { - name: 'dated', + name: 'delivered', label: t('route.delivered'), - field: (row) => dashIfEmpty(toDate(row?.landed)), + field: (row) => dashIfEmpty(toDate(row?.delivered)), sortable: false, align: 'center', }, { - name: 'prevision', + name: 'forecast', label: t('route.forecast'), - field: (row) => dashIfEmpty(toDate(row?.eta)), + field: (row) => dashIfEmpty(toDate(row?.forecast)), sortable: false, align: 'center', }, From 5b870c2c2c24e1517dce63388492b3f904d5421d Mon Sep 17 00:00:00 2001 From: jorgep Date: Thu, 17 Apr 2025 11:39:48 +0200 Subject: [PATCH 04/74] fix: refs #7939 show userErr & useNotify composable --- src/pages/Login/LoginMain.vue | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/pages/Login/LoginMain.vue b/src/pages/Login/LoginMain.vue index a4c3566a9..ce945e0ad 100644 --- a/src/pages/Login/LoginMain.vue +++ b/src/pages/Login/LoginMain.vue @@ -6,7 +6,7 @@ import { useRouter } from 'vue-router'; import VnInputPassword from 'src/components/common/VnInputPassword.vue'; import { useSession } from 'src/composables/useSession'; import { useLogin } from 'src/composables/useLogin'; - +import useNotify from 'src/composables/useNotify'; import VnLogo from 'components/ui/VnLogo.vue'; import VnInput from 'src/components/common/VnInput.vue'; import axios from 'axios'; @@ -15,6 +15,7 @@ const session = useSession(); const loginCache = useLogin(); const router = useRouter(); const { t } = useI18n(); +const { notify } = useNotify(); const username = ref(''); const password = ref(''); @@ -32,23 +33,20 @@ async function onSubmit() { data.keepLogin = keepLogin.value; await session.setLogin(data); } catch (res) { - if (res.response?.data?.error?.code === 'REQUIRES_2FA') { - Notify.create({ - message: t('login.twoFactorRequired'), - icon: 'phoneLink_lock', - type: 'warning', - }); + const err = res.response?.data?.error; + if (err?.code === 'REQUIRES_2FA') { + notify(t('login.twoFactorRequired'), 'warning', 'phoneLink_lock'); params.keepLogin = keepLogin.value; loginCache.setUser(params); return router.push({ name: 'TwoFactor', query: router.currentRoute.value?.query, }); + } else if (err?.name == 'UserError') { + notify(err.message, 'negative'); + } else { + notify(t('login.loginError'), 'negative'); } - Notify.create({ - message: t('login.loginError'), - type: 'negative', - }); } } From a8d39a9b9663a4510c0be8ad180060588da0c30c Mon Sep 17 00:00:00 2001 From: jorgep Date: Tue, 22 Apr 2025 16:48:13 +0200 Subject: [PATCH 05/74] feat(login): refs #7939 add session expiration handling and improve error notifications --- src/boot/quasar.js | 10 +++++++++- src/i18n/locale/en.yml | 2 ++ src/i18n/locale/es.yml | 2 ++ src/pages/Login/LoginMain.vue | 14 +++----------- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/boot/quasar.js b/src/boot/quasar.js index a8c397b83..8ef748c01 100644 --- a/src/boot/quasar.js +++ b/src/boot/quasar.js @@ -7,7 +7,7 @@ import { QLayout } from 'quasar'; import mainShortcutMixin from './mainShortcutMixin'; import { useCau } from 'src/composables/useCau'; -export default boot(({ app }) => { +export default boot(({ app, router }) => { QForm.mixins = [qFormMixin]; QLayout.mixins = [mainShortcutMixin]; @@ -22,6 +22,14 @@ export default boot(({ app }) => { } switch (response?.status) { + case 401: + if (!router.currentRoute.value.name.includes('login')) { + message = 'errors.sessionExpired'; + } else message = 'login.loginError'; + break; + case 403: + if (!message || message.toLowerCase() === 'access denied') + message = 'errors.accessDenied'; case 422: if (error.name == 'ValidationError') message += diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml index 3c1c80954..efcad468e 100644 --- a/src/i18n/locale/en.yml +++ b/src/i18n/locale/en.yml @@ -395,6 +395,8 @@ errors: updateUserConfig: Error updating user config tokenConfig: Error fetching token config writeRequest: The requested operation could not be completed + sessionExpired: Your session has expired. Please log in again + accessDenied: Access denied login: title: Login username: Username diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml index 518985831..71105db3e 100644 --- a/src/i18n/locale/es.yml +++ b/src/i18n/locale/es.yml @@ -391,6 +391,8 @@ errors: updateUserConfig: Error al actualizar la configuración de usuario tokenConfig: Error al obtener configuración de token writeRequest: No se pudo completar la operación solicitada + sessionExpired: Tu sesión ha expirado, por favor vuelve a iniciar sesión + accessDenied: Acceso denegado login: title: Inicio de sesión username: Nombre de usuario diff --git a/src/pages/Login/LoginMain.vue b/src/pages/Login/LoginMain.vue index ce945e0ad..0a84f8d02 100644 --- a/src/pages/Login/LoginMain.vue +++ b/src/pages/Login/LoginMain.vue @@ -1,6 +1,5 @@ From c3f60c68bc25abc0f2533fab76adf0dbfdbcefe7 Mon Sep 17 00:00:00 2001 From: jtubau Date: Wed, 23 Apr 2025 11:44:33 +0200 Subject: [PATCH 06/74] feat: refs #7385 add delivered and estimated info in routeTicket --- src/pages/Route/Card/RouteSummary.vue | 58 ------------------- src/pages/Route/RouteTickets.vue | 81 ++++++++++++--------------- 2 files changed, 37 insertions(+), 102 deletions(-) diff --git a/src/pages/Route/Card/RouteSummary.vue b/src/pages/Route/Card/RouteSummary.vue index 17295905b..6c1f51625 100644 --- a/src/pages/Route/Card/RouteSummary.vue +++ b/src/pages/Route/Card/RouteSummary.vue @@ -281,61 +281,3 @@ const ticketColumns = ref([
- -en: - route: - summary: - date: Date - agency: Agency - vehicle: Vehicle - driver: Driver - cost: Cost - started: Started time - finished: Finished time - kmStart: Km start - kmEnd: Km end - volume: Volume - packages: Packages - description: Description - tickets: Tickets - order: Order - street: Street - city: City - pc: PC - client: Client - state: State - m3: m³ - packaging: Packaging - ticket: Ticket - closed: Closed - open: Open - yes: Yes - no: No -es: - route: - summary: - date: Fecha - agency: Agencia - vehicle: Vehículo - driver: Conductor - cost: Costo - started: Hora inicio - finished: Hora fin - kmStart: Km inicio - kmEnd: Km fin - volume: Volumen - packages: Bultos - description: Descripción - tickets: Tickets - order: Orden - street: Dirección fiscal - city: Población - pc: CP - client: Cliente - state: Estado - packaging: Encajado - closed: Cerrada - open: Abierta - yes: Sí - no: No - diff --git a/src/pages/Route/RouteTickets.vue b/src/pages/Route/RouteTickets.vue index 1b9545905..fe2c61aca 100644 --- a/src/pages/Route/RouteTickets.vue +++ b/src/pages/Route/RouteTickets.vue @@ -24,49 +24,63 @@ const selectedRows = ref([]); const columns = computed(() => [ { name: 'order', - label: t('Order'), + label: t('route.ticket.order'), field: (row) => dashIfEmpty(row?.priority), sortable: false, align: 'center', }, { name: 'client', - label: t('Client'), + label: t('route.ticket.client'), field: (row) => row?.nickname, sortable: false, align: 'left', }, { name: 'street', - label: t('Street'), + label: t('route.ticket.street'), field: (row) => row?.street, sortable: false, align: 'left', }, { name: 'pc', - label: t('PC'), + label: t('route.ticket.PC'), field: (row) => row?.postalCode, sortable: false, align: 'center', }, { name: 'city', - label: t('City'), + label: t('route.ticket.city'), field: (row) => row?.city, sortable: false, align: 'left', }, { name: 'warehouse', - label: t('Warehouse'), + label: t('route.ticket.warehouse'), field: (row) => row?.warehouseName, sortable: false, align: 'left', }, + { + name: 'delivered', + label: t('route.ticket.delivered'), + field: (row) => dashIfEmpty(row?.delivered), + sortable: false, + align: 'left', + }, + { + name: 'estimated', + label: t('route.ticket.estimated'), + field: (row) => dashIfEmpty(row?.estimated), + sortable: false, + align: 'left', + }, { name: 'packages', - label: t('Packages'), + label: t('route.ticket.packages'), field: (row) => row?.packages, sortable: false, align: 'center', @@ -80,14 +94,14 @@ const columns = computed(() => [ }, { name: 'packaging', - label: t('Packaging'), + label: t('route.ticket.packaging'), field: (row) => row?.ipt, sortable: false, align: 'center', }, { name: 'ticket', - label: t('Ticket'), + label: t('route.ticket.ticket'), field: (row) => row?.id, sortable: false, align: 'center', @@ -188,8 +202,8 @@ const confirmRemove = (ticket) => { .dialog({ component: VnConfirm, componentProps: { - title: t('Confirm removal from route'), - message: t('Are you sure you want to remove this ticket from the route?'), + title: t('route.ticket.confirmRemoval'), + message: t('route.ticket.confirmRemovalConfirmation'), promise: () => removeTicket(ticket), }, }) @@ -219,7 +233,7 @@ const openSmsDialog = async () => { quasar.dialog({ component: SendSmsDialog, componentProps: { - title: t('Send SMS to the selected tickets'), + title: t('route.ticket.sendSmsTickets'), url: 'Routes/sendSms', destinationFk: clientsId.toString(), destination: clientsPhone.toString(), @@ -240,18 +254,18 @@ const openSmsDialog = async () => { -

{{ t('Select the starting date') }}

+

{{ t('route.ticket.selectStartingDate') }}

- + {{ t('globals.clone') }} @@ -262,7 +276,7 @@ const openSmsDialog = async () => {
- {{ t('Sort routes') }} + {{ t('route.ticket.sortRoutes') }} { :disable="!selectedRows?.length" @click="goToBuscaman()" > - {{ t('Open buscaman') }} + {{ t('route.ticket.openBuscaman') }} { :disable="!selectedRows?.length" @click="deletePriorities" > - {{ t('Delete priority') }} + {{ t('route.ticket.deletePriority') }} { > {{ - t('Renumber all tickets in the order you see on the screen') + t('route.ticket.renumberAllTickets') }} @@ -301,7 +315,7 @@ const openSmsDialog = async () => { :disable="!selectedRows?.length" @click="openSmsDialog" > - {{ t('Send SMS to all clients') }} + {{ t('route.ticket.sendSmsClients') }}
@@ -339,7 +353,7 @@ const openSmsDialog = async () => { @click="setHighestPriority(row, rows)" > - {{ t('Assign highest priority') }} + {{ t('route.ticket.assignHighestPriority') }} { {{ value }} - {{ t('Open buscaman') }} + {{ t('route.ticket.openBuscaman') }} @@ -411,7 +425,7 @@ const openSmsDialog = async () => { @click="openTicketsDialog" > - {{ t('Add ticket') }} + {{ t('route.ticket.addTicket') }}
@@ -432,24 +446,3 @@ const openSmsDialog = async () => { gap: 12px; } - -es: - Order: Orden - Street: Dirección fiscal - City: Población - PC: CP - Client: Cliente - Warehouse: Almacén - Packages: Bultos - Packaging: Encajado - Confirm removal from route: Quitar de la ruta - Are you sure you want to remove this ticket from the route?: ¿Seguro que quieres quitar este ticket de la ruta? - Sort routes: Ordenar rutas - Open buscaman: Abrir buscaman - Delete priority: Borrar orden - Renumber all tickets in the order you see on the screen: Renumerar todos los tickets con el orden que ves por pantalla - Assign highest priority: Asignar máxima prioridad - Send SMS to all clients: Mandar sms a todos los clientes de las rutas - Send SMS to the selected tickets: Enviar SMS a los tickets seleccionados - Add ticket: Añadir ticket - From f4ecf9ad51fe3550b0aaf3ac5e748563dc9ac71e Mon Sep 17 00:00:00 2001 From: jtubau Date: Wed, 23 Apr 2025 11:44:54 +0200 Subject: [PATCH 07/74] refactor: refs #7385 add detailed summary and ticket fields in English and Spanish locales --- src/pages/Route/locale/en.yml | 51 +++++++++++++++++++++++++++++++++++ src/pages/Route/locale/es.yml | 49 +++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/src/pages/Route/locale/en.yml b/src/pages/Route/locale/en.yml index de7af53e8..b9e31effa 100644 --- a/src/pages/Route/locale/en.yml +++ b/src/pages/Route/locale/en.yml @@ -1,6 +1,33 @@ route: filter: Served: Served + summary: + date: Date + agency: Agency + vehicle: Vehicle + driver: Driver + cost: Cost + started: Started time + finished: Finished time + kmStart: Km start + kmEnd: Km end + volume: Volume + packages: Packages + description: Description + tickets: Tickets + order: Order + street: Street + city: City + pc: PC + client: Client + state: State + m3: m³ + packaging: Packaging + ticket: Ticket + closed: Closed + open: Open + yes: Yes + no: No extendedList: selectStartingDate: Select the starting date startingDate: Starting date @@ -90,3 +117,27 @@ route: viewCmr: View CMR downloadCmrs: Download CMRs search: General search + ticket: + order: Order + street: Street + city: City + PC: PC + client: Client + warehouse: Warehouse + delivered: Delivered + estimated: Estimated + packages: Packages + packaging: Packaging + ticket: Ticket + confirmRemoval: Confirm removal from route + confirmRemovalConfirmation: Are you sure you want to remove this ticket from the route? + selectStartingDate: Select the starting date + startingDate: Starting date + sortRoutes: Sort routes + openBuscaman: Open buscaman + deletePriority: Delete priority + renumberAllTickets: Renumber all tickets in the order you see on the screen + assignHighest: Assign highest priority + sendSmsTickets: Send SMS to the selected tickets + sendSmsClients: Send SMS to all clients + addTicket: Add ticket diff --git a/src/pages/Route/locale/es.yml b/src/pages/Route/locale/es.yml index 857bebc17..a2acf26e5 100644 --- a/src/pages/Route/locale/es.yml +++ b/src/pages/Route/locale/es.yml @@ -1,6 +1,31 @@ route: filter: Served: Servida + summary: + date: Fecha + agency: Agencia + vehicle: Vehículo + driver: Conductor + cost: Costo + started: Hora inicio + finished: Hora fin + kmStart: Km inicio + kmEnd: Km fin + volume: Volumen + packages: Bultos + description: Descripción + tickets: Tickets + order: Orden + street: Dirección fiscal + city: Población + pc: CP + client: Cliente + state: Estado + packaging: Encajado + closed: Cerrada + open: Abierta + yes: Sí + no: No extendedList: selectStartingDate: Seleccione la fecha de inicio statingDate: Fecha de inicio @@ -87,3 +112,27 @@ route: shipped: Fecha preparación viewCmr: Ver CMR downloadCmrs: Descargar CMRs + ticket: + order: Orden + street: Dirección fiscal + city: Población + PC: CP + client: Cliente + warehouse: Almacén + delivered: Entregado + estimated: Pronóstico + packages: Bultos + packaging: Encajado + ticket: Ticket + confirmRemoval: Quitar de la ruta + confirmRemovalConfirmation: ¿Seguro que quieres quitar este ticket de la ruta? + selectStartingDate: Seleccionar fecha de inicio + startingDate: F. Inicio + sortRoutes: Ordenar rutas + openBuscaman: Abrir buscaman + deletePriority: Borrar orden + renumberAllTickets: Renumerar todos los tickets con el orden que ves por pantalla + assignHighest: Asignar máxima prioridad + sendSmsTickets: Enviar SMS a los tickets seleccionados + sendSmsClients: Mandar sms a todos los clientes de las rutas + addTicket: Añadir ticket From 4ad9a3e613143fe74d8379d705e8aedd84e16c88 Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 23 Apr 2025 13:39:33 +0200 Subject: [PATCH 08/74] feat: refs #8224 exclude filter --- src/components/VnTable/VnContextMenu.vue | 70 +++++++++++++++------ src/components/VnTable/VnFilter.vue | 3 + src/components/VnTable/VnTable.vue | 3 +- src/components/VnTable/VnTableFilter.vue | 7 ++- src/components/common/VnSelect.vue | 67 ++++++++++++++++---- src/pages/Ticket/TicketList.vue | 80 +++++++++++++++--------- 6 files changed, 167 insertions(+), 63 deletions(-) diff --git a/src/components/VnTable/VnContextMenu.vue b/src/components/VnTable/VnContextMenu.vue index f9922538e..7004469a9 100644 --- a/src/components/VnTable/VnContextMenu.vue +++ b/src/components/VnTable/VnContextMenu.vue @@ -9,18 +9,18 @@ const colField = ref(); let colValue = ''; let textValue = ''; +defineExpose({ handler }); + const arrayData = defineModel({ type: Array, }); -defineExpose({ - handler, -}); - function handler(event) { + const clickedElement = event.target.closest('td'); + if (!clickedElement) return; + target.value = event.target; qmenuRef.value.show(); - const clickedElement = event.target.closest('td'); colField.value = clickedElement.getAttribute('data-col-field'); colValue = isNaN(+clickedElement.getAttribute('data-col-value')) ? clickedElement.getAttribute('data-col-value') @@ -45,22 +45,22 @@ function getDeepestText(node) { return lastText; } -function selectionFilter() { - arrayData.value.addFilter({ params: { [colField.value]: colValue } }); +async function selectionFilter() { + await arrayData.value.addFilter({ params: { [colField.value]: colValue } }); } -function selectionExclude() { - arrayData.value.addFilter({ - params: { [colField.value]: { neq: +colValue } }, +async function selectionExclude() { + await arrayData.value.addFilter({ + params: { [colField.value]: { neq: colValue } }, }); } -function selectionRemoveFilter() { - arrayData.value.addFilter({ params: { [colField.value]: undefined } }); +async function selectionRemoveFilter() { + await arrayData.value.addFilter({ params: { [colField.value]: undefined } }); } -function removeAllFilters() { - arrayData.value.applyFilter({ params: {} }); +async function removeAllFilters() { + await arrayData.value.applyFilter({ params: {} }); } function copyValue() { @@ -72,12 +72,42 @@ function copyValue() { } diff --git a/src/components/VnTable/VnFilter.vue b/src/components/VnTable/VnFilter.vue index 82d7c772c..1ebad1abe 100644 --- a/src/components/VnTable/VnFilter.vue +++ b/src/components/VnTable/VnFilter.vue @@ -136,6 +136,9 @@ async function addFilter(value, name) { value = value === '' ? undefined : value; let field = columnFilter.value?.name ?? $props.column.name ?? name; + delete arrayData.store?.userParams?.[field]; + delete arrayData.store?.filter?.where?.[field]; + if (columnFilter.value?.inWhere) { if (columnFilter.value.alias) field = columnFilter.value.alias + '.' + field; return await arrayData.addFilterWhere({ [field]: value }); diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue index c94089604..3eea028d8 100644 --- a/src/components/VnTable/VnTable.vue +++ b/src/components/VnTable/VnTable.vue @@ -210,11 +210,11 @@ onBeforeMount(() => { }); onMounted(async () => { + if ($props.isEditable) document.addEventListener('click', clickHandler); document.addEventListener('contextmenu', (event) => { event.preventDefault(); contextMenuRef.value.handler(event); }); - if ($props.isEditable) document.addEventListener('click', clickHandler); mode.value = quasar.platform.is.mobile && !$props.disableOption?.card ? CARD_MODE @@ -238,6 +238,7 @@ onMounted(async () => { onUnmounted(async () => { if ($props.isEditable) document.removeEventListener('click', clickHandler); + document.removeEventListener('contextmenu', {}); }); watch( diff --git a/src/components/VnTable/VnTableFilter.vue b/src/components/VnTable/VnTableFilter.vue index a7b2108ed..5d24245ac 100644 --- a/src/components/VnTable/VnTableFilter.vue +++ b/src/components/VnTable/VnTableFilter.vue @@ -77,7 +77,12 @@ function columnName(col) { + en: params: @@ -107,6 +113,8 @@ en: mine: Mine showBadDates: Show future items hasMinPrice: Has Min Price + date: Date + incompatibleFilters: Cannot select "Date" and "Show future items" at the same time es: params: buyerFk: Comprador @@ -116,4 +124,6 @@ es: mine: Para mi showBadDates: Ver items a futuro hasMinPrice: Precio mínimo + date: Fecha + incompatibleFilters: No se puede seleccionar "Fecha" y "Ver items a futuro" a la vez From 8dd67efeb99bd7e5bf4942282c6e783065205a43 Mon Sep 17 00:00:00 2001 From: jorgep Date: Fri, 25 Apr 2025 13:16:50 +0200 Subject: [PATCH 14/74] fix: refs #7939 normalize login route check to be case insensitive --- 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 8ef748c01..a5d915305 100644 --- a/src/boot/quasar.js +++ b/src/boot/quasar.js @@ -23,7 +23,7 @@ export default boot(({ app, router }) => { switch (response?.status) { case 401: - if (!router.currentRoute.value.name.includes('login')) { + if (!router.currentRoute.value.name.toLowerCase().includes('login')) { message = 'errors.sessionExpired'; } else message = 'login.loginError'; break; From 3ceabd5831ebbb22341281ec6f05c9705993984f Mon Sep 17 00:00:00 2001 From: jorgep Date: Fri, 25 Apr 2025 13:28:32 +0200 Subject: [PATCH 15/74] refactor: refs #7939 streamline logout tests and improve session expiration error handling --- test/cypress/integration/login/logout.spec.js | 45 +++++++++---------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/test/cypress/integration/login/logout.spec.js b/test/cypress/integration/login/logout.spec.js index b17e42794..174ca6066 100644 --- a/test/cypress/integration/login/logout.spec.js +++ b/test/cypress/integration/login/logout.spec.js @@ -5,33 +5,28 @@ describe('Logout', () => { cy.visit(`/#/dashboard`); cy.waitForElement('.q-page', 6000); }); - describe('by user', () => { - it('should logout', () => { - cy.get('#user').click(); - cy.get('#logout').click(); - }); + + it('should logout', () => { + cy.get('#user').click(); + cy.get('#logout').click(); }); - describe('not user', () => { - beforeEach(() => { - cy.intercept('GET', '**StarredModules**', { - statusCode: 401, - body: { - error: { - statusCode: 401, - name: 'Error', - message: 'Authorization Required', - code: 'AUTHORIZATION_REQUIRED', - }, + + it('should throw session expired error if token has expired or is not valid during navigation', () => { + cy.intercept('GET', '**StarredModules**', { + statusCode: 401, + body: { + error: { + statusCode: 401, + name: 'Error', + message: 'Authorization Required', + code: 'AUTHORIZATION_REQUIRED', }, - statusMessage: 'AUTHORIZATION_REQUIRED', - }).as('badRequest'); - }); + }, + statusMessage: 'AUTHORIZATION_REQUIRED', + }).as('badRequest'); + cy.get('.q-list').should('be.visible').first().should('be.visible').click(); + cy.wait('@badRequest'); - it('when token not exists', () => { - cy.get('.q-list').should('be.visible').first().should('be.visible').click(); - cy.wait('@badRequest'); - - cy.checkNotification('Authorization Required'); - }); + cy.checkNotification('Your session has expired. Please log in again'); }); }); From b1d637f382fe1e955fe91919aecc56d5146a9bb6 Mon Sep 17 00:00:00 2001 From: alexm Date: Fri, 25 Apr 2025 14:13:45 +0200 Subject: [PATCH 16/74] test: refs #8224 fix e2e using select, use containts() --- src/components/common/VnSelect.vue | 2 +- test/cypress/integration/customer/clientList.spec.js | 8 ++++---- .../integration/entry/entryCard/entryBuys.spec.js | 2 +- .../integration/entry/entryCard/entryNotes.spec.js | 2 -- .../invoiceIn/invoiceInCorrective.spec.js | 12 +++++++++--- .../invoiceIn/invoiceInDescriptor.spec.js | 6 +++--- .../integration/invoiceIn/invoiceInList.spec.js | 2 +- .../integration/invoiceIn/invoiceInVat.spec.js | 6 ++---- test/cypress/integration/order/orderList.spec.js | 6 +++--- .../shelving/parking/parkingBasicData.spec.js | 2 +- test/cypress/integration/ticket/ticketList.spec.js | 4 ++-- 11 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/components/common/VnSelect.vue b/src/components/common/VnSelect.vue index 2078728b9..e17f71bbc 100644 --- a/src/components/common/VnSelect.vue +++ b/src/components/common/VnSelect.vue @@ -454,7 +454,7 @@ function getOptionLabel(property) { -