diff --git a/src/assets/js/map-util.js b/src/assets/js/map-util.js index a949d80a330b258dd90baeb60985c134e641f412..b96a1fea724f3cbbbe40a2021d5566d5649486b0 100644 --- a/src/assets/js/map-util.js +++ b/src/assets/js/map-util.js @@ -1,14 +1,8 @@ -/* eslint-disable no-mixed-spaces-and-tabs */ -/* eslint-disable no-unused-vars */ -/* eslint-disable no-undef */ import L from 'leaflet'; import 'leaflet/dist/leaflet.css'; import flip from '@turf/flip'; import axios from '@/axios-client.js'; import 'leaflet.vectorgrid'; -import store from '@/store'; - -import { FillSymbolizer, PointSymbolizer, LineSymbolizer } from '@/assets/js/vector_tile_fix.js'; let map; let dictLayersToLeaflet = {}; @@ -59,7 +53,6 @@ L.TileLayer.BetterWMS = L.TileLayer.WMS.extend({ window.proxy_url, { params: params, - //dataType: "json", } ).then(response => { let data = response.data; @@ -70,8 +63,6 @@ L.TileLayer.BetterWMS = L.TileLayer.WMS.extend({ }) .catch(error => { throw (error); - //xhr.status; - //xhr.responseText; } ); @@ -369,7 +360,8 @@ const mapUtil = { const featureGroup = new L.FeatureGroup(); features.forEach((feature) => { const featureProperties = feature.properties ? feature.properties : feature; - const featureType = featureTypes.find((ft) => ft.slug === (featureProperties.feature_type.slug || featureProperties.feature_type)); + const featureType = featureTypes + .find((ft) => ft.slug === (featureProperties.feature_type.slug || featureProperties.feature_type)); let filters = []; if (filter) { const typeCheck = filter.featureType && featureProperties.feature_type.slug === filter.featureType; @@ -390,8 +382,12 @@ const mapUtil = { // Look for a custom field let customField; let customFieldOption; - if (featureType.customfield_set && Object.keys(featureProperties).some(el => featureType.customfield_set.map(e => e.name).includes(el))) { - customField = Object.keys(featureProperties).filter(el => featureType.customfield_set.map(e => e.name).includes(el)); + if ( + featureType.customfield_set && + Object.keys(featureProperties).some(el => featureType.customfield_set.map(e => e.name).includes(el)) + ) { + customField = Object.keys(featureProperties) + .filter(el => featureType.customfield_set.map(e => e.name).includes(el)); customFieldOption = featureProperties[customField[0]]; } let color = this.retrieveFeatureColor(featureType, featureProperties) || featureProperties.color; diff --git a/src/assets/resources/semantic-ui-2.4.2/semantic.min.css b/src/assets/resources/semantic-ui-2.4.2/semantic.min.css index 1a81e0b53764d8404d0c8498bdba12917cb56504..e31f026a991481fef798eb0b167c0bdc10ab5284 100644 --- a/src/assets/resources/semantic-ui-2.4.2/semantic.min.css +++ b/src/assets/resources/semantic-ui-2.4.2/semantic.min.css @@ -26066,14 +26066,9 @@ select.ui.dropdown { .ui.modal>.actions { background: #f9fafb; padding: 1rem 1rem; - border-top: 1px solid rgba(34, 36, 38, .15); text-align: right } -.ui.modal .actions>.button { - margin-left: .75em -} - @media only screen and (max-width:767px) { .ui.modal { width: 95%; diff --git a/src/assets/styles/base.css b/src/assets/styles/base.css index 0777e8e3742e08d03179550ddfff9e40778efb21..2197771371abbb1734a690797c92376429a94a55 100644 --- a/src/assets/styles/base.css +++ b/src/assets/styles/base.css @@ -9,7 +9,16 @@ header { main { padding: 2em 0em; } +/* ---------------------------------- */ + /* UTILS */ +/* ---------------------------------- */ +.no-margin { + margin: 0 !important; +} +.margin-top { + margin-top: 1rem; +} /* ---------------------------------- */ /* MAIN */ /* ---------------------------------- */ diff --git a/src/components/Dropdown.vue b/src/components/Dropdown.vue index bbebbec7d784840a8d7c41f4fe349cb878065974..d658cb72f7df541516c86220855f4c620e50d6bc 100644 --- a/src/components/Dropdown.vue +++ b/src/components/Dropdown.vue @@ -10,10 +10,10 @@ > <input v-if="search" + ref="input" v-model="input" class="search" autocomplete="off" - ref="input" tabindex="0" :placeholder="placehold" @input="isOpen = true" @@ -24,7 +24,6 @@ v-if="!input" class="default text" > - <!-- {{ selected }} --> <div v-if="Array.isArray(selected)"> <span v-if="selected[0]"> {{ selected[0] }} - </span> <span class="italic">{{ selected[1] }}</span> @@ -66,14 +65,32 @@ export default { name: 'Dropdown', - props: [ - 'options', - 'selected', - 'disabled', - 'search', - 'placeholder', - 'clearable', - ], + props: { + clearable: { + type: Boolean, + default: null, + }, + disabled: { + type: Boolean, + default: null, + }, + options: { + type: Array, + default: null, + }, + placeholder: { + type: String, + default: null, + }, + selected: { + type: [String, Array], + default: null, + }, + search: { + type: Boolean, + default: null, + }, + }, data() { return { diff --git a/src/components/feature/FeatureLinkedForm.vue b/src/components/feature/FeatureLinkedForm.vue index cae155139858c0074016783c32e12cdf33038bf4..09f5686322a21c53c5d2ddf82fd8e7911add0eb2 100644 --- a/src/components/feature/FeatureLinkedForm.vue +++ b/src/components/feature/FeatureLinkedForm.vue @@ -17,8 +17,9 @@ <li v-for="error in form.errors" :key="error" - v-html="error" - /> + > + {{ error }} + </li> </ul> <div class="visible-fields"> <div class="two fields"> @@ -60,7 +61,12 @@ export default { SearchFeature }, - props: ['linkedForm', 'features'], + props: { + linkedForm: { + type: Object, + default: null, + } + }, data() { return { diff --git a/src/components/map-layers/SidebarLayers.vue b/src/components/map-layers/SidebarLayers.vue index bbe8dbafd13b89e4347409e944b644781a485da7..59c9b2addd2efc52d51f9443d944be6af1ae4aba 100644 --- a/src/components/map-layers/SidebarLayers.vue +++ b/src/components/map-layers/SidebarLayers.vue @@ -20,6 +20,7 @@ > <g> <g> + <!-- eslint-disable max-len --> <path d="M487.298,326.733l-62.304-37.128l62.304-37.128c2.421-1.443,3.904-4.054,3.904-6.872s-1.483-5.429-3.904-6.872 l-62.304-37.128l62.304-37.128c3.795-2.262,5.038-7.172,2.776-10.968c-0.68-1.142-1.635-2.096-2.776-2.776l-237.6-141.6 @@ -32,6 +33,7 @@ L245.601,377.893L23.625,245.605z M245.601,465.893L23.625,333.605l58.208-34.68l159.672,95.2c2.524,1.504,5.668,1.504,8.192,0 l159.672-95.2l58.208,34.68L245.601,465.893z" /> + <!--eslint-enable--> </g> </g> </svg> diff --git a/src/components/project/ProjectMappingContextLayer.vue b/src/components/project/ProjectMappingContextLayer.vue index 0c39a07ade948f17bd0035909fbb2deef574fe1c..eacd0d968943544419b3d872796cfc18323139f0 100644 --- a/src/components/project/ProjectMappingContextLayer.vue +++ b/src/components/project/ProjectMappingContextLayer.vue @@ -14,11 +14,6 @@ > <i class="th icon" />couche </label> - <!-- {% if is_empty %} {# TODO arranger le dropdown pour les ajout à la volée - #} {# le selecteur de couche ne s'affichant pas correctement on passe - par un field django par defaut en attendant #} --> - <!-- {{ form.layer }} --> - <!-- {% else %} --> <Dropdown :options="availableLayerOptions" :selected="selectedLayer.name" @@ -26,7 +21,6 @@ :search="true" :placeholder="placeholder" /> - <!-- {{ form.layer.errors }} --> </div> <div class="fields"> <div @@ -41,7 +35,6 @@ min="0" max="1" > - <!-- {{ form.opacity.errors }} --> </div> <div class="field three wide"> <div @@ -55,7 +48,6 @@ > <label for="queryable"> Requêtable</label> </div> - <!-- {{ form.queryable.errors }} --> </div> </div> @@ -83,7 +75,18 @@ export default { Dropdown, }, - props: ['layer', 'basemapid'], + props: { + layer: + { + type: Object, + default: null, + }, + basemapid: + { + type: Number, + default: null, + }, + }, computed: { ...mapState('map', ['availableLayers']), diff --git a/src/components/project/project_mapping_basemap.vue b/src/components/project/project_mapping_basemap.vue index c606f2f8ee0f23498c8a527fb9513aadbb1ab98b..36684a2357dd210b1d2e07e1a537acb430d09783 100644 --- a/src/components/project/project_mapping_basemap.vue +++ b/src/components/project/project_mapping_basemap.vue @@ -21,9 +21,8 @@ <div class="nested"> <div - v-if="basemap.layers" :id="`list-${basemap.id}`" - class="ui segments layers-container" + :class="[basemap.layers.length > 0 ? 'ui segments': '', 'layers-container']" > <ProjectMappingContextLayer v-for="layer in basemap.layers" @@ -77,7 +76,12 @@ export default { ProjectMappingContextLayer, }, - props: ['basemap'], + props: { + basemap: { + type: Object, + default: null, + } + }, computed: { maxLayersCount: function () { @@ -112,19 +116,9 @@ export default { this.fillLayersWithDatakey(this.basemap.layers); } }, - // destroyed(){ - // this.errors = []; - // } mounted() { - //* not present in original this.initSortable(); - // if (!this.basemap.title) { - // this.$store.commit("map/UPDATE_BASEMAP", { - // id: this.basemap.id, - // title: newValue, - // }); - // } }, methods: { @@ -173,7 +167,6 @@ export default { }, //* drag & drop *// - onlayerMove() { //* Get the names of the current layers in order. const currentLayersNamesInOrder = Array.from( diff --git a/src/service-worker.js b/src/service-worker.js index 91c03b3a6d99225b9f65d4d7cb652ed8e4cfe4f1..2b50cf5562db86e66812a56a741b734c3d5a1a26 100644 --- a/src/service-worker.js +++ b/src/service-worker.js @@ -1,3 +1,4 @@ +/* global workbox */ //* allow undefined variable for 'workbox' in this file (because global variable) to avoid eslint error // custom service-worker.js if (workbox) { // adjust log level for displaying workbox logs diff --git a/src/store/modules/feature.js b/src/store/modules/feature.js index 694e28eef0f3eb44a983fb76c461bd1ed935fc67..e00e202415762ef4fab1d7c80656b0863b6f4d1d 100644 --- a/src/store/modules/feature.js +++ b/src/store/modules/feature.js @@ -105,7 +105,14 @@ const feature = { getters: { }, actions: { - async GET_PROJECT_FEATURES({ commit, rootState }, { project_slug, feature_type__slug, ordering, search, limit, geojson = false }) { + async GET_PROJECT_FEATURES({ commit, rootState }, { + project_slug, + feature_type__slug, + ordering, + search, + limit, + geojson = false + }) { if (rootState.cancellableSearchRequest.length > 0) { const currentRequestCancelToken = rootState.cancellableSearchRequest[rootState.cancellableSearchRequest.length - 1]; @@ -233,7 +240,9 @@ const feature = { data: geojson }).then((response) => { if ((response.status === 200 || response.status === 201) && response.data) { - if (state.attachmentFormset.length > 0 || state.linkedFormset.length > 0 || state.attachmentFormset.length > 0 || state.attachmentsToDelete.length > 0) { + if (state.attachmentFormset.length > 0 || + state.linkedFormset.length > 0 || + state.attachmentsToDelete.length > 0) { handleOtherForms(response.data.id); } else { redirect(response.data.id); diff --git a/src/store/modules/feature_type.js b/src/store/modules/feature_type.js index 156f1330ed7de9eaf125305e4a8190e024ec39f1..31221ca56e5b68e135921afe9d08dc8665575b00 100644 --- a/src/store/modules/feature_type.js +++ b/src/store/modules/feature_type.js @@ -1,9 +1,11 @@ import axios from '@/axios-client.js'; -const getColorsStyles = (customForms) => customForms.filter(customForm => customForm.options && customForm.options.length).map(el => { +const getColorsStyles = (customForms) => customForms + .filter(customForm => customForm.options && customForm.options.length) + .map(el => { //* in dropdown, value is the name and name is the label to be displayed, could be changed... - return { value: el.name, name: el.label, options: el.options }; -}); + return { value: el.name, name: el.label, options: el.options }; + }); const pending2draftFeatures = (features) => { let result = []; @@ -176,7 +178,11 @@ const feature_type = { const newGeojson= { type: 'FeatureCollection', features: unmoderatedFeatures }; - const newFile = new File([JSON.stringify(newGeojson)], state.fileToImport.name, { type: state.fileToImport.type }); + const newFile = new File( + [JSON.stringify(newGeojson)], + state.fileToImport.name, + { type: state.fileToImport.type } + ); formData.append('json_file', newFile); } else { formData.append('json_file', state.fileToImport); diff --git a/src/store/modules/map.js b/src/store/modules/map.js index af15ae053f057d7a370af240a4783b25ec07eb02..cc4d836f36ca5df1b5a1559e3fdba407087e7194 100644 --- a/src/store/modules/map.js +++ b/src/store/modules/map.js @@ -151,7 +151,11 @@ const map = { }); layersToLoad.reverse(); } - mapUtil.addLayers(layersToLoad, this.state.configuration.DEFAULT_BASE_MAP.SERVICE, this.state.configuration.DEFAULT_BASE_MAP.OPTIONS); + mapUtil.addLayers( + layersToLoad, + this.state.configuration.DEFAULT_BASE_MAP.SERVICE, + this.state.configuration.DEFAULT_BASE_MAP.OPTIONS + ); // Remove multiple interactions with the map //mapUtil.getMap().dragging.disable(); @@ -190,8 +194,10 @@ const map = { } const promisesResult = await Promise.all( - [...state.basemaps.map((basemap) => postOrPut(basemap)), ...state.basemapsToDelete.map((basemapId) => deleteBMap(basemapId))] - + [ + ...state.basemaps.map((basemap) => postOrPut(basemap)), + ...state.basemapsToDelete.map((basemapId) => deleteBMap(basemapId)) + ] ); state.basemapsToDelete = []; return promisesResult; diff --git a/src/views/feature/Feature_detail.vue b/src/views/feature/Feature_detail.vue index 4aa684dfa96a740da0fc7a38348e9d01e028bd93..0e40ed7c266f25cbe7ab91152fb615861b81e112 100644 --- a/src/views/feature/Feature_detail.vue +++ b/src/views/feature/Feature_detail.vue @@ -114,18 +114,6 @@ {{ feature.updated_on | formatDate }} </td> </tr> - <!-- <tr> - <td>Date d'archivage automatique</td> - <td v-if="feature.archived_on"> - {{ feature.archived_on }} - </td> - </tr> - <tr> - <td>Date de suppression automatique</td> - <td v-if="feature.deletion_on"> - {{ feature.deletion_on }} - </td> - </tr> --> </tbody> </table> @@ -378,23 +366,13 @@ Supprimer le signalement </div> <div class="actions"> - <form - action="{% url 'geocontrib:feature_delete' slug=feature.project.slug feature_type_slug=feature.feature_type.slug feature_id=feature.feature_id %}" - method="POST" + <button + type="button" + class="ui red compact fluid button" + @click="deleteFeature" > - <input - type="hidden" - name="_method" - value="delete" - > - <button - type="button" - class="ui red compact fluid button" - @click="deleteFeature" - > - Confirmer la suppression - </button> - </form> + Confirmer la suppression + </button> </div> </div> </div> @@ -422,6 +400,14 @@ export default { frag, }, + filters: { + formatDate(value) { + let date = new Date(value); + date = date.toLocaleString().replace(',', ''); + return date.substr(0, date.length - 3); //* quick & dirty way to remove seconds from date + }, + }, + data() { return { isCanceling: false, @@ -501,12 +487,49 @@ export default { return status ? status.name : ''; }, }, - filters: { - formatDate(value) { - let date = new Date(value); - date = date.toLocaleString().replace(',', ''); - return date.substr(0, date.length - 3); //* quick & dirty way to remove seconds from date - }, + + created() { + this.$store.commit( + 'feature_type/SET_CURRENT_FEATURE_TYPE_SLUG', + this.$route.params.slug_type_signal + ); + this.getFeatureEvents(); + this.getFeatureAttachments(); + this.getLinkedFeatures(); + }, + + mounted() { + this.$store.commit('DISPLAY_LOADER', 'Recherche du signalement'); + if (!this.project) { + // Chargements des features et infos projet en cas d'arrivée directe sur la page ou de refresh + axios.all([ + this.$store + .dispatch('GET_PROJECT_INFO', this.$route.params.slug), + this.$store.dispatch('feature/GET_PROJECT_FEATURE', { + project_slug: this.$route.params.slug, + feature_id: this.$route.params.slug_signal + })]) + .then(() => { + this.$store.commit('DISCARD_LOADER'); + this.initMap(); + }); + } if (!this.feature || this.feature.feature_id != this.$route.params.slug_signal) { + this.$store.dispatch('feature/GET_PROJECT_FEATURE', { + project_slug: this.$route.params.slug, + feature_id: this.$route.params.slug_signal + }) + .then(() => { + this.$store.commit('DISCARD_LOADER'); + this.initMap(); + }); + } else { + this.$store.commit('DISCARD_LOADER'); + this.initMap(); + } + }, + + beforeDestroy() { + this.$store.commit('CLEAR_MESSAGES'); }, methods: { @@ -738,50 +761,6 @@ export default { ); }, }, - - created() { - this.$store.commit( - 'feature_type/SET_CURRENT_FEATURE_TYPE_SLUG', - this.$route.params.slug_type_signal - ); - this.getFeatureEvents(); - this.getFeatureAttachments(); - this.getLinkedFeatures(); - }, - - mounted() { - this.$store.commit('DISPLAY_LOADER', 'Recherche du signalement'); - if (!this.project) { - // Chargements des features et infos projet en cas d'arrivée directe sur la page ou de refresh - axios.all([ - this.$store - .dispatch('GET_PROJECT_INFO', this.$route.params.slug), - this.$store.dispatch('feature/GET_PROJECT_FEATURE', { - project_slug: this.$route.params.slug, - feature_id: this.$route.params.slug_signal - })]) - .then(() => { - this.$store.commit('DISCARD_LOADER'); - this.initMap(); - }); - } if (!this.feature || this.feature.feature_id != this.$route.params.slug_signal) { - this.$store.dispatch('feature/GET_PROJECT_FEATURE', { - project_slug: this.$route.params.slug, - feature_id: this.$route.params.slug_signal - }) - .then(() => { - this.$store.commit('DISCARD_LOADER'); - this.initMap(); - }); - } else { - this.$store.commit('DISCARD_LOADER'); - this.initMap(); - } - }, - - beforeDestroy() { - this.$store.commit('CLEAR_MESSAGES'); - }, }; </script> diff --git a/src/views/feature/Feature_edit.vue b/src/views/feature/Feature_edit.vue index be4b4d72d474757c7602d4e956dd7627f5653c87..7fc6e51ac18cc4cfd2ce148947ddea292c6401d7 100644 --- a/src/views/feature/Feature_edit.vue +++ b/src/views/feature/Feature_edit.vue @@ -238,10 +238,10 @@ id="formsets-attachment" > <FeatureAttachmentForm - v-for="form in attachmentFormset" - :key="form.dataKey" + v-for="attachForm in attachmentFormset" + :key="attachForm.dataKey" ref="attachementForm" - :attachment-form="form" + :attachment-form="attachForm" /> </div> @@ -262,11 +262,10 @@ </div> <div id="formsets-link"> <FeatureLinkedForm - v-for="form in linkedFormset" - :key="form.dataKey" + v-for="linkForm in linkedFormset" + :key="linkForm.dataKey" ref="linkedForm" - :linked-form="form" - :features="features" + :linked-form="linkForm" /> </div> <button @@ -308,12 +307,6 @@ import { mapUtil } from '@/assets/js/map-util.js'; import axios from '@/axios-client.js'; import flip from '@turf/flip'; -// axios.defaults.headers.common["X-CSRFToken"] = ((name) => { -// var re = new RegExp(name + "=([^;]+)"); -// var value = re.exec(document.cookie); -// return value !== null ? unescape(value[1]) : null; -// })("csrftoken"); - export default { name: 'FeatureEdit', @@ -383,12 +376,9 @@ export default { ...mapState('map', ['basemaps']), ...mapState('feature', [ 'attachmentFormset', - 'attachmentsToDelete', - 'attachmentsToPut', 'linkedFormset', 'features', 'extra_form', - 'linked_features', 'statusChoices', ]), @@ -955,7 +945,6 @@ export default { var layers = e.layers; let self = this; layers.eachLayer(function (layer) { - //this.updateGeomField(wellknown.stringify(layer.toGeoJSON())) self.updateGeomField(layer.toGeoJSON()); }); }.bind(this) @@ -979,7 +968,7 @@ export default { if (this.drawnItems) this.drawnItems.clearLayers(); var geomType = this.feature_type.geom_type; if (geomFeatureJSON) { - var geomJSON = flip(geomFeatureJSON.geometry); //turf.flip(geomFeatureJSON) + var geomJSON = flip(geomFeatureJSON.geometry); if (geomType === 'point') { L.circleMarker(geomJSON.coordinates).addTo(this.drawnItems); } else if (geomType === 'linestring') { @@ -1062,7 +1051,6 @@ export default { this.drawControlFull.remove(this.map); this.drawControlEditOnly.addTo(this.map); //var wellknown;// TODO Remplacer par autre chose - //this.updateGeomField(wellknown.stringify(layer.toGeoJSON())) this.updateGeomField(layer.toGeoJSON()); if (this.feature_type.geomType === 'point') { this.showGeoPositionBtn = false; @@ -1120,13 +1108,13 @@ export default { height: 80vh; } } -/* // ! missing style in semantic.min.css, je ne comprends pas comment... */ +/* // ! missing style in semantic.min.css */ .ui.right.floated.button { float: right; margin-right: 0; margin-left: 0.25em; } -/* // ! margin écrasé par class last-child first-child, pas normal ... */ +/* // ! margin écrasé par class last-child first-child */ .ui.segment { margin: 1rem 0 !important; } diff --git a/src/views/feature/Feature_list.vue b/src/views/feature/Feature_list.vue index d429df957c1b1966f184f962fbd5202b754beadc..b50a313c0cd7358f2e303453f4d9849090180fab 100644 --- a/src/views/feature/Feature_list.vue +++ b/src/views/feature/Feature_list.vue @@ -27,9 +27,6 @@ <div class="item"> <h4> {{ featuresCount }} signalement{{ featuresCount > 1 ? "s" : "" }} - <!-- {{ filteredFeatures.length }} signalement{{ - filteredFeatures.length > 1 ? "s" : "" - }} --> </h4> </div> @@ -199,7 +196,7 @@ <div class="actions"> <button type="button" - class="ui red compact fluid button no-margin" + class="ui red compact fluid button" @click="deleteAllFeatureSelection" > Confirmer la suppression @@ -283,6 +280,36 @@ export default { }; }, + computed: { + ...mapGetters([ + 'project', 'permissions' + ]), + ...mapState('feature', [ + 'checkedFeatures' + ]), + ...mapState('feature_type', [ + 'feature_types' + ]), + ...mapState('map', [ + 'basemaps' + ]), + + API_BASE_URL() { + return this.$store.state.configuration.VUE_APP_DJANGO_API_BASE; + }, + + statusChoices() { + //* if project is not moderate, remove pending status + return this.form.status.choices.filter((el) => + this.project && this.project.moderation ? true : el.value !== 'pending' + ); + }, + + featureTypeChoices() { + return this.feature_types.map((el) => el.title); + }, + }, + watch: { 'form.type.selected'() { this.fetchPagedFeatures(); @@ -327,34 +354,21 @@ export default { } }, - computed: { - ...mapGetters([ - 'project', 'permissions' - ]), - ...mapState('feature', [ - 'checkedFeatures' - ]), - ...mapState('feature_type', [ - 'feature_types' - ]), - ...mapState('map', [ - 'basemaps' - ]), - - API_BASE_URL() { - return this.$store.state.configuration.VUE_APP_DJANGO_API_BASE; - }, - - statusChoices() { - //* if project is not moderate, remove pending status - return this.form.status.choices.filter((el) => - this.project && this.project.moderation ? true : el.value !== 'pending' - ); - }, + mounted() { + if (!this.project) { + // Chargements des features et infos projet en cas d'arrivée directe sur la page ou de refresh + this.$store + .dispatch('GET_PROJECT_INFO', this.$route.params.slug) + .then(() => this.initMap()); + } else { + this.initMap(); + } + this.fetchPagedFeatures(); + }, - featureTypeChoices() { - return this.feature_types.map((el) => el.title); - }, + destroyed() { + //* allow user to change page if ever stuck on loader + this.$store.commit('DISCARD_LOADER'); }, methods: { @@ -569,23 +583,6 @@ export default { } }, }, - - mounted() { - if (!this.project) { - // Chargements des features et infos projet en cas d'arrivée directe sur la page ou de refresh - this.$store - .dispatch('GET_PROJECT_INFO', this.$route.params.slug) - .then(() => this.initMap()); - } else { - this.initMap(); - } - this.fetchPagedFeatures(); - }, - - destroyed() { - //* allow user to change page if ever stuck on loader - this.$store.commit('DISCARD_LOADER'); - }, }; </script> @@ -622,10 +619,6 @@ export default { margin-left: 0.25em !important; } -.no-margin { - margin: 0 !important; -} - .no-padding { padding: 0 !important; } diff --git a/src/views/feature/Feature_offline.vue b/src/views/feature/Feature_offline.vue index b75ba3c57e6c0bb29acf21990ccfc65574478ca4..8bbe1718e7dff467c10f594dcf6921b1ee310d07 100644 --- a/src/views/feature/Feature_offline.vue +++ b/src/views/feature/Feature_offline.vue @@ -1,42 +1,35 @@ <template> - <div v-frag> - Erreur Réseau lors de l'envoi du signalement. Votre signalement devra être envoyé au serveur quand vous aurez de nouveau accès à internet. - Veuillez à ce moment là cliquer sur Envoyer sur la page principale du projet + <div> + <div class="margin-1"> + Erreur réseau lors de l'envoi du signalement. + </div> + <div class="margin-1"> + Votre signalement devra être envoyé au serveur quand vous aurez de nouveau accès à internet. + </div> + <div class="margin-1"> + Veuillez à ce moment là , cliquer sur le bouton "Envoyer", sur la page principale du projet + </div> <router-link :to="{ name: 'project_detail', params: { slug: $route.params.slug }, }" - class="header" + class="ui positive left labeled icon button margin-1" > - Retour au projet + <i class="arrow left icon" />Retour au projet </router-link> </div> </template> <script> -import frag from 'vue-frag'; export default { name: 'FeatureOffline', - - directives: { - frag, - }, - - data() { - return { - }; - }, - - computed: { - }, - methods: { - - } }; </script> -<style> - -</style> \ No newline at end of file +<style scoped> +.margin-1 { + margin: 1rem; +} +</style> diff --git a/src/views/feature_type/Feature_type_detail.vue b/src/views/feature_type/Feature_type_detail.vue index a0993450403e48df9b31edac02fee847553fbc17..a7852840c42478c642d1ff625117e0ce0487f969 100644 --- a/src/views/feature_type/Feature_type_detail.vue +++ b/src/views/feature_type/Feature_type_detail.vue @@ -160,13 +160,15 @@ </div> <div v-if=" - importFeatureTypeData && importFeatureTypeData.length && importFeatureTypeData.some(el => el.status === 'pending') + importFeatureTypeData && + importFeatureTypeData.length && + importFeatureTypeData.some((el) => el.status === 'pending') " class="ui message info" > <p> - Des signalements sont en cours d'import. - Pour suivre le statut de l'import, cliquez sur "Importer des Signalements". + Des signalements sont en cours d'import. Pour suivre le statut de + l'import, cliquez sur "Importer des Signalements". </p> </div> <div @@ -279,36 +281,26 @@ export default { }, showImport: false, featuresLoading: true, - loadingImportFile: false + loadingImportFile: false, }; }, computed: { - ...mapGetters([ - 'project', - 'permissions' - ]), - ...mapState('feature', [ - 'features', - 'features_count' - ]), - ...mapState('feature_type', [ - 'feature_types', - 'importFeatureTypeData' - ]), + ...mapGetters(['project', 'permissions']), + ...mapState('feature', ['features', 'features_count']), + ...mapState('feature_type', ['feature_types', 'importFeatureTypeData']), structure: function () { if (Object.keys(this.feature_types).length) { let st = this.feature_types.find( (el) => el.slug === this.$route.params.feature_type_slug ); - if (st) - return st; + if (st) return st; } return {}; }, feature_type_features: function () { - if(this.features.length) + if (this.features.length) return this.features.filter( (el) => el.feature_type.slug === this.$route.params.feature_type_slug ); @@ -330,14 +322,14 @@ export default { }, }, - watch:{ - structure(newValue){ - if (newValue.slug){ + watch: { + structure(newValue) { + if (newValue.slug) { this.GET_IMPORTS({ - feature_type: this.$route.params.feature_type_slug + feature_type: this.$route.params.feature_type_slug, }); } - } + }, }, created() { @@ -348,29 +340,19 @@ export default { this.getFeatures(); // .then(res => resolve(res)) // .catch(err => reject(err)); - this.SET_CURRENT_FEATURE_TYPE_SLUG( - this.$route.params.feature_type_slug - ); + this.SET_CURRENT_FEATURE_TYPE_SLUG(this.$route.params.feature_type_slug); }, methods: { - ...mapMutations('feature_type', [ - 'SET_CURRENT_FEATURE_TYPE_SLUG' - ]), - ...mapActions([ - 'GET_PROJECT_INFO' - ]), - ...mapActions('feature_type', [ - 'GET_IMPORTS' - ]), - ...mapActions('feature', [ - 'GET_PROJECT_FEATURES' - ]), + ...mapMutations('feature_type', ['SET_CURRENT_FEATURE_TYPE_SLUG']), + ...mapActions(['GET_PROJECT_INFO']), + ...mapActions('feature_type', ['GET_IMPORTS']), + ...mapActions('feature', ['GET_PROJECT_FEATURES']), toggleShowImport() { this.showImport = !this.showImport; if (this.showImport) { this.$store.dispatch('feature_type/GET_IMPORTS', { - feature_type: this.$route.params.feature_type_slug + feature_type: this.$route.params.feature_type_slug, }); } }, @@ -384,7 +366,7 @@ export default { return 'integer'; } else if ( type === 'string' && - ['/', ':', '-'].some(el => prop.includes(el)) && // check for chars found in datestring + ['/', ':', '-'].some((el) => prop.includes(el)) && // check for chars found in datestring date instanceof Date && !isNaN(date.valueOf()) ) { @@ -479,20 +461,19 @@ export default { } }); }, - async getFeatures(){ - const response = await - this.GET_PROJECT_FEATURES({ - project_slug: this.$route.params.slug, - feature_type__slug : this.$route.params.feature_type_slug, + async getFeatures() { + const response = await this.GET_PROJECT_FEATURES({ + project_slug: this.$route.params.slug, + feature_type__slug: this.$route.params.feature_type_slug, ordering: '-created_on', - limit: '5' + limit: '5', }); - if (response){ + if (response) { this.featuresLoading = false; } - } - } + }, + }, }; </script> diff --git a/src/views/feature_type/Feature_type_edit.vue b/src/views/feature_type/Feature_type_edit.vue index 1a7bf5d96e5e9edfeeba42f356e262bcf6c1b4fd..f2ff4364782d1732906aa4623173b35d93938600 100644 --- a/src/views/feature_type/Feature_type_edit.vue +++ b/src/views/feature_type/Feature_type_edit.vue @@ -55,10 +55,10 @@ class="errorlist" > <li - v-for="error in form.title.errors" - :key="error" + v-for="err in form.title.errors" + :key="err" > - {{ error }} + {{ err }} </li> </ul> </div> @@ -187,7 +187,16 @@ export default { FeatureTypeCustomForm, }, - props: ['geojson', 'fileToImport'], + props: { + geojson: { + type: Object, + default: null, + }, + fileToImport: { + type: File, + default: null, + } + }, data() { return { diff --git a/src/views/flatpages/Default.vue b/src/views/flatpages/Default.vue index af25966bcc332553fcd0bfcde3c68ac16f6742d2..e095712207ca4c80eed6491ed7ba3c2e3b453cf8 100644 --- a/src/views/flatpages/Default.vue +++ b/src/views/flatpages/Default.vue @@ -5,7 +5,9 @@ > <div class="ten wide column"> <h1>{{ flatpage.title }}</h1> + <!-- eslint-disable vue/no-v-html --> <div v-html="flatpage.content" /> + <!--eslint-enable--> </div> </div> </template> diff --git a/src/views/flatpages/with_right_menu.vue b/src/views/flatpages/with_right_menu.vue index 262c397498793005b1545c7f7cc5c759c5505043..46a5ff9bccf2f6e18d4fcb81c189be7da932c87c 100644 --- a/src/views/flatpages/with_right_menu.vue +++ b/src/views/flatpages/with_right_menu.vue @@ -2,8 +2,9 @@ <div class="row"> <div class="ten wide column"> <h1>{{ flatpage.title }}</h1> + <!-- eslint-disable vue/no-v-html --> <div v-html="flatpage.content" /> - + <!--eslint-enable--> <div class="ui right rail"> <div id="toc-container" diff --git a/src/views/project/Project_detail.vue b/src/views/project/Project_detail.vue index c4ff33418daefa9d0dfefef2f210d93cfc8ebd59..9d7adc2c9b831d5a09d26be337cae6bf0467dc4c 100644 --- a/src/views/project/Project_detail.vue +++ b/src/views/project/Project_detail.vue @@ -65,7 +65,9 @@ class="ui basic teal label" data-tooltip="Commentaires" > - <i class="comment icon" />{{ project.nb_published_features_comments }} + <i class="comment icon" />{{ + project.nb_published_features_comments + }} </div> </div> <div class="ten wide column"> @@ -73,7 +75,10 @@ <div class="content"> {{ project.title }} <div v-if="arraysOffline.length > 0"> - {{ arraysOffline.length }} modification<span v-if="arraysOffline.length>1">s</span> en attente + {{ arraysOffline.length }} modification<span + v-if="arraysOffline.length > 1" + >s</span> + en attente <button :disabled="isOffline()" class="ui fluid teal icon button" @@ -130,7 +135,7 @@ </h3> <div class="ui middle aligned divided list"> <div - :class="{ active : projectInfoLoading }" + :class="{ active: projectInfoLoading }" class="ui inverted dimmer" > <div class="ui text loader"> @@ -257,14 +262,14 @@ params: { slug_type_signal: type.slug }, }" class=" - ui - compact - small - icon - right - floated - button button-hover-green - " + ui + compact + small + icon + right + floated + button button-hover-green + " data-tooltip="Éditer la symbologie du type de signalement" data-position="left center" data-variation="mini" @@ -284,14 +289,14 @@ params: { slug_type_signal: type.slug }, }" class=" - ui - compact - small - icon - right - floated - button button-hover-green - " + ui + compact + small + icon + right + floated + button button-hover-green + " data-tooltip="Éditer le type de signalement" data-position="left center" data-variation="mini" @@ -377,7 +382,7 @@ </div> <div class="seven wide column"> <div - :class="{ active : mapLoading }" + :class="{ active: mapLoading }" class="ui inverted dimmer" > <div class="ui text loader"> @@ -421,7 +426,8 @@ name: 'details-signalement', params: { slug: project.slug, - slug_type_signal: item.properties.feature_type.slug, + slug_type_signal: + item.properties.feature_type.slug, slug_signal: item.id, }, }" @@ -432,13 +438,12 @@ <div class="description"> <i> [{{ item.properties.created_on }} - <span - v-if="user && item.properties.creator" - > - , par {{ - item.properties.creator.full_name ? - item.properties.creator.full_name : - item.properties.creator.username + <span v-if="user && item.properties.creator"> + , par + {{ + item.properties.creator.full_name + ? item.properties.creator.full_name + : item.properties.creator.username }} </span> ] @@ -633,8 +638,8 @@ </div> <div class="content"> <p> - Impossible de créer un type de signalement à partir d'un fichier GeoJSON - de plus de 10Mo (celui importé fait {{ fileSize }} Mo). + Impossible de créer un type de signalement à partir d'un fichier + GeoJSON de plus de 10Mo (celui importé fait {{ fileSize }} Mo). </p> </div> <div class="actions"> @@ -680,7 +685,12 @@ export default { }, }, - props: ['message'], + props: { + message: { + type: String, + default: '' + } + }, data() { return { @@ -704,25 +714,11 @@ export default { }, computed: { - ...mapGetters([ - 'project', - 'permissions' - ]), - ...mapState('feature_type', [ - 'feature_types', - 'importFeatureTypeData' - ]), - ...mapState('feature', [ - 'features' - ]), - ...mapState([ - 'last_comments', - 'user', - 'reloadIntervalId' - ]), - ...mapState('map', [ - 'map' - ]), + ...mapGetters(['project', 'permissions']), + ...mapState('feature_type', ['feature_types', 'importFeatureTypeData']), + ...mapState('feature', ['features']), + ...mapState(['last_comments', 'user', 'reloadIntervalId']), + ...mapState('map', ['map']), DJANGO_BASE_URL() { return this.$store.state.configuration.VUE_APP_DJANGO_BASE; }, @@ -731,7 +727,7 @@ export default { }, fileSize() { return fileConvertSizeToMo(this.fileToImport.size); - } + }, }, watch: { @@ -740,51 +736,55 @@ export default { handler(newValue, oldValue) { if (newValue && newValue !== oldValue) { this.GET_IMPORTS({ - project_slug: this.$route.params.slug + project_slug: this.$route.params.slug, }); } - } + }, }, importFeatureTypeData: { deep: true, handler(newValue) { - if (newValue && newValue.some(el => el.status === 'pending') && !this.reloadIntervalId) { - this.SET_RELOAD_INTERVAL_ID(setInterval(() => { - this.GET_IMPORTS({ - project_slug: this.$route.params.slug - }); - }, this.$store.state.configuration.VUE_APP_RELOAD_INTERVAL)); - } else if (newValue && !newValue.some(el => el.status === 'pending') && this.reloadIntervalId) { + if ( + newValue && + newValue.some((el) => el.status === 'pending') && + !this.reloadIntervalId + ) { + this.SET_RELOAD_INTERVAL_ID( + setInterval(() => { + this.GET_IMPORTS({ + project_slug: this.$route.params.slug, + }); + }, this.$store.state.configuration.VUE_APP_RELOAD_INTERVAL) + ); + } else if ( + newValue && + !newValue.some((el) => el.status === 'pending') && + this.reloadIntervalId + ) { this.GET_PROJECT_FEATURE_TYPES(this.project.slug); this.CLEAR_RELOAD_INTERVAL_ID(); } - } + }, }, features: { deep: true, handler(newValue, oldValue) { if (newValue && newValue.length && newValue !== oldValue) { - mapUtil.addFeatures( - this.features, - {}, - true, - this.feature_types - ); + mapUtil.addFeatures(this.features, {}, true, this.feature_types); this.mapLoading = false; } - } + }, }, featuresLoading(newValue) { if (!newValue && this.features && this.features.length === 0) { this.mapLoading = false; } - } + }, }, created() { - if (this.user) { projectAPI .getProjectSubscription({ projectSlug: this.$route.params.slug }) @@ -819,25 +819,12 @@ export default { }, methods: { - ...mapMutations([ - 'SET_RELOAD_INTERVAL_ID', - 'CLEAR_RELOAD_INTERVAL_ID' - ]), - ...mapActions([ - 'GET_PROJECT_INFO' - ]), - ...mapActions('map', [ - 'INITIATE_MAP' - ]), - ...mapActions('feature_type', [ - 'GET_IMPORTS' - ]), - ...mapActions('feature', [ - 'GET_PROJECT_FEATURES' - ]), - ...mapActions('feature_type', [ - 'GET_PROJECT_FEATURE_TYPES' - ]), + ...mapMutations(['SET_RELOAD_INTERVAL_ID', 'CLEAR_RELOAD_INTERVAL_ID']), + ...mapActions(['GET_PROJECT_INFO']), + ...mapActions('map', ['INITIATE_MAP']), + ...mapActions('feature_type', ['GET_IMPORTS']), + ...mapActions('feature', ['GET_PROJECT_FEATURES']), + ...mapActions('feature_type', ['GET_PROJECT_FEATURE_TYPES']), refreshId() { return '?ver=' + Math.random(); }, @@ -849,7 +836,9 @@ export default { }, isImporting(type) { if (this.importFeatureTypeData) { - const singleImportData = this.importFeatureTypeData.find(el => el.feature_type_title === type.slug); + const singleImportData = this.importFeatureTypeData.find( + (el) => el.feature_type_title === type.slug + ); return singleImportData && singleImportData.status === 'pending'; } return false; @@ -878,8 +867,7 @@ export default { .then((response) => { if (response.status === 201 && response.data) { return 'OK'; - } - else{ + } else { self.arraysOfflineErrors.push(feature); } }) @@ -898,8 +886,7 @@ export default { .then((response) => { if (response.status === 200 && response.data) { return 'OK'; - } - else{ + } else { self.arraysOfflineErrors.push(feature); } }) @@ -926,7 +913,9 @@ export default { (x) => x.project !== this.project.slug ); this.arraysOffline = []; - arraysOffline = arraysOfflineOtherProject.concat(this.arraysOfflineErrors); + arraysOffline = arraysOfflineOtherProject.concat( + this.arraysOfflineErrors + ); localStorage.setItem('geocontrib_offline', JSON.stringify(arraysOffline)); }, @@ -1020,7 +1009,7 @@ export default { project_slug: this.slug, ordering: '-created_on', limit: null, - geojson: true + geojson: true, }) .then(() => { this.featuresLoading = false; @@ -1030,13 +1019,11 @@ export default { this.featuresLoading = false; }); - featureAPI - .getFeaturesBbox(this.project.slug) - .then((bbox) => { - if (bbox) { - mapUtil.getMap().fitBounds(bbox, { padding: [25, 25] }); - } - }); + featureAPI.getFeaturesBbox(this.project.slug).then((bbox) => { + if (bbox) { + mapUtil.getMap().fitBounds(bbox, { padding: [25, 25] }); + } + }); } }, }, @@ -1082,7 +1069,7 @@ export default { cursor: pointer; padding-top: 1em; } -.nouveau-type-signalement > a > .ui > .label{ +.nouveau-type-signalement > a > .ui > .label { cursor: pointer; } diff --git a/src/views/project/Project_mapping.vue b/src/views/project/Project_mapping.vue index 2c2bb7c1e11562ed6142dba2cde07998a9a4befb..c8b110ab4abdf51d1fa76ed4dae60436450db7eb 100644 --- a/src/views/project/Project_mapping.vue +++ b/src/views/project/Project_mapping.vue @@ -37,7 +37,7 @@ @click="addBasemap" > <i class="ui plus icon" /> - <span>Créer un fond cartographique</span> + <span> Créer un fond cartographique</span> </a> </div> @@ -51,14 +51,15 @@ :basemap="basemap" /> </div> - - <button - type="button" - class="ui teal icon floated button" - @click="saveChanges" - > - <i class="white save icon" /> Enregistrer les changements - </button> + <div class="margin-top"> + <button + type="button" + class="ui teal icon floated button" + @click="saveChanges" + > + <i class="white save icon" /> Enregistrer les changements + </button> + </div> </form> </div> </template> diff --git a/src/views/project/Project_members.vue b/src/views/project/Project_members.vue index 1426d182cf9c65ad5743e318b2c61a219dbf6460..4683a90156c8a93c9dfdb6738a4af8861a20064f 100644 --- a/src/views/project/Project_members.vue +++ b/src/views/project/Project_members.vue @@ -13,8 +13,6 @@ > <div class="two fields"> <div class="field"> - <!-- <label :for="">{{ form.title.label }}</label> --> - <!-- <input type="text" v-model="newMember.name" /> --> <Dropdown :options="userOptions" :selected="newMember.user.name" @@ -35,7 +33,6 @@ </ul> </div> <div class="field"> - <!-- <label for="add-member"></label> --> <Dropdown :options="levelOptions" :selected="newMember.role.name" @@ -45,16 +42,15 @@ </div> <button type="button" - class="ui teal icon button" + class="ui green icon button" + :disabled="newMember.user" @click="addMember" > - <i class="white save icon" /> + <i class="white add icon" /> <span class="padding-1">Ajouter</span> </button> </div> - <!-- <input type="text" v-model="newMember.name" /> --> - <h4>Modifier le rôle d'un membre</h4> <div id="form-members" @@ -123,7 +119,7 @@ class="ui teal icon button" @click="saveMembers" > - <i class="white save icon" /> Enregistrer les changements + <i class="white save icon" /> Enregistrer les changements </button> </div> </div>