diff --git a/src/App.vue b/src/App.vue index 5c941e33ffd3add1778c4ecff63574bfde6f0394..b45820b6b21df309dee4b1368a6b29b23238866e 100644 --- a/src/App.vue +++ b/src/App.vue @@ -3,6 +3,7 @@ <AppHeader /> <div id="app-content"> + <span id="scroll-top-anchor" /> <div :class="{ active: loader.isLoading }" class="ui inverted dimmer" diff --git a/src/assets/styles/base.css b/src/assets/styles/base.css index 3cfa87e2c7436e3050524c91a631a4ea7e19aa12..7aa4d2c9f059cd18a16baea523fc0c0b9200e508 100644 --- a/src/assets/styles/base.css +++ b/src/assets/styles/base.css @@ -25,8 +25,17 @@ body { #app-content { overflow: auto; flex: 1 0 auto; /* used to fix height on sticky header and footer */ + height: 61px; /* value by default of the header, defined here to be sync with anchor below */ + position: relative; /* for anchor below */ } +#scroll-top-anchor { + position: absolute; + top: -61px; + visibility: hidden; +} + + .page-content { max-width: 1200px; padding: 0 2em; @@ -68,6 +77,9 @@ body { /* ---------------------------------- */ /* UTILS */ /* ---------------------------------- */ +.inline { + display: inline; +} .no-margin { margin: 0 !important; } diff --git a/src/components/Feature/Detail/FeatureHeader.vue b/src/components/Feature/Detail/FeatureHeader.vue index 913398f85f03872b3f4ebd2456f4742faf04d7b7..d1ab51b94908bffa2dae66f0f15f177802f1c326 100644 --- a/src/components/Feature/Detail/FeatureHeader.vue +++ b/src/components/Feature/Detail/FeatureHeader.vue @@ -2,7 +2,24 @@ <div> <h1 class="ui header"> <div class="content"> - {{ currentFeature.title || currentFeature.feature_id }} + <span + v-if="fastEditionMode && form" + class="form ui half-block" + > + <input + id="feature_detail_title_input" + :value="form.title" + type="text" + required + maxlength="128" + name="title" + @blur="updateTitle" + > + </span> + <span v-else> + {{ currentFeature.title || currentFeature.feature_id }} + </span> + <div class="ui icon right floated compact buttons"> <router-link v-if="displayToListButton" @@ -55,6 +72,20 @@ /> </button> + <button + v-if="fastEditionMode && userCanFastEdit" + id="previous-feature" + :class="['ui button button-hover-orange tiny-margin', { disabled: false }]" + data-tooltip="Enregistrer les modifications" + data-position="bottom center" + @click="$store.dispatch('feature/SEND_FEATURE', $route.name)" + > + <i + class="save fitted icon" + aria-hidden="true" + /> + </button> + <router-link v-if="permissions && permissions.can_create_feature" id="add-feature" @@ -115,7 +146,20 @@ </div> <div class="ui hidden divider" /> <div class="sub header prewrap"> - {{ currentFeature.description }} + <span + v-if="fastEditionMode && form" + class="form ui half-block" + > + <textarea + :value="form.description.value" + name="description" + rows="5" + @blur="updateDescription" + /> + </span> + <span v-else> + {{ currentFeature.description }} + </span> </div> </div> </h1> @@ -126,6 +170,7 @@ import { mapState, mapGetters } from 'vuex'; + export default { name: 'FeatureHeader', @@ -143,6 +188,10 @@ export default { type: Object, default: () => {}, }, + fastEditionMode: { + type: Boolean, + default: false, + }, displayToListButton: { type: Boolean, default: false, @@ -156,9 +205,9 @@ export default { 'isOnline', ]), ...mapState('feature', [ - 'currentFeature' + 'currentFeature', + 'form', ]), - ...mapGetters([ 'permissions', ]), @@ -174,6 +223,13 @@ export default { return this.USER_LEVEL_PROJECTS && this.USER_LEVEL_PROJECTS[this.$route.params.slug] === 'Modérateur'; }, + userCanFastEdit() { + const superiorRoles = ['contributor', 'super_contributor', 'moderator', 'admin']; + return this.USER_LEVEL_PROJECTS && + superiorRoles.includes(this.USER_LEVEL_PROJECTS[this.$route.params.slug]) || + this.user.is_superuser; + }, + queryparams() { return this.$route.query.offset >= 0 ? { previous: parseInt(this.$route.query.offset) - 1, @@ -194,6 +250,14 @@ export default { offset: this.queryparams[direction] } }); + }, + + updateTitle(e) { + this.$store.commit('feature/UPDATE_FORM_FIELD', { name: 'title', value: e.target.value }); + }, + + updateDescription(e) { + this.$store.commit('feature/UPDATE_FORM_FIELD', { name: 'description', value: e.target.value }); } } }; @@ -207,4 +271,13 @@ export default { line-height: 0; margin-right: 5px; } +.half-block { + display: inline-block; + width: 50%; +} +#feature_detail_title_input { + font-weight: bold; + font-size: 2em; + padding: .25em; +} </style> \ No newline at end of file diff --git a/src/components/Feature/Detail/FeatureTable.vue b/src/components/Feature/Detail/FeatureTable.vue index ce19426b2854da96502073c75f30a52f06c90b76..fd124755b3a821ca21da6b3eaab97b48a6e1a627 100644 --- a/src/components/Feature/Detail/FeatureTable.vue +++ b/src/components/Feature/Detail/FeatureTable.vue @@ -21,9 +21,16 @@ <strong>{{ field.label }}</strong> </td> <td> - <strong> + <strong class="ui form"> + <span + v-if="fastEditionMode && extra_forms.length > 0" + > + <FeatureExtraForm + :field="getExtraForm(field)" + /> + </span> <i - v-if="field.field_type === 'boolean'" + v-else-if="field.field_type === 'boolean'" :class="[ 'icon', field.value ? 'olive check' : 'grey times', @@ -52,7 +59,14 @@ :class="['icon', statusIcon]" aria-hidden="true" /> - {{ statusLabel }} + <FeatureEditStatusField + v-if="fastEditionMode && form" + :status="form.status.value" + class="inline" + /> + <span v-else> + {{ statusLabel }} + </span> </td> </tr> <tr> @@ -110,6 +124,8 @@ import { mapState } from 'vuex'; import FeatureTypeLink from '@/components/FeatureType/FeatureTypeLink'; +import FeatureEditStatusField from '@/components/Feature/FeatureEditStatusField'; +import FeatureExtraForm from '@/components/Feature/Edit/FeatureExtraForm'; import { statusChoices } from '@/utils'; export default { @@ -117,7 +133,9 @@ export default { name: 'FeatureTable', components: { - FeatureTypeLink + FeatureTypeLink, + FeatureEditStatusField, + FeatureExtraForm, }, filters: { @@ -133,12 +151,18 @@ export default { type: Object, default: () => {}, }, + fastEditionMode: { + type: Boolean, + default: false, + } }, computed: { ...mapState('feature', [ 'currentFeature', 'linked_features', + 'form', + 'extra_forms', ]), statusIcon() { @@ -172,6 +196,10 @@ export default { slug_signal: link.feature_to.feature_id, }, }); + }, + + getExtraForm(field) { + return this.extra_forms.find(exF => exF.label === field.label); } } diff --git a/src/components/Feature/Edit/FeatureExtraForm.vue b/src/components/Feature/Edit/FeatureExtraForm.vue index 1e10e8962e08fa0123bff2a534314e347abdd64c..c578e5c75f6642764c7c6204a8e61e0713462c49 100644 --- a/src/components/Feature/Edit/FeatureExtraForm.vue +++ b/src/components/Feature/Edit/FeatureExtraForm.vue @@ -1,8 +1,13 @@ <template> <div - v-if="field.field_type === 'char'" + v-if="field && field.field_type === 'char'" > - <label for="field.name">{{ field.label }}</label> + <label + v-if="$route.name === 'editer-signalement'" + :for="field.name" + > + {{ field.label }} + </label> <input :id="field.name" :value="field.value" @@ -13,9 +18,14 @@ </div> <div - v-else-if="field.field_type === 'list'" + v-else-if="field && field.field_type === 'list'" > - <label for="field.name">{{ field.label }}</label> + <label + v-if="$route.name === 'editer-signalement'" + :for="field.name" + > + {{ field.label }} + </label> <Dropdown :options="field.options" :selected="selected_extra_form_list" @@ -23,9 +33,14 @@ /> </div> <div - v-else-if="field.field_type === 'integer'" + v-else-if="field && field.field_type === 'integer'" > - <label for="field.name">{{ field.label }}</label> + <label + v-if="$route.name === 'editer-signalement'" + :for="field.name" + > + {{ field.label }} + </label> <div class="ui input"> <!-- //* si click sur fléche dans champ input, pas de focus, donc pas de blur, donc utilisation de @change --> <input @@ -38,7 +53,7 @@ </div> </div> <div - v-else-if="field.field_type === 'boolean'" + v-else-if="field && field.field_type === 'boolean'" > <div class="ui checkbox"> <input @@ -48,13 +63,23 @@ :name="field.name" @change="updateStore_extra_form" > - <label for="field.name">{{ field.label }}</label> + <label + v-if="$route.name === 'editer-signalement'" + :for="field.name" + > + {{ field.label }} + </label> </div> </div> <div - v-else-if="field.field_type === 'date'" + v-else-if="field && field.field_type === 'date'" > - <label for="field.name">{{ field.label }}</label> + <label + v-if="$route.name === 'editer-signalement'" + :for="field.name" + > + {{ field.label }} + </label> <input :id="field.name" :value="field.value" @@ -64,9 +89,14 @@ > </div> <div - v-else-if="field.field_type === 'decimal'" + v-else-if="field && field.field_type === 'decimal'" > - <label for="field.name">{{ field.label }}</label> + <label + v-if="$route.name === 'editer-signalement'" + :for="field.name" + > + {{ field.label }} + </label> <div class="ui input"> <input :id="field.name" @@ -79,9 +109,14 @@ </div> </div> <div - v-else-if="field.field_type === 'text'" + v-else-if="field && field.field_type === 'text'" > - <label :for="field.name">{{ field.label }}</label> + <label + v-if="$route.name === 'editer-signalement'" + :for="field.name" + > + {{ field.label }} + </label> <textarea :value="field.value" :name="field.name" diff --git a/src/components/Feature/FeatureEditStatusField.vue b/src/components/Feature/FeatureEditStatusField.vue new file mode 100644 index 0000000000000000000000000000000000000000..19661d365b4baf2ff404f4d9707aa18448e216f8 --- /dev/null +++ b/src/components/Feature/FeatureEditStatusField.vue @@ -0,0 +1,68 @@ +<template> + <div class="field"> + <Dropdown + v-if="selectedStatus" + :options="allowedStatusChoices" + :selected="selectedStatus.name" + :selection.sync="selectedStatus" + /> + </div> +</template> + +<script> +import Dropdown from '@/components/Dropdown.vue'; +import { statusChoices, allowedStatus2change } from '@/utils'; +import { mapState } from 'vuex'; + + +export default { + name: 'FeatureEditStatusField', + + components: { + Dropdown, + }, + + props: { + status: { + type: String, + default: '', + }, + }, + + computed: { + ...mapState([ + 'user', + 'USER_LEVEL_PROJECTS', + ]), + ...mapState('projects', [ + 'project' + ]), + ...mapState('feature', [ + 'currentFeature' + ]), + statusObject() { + return statusChoices.find((key) => key.value === this.status); + }, + + selectedStatus: { + get() { + return this.statusObject; + + }, + set(newValue) { + this.$store.commit('feature/UPDATE_FORM_FIELD', { name: 'status', value: newValue.value }); + }, + }, + + allowedStatusChoices() { + if (this.project && this.currentFeature && this.user) { + const isModerate = this.project.moderation; + const userStatus = this.USER_LEVEL_PROJECTS[this.project.slug]; + const isOwnFeature = this.currentFeature.creator === this.user.id; //* si le contributeur est l'auteur du signalement + return allowedStatus2change(this.user, isModerate, userStatus, isOwnFeature, /* this.currentRouteName */); + } + return []; + }, + }, +}; +</script> \ No newline at end of file diff --git a/src/components/Project/Detail/ProjectHeader.vue b/src/components/Project/Detail/ProjectHeader.vue index 35d1871095f4b433b15415a0a40d81292cd37f68..610e46a06da6166f87938f102fec0172b3b5093c 100644 --- a/src/components/Project/Detail/ProjectHeader.vue +++ b/src/components/Project/Detail/ProjectHeader.vue @@ -67,7 +67,7 @@ id="subscribe-button" class="ui button button-hover-green tiny-margin" data-tooltip="S'abonner au projet" - data-position="top center" + data-position="bottom center" data-variation="mini" @click="OPEN_PROJECT_MODAL('subscribe')" > @@ -85,7 +85,7 @@ :to="{ name: 'project_edit', params: { slug } }" class="ui button button-hover-orange tiny-margin" data-tooltip="Modifier le projet" - data-position="top center" + data-position="bottom center" data-variation="mini" > <i @@ -98,7 +98,7 @@ id="delete-button" class="ui button button-hover-red tiny-margin" data-tooltip="Supprimer le projet" - data-position="top center" + data-position="bottom right" data-variation="mini" @click="OPEN_PROJECT_MODAL('deleteProject')" > diff --git a/src/store/index.js b/src/store/index.js index 6def4d63334533a704be681ce0cde6ed4a144582..f5ed15a226fbf68d621784197be62e48aa7c1968 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -76,8 +76,8 @@ export default new Vuex.Store({ }, DISPLAY_MESSAGE(state, message) { state.messages = [message, ...state.messages]; - if (document.getElementById('app-content')) { - document.getElementById('app-content').scrollIntoView({ block: 'start', inline: 'nearest' }); + if (document.getElementById('scroll-top-anchor')) { + document.getElementById('scroll-top-anchor').scrollIntoView({ block: 'start', inline: 'nearest' }); } setTimeout(() => { state.messages = []; diff --git a/src/store/modules/feature.store.js b/src/store/modules/feature.store.js index 5d7858136b77be43e1d4362d4bd887a924ea6fb8..ef93083a8691c11c3de37a5dbd79082f3058b67f 100644 --- a/src/store/modules/feature.store.js +++ b/src/store/modules/feature.store.js @@ -8,7 +8,7 @@ const feature = { attachmentsToDelete: [], checkedFeatures: [], clickedFeatures: [], - extra_form: [], + extra_forms: [], features: [], features_count: 0, currentFeature: null, @@ -32,17 +32,31 @@ const feature = { UPDATE_FORM(state, payload) { state.form = payload; }, + INIT_FORM(state) { + state.form = { + title: state.currentFeature.title, + description: { value: state.currentFeature.description }, + status: { value: state.currentFeature.status }, + }; + }, + UPDATE_FORM_FIELD(state, field) { + if (state.form[field.name].value !== undefined) { + state.form[field.name].value = field.value; + } else { + state.form[field.name] = field.value; + } + }, UPDATE_EXTRA_FORM(state, extra_form) { - const index = state.extra_form.findIndex(el => el.label === extra_form.label); + const index = state.extra_forms.findIndex(el => el.label === extra_form.label); if (index !== -1) { - state.extra_form[index] = extra_form; + state.extra_forms[index] = extra_form; } }, - SET_EXTRA_FORM(state, extra_form) { - state.extra_form = extra_form; + SET_EXTRA_FORMS(state, extra_forms) { + state.extra_forms = extra_forms; }, CLEAR_EXTRA_FORM(state) { - state.extra_form = []; + state.extra_forms = []; }, ADD_ATTACHMENT_FORM(state, attachmentFormset) { state.attachmentFormset = [...state.attachmentFormset, attachmentFormset]; @@ -176,25 +190,34 @@ const feature = { }); }, - SEND_FEATURE({ state, rootState, dispatch }, routeName) { + SEND_FEATURE({ state, rootState, commit, dispatch }, routeName) { function redirect(featureId) { + commit( + 'DISPLAY_MESSAGE', + { + comment: routeName === 'ajouter-signalement' ? + 'Le signalement a été crée' : + 'Le signalement a été mis à jour', + level: 'positive' + }, + { root: true }, + ); dispatch( 'GET_PROJECT_FEATURE', { project_slug: rootState.projects.project.slug, feature_id: featureId - } - ) + }) .then(() => { + if (routeName.includes('details-signalement')) return; router.push({ name: 'details-signalement', params: { slug_type_signal: rootState['feature-type'].current_feature_type_slug, slug_signal: featureId, - message: routeName === 'editer-signalement' ? 'Le signalement a été mis à jour' : 'Le signalement a été crée' + message: routeName === 'ajouter-signalement' ? 'Le signalement a été crée' : 'Le signalement a été mis à jour' }, }); - dispatch('projects/GET_ALL_PROJECTS', null, { root:true }); //* & refresh project list }); } @@ -206,13 +229,15 @@ const feature = { function createGeojson() { //* prepare feature data to send const extraFormObject = {}; //* prepare an object to be flatten in properties of geojson - for (const field of state.extra_form) { + for (const field of state.extra_forms) { extraFormObject[field.name] = field.value; } + //const feature = state.form || state.currentFeature; return { - id: state.form.feature_id, + id: state.form.feature_id || state.currentFeature.feature_id, type: 'Feature', - geometry: state.form.geometry, + geometry: state.form.geometry || state.form.geom || + state.currentFeature.geometry || state.currentFeature.geom, properties: { title: state.form.title, description: state.form.description.value, @@ -226,8 +251,8 @@ const feature = { const geojson = createGeojson(); let url = `${rootState.configuration.VUE_APP_DJANGO_API_BASE}features/`; - if (routeName === 'editer-signalement') { - url += `${state.form.feature_id}/? + if (routeName !== 'ajouter-signalement') { + url += `${geojson.id}/? feature_type__slug=${rootState['feature-type'].current_feature_type_slug} &project__slug=${rootState.projects.project.slug}`; } @@ -237,7 +262,7 @@ const feature = { //* which could create regression return axios({ url, - method: routeName === 'editer-signalement' ? 'PUT' : 'POST', + method: routeName === 'ajouter-signalement' ? 'POST' : 'PUT', data: geojson }).then((response) => { if ((response.status === 200 || response.status === 201) && response.data) { @@ -259,8 +284,8 @@ const feature = { } const updateMsg = { project: rootState.projects.project.slug, - type: routeName === 'editer-signalement' ? 'put' : 'post', - featureId: state.form.feature_id, + type: routeName === 'ajouter-signalement' ? 'post' : 'put', + featureId: geojson.id, geojson: geojson }; arraysOffline.push(updateMsg); @@ -385,6 +410,26 @@ const feature = { return false; }); }, + + INIT_EXTRA_FORMS({ state, rootGetters, commit }) { + const feature = state.currentFeature; + function findCurrentValue(label) { + const field = feature.feature_data.find((el) => el.label === label); + return field ? field.value : null; + } + //* retrieve 'name', 'options', 'position' from current feature_type data to display in the form + const extraForm = rootGetters['feature-type/feature_type'].customfield_set.map((field) => { + return { + ...field, + //* add value field to extra forms from feature_type and existing values if feature is defined + value: + feature && feature.feature_data + ? findCurrentValue(field.label) + : null, + }; + }); + commit('SET_EXTRA_FORMS', extraForm); + }, }, }; diff --git a/src/store/modules/projects.store.js b/src/store/modules/projects.store.js index 969f79b2cb8c7cb0930dc5abf814379aca2f58e7..cfb9b6c3aa023b0bb9e5fbee1502c61c8bc50cde 100644 --- a/src/store/modules/projects.store.js +++ b/src/store/modules/projects.store.js @@ -66,19 +66,6 @@ const projectsStore = { }, actions: { - async GET_ALL_PROJECTS({ rootState, commit }) { - try { - const response = await axios - .get(`${rootState.configuration.VUE_APP_DJANGO_API_BASE}projects/`); - if (response.status === 200 && response.data) { - commit('SET_PROJECTS', response.data); - } - } catch (error) { - console.error(error); - throw error; - } - }, - async GET_PROJECTS({ state, rootState, commit }, payload) { let { page, myaccount, projectSlug } = payload || {}; if (!page) { diff --git a/src/views/Feature/FeatureDetail.vue b/src/views/Feature/FeatureDetail.vue index 58af63ea9cda720616136a8c8d354320f8e512de..487de4032e5b3e397940fd6a525c1a94edcea06a 100644 --- a/src/views/Feature/FeatureDetail.vue +++ b/src/views/Feature/FeatureDetail.vue @@ -7,9 +7,11 @@ <div class="row"> <div class="sixteen wide column"> <FeatureHeader + v-if="project" :features-count="featuresCount" :slug-signal="slugSignal" :feature-type="featureType" + :fast-edition-mode="project.fast_edition_mode" :display-to-list-button="displayToListButton" @setIsCancelling="isCanceling = true" @tofeature="pushNgo" @@ -19,7 +21,9 @@ <div class="row"> <div class="eight wide column"> <FeatureTable + v-if="project" :feature-type="featureType" + :fast-edition-mode="project.fast_edition_mode" @tofeature="pushNgo" /> </div> @@ -131,16 +135,20 @@ export default { next(); // continue page loading }, + beforeRouteUpdate (to, from, next) { + let leaving = true; // by default navigate to next route + if (this.hasUnsavedChange) { + leaving = this.confirmLeave(); // prompt user that there is unsaved changes or that features order might change + } + next(leaving); + }, + beforeRouteLeave (to, from, next) { - if (// In case of filtered listed featuers, if the user wants to edit a feature, - from.query.offset >= 0 && - to.name === 'editer-signalement' && - !this.confirmLeave() // warn the user that features order might change - ){ - next(false); - } else {// Navigate to next view - next(); + let leaving = true; // by default navigate to next route + if (this.hasUnsavedChange || (from.query.offset >= 0 && to.name === 'editer-signalement')) { + leaving = this.confirmLeave(); // prompt user that there is unsaved changes or that features order might change } + next(leaving); }, data() { @@ -177,8 +185,20 @@ export default { 'feature_type', ]), ...mapState('feature', [ - 'currentFeature' + 'currentFeature', + 'form', ]), + + hasUnsavedChange() { + if (this.form.title !== this.currentFeature.title) return true; + if (this.form.description.value !== this.currentFeature.description) return true; + if (this.form.status.value !== this.currentFeature.status) return true; + for (const xForm of this.$store.state.feature.extra_forms) { + const originalField = this.currentFeature.feature_data.find(el => el.label === xForm.label); + if (originalField && xForm.value !== originalField.value) return true; + } + return false; + } }, watch: { @@ -189,12 +209,6 @@ export default { }, }, - created() { - if (this.$route.params.slug_type_signal) { - this.SET_CURRENT_FEATURE_TYPE_SLUG(this.$route.params.slug_type_signal); - } - }, - mounted() { this.initPage(); // when this is available, set the value with previously stored value in windows to pass it as a prop @@ -231,7 +245,8 @@ export default { }, async getPageInfo() { - if (this.$route.params.slug_signal) { // if coming from the route with an id + if (this.$route.params.slug_signal && this.$route.params.slug_type_signal) { // if coming from the route with an id + this.SET_CURRENT_FEATURE_TYPE_SLUG(this.$route.params.slug_type_signal); this.slugSignal = this.$route.params.slug_signal; this.featureType = this.feature_type; } //* else it would be retrieve after fetchFilteredFeature with offset @@ -260,19 +275,32 @@ export default { this.getFeatureAttachments(); this.getLinkedFeatures(); this.DISCARD_LOADER(); + if (this.project.fast_edition_mode) { + this.$store.commit('feature/INIT_FORM'); + this.$store.dispatch('feature/INIT_EXTRA_FORMS'); + } }, confirmLeave() { - return window.confirm('Vous allez quittez la vue signalement filtré, l\'ordre des signalements pourrait changer après édition d\'un signalement.'); + return window.confirm(this.project.fast_edition_mode && this.hasUnsavedChange ? + 'Les modifications apportées au signalement ne seront pas sauvegardées, continuer ?': + 'Vous allez quittez la vue signalement filtré, l\'ordre des signalements pourrait changer après édition d\'un signalement.'); }, - async pushNgo(newEntry) { - this.$router.push(newEntry); //* update the params or queries in the route/url + async reloadPage() { await this.getPageInfo(); mapService.removeFeatures(); this.addFeatureToMap(); }, + pushNgo(newEntry) { + this.$router.push(newEntry) //* update the params or queries in the route/url + .then(() => { + this.reloadPage(); + }) + .catch(() => true); //* catch error if navigation get aborted (in beforeRouteUpdate) + }, + goBackToProject(message) { this.$router.push({ name: 'project_detail', @@ -309,6 +337,7 @@ export default { const { feature_id, feature_type } = data.results[0]; this.slugSignal = feature_id; this.featureType = feature_type; + this.SET_CURRENT_FEATURE_TYPE_SLUG(feature_type.slug); return { feature_id }; } return; diff --git a/src/views/Feature/FeatureEdit.vue b/src/views/Feature/FeatureEdit.vue index 992e012f76928dbad713a13f6e8002dfd4302009..ce39380330ef83d5ac10aa38060f513bc8308e56 100644 --- a/src/views/Feature/FeatureEdit.vue +++ b/src/views/Feature/FeatureEdit.vue @@ -438,7 +438,7 @@ export default { 'attachmentFormset', 'linkedFormset', 'features', - 'extra_form', + 'extra_forms', ]), ...mapState('feature-type', [ 'feature_types' @@ -469,7 +469,7 @@ export default { }, orderedCustomFields() { - return [...this.extra_form].sort((a, b) => a.position - b.position); + return [...this.extra_forms].sort((a, b) => a.position - b.position); }, geoRefFileLabel() { @@ -545,7 +545,7 @@ export default { this.initForm(); this.initMap(); this.onFeatureTypeLoaded(); - this.initExtraForms(this.feature); + this.$store.dispatch('feature/INIT_EXTRA_FORMS'); }); }, @@ -666,24 +666,6 @@ export default { }); }, - initExtraForms(feature) { - function findCurrentValue(label) { - const field = feature.feature_data.find((el) => el.label === label); - return field ? field.value : null; - } - const extraForm = this.feature_type.customfield_set.map((field) => { - return { - ...field, - //* add value field to extra forms from feature_type and existing values if feature is defined - value: - feature && feature.feature_data - ? findCurrentValue(field.label) - : null, - }; - }); - this.$store.commit('feature/SET_EXTRA_FORM', extraForm); - }, - add_attachement_formset() { this.$store.commit('feature/ADD_ATTACHMENT_FORM', { dataKey: this.attachmentDataKey, diff --git a/src/views/Project/ProjectDetail.vue b/src/views/Project/ProjectDetail.vue index 3fb599f496fa5f14b6870f90a7ab4034d6b8fc43..a08a02dd24f6a9fc5c41fdae3eade999eef91723 100644 --- a/src/views/Project/ProjectDetail.vue +++ b/src/views/Project/ProjectDetail.vue @@ -21,28 +21,6 @@ </p> </div> </div> - <div - v-if="infoMessage" - id="message_info" - class="fullwidth" - > - <div - class="ui info message" - style="text-align: left" - > - <div class="header"> - <i - class="info circle icon" - aria-hidden="true" - /> Informations - </div> - <ul class="list"> - {{ - infoMessage - }} - </ul> - </div> - </div> <ProjectHeader :arrays-offline="arraysOffline" @@ -363,13 +341,14 @@ export default { this.is_suscriber = data.is_suscriber; this.CLOSE_PROJECT_MODAL(); if (this.is_suscriber) { - this.infoMessage = - 'Vous êtes maintenant abonné aux notifications de ce projet.'; + this.DISPLAY_MESSAGE({ + comment: 'Vous êtes maintenant abonné aux notifications de ce projet.', level: 'positive' + }); } else { - this.infoMessage = - 'Vous ne recevrez plus les notifications de ce projet.'; + this.DISPLAY_MESSAGE({ + comment: 'Vous ne recevrez plus les notifications de ce projet.', level: 'negative' + }); } - setTimeout(() => (this.infoMessage = ''), 3000); }); }, diff --git a/src/views/Project/ProjectEdit.vue b/src/views/Project/ProjectEdit.vue index 630eecd73383fa5995384a8593358f4e51258f66..9a6de25196772b62b9d9f30eb3fea53d3fc7eb72 100644 --- a/src/views/Project/ProjectEdit.vue +++ b/src/views/Project/ProjectEdit.vue @@ -195,6 +195,19 @@ </div> </div> + <div class="field"> + <div class="ui checkbox"> + <input + id="fast_edition_mode" + v-model="form.fast_edition_mode" + class="hidden" + type="checkbox" + name="fast_edition_mode" + > + <label for="fast_edition_mode">Mode d'édition rapide de signalements</label> + </div> + </div> + <div class="ui divider" /> <button @@ -216,7 +229,7 @@ import axios from '@/axios-client.js'; import Dropdown from '@/components/Dropdown.vue'; -import { mapState, mapActions } from 'vuex'; +import { mapState } from 'vuex'; export default { name: 'ProjectEdit', @@ -261,6 +274,7 @@ export default { nb_contributors: 0, is_project_type: false, generate_share_link: false, + fast_edition_mode: false, }, thumbnailFileSrc: '', }; @@ -338,9 +352,6 @@ export default { }, methods: { - ...mapActions('projects', [ - 'GET_ALL_PROJECTS' - ]), definePageType() { if (this.$router.history.current.name === 'project_create') { this.action = 'create'; @@ -431,7 +442,6 @@ export default { Promise.all([ this.$store.dispatch('GET_USER_LEVEL_PROJECTS'), //* refresh projects user levels this.$store.dispatch('GET_USER_LEVEL_PERMISSIONS'), //* refresh projects permissions - this.GET_ALL_PROJECTS(), //* & refresh project list ]).then(() => // * go back to project list this.$router.push({ @@ -512,6 +522,7 @@ export default { delete_feature: this.form.delete_feature, is_project_type: this.form.is_project_type, generate_share_link: this.form.generate_share_link, + fast_edition_mode: this.form.fast_edition_mode, moderation: this.form.moderation, }; let url = `${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}projects/`;