From 94514a325466b21af87b70677225b422d1e503d5 Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Thu, 21 Nov 2024 20:14:54 +0100 Subject: [PATCH 01/22] feat: #8217 send just changes --- src/components/CrudModel.vue | 23 +---------------------- src/components/FormModel.vue | 21 ++++++++++++++++----- src/filters/getDifferences.js | 21 +++++++++++++++++++++ src/filters/index.js | 2 ++ 4 files changed, 40 insertions(+), 27 deletions(-) create mode 100644 src/filters/getDifferences.js diff --git a/src/components/CrudModel.vue b/src/components/CrudModel.vue index 0de5d3aa2..ca8f0a14d 100644 --- a/src/components/CrudModel.vue +++ b/src/components/CrudModel.vue @@ -10,6 +10,7 @@ import VnPaginate from 'components/ui/VnPaginate.vue'; import VnConfirm from 'components/ui/VnConfirm.vue'; import SkeletonTable from 'components/ui/SkeletonTable.vue'; import { tMobile } from 'src/composables/tMobile'; +import getDifferences from 'src/filters/getDifferences'; const { push } = useRouter(); const quasar = useQuasar(); @@ -267,28 +268,6 @@ function getChanges() { return changes; } -function getDifferences(obj1, obj2) { - let diff = {}; - delete obj1.$index; - delete obj2.$index; - - for (let key in obj1) { - if (obj2[key] && JSON.stringify(obj1[key]) !== JSON.stringify(obj2[key])) { - diff[key] = obj2[key]; - } - } - for (let key in obj2) { - if ( - obj1[key] === undefined || - JSON.stringify(obj1[key]) !== JSON.stringify(obj2[key]) - ) { - diff[key] = obj2[key]; - } - } - - return diff; -} - function isEmpty(obj) { if (obj == null) return true; if (obj === undefined) return true; diff --git a/src/components/FormModel.vue b/src/components/FormModel.vue index 05f947cf3..0b6e270ad 100644 --- a/src/components/FormModel.vue +++ b/src/components/FormModel.vue @@ -13,6 +13,7 @@ import VnConfirm from './ui/VnConfirm.vue'; import { tMobile } from 'src/composables/tMobile'; import { useArrayData } from 'src/composables/useArrayData'; import { useRoute } from 'vue-router'; +import { getDifferences } from 'src/filters'; const { push } = useRouter(); const quasar = useQuasar(); @@ -195,7 +196,19 @@ async function fetch() { originalData.value = {}; } } - +function HandleRequestArgs() { + const isUrlCreate = $props.urlCreate; + const differences = getDifferences(formData.value, originalData.value); + return { + method: isUrlCreate ? 'post' : 'patch', + url: isUrlCreate || $props.urlUpdate || $props.url || arrayData.store.url, + body: $props.mapper + ? $props.mapper(formData.value) + : isUrlCreate + ? formData.value + : differences, + }; +} async function save() { if ($props.observeFormChanges && !hasChanges.value) return notify('globals.noChanges', 'negative'); @@ -203,10 +216,8 @@ async function save() { isLoading.value = true; try { formData.value = trimData(formData.value); - const body = $props.mapper ? $props.mapper(formData.value) : formData.value; - const method = $props.urlCreate ? 'post' : 'patch'; - const url = - $props.urlCreate || $props.urlUpdate || $props.url || arrayData.store.url; + const { method, body, url } = HandleRequestArgs(); + let response; if ($props.saveFn) response = await $props.saveFn(body); diff --git a/src/filters/getDifferences.js b/src/filters/getDifferences.js new file mode 100644 index 000000000..3e1061aba --- /dev/null +++ b/src/filters/getDifferences.js @@ -0,0 +1,21 @@ +export default function getDifferences(obj1, obj2) { + let diff = {}; + delete obj1.$index; + delete obj2.$index; + + for (let key in obj1) { + if (obj2[key] && JSON.stringify(obj1[key]) !== JSON.stringify(obj2[key])) { + diff[key] = obj2[key]; + } + } + for (let key in obj2) { + if ( + obj1[key] === undefined || + JSON.stringify(obj1[key]) !== JSON.stringify(obj2[key]) + ) { + diff[key] = obj2[key]; + } + } + + return diff; +} diff --git a/src/filters/index.js b/src/filters/index.js index 5f08f19c7..4a49c47ac 100644 --- a/src/filters/index.js +++ b/src/filters/index.js @@ -11,9 +11,11 @@ import dashIfEmpty from './dashIfEmpty'; import dateRange from './dateRange'; import toHour from './toHour'; import dashOrCurrency from './dashOrCurrency'; +import getDifferences from './getDifferences'; import getParamWhere from './getParamWhere'; export { + getDifferences, toLowerCase, toLowerCamel, toDate, From c6b547bc5594c0bef575dd517a6ef7ce0ea4b545 Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Fri, 22 Nov 2024 10:04:17 +0100 Subject: [PATCH 02/22] perf: change fn name --- src/components/FormModel.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/FormModel.vue b/src/components/FormModel.vue index 0b6e270ad..09a78c298 100644 --- a/src/components/FormModel.vue +++ b/src/components/FormModel.vue @@ -196,7 +196,7 @@ async function fetch() { originalData.value = {}; } } -function HandleRequestArgs() { +function handleRequestArgs() { const isUrlCreate = $props.urlCreate; const differences = getDifferences(formData.value, originalData.value); return { @@ -216,7 +216,7 @@ async function save() { isLoading.value = true; try { formData.value = trimData(formData.value); - const { method, body, url } = HandleRequestArgs(); + const { method, body, url } = handleRequestArgs(); let response; From 8a4a6061e7d0e9faa4af5be0f30f1d77ed67a303 Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Fri, 22 Nov 2024 10:16:56 +0100 Subject: [PATCH 03/22] test: add e2e --- src/pages/Customer/Card/CustomerBasicData.vue | 1 + .../integration/client/clientBasicData.spec.js | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/pages/Customer/Card/CustomerBasicData.vue b/src/pages/Customer/Card/CustomerBasicData.vue index d31669b43..e32507c7d 100644 --- a/src/pages/Customer/Card/CustomerBasicData.vue +++ b/src/pages/Customer/Card/CustomerBasicData.vue @@ -94,6 +94,7 @@ const exprBuilder = (param, value) => { :rules="validate('client.phone')" clearable v-model="data.phone" + data-cy="customerPhone" /> { beforeEach(() => { cy.viewport(1280, 720); cy.login('developer'); - cy.visit('#/customer/1110/basic-data', { - timeout: 5000, - }); + cy.visit('#/customer/1102/basic-data'); }); it('Should load layout', () => { cy.get('.q-card').should('be.visible'); + cy.get('[data-cy="customerPhone"]').filter('input').should('be.visible'); + cy.get('[data-cy="customerPhone"]').filter('input').type('123456789'); + cy.get('.q-btn-group > .q-btn--standard').click(); + cy.intercept('PATCH', '/api/Clients/1102', (req) => { + const { body } = req; + cy.wrap(body).should('have.property', 'phone', '123456789'); + }); + cy.get('.q-notification__message').should('have.text', 'Data saved'); }); }); From 4ea0d04b86113a128fbe5de00eed10fb21bbe7d4 Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Fri, 22 Nov 2024 10:48:03 +0100 Subject: [PATCH 04/22] perf: formModel --- src/components/FormModel.vue | 46 +++++++++++++++++-- .../client/clientBasicData.spec.js | 4 +- test/cypress/support/commands.js | 4 ++ 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/components/FormModel.vue b/src/components/FormModel.vue index 09a78c298..d45bb51c1 100644 --- a/src/components/FormModel.vue +++ b/src/components/FormModel.vue @@ -103,6 +103,7 @@ const isLoading = ref(false); // Si elegimos observar los cambios del form significa que inicialmente las actions estaran deshabilitadas const isResetting = ref(false); const hasChanges = ref(!$props.observeFormChanges); +const changes = ref({}); const originalData = ref({}); const formData = computed(() => state.get(modelValue)); const defaultButtons = computed(() => ({ @@ -142,13 +143,40 @@ onMounted(async () => { hasChanges.value = !isResetting.value && JSON.stringify(newVal) !== JSON.stringify(originalData.value); + console.error(getDifferences(originalData.value, newVal)); + console.error(getDifferences(newVal, originalData.value)); + console.error(getDiff(newVal, originalData.value)); + console.error(getDiff(originalData.value, newVal)); + console.error(getDifferencess(originalData.value, newVal)); + changes.value = { + ...changes.value, + ...getDifferences(originalData.value, oldVal), + }; isResetting.value = false; }, - { deep: true } + { deep: true, flush: 'sync' } ); } }); +function getDifferencess(oldVal, newVal) { + return Object.keys(newVal).reduce((diff, key) => { + if (oldVal[key] !== newVal[key]) { + diff[key] = newVal[key]; + } + return diff; + }, {}); +} +function getDiff(o2, o1) { + let diff = Object.keys(o2).reduce((diff, key) => { + if (o1[key] === o2[key]) return diff; + return { + ...diff, + [key]: o2[key], + }; + }, {}); + return diff; +} if (!$props.url) watch( () => arrayData.store.data, @@ -209,6 +237,12 @@ function handleRequestArgs() { : differences, }; } +function getUpdatedValues(keys, formData) { + return keys.reduce((acc, key) => { + acc[key] = formData[key]; + return acc; + }, {}); +} async function save() { if ($props.observeFormChanges && !hasChanges.value) return notify('globals.noChanges', 'negative'); @@ -217,11 +251,16 @@ async function save() { try { formData.value = trimData(formData.value); const { method, body, url } = handleRequestArgs(); + // Obtener las claves del objeto original + const originalKeys = Object.keys(body); + + // Construir el objeto con valores actualizados + const updatedValues = getUpdatedValues(originalKeys, formData.value); let response; - if ($props.saveFn) response = await $props.saveFn(body); - else response = await axios[method](url, body); + if ($props.saveFn) response = await $props.saveFn(updatedValues); + else response = await axios[method](url, updatedValues); if ($props.urlCreate) notify('globals.dataCreated', 'positive'); @@ -290,6 +329,7 @@ defineExpose({