diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a679cdfc..43bd6da77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,31 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2418.01] + +## [2416.01] - 2024-04-18 + +### Added + +### Fixed + +- (General) => Se vuelven a mostrar los parámetros en la url al aplicar un filtro + +## [2414.01] - 2024-04-04 + +### Added + +- (Tickets) => Se añade la opción de clonar ticket. #6951 +- (Parking) => Se añade la sección Parking. #5186 + +- (Rutas) => Se añade el campo "servida" a la tabla y se añade también a los filtros. #7130 + +### Changed + +### Fixed + +- (General) => Se corrige la redirección cuando hay 1 solo registro y cuando se aplica un filtro diferente al id al hacer una búsqueda general. #6893 + ## [2400.01] - 2024-01-04 ### Added diff --git a/README.md b/README.md index 86fe11ca7..e87a84d60 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,13 @@ Lilium frontend ## Install the dependencies ```bash -bun install +pnpm install ``` ### Install quasar cli ```bash -sudo bun install -g @quasar/cli +sudo npm install -g @quasar/cli ``` ### Start the app in development mode (hot-code reloading, error reporting, etc.) @@ -23,13 +23,13 @@ quasar dev ### Run unit tests ```bash -bun run test:unit +pnpm run test:unit ``` ### Run e2e tests ```bash -npm run test:e2e +pnpm run test:e2e ``` ### Build the app for production diff --git a/cypress.config.js b/cypress.config.js index 1934f833e..e2046d6c4 100644 --- a/cypress.config.js +++ b/cypress.config.js @@ -3,6 +3,7 @@ const { defineConfig } = require('cypress'); module.exports = defineConfig({ e2e: { baseUrl: 'http://localhost:9000/', + experimentalStudio: true, fixturesFolder: 'test/cypress/fixtures', screenshotsFolder: 'test/cypress/screenshots', supportFile: 'test/cypress/support/index.js', diff --git a/package.json b/package.json index beae0b7b9..8398eb3f3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "salix-front", - "version": "24.12.0", + "version": "24.18.0", "description": "Salix frontend", "productName": "Salix", "author": "Verdnatura", @@ -32,6 +32,7 @@ "@intlify/unplugin-vue-i18n": "^0.8.1", "@pinia/testing": "^0.1.2", "@quasar/app-vite": "^1.7.3", + "@quasar/quasar-app-extension-qcalendar": "4.0.0-beta.15", "@quasar/quasar-app-extension-testing-unit-vitest": "^0.4.0", "@vue/test-utils": "^2.4.4", "autoprefixer": "^10.4.14", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f3fe7df55..bdff559cc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -49,6 +49,9 @@ devDependencies: '@quasar/app-vite': specifier: ^1.7.3 version: 1.7.3(eslint@8.56.0)(pinia@2.1.7)(quasar@2.14.5)(vue-router@4.2.5)(vue@3.4.19) + '@quasar/quasar-app-extension-qcalendar': + specifier: 4.0.0-beta.15 + version: 4.0.0-beta.15 '@quasar/quasar-app-extension-testing-unit-vitest': specifier: ^0.4.0 version: 0.4.0(@vue/test-utils@2.4.4)(quasar@2.14.5)(vite@5.1.4)(vitest@0.31.4)(vue@3.4.19) @@ -912,6 +915,13 @@ packages: resolution: {integrity: sha512-SlOhwzXyPQHWgQIS2ncyDdYdksCJvUYNtgsDQqzAKEG3r3d/ejOxvThle79HTK3Q6HB+gQWFG21Ux00Osr5XSw==} dev: false + /@quasar/quasar-app-extension-qcalendar@4.0.0-beta.15: + resolution: {integrity: sha512-i6hQkcP70LXLfVMPZMKQjSg3681gjZmASV3vq6ULzc0LhtBiPneLdVNNtH2itkWxAmaUj+1heQDI5Pa0F7VKLQ==} + engines: {node: '>= 10.0.0', npm: '>= 5.6.0', yarn: '>= 1.6.0'} + dependencies: + '@quasar/quasar-ui-qcalendar': 4.0.0-beta.19 + dev: true + /@quasar/quasar-app-extension-testing-unit-vitest@0.4.0(@vue/test-utils@2.4.4)(quasar@2.14.5)(vite@5.1.4)(vitest@0.31.4)(vue@3.4.19): resolution: {integrity: sha512-eyzdUdmZiCueNS+5nedjMmzdbpCetSrtdGIwW6KplW1dTzRbLiNvYUjpBOxQGmJCgEhWy9zuswJ7MZ/bTql24Q==} engines: {node: '>= 12.22.1', npm: '>= 6.14.12', yarn: '>= 1.17.3'} @@ -939,6 +949,10 @@ packages: - vite dev: true + /@quasar/quasar-ui-qcalendar@4.0.0-beta.19: + resolution: {integrity: sha512-BT0G2JjgKl1bqNrY5utcYeoy8gK+U9k3Pz1YDi1OB265W/jHU6nFoWMEUdY3JdvMccwkXTL2DLVyl3eqAUyLyg==} + dev: true + /@quasar/render-ssr-error@1.0.3: resolution: {integrity: sha512-A8RF99q6/sOSe1Ighnh5syEIbliD3qUYEJd2HyfFyBPSMF+WYGXon5dmzg4nUoK662NgOggInevkDyBDJcZugg==} engines: {node: '>= 16'} diff --git a/quasar.config.js b/quasar.config.js index 2d8289508..dd7a91002 100644 --- a/quasar.config.js +++ b/quasar.config.js @@ -29,7 +29,7 @@ module.exports = configure(function (/* ctx */) { // app boot file (/src/boot) // --> boot files are part of "main.js" // https://v2.quasar.dev/quasar-cli/boot-files - boot: ['i18n', 'axios', 'vnDate', 'validations'], + boot: ['i18n', 'axios', 'vnDate', 'validations', 'quasar.defaults'], // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css css: ['app.scss'], @@ -93,13 +93,11 @@ module.exports = configure(function (/* ctx */) { [ VueI18nPlugin({ runtimeOnly: false, + include: [ + path.resolve(__dirname, './src/i18n/locale/**'), + path.resolve(__dirname, './src/pages/**/locale/**'), + ], }), - { - // if you want to use Vue I18n Legacy API, you need to set `compositionOnly: false` - // compositionOnly: false, - // you need to set i18n resource including paths ! - include: path.resolve(__dirname, './src/i18n/**'), - }, ], ], }, @@ -117,6 +115,7 @@ module.exports = configure(function (/* ctx */) { secure: false, }, }, + open: false, }, // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#framework diff --git a/quasar.extensions.json b/quasar.extensions.json index e5c5cbfaa..867769090 100644 --- a/quasar.extensions.json +++ b/quasar.extensions.json @@ -1,7 +1,6 @@ { - "@quasar/testing-unit-vitest": { - "options": [ - "scripts" - ] - } -} \ No newline at end of file + "@quasar/testing-unit-vitest": { + "options": ["scripts"] + }, + "@quasar/qcalendar": {} +} diff --git a/src/App.vue b/src/App.vue index d0d8c9358..27cc34c38 100644 --- a/src/App.vue +++ b/src/App.vue @@ -16,7 +16,7 @@ onMounted(() => { if (availableLocales.includes(userLang)) { locale.value = userLang; } else { - locale.value = fallbackLocale; + locale.value = fallbackLocale.value; } }); diff --git a/src/boot/axios.js b/src/boot/axios.js index c58cc2d08..e3e7289af 100644 --- a/src/boot/axios.js +++ b/src/boot/axios.js @@ -11,7 +11,7 @@ axios.defaults.baseURL = '/api/'; const onRequest = (config) => { const token = session.getToken(); - if (token.length && config.headers) { + if (token.length && !config.headers.Authorization) { config.headers.Authorization = token; } diff --git a/src/boot/defaults/qTable.js b/src/boot/defaults/qTable.js new file mode 100644 index 000000000..8902d4266 --- /dev/null +++ b/src/boot/defaults/qTable.js @@ -0,0 +1,5 @@ +import { QTable } from 'quasar'; +import setDefault from './setDefault'; + +setDefault(QTable, 'pagination', { rowsPerPage: 0 }); +setDefault(QTable, 'hidePagination', true); diff --git a/src/boot/defaults/setDefault.js b/src/boot/defaults/setDefault.js new file mode 100644 index 000000000..7d56a1a3e --- /dev/null +++ b/src/boot/defaults/setDefault.js @@ -0,0 +1,18 @@ +export default function (component, key, value) { + const prop = component.props[key]; + switch (typeof prop) { + case 'object': + prop.default = value; + break; + case 'function': + component.props[key] = { + type: prop, + default: value, + }; + break; + case 'undefined': + throw new Error('unknown prop: ' + key); + default: + throw new Error('unhandled type: ' + typeof prop); + } +} diff --git a/src/boot/qformMixin.js b/src/boot/qformMixin.js new file mode 100644 index 000000000..8c89c9202 --- /dev/null +++ b/src/boot/qformMixin.js @@ -0,0 +1,21 @@ +import { getCurrentInstance } from 'vue'; + +const filterAvailableInput = element => element.classList.contains('q-field__native') && !element.disabled +const filterAvailableText = element => element.__vueParentComponent.type.name === 'QInput' && element.__vueParentComponent?.attrs?.class !== 'vn-input-date'; + + +export default { + mounted: function () { + const vm = getCurrentInstance(); + if (vm.type.name === 'QForm') + if (!['searchbarForm','filterPanelForm'].includes(this.$el?.id)) { + // AUTOFOCUS + const elementsArray = Array.from(this.$el.elements); + const firstInputElement = elementsArray.filter(filterAvailableInput).find(filterAvailableText); + + if (firstInputElement) { + firstInputElement.focus(); + } + } + }, +}; diff --git a/src/boot/quasar.defaults.js b/src/boot/quasar.defaults.js new file mode 100644 index 000000000..c792100d7 --- /dev/null +++ b/src/boot/quasar.defaults.js @@ -0,0 +1 @@ +export * from './defaults/qTable'; diff --git a/src/boot/quasar.js b/src/boot/quasar.js new file mode 100644 index 000000000..a8d9b7ad9 --- /dev/null +++ b/src/boot/quasar.js @@ -0,0 +1,6 @@ +import { boot } from 'quasar/wrappers'; +import qFormMixin from './qformMixin'; + +export default boot(({ app }) => { + app.mixin(qFormMixin); +}); diff --git a/src/components/CreateManualInvoiceForm.vue b/src/components/CreateManualInvoiceForm.vue new file mode 100644 index 000000000..f03afbf35 --- /dev/null +++ b/src/components/CreateManualInvoiceForm.vue @@ -0,0 +1,174 @@ + + + + + + + +es: + Create manual invoice: Crear factura manual + Ticket: Ticket + Client: Cliente + Max date: Fecha límite + Serial: Serie + Area: Area + Reference: Referencia + Or: O + Invoicing in progress...: Facturación en progreso... + diff --git a/src/components/CreateNewPostcodeForm.vue b/src/components/CreateNewPostcodeForm.vue index 47836c05b..02e84849c 100644 --- a/src/components/CreateNewPostcodeForm.vue +++ b/src/components/CreateNewPostcodeForm.vue @@ -28,8 +28,23 @@ const countriesOptions = ref([]); const provincesOptions = ref([]); const townsLocationOptions = ref([]); -const onDataSaved = (dataSaved) => { - emit('onDataSaved', dataSaved); +const onDataSaved = (formData) => { + const newPostcode = { + ...formData + }; + const townObject = townsLocationOptions.value.find( + ({id}) => id === formData.townFk + ); + newPostcode.town = townObject?.name; + const provinceObject = provincesOptions.value.find( + ({id}) => id === formData.provinceFk + ); + newPostcode.province = provinceObject?.name; + const countryObject = countriesOptions.value.find( + ({id}) => id === formData.countryFk + ); + newPostcode.country = countryObject?.country; + emit('onDataSaved', newPostcode); }; const onCityCreated = async ({ name, provinceFk }, formData) => { @@ -73,7 +88,7 @@ const onProvinceCreated = async ({ name }, formData) => { :title="t('New postcode')" :subtitle="t('Please, ensure you put the correct data!')" :form-initial-data="postcodeFormData" - @on-data-saved="onDataSaved($event)" + @on-data-saved="onDataSaved" >