From d801c4e6b5e5ff57888989903254769eda1a772e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e?= <tpoussard@neogeo.fr> Date: Wed, 10 Aug 2022 18:50:22 +0200 Subject: [PATCH] fix & improve type detection, refactor & clean code, fix partially csv import --- .../FeatureType/FeatureTypeCustomForm.vue | 33 ++--- src/utils/index.js | 27 +++++ src/views/FeatureType/FeatureTypeDetail.vue | 29 +---- src/views/FeatureType/FeatureTypeEdit.vue | 114 +++--------------- 4 files changed, 64 insertions(+), 139 deletions(-) diff --git a/src/components/FeatureType/FeatureTypeCustomForm.vue b/src/components/FeatureType/FeatureTypeCustomForm.vue index e71b1758..51f068a1 100644 --- a/src/components/FeatureType/FeatureTypeCustomForm.vue +++ b/src/components/FeatureType/FeatureTypeCustomForm.vue @@ -365,53 +365,46 @@ export default { return occurences.length === 1; }, - checkFilledOptions() { - if (this.form.field_type.value === 'list') { - if (this.form.options.value.length < 1) { - return false; - } else if ( - this.form.options.value.length === 1 && - this.form.options.value[0] === '' - ) { - return false; - } - } - return true; + checkListOptions() { + if (this.form.field_type.value !== 'list') return true; + return this.form.options.value.length >= 2 && !this.form.options.value.includes(''); }, checkCustomForm() { this.form.label.errors = []; this.form.name.errors = []; this.form.options.errors = []; + let isValid = true; if (!this.form.label.value) { //* vérifier que le label est renseigné this.form.label.errors = ['Veuillez compléter ce champ.']; - return false; + isValid = false; } else if (!this.form.name.value) { //* vérifier que le nom est renseigné this.form.name.errors = ['Veuillez compléter ce champ.']; - return false; + isValid = false; } else if (!this.hasRegularCharacters(this.form.name.value)) { //* vérifier qu'il n'y a pas de caractères spéciaux this.form.name.errors = [ 'Veuillez utiliser seulement les caratères autorisés.', ]; - return false; + isValid = false; } else if (!this.checkUniqueName()) { //* vérifier si les noms sont pas dupliqués this.form.name.errors = [ 'Les champs personnalisés ne peuvent pas avoir des noms similaires.', ]; - return false; - } else if (!this.checkFilledOptions()) { + isValid = false; + } else if (!this.checkListOptions()) { //* s'il s'agit d'un type liste, vérifier que le champ option est bien renseigné this.form.options.errors = ['Veuillez compléter ce champ.']; - return false; + isValid = false; } else if (this.hasDuplicateOptions()) { //* pour le cas d'options dupliqués - return false; + isValid = false; } - return true; + if (!isValid) document.getElementById(`custom_form-${this.form.position.value}`).scrollIntoView({ block: 'start', inline: 'nearest' }); + return isValid; }, }, }; diff --git a/src/utils/index.js b/src/utils/index.js index 432cd297..26f29312 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -58,4 +58,31 @@ export function allowedStatus2change(user, isModerate, userStatus, isOwnFeature, } } return []; +} + +export function transformProperties(prop) { + const type = typeof prop; + const date = new Date(prop); + const regInteger = /^-*?\d+$/; + const regFloat = /^-*?\d*?\.\d+$/; + const regText = /[\r\n]/; + console.log(prop); + if (type === 'boolean' || prop.toLowerCase() === 'true' || prop.toLowerCase() === 'False') { + return 'boolean'; + } else if (regInteger.test(prop) || Number.isSafeInteger(prop)) { + return 'integer'; + } else if ( + type === 'string' && + ['/', ':', '-'].some((el) => prop.includes(el)) && // check for chars found in datestring + date instanceof Date && + !isNaN(date.valueOf()) + ) { + return 'date'; + } else if (regFloat.test(prop) || type === 'number' && !isNaN(parseFloat(prop))) { + console.log({ prop }); + return 'decimal'; + } else if (regText.test(prop)) { + return 'text'; + } + return 'char'; //* string by default, most accepted type in database } \ No newline at end of file diff --git a/src/views/FeatureType/FeatureTypeDetail.vue b/src/views/FeatureType/FeatureTypeDetail.vue index 2c20b6c9..db49bba3 100644 --- a/src/views/FeatureType/FeatureTypeDetail.vue +++ b/src/views/FeatureType/FeatureTypeDetail.vue @@ -353,11 +353,11 @@ <script> import { mapActions, mapMutations, mapGetters, mapState } from 'vuex'; -import { formatStringDate } from '@/utils'; +import { formatStringDate, transformProperties } from '@/utils'; import ImportTask from '@/components/ImportTask'; import featureAPI from '@/services/feature-api'; -import { fileConvertSizeToMo, csvToJson } from '@/assets/js/utils'; +import { fileConvertSizeToMo, csvToJson } from '@/assets/js/utils'; // TODO: refactor with above utils, those files are similar export default { name: 'FeatureTypeDetail', @@ -539,26 +539,6 @@ export default { } }, - transformProperties(prop) { - const type = typeof prop; - const date = new Date(prop); - if (type === 'boolean') { - return 'boolean'; - } else if (Number.isSafeInteger(prop)) { - return 'integer'; - } else if ( - type === 'string' && - ['/', ':', '-'].some((el) => prop.includes(el)) && // check for chars found in datestring - date instanceof Date && - !isNaN(date.valueOf()) - ) { - return 'char'; - } else if (type === 'number' && !isNaN(parseFloat(prop))) { - return 'decimal'; - } - return 'char'; //* string by default, most accepted type in database - }, - checkJsonValidity(json) { this.importError = ''; const fields = this.structure.customfield_set.map((el) => { @@ -572,7 +552,7 @@ export default { for (const { name, field_type, options } of fields) { if (name in feature.properties) { const fieldInFeature = feature.properties[name]; - const customType = this.transformProperties(fieldInFeature); + const customType = transformProperties(fieldInFeature); //* if custom field value is not null, then check validity of field if (fieldInFeature !== null) { //* if field type is list, it's not possible to guess from value type @@ -658,7 +638,7 @@ export default { field_type = 'char'; } - const customType = this.transformProperties(fieldInFeature); + const customType = transformProperties(fieldInFeature); //* if custom field value is not null, then check validity of field if (fieldInFeature !== null) { //* if field type is list, it's not possible to guess from value type @@ -671,6 +651,7 @@ export default { } } else if (customType !== field_type) { //* check if custom field value match + console.log({ csv, headersLine, customType, fieldInFeature, name, fields, field_type }); this.importError = `Le fichier est invalide: Un champ de type ${field_type} ne peut pas avoir la valeur [ ${fieldInFeature} ]`; return false; } diff --git a/src/views/FeatureType/FeatureTypeEdit.vue b/src/views/FeatureType/FeatureTypeEdit.vue index 315acba7..b0e40885 100644 --- a/src/views/FeatureType/FeatureTypeEdit.vue +++ b/src/views/FeatureType/FeatureTypeEdit.vue @@ -159,6 +159,7 @@ import { mapGetters, mapState, mapMutations, mapActions } from 'vuex'; import Dropdown from '@/components/Dropdown.vue'; import FeatureTypeCustomForm from '@/components/FeatureType/FeatureTypeCustomForm.vue'; +import { transformProperties } from'@/utils'; export default { name: 'FeatureTypeEdit', @@ -639,23 +640,23 @@ export default { return 'point'; }, - transformProperties(prop) { - const type = typeof prop; - const date = new Date(prop); - if (type === 'boolean') { - return 'boolean'; - } else if (Number.isSafeInteger(prop)) { - return 'integer'; - } else if ( - type === 'string' && - date instanceof Date && - !isNaN(date.valueOf()) - ) { - return 'date'; - } else if (type === 'number' && !isNaN(parseFloat(prop))) { - return 'decimal'; + buildCustomForm(properties) { + for (const [key, val] of Object.entries(properties)) { + //* check that the property is not a keyword from the backend or map style + // todo: add map style keywords + if (!this.reservedKeywords.includes(key)) { + const customForm = { + label: { value: key || '' }, + name: { value: key || '' }, + position: this.dataKey, // * use dataKey already incremented by addCustomForm + field_type: { value: transformProperties(val) }, // * guessed from the type + options: { value: [] }, // * not available in export + }; + console.log(customForm); + if (customForm.field_type === 'decimal') console.log(customForm, properties, key, val); + this.addCustomForm(customForm); + } } - return 'char'; //* string by default, most accepted type in database }, importGeoJsonFeatureType() { @@ -665,93 +666,16 @@ export default { this.form.title.value = properties.feature_type; this.form.geom_type.value = this.translateLabel(geometry.type); this.updateStore(); //* register title & geom_type in store - - //* loop properties to create a customForm for each of them - for (const [key, val] of Object.entries(properties)) { - //* check that the property is not a keyword from the backend or map style - // todo: add map style keywords - if (!this.reservedKeywords.includes(key)) { - const customForm = { - label: { value: key || '' }, - name: { value: key || '' }, - position: this.dataKey, // * use dataKey already incremented by addCustomForm - field_type: { value: this.transformProperties(val) }, // * guessed from the type - options: { value: [] }, // * not available in export - }; - this.addCustomForm(customForm); - } - } + this.buildCustomForm(properties); } }, importCSVFeatureType() { if (this.csv.length) { this.updateStore(); //* register title & geom_type in store - // List fileds for user to select coords fields - // this.csvFields = - // Object.keys(this.csv[0]) - // .map(el => { - // return { - // field: el, - // x: false, - // y:false - // }; - // }); - for (const [key, val] of Object.entries(this.csv[0])) { - //* check that the property is not a keyword from the backend or map style - // todo: add map style keywords - if (!this.reservedKeywords.includes(key)) { - const customForm = { - label: { value: key || '' }, - name: { value: key || '' }, - position: this.dataKey, // * use dataKey already incremented by addCustomForm - field_type: { value: this.transformProperties(val) }, // * guessed from the type - options: { value: [] }, // * not available in export - }; - this.addCustomForm(customForm); - } - } + this.buildCustomForm(this.csv[0]); } }, - - // pickXcsvCoordField(e) { - // this.csvFields.forEach(el => { - // if (el.field === e.field) { - // el.x = true; - // } else { - // el.x = false; - // } - // }); - // }, - // pickYcsvCoordField(e) { - // this.csvFields.forEach(el => { - // if (el.field === e.field) { - // el.y = true; - // } else { - // el.y = false; - // } - // }); - // }, - // setCSVCoordsFields() { - // const xField = this.csvFields.find(el => el.x === true).field; - // const yField = this.csvFields.find(el => el.y === true).field; - // this.csvFields = null; - - // for (const [key, val] of Object.entries(this.csv[0])) { - // //* check that the property is not a keyword from the backend or map style - // // todo: add map style keywords - // if (!this.reservedKeywords.includes(key) && key !== xField && key !== yField) { - // const customForm = { - // label: { value: key || '' }, - // name: { value: key || '' }, - // position: this.dataKey, // * use dataKey already incremented by addCustomForm - // field_type: { value: this.transformProperties(val) }, // * guessed from the type - // options: { value: [] }, // * not available in export - // }; - // this.addCustomForm(customForm); - // } - // } - // } }, }; </script> -- GitLab