diff --git a/package-lock.json b/package-lock.json index 760a6311..56c32abc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2120,9 +2120,9 @@ } }, "node_modules/@babel/types": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.4.tgz", - "integrity": "sha512-7uIFwVYpoplT5jp/kVv6EF93VaJ8H+Yn5IczYiaAi98ajzjfoZfslet/e0sLh+wVBjb2qqIut1b0S26VSafsSQ==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz", + "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.23.4", @@ -4026,6 +4026,12 @@ "@types/ms": "*" } }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, "node_modules/@types/geojson": { "version": "7946.0.13", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.13.tgz", @@ -4378,9 +4384,9 @@ } }, "node_modules/@vitest/coverage-istanbul": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@vitest/coverage-istanbul/-/coverage-istanbul-1.0.4.tgz", - "integrity": "sha512-6qoSzTR+sanwY/dREqu6OFJupo/mHzCcboh03rLwqH2V2B39505lDr9FpqaLwU1vQgeUKNA+CdHPkpNpusxkDw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@vitest/coverage-istanbul/-/coverage-istanbul-1.2.1.tgz", + "integrity": "sha512-j8M4R3XbQ7cmLqJd7mfxCpEc0bQ7S6o5VIEt7c0Auri2lT1hkd89Sa/mOYDnuGasTNawamW+0d9vDRK/5uhVXw==", "dev": true, "dependencies": { "debug": "^4.3.4", @@ -4389,7 +4395,7 @@ "istanbul-lib-report": "^3.0.1", "istanbul-lib-source-maps": "^4.0.1", "istanbul-reports": "^3.1.6", - "magicast": "^0.3.2", + "magicast": "^0.3.3", "picocolors": "^1.0.0", "test-exclude": "^6.0.0" }, @@ -4401,13 +4407,13 @@ } }, "node_modules/@vitest/expect": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.0.4.tgz", - "integrity": "sha512-/NRN9N88qjg3dkhmFcCBwhn/Ie4h064pY3iv7WLRsDJW7dXnEgeoa8W9zy7gIPluhz6CkgqiB3HmpIXgmEY5dQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.2.1.tgz", + "integrity": "sha512-/bqGXcHfyKgFWYwIgFr1QYDaR9e64pRKxgBNWNXPefPFRhgm+K3+a/dS0cUGEreWngets3dlr8w8SBRw2fCfFQ==", "dev": true, "dependencies": { - "@vitest/spy": "1.0.4", - "@vitest/utils": "1.0.4", + "@vitest/spy": "1.2.1", + "@vitest/utils": "1.2.1", "chai": "^4.3.10" }, "funding": { @@ -4415,12 +4421,12 @@ } }, "node_modules/@vitest/runner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.0.4.tgz", - "integrity": "sha512-rhOQ9FZTEkV41JWXozFM8YgOqaG9zA7QXbhg5gy6mFOVqh4PcupirIJ+wN7QjeJt8S8nJRYuZH1OjJjsbxAXTQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.2.1.tgz", + "integrity": "sha512-zc2dP5LQpzNzbpaBt7OeYAvmIsRS1KpZQw4G3WM/yqSV1cQKNKwLGmnm79GyZZjMhQGlRcSFMImLjZaUQvNVZQ==", "dev": true, "dependencies": { - "@vitest/utils": "1.0.4", + "@vitest/utils": "1.2.1", "p-limit": "^5.0.0", "pathe": "^1.1.1" }, @@ -4456,9 +4462,9 @@ } }, "node_modules/@vitest/snapshot": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.0.4.tgz", - "integrity": "sha512-vkfXUrNyNRA/Gzsp2lpyJxh94vU2OHT1amoD6WuvUAA12n32xeVZQ0KjjQIf8F6u7bcq2A2k969fMVxEsxeKYA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.2.1.tgz", + "integrity": "sha512-Tmp/IcYEemKaqAYCS08sh0vORLJkMr0NRV76Gl8sHGxXT5151cITJCET20063wk0Yr/1koQ6dnmP6eEqezmd/Q==", "dev": true, "dependencies": { "magic-string": "^0.30.5", @@ -4502,9 +4508,9 @@ "dev": true }, "node_modules/@vitest/spy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.0.4.tgz", - "integrity": "sha512-9ojTFRL1AJVh0hvfzAQpm0QS6xIS+1HFIw94kl/1ucTfGCaj1LV/iuJU4Y6cdR03EzPDygxTHwE1JOm+5RCcvA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.2.1.tgz", + "integrity": "sha512-vG3a/b7INKH7L49Lbp0IWrG6sw9j4waWAucwnksPB1r1FTJgV7nkBByd9ufzu6VWya/QTvQW4V9FShZbZIB2UQ==", "dev": true, "dependencies": { "tinyspy": "^2.2.0" @@ -4514,12 +4520,13 @@ } }, "node_modules/@vitest/utils": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.0.4.tgz", - "integrity": "sha512-gsswWDXxtt0QvtK/y/LWukN7sGMYmnCcv1qv05CsY6cU/Y1zpGX1QuvLs+GO1inczpE6Owixeel3ShkjhYtGfA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-bsH6WVZYe/J2v3+81M5LDU8kW76xWObKIURpPrOXm2pjBniBu2MERI/XP60GpS4PHU3jyK50LUutOwrx4CyHUg==", "dev": true, "dependencies": { "diff-sequences": "^29.6.3", + "estree-walker": "^3.0.3", "loupe": "^2.3.7", "pretty-format": "^29.7.0" }, @@ -4539,6 +4546,15 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/@vitest/utils/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/@vitest/utils/node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -4691,9 +4707,9 @@ "integrity": "sha512-u2G8ZQ9IhMWTMXaWqZycnK4UthG1fA238CD+DP4Dm4WJi5hdUKKLg0RMRaRpDPNMdkTwIDkp7WtD0Rd9BH9fLw==" }, "node_modules/@vue/test-utils": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.3.tgz", - "integrity": "sha512-F4K7mF+ad++VlTrxMJVRnenKSJmO6fkQt2wpRDiKDesQMkfpniGWsqEi/JevxGBo2qEkwwjvTUAoiGJLNx++CA==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.4.tgz", + "integrity": "sha512-8jkRxz8pNhClAf4Co4ZrpAoFISdvT3nuSkUlY6Ys6rmTpw3DMWG/X3mw3gQ7QJzgCZO9f+zuE2kW57fi09MW7Q==", "dev": true, "dependencies": { "js-beautify": "^1.14.9", @@ -4823,9 +4839,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz", - "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", "dev": true, "engines": { "node": ">=0.4.0" @@ -5243,9 +5259,9 @@ } }, "node_modules/chai": { - "version": "4.3.10", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", - "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", + "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", "dev": true, "dependencies": { "assertion-error": "^1.1.0", @@ -7479,13 +7495,13 @@ } }, "node_modules/magicast": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.2.tgz", - "integrity": "sha512-Fjwkl6a0syt9TFN0JSYpOybxiMCkYNEeOTnOTNRbjphirLakznZXAqrXgj/7GG3D1dvETONNwrBfinvAbpunDg==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.3.tgz", + "integrity": "sha512-ZbrP1Qxnpoes8sz47AM0z08U+jW6TyRgZzcWy3Ma3vDhJttwMwAFDMMQFobwdBxByBD46JYmxRzeF7w2+wJEuw==", "dev": true, "dependencies": { - "@babel/parser": "^7.23.3", - "@babel/types": "^7.23.3", + "@babel/parser": "^7.23.6", + "@babel/types": "^7.23.6", "source-map-js": "^1.0.2" } }, @@ -9928,9 +9944,9 @@ "dev": true }, "node_modules/vite": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.8.tgz", - "integrity": "sha512-jYMALd8aeqR3yS9xlHd0OzQJndS9fH5ylVgWdB+pxTwxLKdO1pgC5Dlb398BUxpfaBxa4M9oT7j1g503Gaj5IQ==", + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.12.tgz", + "integrity": "sha512-4hsnEkG3q0N4Tzf1+t6NdN9dg/L3BM+q8SWgbSPnJvrgH2kgdyzfVJwbR1ic69/4uMJJ/3dqDZZE5/WwqW8U1w==", "dev": true, "dependencies": { "esbuild": "^0.19.3", @@ -9983,9 +9999,9 @@ } }, "node_modules/vite-node": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.0.4.tgz", - "integrity": "sha512-9xQQtHdsz5Qn8hqbV7UKqkm8YkJhzT/zr41Dmt5N7AlD8hJXw/Z7y0QiD5I8lnTthV9Rvcvi0QW7PI0Fq83ZPg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.2.1.tgz", + "integrity": "sha512-fNzHmQUSOY+y30naohBvSW7pPn/xn3Ib/uqm+5wAJQJiqQsU0NBR78XdRJb04l4bOFKjpTWld0XAfkKlrDbySg==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -10031,17 +10047,17 @@ } }, "node_modules/vitest": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.0.4.tgz", - "integrity": "sha512-s1GQHp/UOeWEo4+aXDOeFBJwFzL6mjycbQwwKWX2QcYfh/7tIerS59hWQ20mxzupTJluA2SdwiBuWwQHH67ckg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.2.1.tgz", + "integrity": "sha512-TRph8N8rnSDa5M2wKWJCMnztCZS9cDcgVTQ6tsTFTG/odHJ4l5yNVqvbeDJYJRZ6is3uxaEpFs8LL6QM+YFSdA==", "dev": true, "dependencies": { - "@vitest/expect": "1.0.4", - "@vitest/runner": "1.0.4", - "@vitest/snapshot": "1.0.4", - "@vitest/spy": "1.0.4", - "@vitest/utils": "1.0.4", - "acorn-walk": "^8.3.0", + "@vitest/expect": "1.2.1", + "@vitest/runner": "1.2.1", + "@vitest/snapshot": "1.2.1", + "@vitest/spy": "1.2.1", + "@vitest/utils": "1.2.1", + "acorn-walk": "^8.3.2", "cac": "^6.7.14", "chai": "^4.3.10", "debug": "^4.3.4", @@ -10055,7 +10071,7 @@ "tinybench": "^2.5.1", "tinypool": "^0.8.1", "vite": "^5.0.0", - "vite-node": "1.0.4", + "vite-node": "1.2.1", "why-is-node-running": "^2.2.2" }, "bin": { diff --git a/src/cartobio-api.js b/src/cartobio-api.js index 9b314855..550f1038 100644 --- a/src/cartobio-api.js +++ b/src/cartobio-api.js @@ -111,14 +111,25 @@ export const EventType = { * @property {UserRole} mainGroup */ -const cartobioApi = axios.create({ baseURL, timeout: 10000 }) +const apiClient = axios.create({ baseURL, timeout: 10000 }) /** * @param {number} numeroBio * @returns {Promise} */ export async function getOperatorParcelles (numeroBio) { - const { data } = await cartobioApi.get(`/v2/operator/${numeroBio}`) + const { data } = await apiClient.get(`/v2/operator/${numeroBio}`) + + return data +} + +/** + * + * @param {{ evv: String, numeroBio: String }} params + * @returns {Promise} + */ +export async function getOperatorNcviFeatures ({ evv, numeroBio }) { + const { data } = await apiClient.get(`/v2/import/evv/${evv}+${numeroBio}`) return data } @@ -128,7 +139,7 @@ export async function getOperatorParcelles (numeroBio) { * @returns {Promise} */ export async function searchOperators (input) { - const { data } = await cartobioApi.post(`/v2/certification/operators/search`, { input }) + const { data } = await apiClient.post(`/v2/certification/operators/search`, { input }) return data } @@ -137,7 +148,7 @@ export async function searchOperators (input) { * @return {Promise} */ export async function getUserOperators () { - const { data } = await cartobioApi.get(`/v2/operators`) + const { data } = await apiClient.get(`/v2/operators`) return data } @@ -147,7 +158,7 @@ export async function getUserOperators () { * @returns {Promise} */ export async function pacageLookup (pacage) { - const { data } = await cartobioApi.get(`/v2/import/pacage/${pacage}`) + const { data } = await apiClient.get(`/v2/import/pacage/${pacage}`) return data } @@ -156,7 +167,7 @@ export async function pacageLookup (pacage) { * @returns {Promise} */ export async function fetchLatestOperators () { - const { data } = await cartobioApi.get(`/v2/certification/operators/latest`, { timeout: 10000 }) + const { data } = await apiClient.get(`/v2/certification/operators/latest`, { timeout: 10000 }) return data.operators } @@ -168,13 +179,13 @@ export async function fetchLatestOperators () { * @returns {Promise} */ export async function createOperatorRecord (numeroBio, payload) { - const { data } = await cartobioApi.post(`/v2/audits/${numeroBio}`, payload) + const { data } = await apiClient.post(`/v2/audits/${numeroBio}`, payload) return data } export async function deleteSingleFeature ({ recordId }, { id, reason }) { - const { data } = await cartobioApi.delete(`/v2/audits/${recordId}/parcelles/${id}`, {data: { reason }}) + const { data } = await apiClient.delete(`/v2/audits/${recordId}/parcelles/${id}`, {data: { reason }}) return data } @@ -187,7 +198,7 @@ export async function deleteSingleFeature ({ recordId }, { id, reason }) { * @returns {Promise} */ export async function updateFeatureCollectionProperties ({ recordId }, featureCollection) { - const { data } = await cartobioApi.patch(`/v2/audits/${recordId}/parcelles`, featureCollection) + const { data } = await apiClient.patch(`/v2/audits/${recordId}/parcelles`, featureCollection) return data } @@ -200,7 +211,7 @@ export async function updateFeatureCollectionProperties ({ recordId }, featureCo * @returns {Promise} */ export async function updateSingleFeature ({ recordId }, { id, properties, geometry }) { - const { data } = await cartobioApi.put(`/v2/audits/${recordId}/parcelles/${id}`, { properties, geometry }) + const { data } = await apiClient.put(`/v2/audits/${recordId}/parcelles/${id}`, { properties, geometry }) return data } @@ -212,7 +223,7 @@ export async function updateSingleFeature ({ recordId }, { id, properties, geome * @returns {Promise} */ export async function updateAuditState ({ recordId }, patch) { - const { data } = await cartobioApi.patch(`/v2/audits/${recordId}`, patch) + const { data } = await apiClient.patch(`/v2/audits/${recordId}`, patch) return data } @@ -222,7 +233,7 @@ export async function updateAuditState ({ recordId }, patch) { * @returns {Promise} */ export async function deleteRecord (recordId) { - const { data } = await cartobioApi.delete(`/v2/audits/${recordId}`) + const { data } = await apiClient.delete(`/v2/audits/${recordId}`) return data } @@ -235,7 +246,7 @@ export async function deleteRecord (recordId) { * @returns {Promise} */ export async function submitNewParcelle ({ recordId }, feature) { - const { data } = await cartobioApi.post(`/v2/audits/${recordId}/parcelles`, { + const { data } = await apiClient.post(`/v2/audits/${recordId}/parcelles`, { feature }) @@ -247,7 +258,7 @@ export async function submitNewParcelle ({ recordId }, feature) { * @returns {Promise} */ export async function verifyToken (userToken) { - const { data } = await cartobioApi.get(`/v2/user/verify`, { + const { data } = await apiClient.get(`/v2/user/verify`, { headers: { Authorization: `Bearer ${userToken}` } @@ -257,7 +268,7 @@ export async function verifyToken (userToken) { } export async function exchangeNotificationToken (token) { - const { data } = await cartobioApi.get(`/v2/user/exchangeToken`, { + const { data } = await apiClient.get(`/v2/user/exchangeToken`, { headers: { Authorization: `Bearer ${token}` } @@ -268,10 +279,10 @@ export async function exchangeNotificationToken (token) { export function setAuthorization (userToken) { if (userToken) { - cartobioApi.defaults.headers.common['Authorization'] = `Bearer ${userToken}` + apiClient.defaults.headers.common['Authorization'] = `Bearer ${userToken}` } else { - delete cartobioApi.defaults.headers.common['Authorization'] + delete apiClient.defaults.headers.common['Authorization'] } } @@ -284,7 +295,7 @@ export function setAuthorization (userToken) { export async function convertShapefileArchiveToGeoJSON (archive) { const form = new FormData() form.append('archive', archive) - const { data: geojson } = await cartobioApi.post(`/v2/convert/shapefile/geojson`, form) + const { data: geojson } = await apiClient.post(`/v2/convert/shapefile/geojson`, form) return geojson } @@ -297,6 +308,6 @@ export async function convertShapefileArchiveToGeoJSON (archive) { export async function convertGeofoliaArchiveToGeoJSON (archive) { const form = new FormData() form.append('archive', archive) - const { data: geojson } = await cartobioApi.post(`/v2/convert/geofolia/geojson`, form) + const { data: geojson } = await apiClient.post(`/v2/convert/geofolia/geojson`, form) return geojson } diff --git a/src/components/Features/AddFlow.vue b/src/components/Features/AddFlow.vue index a4bc697c..ad04e546 100644 --- a/src/components/Features/AddFlow.vue +++ b/src/components/Features/AddFlow.vue @@ -11,7 +11,6 @@ -
diff --git a/src/components/Features/SingleItemCertificationBodyForm.test.js b/src/components/Features/SingleItemCertificationBodyForm.test.js index 81e27a7f..8491e045 100644 --- a/src/components/Features/SingleItemCertificationBodyForm.test.js +++ b/src/components/Features/SingleItemCertificationBodyForm.test.js @@ -2,7 +2,7 @@ import { afterEach, beforeEach, describe, expect, test, vi } from "vitest" import { defineComponent, markRaw } from "vue" import { createTestingPinia } from "@pinia/testing" import { flushPromises, mount } from "@vue/test-utils" -import { updateSingleFeature } from '@/cartobio-api.js' +import axios from 'axios' import { usePermissions, useRecordStore } from "@/stores/index.js" import { ANNOTATIONS, @@ -103,10 +103,9 @@ describe("SingleItemCertificationBodyForm", () => { await form.find('.fr-modal__footer button.fr-btn').trigger('click') expect(wrapper.findComponent(EditForm).exists()).toEqual(false) - expect(updateSingleFeature.mock.lastCall).toMatchObject([ - { recordId: '054f0d70-c3da-448f-823e-81fcf7c2bf6e' }, + expect(axios.__createMock.put.mock.lastCall).toMatchObject([ + '/v2/audits/054f0d70-c3da-448f-823e-81fcf7c2bf6e/parcelles/2', { - id: 2, properties: { annotations: [ { diff --git a/src/components/Features/Table.test.js b/src/components/Features/Table.test.js index 3ebf638d..fdc2deaa 100644 --- a/src/components/Features/Table.test.js +++ b/src/components/Features/Table.test.js @@ -2,7 +2,7 @@ import { afterEach, beforeEach, describe, expect, test, vi } from "vitest" import { defineComponent, markRaw } from "vue" import { createTestingPinia } from "@pinia/testing" import { flushPromises, mount } from "@vue/test-utils" -import { deleteSingleFeature, updateSingleFeature } from '@/cartobio-api.js' +import axios from 'axios' import { DeletionReasonsCode, GROUPE_COMMUNE } from "@/components/Features/index.js" import { useFeaturesStore, usePermissions, useRecordStore } from "@/stores/index.js" @@ -128,7 +128,7 @@ describe("Features Table", () => { await table.find('tr.parcelle td').trigger('click') await flushPromises() - updateSingleFeature.mockResolvedValue(record) + axios.__createMock.put.mockResolvedValueOnce(record) // this throws if the modal form does not exist // it catches the Component reference even if it has been Teleport-ed in the @@ -139,7 +139,7 @@ describe("Features Table", () => { await form.find('.fr-modal__footer button.fr-btn').trigger('click') // modal is down, and the table should be updated - expect(updateSingleFeature).toHaveBeenCalled() + expect(axios.__createMock.put).toHaveBeenCalled() expect(wrapper.findComponent(EditForm).exists()).toEqual(false) }) @@ -155,7 +155,7 @@ describe("Features Table", () => { await wrapper.find('.fr-icon-delete-line').trigger('click') // we trigger the deletion - deleteSingleFeature.mockResolvedValue(record) + axios.__createMock.delete.mockResolvedValueOnce(record) const modal = wrapper.getComponent(DeleteFeatureModal) await modal.find('#deletion-reason').setValue(DeletionReasonsCode.OTHER) diff --git a/src/components/Features/index.js b/src/components/Features/index.js index b5396a4e..42e2e8ef 100644 --- a/src/components/Features/index.js +++ b/src/components/Features/index.js @@ -15,6 +15,27 @@ import axios from "axios" * @typedef {import('geojson').FeatureCollection} FeatureCollection */ +/** + * @typedef IgnFeature + * @property {String=} id + * @property {Geometry} geometry + * @property {IgnFeatureProperties} properties + * @property {String} type + */ +/** + * @typedef IgnFeatureProperties + * @property {String} id + * @property {String} departmentcode + * @property {String} municipalitycode + * @property {String} oldmunicipalitycode + * @property {String} districtcode + * @property {String} section + * @property {String} sheet + * @property {String} number + * @property {String} city + * @property {Geometry} truegeometry + */ + /** * @typedef GroupingChoice * @property {String} label @@ -71,6 +92,51 @@ export const deletionReasons = [ { code: DeletionReasonsCode.OTHER, label: 'Autre' }, ] +class FeatureError extends ReferenceError { + name = 'FeatureError' + #label = 'Erreur de parcelle' + + constructor (featureId) { + super(`Problème avec la parcelle ${featureId}`) + + this.id = featureId + } + + /** + * As displayed in the UI + * + * @returns {String} + */ + toString () { + return this.message + } + + /** + * As POSTed via the HTTP API + */ + valueOf () { + return { id: this.id, name: this.#label } + } +} + +export class FeatureNotFoundError extends FeatureError { + name = 'FeatureNotFoundError' + label = 'Parcelle introuvable' + + toString () { + return `La référence cadastrale ${this.id} est introuvable dans le parcellaire informatisé.` + } +} + +export class FeatureWithoutGeometryError extends FeatureError { + name = 'FeatureWithoutGeometryError' + label = 'Contour géographique absent' + + toString () { + return `Impossible d'obtenir le dessin géographique de la référence cadastrale ${this.id} n'a pas été retournée par le parcellaire informatisé.` + } +} + function sortBySurface (groupA, groupB) { return groupB.surface - groupA.surface } @@ -405,3 +471,75 @@ export function merge(features) { return union(mergedFeature, feature) }, null) } + +/** + * Fetch a single geometry for a given cadastral reference + * + * @param {String} q + * @param {Feature} baseFeature + * @throws {Error} + * @returns {Promise<{ geometry: Geometry, feature: Feature }>} + */ +async function fetchCadastreGeometry (q, baseFeature) { + const { data } = await axios.get('https://data.geopf.fr/geocodage/search', { + params: { + q, + index: 'parcel', + limit: 1, + returntruegeometry: true + } + }) + + /** @type {IgnFeature=} */ + const cadastreFeature = data.features.at(0) + + if (!cadastreFeature) { + throw new FeatureNotFoundError(q) + } + + const geometry = cadastreFeature.properties.truegeometry + + if (!geometry) { + throw new FeatureWithoutGeometryError(q) + } + + return { + geometry, + feature: feature(geometry, { + ...baseFeature.properties, + COMMUNE_LABEL: cadastreFeature.properties.city, + COMMUNE: `${cadastreFeature.properties.departmentcode}${cadastreFeature.properties.municipalitycode}` + }, { id: baseFeature.id ?? baseFeature.properties.id }) + } +} + +/** + * Augments features with no geometry and + * @param {FeatureCollection} baseCollection + * @param {String} field feature property name to collect and fetch the geometry against + * @throws {Error} + * @returns {Promise<{ featureCollection: FeatureCollection, warnings: String[] }>} + */ +export async function applyCadastreGeometries (baseCollection, field = 'cadastre') { + const warnings = [] + + const results = await Promise.allSettled(baseCollection.features.map(feature => { + if (!feature.geometry && Array.isArray(feature.properties[field])) { + return fetchCadastreGeometry(feature.properties[field][0], feature) + } + })) + + const featureCollection = { + ...baseCollection, + features: results.map(({ status, value, reason }) => { + if (status === 'rejected') { + warnings.push(reason) + return + } + + return value.feature + }).filter(feature => feature) + } + + return { featureCollection, warnings } +} diff --git a/src/components/Features/index.test.js b/src/components/Features/index.test.js index f65c9d98..5029b47a 100644 --- a/src/components/Features/index.test.js +++ b/src/components/Features/index.test.js @@ -1,7 +1,8 @@ -import { describe, test, expect } from 'vitest' -import { bounds, createGroupingKeys, diff, featureName, getFeatureGroups, surface } from './index.js' +import { describe, test, expect, vi } from 'vitest' +import { applyCadastreGeometries, FeatureNotFoundError, FeatureWithoutGeometryError, bounds, createGroupingKeys, diff, featureName, getFeatureGroups, surface } from './index.js' import { GROUPE_NONE, GROUPE_CULTURE, GROUPE_ILOT, GROUPE_NIVEAU_CONVERSION } from './index.js' -import { featureCollection } from '@turf/helpers' +import { feature as newFeature, featureCollection } from '@turf/helpers' +import axios from 'axios' const geometry = { type: "Polygon", @@ -502,3 +503,94 @@ describe('surface', () => { expect(surface(geometry)).toBeCloseTo(7055.26, 1) }) }) + +describe('applyCadastreGeometries()', () => { + const baseCollection = featureCollection([ + { + id: 1, + type: 'Feature', + properties: { + cadastre: ['014000000D0006'], + cultures: [{ id: 1, CPF: '01.21.12', variete: '1511' }] + } + }, + { + id: 2, + type: 'Feature', + properties: { + cadastre: ['010640000A0542'], + cultures: [{ id: 1, CPF: '01.21.12', variete: '1511' }] + } + } + ]) + + const coordinates = [[ [5.493242, 45.786051], [5.493575, 45.786161], [5.493797, 45.786222], [5.493977, 45.786274], [5.493908, 45.786348], [5.494475, 45.786546], [5.49448, 45.786536], [5.494527, 45.78643], [5.494579, 45.786321], [5.493653, 45.786048], [5.493292, 45.785947], [5.493242, 45.786051] ]] + + vi.mocked(axios.get).mockResolvedValue({ + data: featureCollection([ + { + type: 'Feature', + geometry: { + type: 'Point' + }, + properties: { + id: '014000000D0447', + departmentcode: '01', + municipalitycode: '400', + section: 'OD', + sheet: '03', + number: '0006', + city: 'Seillonnaz', + _type: 'parcel', + truegeometry: { + type: 'Polygon', + coordinates + } + } + } + ]) + }) + + test('two hits features', () => { + const result = applyCadastreGeometries(baseCollection) + + const expectation = { + featureCollection: featureCollection([ + newFeature( + { type: 'Polygon', coordinates }, + { ...baseCollection.features.at(0).properties, COMMUNE_LABEL: 'Seillonnaz', COMMUNE: '01400' }, + { id: 1 } + ), + newFeature( + { type: 'Polygon', coordinates }, + { ...baseCollection.features.at(1).properties, COMMUNE_LABEL: 'Seillonnaz', COMMUNE: '01400' }, + { id: 2 } + ) + ]), + warnings: [] + } + + return expect(result).resolves.toMatchObject(expectation) + }) + + test('one hit and one miss features', () => { + vi.mocked(axios.get).mockResolvedValueOnce({ + data: featureCollection([]) + }) + + const result = applyCadastreGeometries(baseCollection) + + const expectation = { + featureCollection: featureCollection([ + newFeature( + { type: 'Polygon', coordinates }, + { ...baseCollection.features.at(1).properties, COMMUNE_LABEL: 'Seillonnaz', COMMUNE: '01400' }, + { id: 2 } + ) + ]), + warnings: [new FeatureNotFoundError('014000000D0006')] + } + + return expect(result).resolves.toMatchObject(expectation) + }) +}) diff --git a/src/components/Operator/HistoryEntry.vue b/src/components/Operator/HistoryEntry.vue index c8f53fcc..46bf6f44 100644 --- a/src/components/Operator/HistoryEntry.vue +++ b/src/components/Operator/HistoryEntry.vue @@ -8,13 +8,24 @@ ({{ entry.user.organismeCertificateur.nom }})

+

+ +

+

{{ entry.description }}

{{ entry.metadata.source }} {{ entry.metadata.campagne }}, PACAGE {{ entry.metadata.pacage }} + , EVV {{ entry.metadata.evv }}

+
    +
  • + {{ label }} ({{ id }}) +
  • +
+

{{ plurals(entry.featureIds.length, { one: 'parcelle', other: 'parcelles' }) }}

@@ -22,10 +33,6 @@

Raison : {{ deletionReason }}

- -

- -

@@ -87,7 +94,13 @@ const deletionReason = computed(() => { } } - p[class*="fr-icon"] { + ul { + list-style: none; + margin: var(--text-spacing); + padding: 0; + } + + p[class*="fr-icon"], li[class*="fr-icon"] { color: var(--text-mention-grey); font-size: 0.75rem; diff --git a/src/components/OperatorSetup/Actions/ByOperator.vue b/src/components/OperatorSetup/Actions/ByOperator.vue index f0c86d02..421e3f7f 100644 --- a/src/components/OperatorSetup/Actions/ByOperator.vue +++ b/src/components/OperatorSetup/Actions/ByOperator.vue @@ -26,10 +26,7 @@ diff --git a/src/components/OperatorSetup/Actions/FromScratch.vue b/src/components/OperatorSetup/Actions/FromScratch.vue index 421a74f4..857aeb8f 100644 --- a/src/components/OperatorSetup/Actions/FromScratch.vue +++ b/src/components/OperatorSetup/Actions/FromScratch.vue @@ -24,13 +24,6 @@ import { sources } from '@/referentiels/imports.js' const emit = defineEmits(['save']) -defineProps({ - operator: { - type: Object, - required: true - } -}) - function confirmImport () { emit('save', { geojson: { type: 'FeatureCollection', features: [] }, diff --git a/src/components/OperatorSetup/Actions/FromSource.vue b/src/components/OperatorSetup/Actions/FromSource.vue index 13e62a7c..bbb0cd5c 100644 --- a/src/components/OperatorSetup/Actions/FromSource.vue +++ b/src/components/OperatorSetup/Actions/FromSource.vue @@ -32,12 +32,5 @@ diff --git a/src/components/OperatorSetup/index.test.js b/src/components/OperatorSetup/Flow.test.js similarity index 63% rename from src/components/OperatorSetup/index.test.js rename to src/components/OperatorSetup/Flow.test.js index 6f661e9b..4c36a823 100644 --- a/src/components/OperatorSetup/index.test.js +++ b/src/components/OperatorSetup/Flow.test.js @@ -1,16 +1,17 @@ -import { beforeAll, describe, it, expect } from "vitest" +import { beforeAll, describe, it, expect, vi } from "vitest" import { markRaw } from "vue" import { mount, flushPromises } from "@vue/test-utils" import { createPinia, setActivePinia } from "pinia" +import axios, { AxiosError } from "axios" import OperatorSetupFlow from './Flow.vue' import ActionFromScratch from './Actions/FromScratch.vue' import ActionFromSource from './Actions/FromSource.vue' import FlowMultiSources from './Flows/MultiSources.vue' +import CviComponent from "./Sources/Cvi.vue" import record from '../Features/__fixtures__/record-with-features.json' assert { type: 'json' } import { sources } from '@/referentiels/imports.js' -import { convertShapefileArchiveToGeoJSON, createOperatorRecord, pacageLookup } from "@/cartobio-api.js" import { AxiosError } from "axios" setActivePinia(createPinia()) @@ -21,33 +22,28 @@ const operatorSetupActions = [ selector: markRaw(ActionFromSource), wizzard: markRaw(FlowMultiSources), extraProps: { - sources: [sources.TELEPAC, sources.GEOFOLIA, sources.RPG] + sources: [sources.TELEPAC, sources.GEOFOLIA, sources.RPG, sources.CVI] } }, { id: 'manual', selector: markRaw(ActionFromScratch) }, ] -describe("OperatorSetupFlow", () => { - beforeAll(() => { - createOperatorRecord.mockImplementation(async d => d) - const importData = { - type: "FeatureCollection", - features: [ - { - "id": 241348481707929, - "type": "Feature", - "geometry": { - "type": "Polygon", - "coordinates": [[[6.078270281232933,47.68983218066847],[6.077630695731261,47.68673737583907],[6.077276790682129,47.68682804163941],[6.077323749197428,47.68709305155499],[6.077313862256676,47.68710239511393],[6.075499384808161,47.687464147687294],[6.0755065376706705,47.687511624868655],[6.075509558986984,47.687563976669956],[6.075623093601329,47.68854850039209],[6.075368087088886,47.68950738853427],[6.0753390241751815,47.689615399975295],[6.0769513067496845,47.6896708220522],[6.0775442832666595,47.68970512736066],[6.0776362435482145,47.689713506172005],[6.077720385122354,47.689721172010884],[6.077923952581039,47.68973970887201],[6.078146545003976,47.68979914320073],[6.078270281232933,47.68983218066847]],[[6.07701879390926,47.688111446343],[6.076935586303193,47.68813746904597],[6.076791503792409,47.68814841210576],[6.0765342343864175,47.6881551840494],[6.0764554652178635,47.68813580758333],[6.076406212284748,47.68799929070194],[6.07640726138449,47.68785108481969],[6.076356310674983,47.68751876979339],[6.076387157564956,47.68744169341436],[6.076760180177752,47.68736482047356],[6.076823697843435,47.687361088407435],[6.076877084992869,47.68737556069035],[6.076946704762103,47.68777661911073],[6.07701879390926,47.688111446343]]] - }, - "properties": {} - } - ] +const featureCollectionFixture = { + type: "FeatureCollection", + features: [ + { + "id": 241348481707929, + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [[[6.078270281232933,47.68983218066847],[6.077630695731261,47.68673737583907],[6.077276790682129,47.68682804163941],[6.077323749197428,47.68709305155499],[6.077313862256676,47.68710239511393],[6.075499384808161,47.687464147687294],[6.0755065376706705,47.687511624868655],[6.075509558986984,47.687563976669956],[6.075623093601329,47.68854850039209],[6.075368087088886,47.68950738853427],[6.0753390241751815,47.689615399975295],[6.0769513067496845,47.6896708220522],[6.0775442832666595,47.68970512736066],[6.0776362435482145,47.689713506172005],[6.077720385122354,47.689721172010884],[6.077923952581039,47.68973970887201],[6.078146545003976,47.68979914320073],[6.078270281232933,47.68983218066847]],[[6.07701879390926,47.688111446343],[6.076935586303193,47.68813746904597],[6.076791503792409,47.68814841210576],[6.0765342343864175,47.6881551840494],[6.0764554652178635,47.68813580758333],[6.076406212284748,47.68799929070194],[6.07640726138449,47.68785108481969],[6.076356310674983,47.68751876979339],[6.076387157564956,47.68744169341436],[6.076760180177752,47.68736482047356],[6.076823697843435,47.687361088407435],[6.076877084992869,47.68737556069035],[6.076946704762103,47.68777661911073],[6.07701879390926,47.688111446343]]] + }, + "properties": {} } - convertShapefileArchiveToGeoJSON.mockResolvedValue(importData) - pacageLookup.mockResolvedValue(importData) - }) + ] +} +describe("OperatorSetupFlow", () => { it("should render the flow selector at first", async () => { const wrapper = mount(OperatorSetupFlow, { props: { @@ -86,7 +82,7 @@ describe("OperatorSetupFlow", () => { await flushPromises() const tabs = wrapper.findAll('.fr-tabs__tab') - expect(tabs).toHaveLength(3) + expect(tabs).toHaveLength(4) expect(tabs.at(0).attributes()).toHaveProperty('aria-selected', 'true') expect(tabs.at(0).text()).toBe('Telepac') @@ -131,10 +127,46 @@ describe("OperatorSetupFlow", () => { // Click on rpg tab await wrapper.find('ul').find('.import-source-tab--rpg').trigger('click') expect(wrapper.text()).toContain(`Vous pouvez importer le dernier Registre parcellaire graphique (RPG) instruit`) + + }) + + it("should render tab content for CVI when selected", async () => { + const wrapper = mount(OperatorSetupFlow, { + props: { + actions: operatorSetupActions, + flowId: 'source', + operator: record.operator + } + }) + + // Submit an invalid EVV + const error = new AxiosError('EVV et SIRET non correspondants') + error.response = { status : 401, data: { error: 'EVV et SIRET non correspondants' } } + axios.__createMock.get.mockRejectedValueOnce(error) + + await wrapper.find('ul').find('.import-source-tab--cvi').trigger('click') + + const cvi = wrapper.getComponent(CviComponent) + await wrapper.find('#ncvi-evv').setValue('99999') + + // surprisingly, the click on the submit button… does not trigger the submit event + // although it works in a browser UI + await wrapper.find('form').trigger('submit') + // await wrapper.find('.fr-btn').trigger('click') + await flushPromises() + + expect(wrapper.find('.fr-input-group').classes()).toContain('fr-input-group--error') + expect(wrapper.find('.fr-input').classes()).toContain('fr-input--error') + expect(wrapper.find('.fr-error-text').exists()).toBe(true) }) it("should render no tabs otherwise", () => { - const wrapper = mount(OperatorSetupFlow) + const wrapper = mount(OperatorSetupFlow, { + props: { + actions: [], + operator: record.operator + } + }) expect(wrapper.findAll('.fr-tabs__tab')).toHaveLength(0) }) @@ -148,12 +180,15 @@ describe("OperatorSetupFlow", () => { } }) + axios.__createMock.post.mockResolvedValueOnce({ + data: featureCollectionFixture + }) + await wrapper.find('input[type="file"]').setValue('') - expect(convertShapefileArchiveToGeoJSON).toHaveBeenCalledOnce() - // it is now called during preview await flushPromises() + + // it is now called during preview const confirmBtn = await wrapper.find('.fr-btn') - expect(createOperatorRecord).not.toHaveBeenCalled() expect(confirmBtn.text()).toEqual('Importer ces données') }) @@ -168,11 +203,12 @@ describe("OperatorSetupFlow", () => { const error = new AxiosError('Fichier invalide') error.response = { status : 400 } - convertShapefileArchiveToGeoJSON.mockRejectedValueOnce(error) + + axios.__createMock.post.mockRejectedValueOnce(error) + await wrapper.find('input[type="file"]').setValue('') - expect(convertShapefileArchiveToGeoJSON.mock.results.at(0).value).toEqual(error) - expect(createOperatorRecord).not.toHaveBeenCalled() await flushPromises() + expect(wrapper.text()).toContain('Votre fichier ne semble pas être une déclaration') }) @@ -201,12 +237,17 @@ describe("OperatorSetupFlow", () => { } }) + axios.__createMock.get.mockResolvedValueOnce({ + data: featureCollectionFixture + }) + // Click on rpg tab await wrapper.find('ul').find('.import-source-tab--rpg').trigger('click') await wrapper.find('#input-pacage').setValue('012345678') await wrapper.find('.fr-btn').trigger('click') await flushPromises() - expect(pacageLookup).toHaveBeenCalledOnce() + + expect(axios.__createMock.get).toHaveBeenCalledOnce() const confirmBtn = await wrapper.find('.fr-btn') expect(confirmBtn.text()).toEqual('Importer ces données') }) diff --git a/src/components/OperatorSetup/Flow.vue b/src/components/OperatorSetup/Flow.vue index 9dcfb479..7d2d3941 100644 --- a/src/components/OperatorSetup/Flow.vue +++ b/src/components/OperatorSetup/Flow.vue @@ -15,11 +15,11 @@
- +
- + @@ -32,7 +32,7 @@ diff --git a/src/components/OperatorSetup/index.js b/src/components/OperatorSetup/index.js index 45c572fd..86045e17 100644 --- a/src/components/OperatorSetup/index.js +++ b/src/components/OperatorSetup/index.js @@ -1,9 +1,10 @@ import { markRaw } from 'vue' import { sources } from '@/referentiels/imports.js' -import TelepacFeaturesImport from '@/components/OperatorSetup/Sources/Telepac.vue' import GeofoliaFeaturesImport from '@/components/OperatorSetup/Sources/Geofolia.vue' import RPGFeaturesImport from '@/components/OperatorSetup/Sources/RPG.vue' +import CviFeaturesImport from '@/components/OperatorSetup/Sources/Cvi.vue' +import TelepacFeaturesImport from '@/components/OperatorSetup/Sources/Telepac.vue' export default { [sources.TELEPAC]: { @@ -18,9 +19,13 @@ export default { label: 'RPG instruit', component: markRaw(RPGFeaturesImport), }, + [sources.CVI]: { + label: 'ProDouanes (CVI)', + component: markRaw(CviFeaturesImport), + }, [sources.MES_PARCELLES]: { label: 'MesParcelles', - }, + } } export const DEFAULT_SOURCE = sources.TELEPAC diff --git a/src/components/cadastre.js b/src/components/cadastre.js index b4f40274..971fc677 100644 --- a/src/components/cadastre.js +++ b/src/components/cadastre.js @@ -8,7 +8,7 @@ */ // via https://github.com/datagistips/memos/blob/main/regexes.md -const FRENCH_CADASTRE_REFERENCE_RE = /^(?(0[1-9]|1[0-9]|2[AB]|2[1-9]|[3-8][0-9])\d{3}|[90-95]\d|97[1-6]\d{2})(?\d{3})(?
((0|[A-Z])[A-Z]|\d{2}))(?[0-9]{3,4}[a-z]?)$/ +const FRENCH_CADASTRE_REFERENCE_RE = /^(?(0[1-9]|1[0-9]|2[AB]|2[1-9]|[3-8][0-9]|9[0-5])\d{3}|97[1-6]\d{2})(?\d{3})(?
((0|[A-Z])[A-Z]|\d{2}))(?[0-9]{3,4}[a-z]?)$/ export const trimLeadingZero = (ref) => ref.replace(/^0+([^0]+)$/, '$1') const NON_ALPHA_NUM_RE = /[^a-z0-9]+/gi diff --git a/src/components/cadastre.test.js b/src/components/cadastre.test.js index 824d65bf..ccd47ebf 100644 --- a/src/components/cadastre.test.js +++ b/src/components/cadastre.test.js @@ -55,6 +55,10 @@ describe('parseReference', () => { commune: '26108', section: 'AI', prefix: '000', number: '0341' }) + expect(parseReference('95476000AI0520')).toEqual({ + commune: '95476', section: 'AI', prefix: '000', number: '0520' + }) + expect(parseReference('33063000PD0174')).toEqual({ commune: '33063', section: 'PD', prefix: '000', number: '0174' }) @@ -70,6 +74,9 @@ describe('parseReference', () => { expect(parseReference('97100000AO289')).toEqual({ commune: '97100', section: 'AO', prefix: '000', number: '289' }) + expect(parseReference('97411000BP0867')).toEqual({ + commune: '97411', section: 'BP', prefix: '000', number: '0867' + }) }) test('parse a leading 0 section prefix', () => { diff --git a/src/pages/exploitations/[numeroBio]/index.vue b/src/pages/exploitations/[numeroBio]/index.vue index c61b2adb..715c78fd 100644 --- a/src/pages/exploitations/[numeroBio]/index.vue +++ b/src/pages/exploitations/[numeroBio]/index.vue @@ -133,7 +133,7 @@ const operatorSetupActions = [ selector: markRaw(ActionFromSource), wizzard: defineAsyncComponent(() => import('@/components/OperatorSetup/Flows/MultiSources.vue')), extraProps: { - sources: [sources.TELEPAC, ...(permissions.isOc ? [sources.RPG] : [])] + sources: [sources.TELEPAC, ...(permissions.isOc ? [sources.RPG] : []), sources.CVI] } }, { id: 'manual', selector: markRaw(ActionFromScratch) }, diff --git a/src/referentiels/imports.js b/src/referentiels/imports.js index 841afc37..4918761d 100644 --- a/src/referentiels/imports.js +++ b/src/referentiels/imports.js @@ -3,7 +3,7 @@ export const sources = Object.freeze({ GEOFOLIA: 'geofolia', MANUAL: '', MES_PARCELLES: 'mesparcelles', - NCVI: 'ncvi', + CVI: 'cvi', RPG: 'rpg', SMAG_FARMER: 'smagfarmer', TELEPAC: 'telepac', diff --git a/src/stores/record.js b/src/stores/record.js index 4e9cb43d..a4ce086e 100644 --- a/src/stores/record.js +++ b/src/stores/record.js @@ -35,7 +35,7 @@ export const useRecordStore = defineStore('record', () => { * Use case: when navigating from /parcellaire/:id to /parcellaire/:id/new-stuff * @param {import('@/cartobio-api').Record} updatedRecord */ - function update (updatedRecord) { + function update (updatedRecord = {}) { Object.entries(record).forEach(([key]) => { if (key in updatedRecord) { record[key] = updatedRecord[key] diff --git a/tests-setup.js b/tests-setup.js index 0540afb0..4d8ce5b0 100644 --- a/tests-setup.js +++ b/tests-setup.js @@ -15,7 +15,33 @@ const router = createRouter({ routes, history: createWebHistory() }) config.global.plugins = [head, router] -vi.mock('@/cartobio-api.js') +vi.mock('axios', async (importActual) => { + const axios = await importActual() + const createMock = { + delete: vi.fn(), + get: vi.fn(), + post: vi.fn(), + put: vi.fn(), + defaults: { + headers: { + common: {} + } + } + } + return { + __esModule: true, + default: { + create: vi.fn().mockReturnValue(createMock), + __createMock: createMock, + delete: vi.fn(), + get: vi.fn(), + post: vi.fn(), + put: vi.fn() + }, + post: vi.fn(), + AxiosError: axios.AxiosError + } +}) vi.mock('maplibre-gl', () => ({ Map: vi.fn(() => ({ diff --git a/widget/Notification.ce.vue b/widget/Notification.ce.vue index 486817be..612a4036 100644 --- a/widget/Notification.ce.vue +++ b/widget/Notification.ce.vue @@ -44,7 +44,7 @@ const operatorSetupActions = [ selector: null, wizzard: markRaw(FlowMultiSources), extraProps: { - sources: [sources.TELEPAC] + sources: [sources.TELEPAC, sources.CVI] } }, ]