diff --git a/src/views/feature/Feature_detail.vue b/src/views/feature/Feature_detail.vue index 338dbdf228b818fe3f56ff7c389a3e1a566d2aae..b7a2ebf8ebe37cc4d7c23602c6fd96a6ce3d82ba 100644 --- a/src/views/feature/Feature_detail.vue +++ b/src/views/feature/Feature_detail.vue @@ -1,257 +1,231 @@ <template> <div v-frag> - <div - v-if="feature" - v-frag - > - <div class="row"> - <div class="fourteen wide column"> - <h1 class="ui header"> - <div class="content"> - {{ feature.title || feature.feature_id }} - <div class="ui icon right floated compact buttons"> - <router-link - v-if="permissions && permissions.can_create_feature" - :to="{ - name: 'ajouter-signalement', - params: { - slug_type_signal: $route.params.slug_type_signal, - }, - }" - class="ui button button-hover-orange" - data-tooltip="Ajouter un signalement" - data-position="bottom left" - > - <i class="plus fitted icon" /> - </router-link> - <router-link - v-if=" - (permissions && permissions.can_update_feature) || - isFeatureCreator || - isModerator - " - :to="{ - name: 'editer-signalement', - params: { - slug_signal: $route.params.slug_signal, - slug_type_signal: $route.params.slug_type_signal, - }, - }" - class="ui button button-hover-orange" - > - <i class="inverted grey pencil alternate icon" /> - </router-link> - <a - v-if="((permissions && permissions.can_update_feature) || isFeatureCreator) && isOnline" - id="feature-delete" - class="ui button button-hover-red" - @click="isCanceling = true" - > - <i class="inverted grey trash alternate icon" /> - </a> - </div> - <div class="ui hidden divider" /> - <div class="sub header prewrap"> - {{ feature.description }} - </div> + <div class="row"> + <div class="fourteen wide column"> + <h1 class="ui header"> + <div + v-if="feature" + class="content" + > + {{ feature.title || feature.feature_id }} + <div class="ui icon right floated compact buttons"> + <router-link + v-if="permissions && permissions.can_create_feature" + :to="{ + name: 'ajouter-signalement', + params: { + slug_type_signal: $route.params.slug_type_signal, + }, + }" + class="ui button button-hover-orange" + data-tooltip="Ajouter un signalement" + data-position="bottom left" + > + <i class="plus fitted icon" /> + </router-link> + <router-link + v-if=" + (permissions && permissions.can_update_feature) || + isFeatureCreator || + isModerator + " + :to="{ + name: 'editer-signalement', + params: { + slug_signal: $route.params.slug_signal, + slug_type_signal: $route.params.slug_type_signal, + }, + }" + class="ui button button-hover-orange" + > + <i class="inverted grey pencil alternate icon" /> + </router-link> + <a + v-if="((permissions && permissions.can_update_feature) || isFeatureCreator) && isOnline" + id="feature-delete" + class="ui button button-hover-red" + @click="isCanceling = true" + > + <i class="inverted grey trash alternate icon" /> + </a> </div> - </h1> - </div> + <div class="ui hidden divider" /> + <div class="sub header prewrap"> + {{ feature.description }} + </div> + </div> + </h1> </div> + </div> - <div class="row"> - <div class="seven wide column"> - <table class="ui very basic table"> - <tbody> - <div - v-for="(field, index) in feature.feature_data" - :key="'field' + index" - v-frag - > - <tr v-if="field"> - <td> - <b>{{ field.label }}</b> - </td> - <td> - <b> - <i - v-if="field.field_type === 'boolean'" - :class="[ - 'icon', - field.value ? 'olive check' : 'grey times', - ]" - /> - <span v-else> - {{ field.value }} - </span> - </b> - </td> - </tr> - </div> - <tr> - <td>Auteur</td> - <td>{{ feature.display_creator }}</td> - </tr> - <tr> - <td>Statut</td> + <div class="row"> + <div class="seven wide column"> + <table + v-if="feature" + class="ui very basic table" + > + <tbody> + <div + v-for="(field, index) in feature.feature_data" + :key="'field' + index" + v-frag + > + <tr v-if="field"> <td> - <i - v-if="feature.status" - :class="['icon', statusIcon]" - /> - {{ statusLabel }} - </td> - </tr> - <tr> - <td>Date de création</td> - <td v-if="feature.created_on"> - {{ feature.created_on | formatDate }} - </td> - </tr> - <tr> - <td>Date de dernière modification</td> - <td v-if="feature.updated_on"> - {{ feature.updated_on | formatDate }} + <b>{{ field.label }}</b> </td> - </tr> - </tbody> - </table> - - <h3>Liaison entre signalements</h3> - <table class="ui very basic table"> - <tbody> - <tr - v-for="(link, index) in linked_features" - :key="link.feature_to.title + index" - > - <td v-if="link.feature_to.feature_type_slug"> - {{ link.relation_type_display }} - <a @click="pushNgo(link)">{{ link.feature_to.title }} </a> - ({{ link.feature_to.display_creator }} - - {{ link.feature_to.created_on }}) + <td> + <b> + <i + v-if="field.field_type === 'boolean'" + :class="[ + 'icon', + field.value ? 'olive check' : 'grey times', + ]" + /> + <span v-else> + {{ field.value }} + </span> + </b> </td> </tr> - </tbody> - </table> - </div> + </div> + <tr> + <td>Auteur</td> + <td>{{ feature.display_creator }}</td> + </tr> + <tr> + <td>Statut</td> + <td> + <i + v-if="feature.status" + :class="['icon', statusIcon]" + /> + {{ statusLabel }} + </td> + </tr> + <tr> + <td>Date de création</td> + <td v-if="feature.created_on"> + {{ feature.created_on | formatDate }} + </td> + </tr> + <tr> + <td>Date de dernière modification</td> + <td v-if="feature.updated_on"> + {{ feature.updated_on | formatDate }} + </td> + </tr> + </tbody> + </table> + + <h3>Liaison entre signalements</h3> + <table class="ui very basic table"> + <tbody> + <tr + v-for="(link, index) in linked_features" + :key="link.feature_to.title + index" + > + <td v-if="link.feature_to.feature_type_slug"> + {{ link.relation_type_display }} + <a + class="pointer" + @click="pushNgo(link)" + >{{ link.feature_to.title }} </a> + ({{ link.feature_to.display_creator }} - + {{ link.feature_to.created_on }}) + </td> + </tr> + </tbody> + </table> + </div> - <div class="seven wide column"> - <div - id="map" - ref="map" - /> - </div> + <div class="seven wide column"> + <div + id="map" + ref="map" + /> </div> + </div> - <div class="row"> - <div class="seven wide column"> - <h2 class="ui header"> - Pièces jointes - </h2> + <div class="row"> + <div class="seven wide column"> + <h2 class="ui header"> + Pièces jointes + </h2> - <div - v-for="pj in attachments" - :key="pj.id" - class="ui divided items" - > - <div class="item"> + <div + v-for="pj in attachments" + :key="pj.id" + class="ui divided items" + > + <div class="item"> + <a + class="ui tiny image" + target="_blank" + :href="pj.attachment_file" + > + <img + :src=" + pj.extension === '.pdf' + ? require('@/assets/img/pdf.png') + : pj.attachment_file + " + > + </a> + <div class="middle aligned content"> <a - class="ui tiny image" + class="header" target="_blank" :href="pj.attachment_file" - > - <img - :src=" - pj.extension === '.pdf' - ? require('@/assets/img/pdf.png') - : pj.attachment_file - " - > - </a> - <div class="middle aligned content"> - <a - class="header" - target="_blank" - :href="pj.attachment_file" - >{{ - pj.title - }}</a> - <div class="description"> - {{ pj.info }} - </div> + >{{ + pj.title + }}</a> + <div class="description"> + {{ pj.info }} </div> </div> </div> - <i - v-if="attachments.length === 0" - >Aucune pièce jointe associée au signalement.</i> </div> + <i + v-if="attachments.length === 0" + >Aucune pièce jointe associée au signalement.</i> + </div> - <div class="seven wide column"> - <h2 class="ui header"> - Activité et commentaires - </h2> + <div class="seven wide column"> + <h2 class="ui header"> + Activité et commentaires + </h2> + <div + id="feed-event" + class="ui feed" + > <div - id="feed-event" - class="ui feed" + v-for="(event, index) in events" + :key="'event' + index" + v-frag > <div - v-for="(event, index) in events" - :key="'event' + index" + v-if="event.event_type === 'create'" v-frag > <div - v-if="event.event_type === 'create'" - v-frag + v-if="event.object_type === 'feature'" + class="event" > - <div - v-if="event.object_type === 'feature'" - class="event" - > - <div class="content"> - <div class="summary"> - <div class="date"> - {{ event.created_on }} - </div> - Création du signalement - <span v-if="user">par {{ event.display_user }}</span> - </div> - </div> - </div> - <div - v-else-if="event.object_type === 'comment'" - class="event" - > - <div class="content"> - <div class="summary"> - <div class="date"> - {{ event.created_on }} - </div> - Commentaire - <span v-if="user">par {{ event.display_user }}</span> - </div> - <div class="extra text"> - {{ event.related_comment.comment }} - <div - v-if="event.related_comment.attachment" - v-frag - > - <br><a - :href=" - DJANGO_BASE_URL + - event.related_comment.attachment.url - " - target="_blank" - ><i class="paperclip fitted icon" /> - {{ event.related_comment.attachment.title }}</a> - </div> + <div class="content"> + <div class="summary"> + <div class="date"> + {{ event.created_on }} </div> + Création du signalement + <span v-if="user">par {{ event.display_user }}</span> </div> </div> </div> <div - v-else-if="event.event_type === 'update'" + v-else-if="event.object_type === 'comment'" class="event" > <div class="content"> @@ -259,127 +233,156 @@ <div class="date"> {{ event.created_on }} </div> - Signalement mis à jour + Commentaire <span v-if="user">par {{ event.display_user }}</span> </div> + <div class="extra text"> + {{ event.related_comment.comment }} + <div + v-if="event.related_comment.attachment" + v-frag + > + <br><a + :href=" + DJANGO_BASE_URL + + event.related_comment.attachment.url + " + target="_blank" + ><i class="paperclip fitted icon" /> + {{ event.related_comment.attachment.title }}</a> + </div> + </div> </div> </div> </div> - </div> - - <div - v-if="permissions && permissions.can_create_feature && isOnline" - class="ui segment" - > - <form - id="form-comment" - class="ui form" + <div + v-else-if="event.event_type === 'update'" + class="event" > - <div class="required field"> - <label - :for="comment_form.comment.id_for_label" - >Ajouter un commentaire</label> - <ul - v-if="comment_form.comment.errors" - class="errorlist" - > - <li> - {{ comment_form.comment.errors }} - </li> - </ul> - <textarea - v-model="comment_form.comment.value" - :name="comment_form.comment.html_name" - rows="2" - /> - </div> - <label>Pièce jointe (facultative)</label> - <div class="two fields"> - <div class="field"> - <label - class="ui icon button" - for="attachment_file" - > - <i class="paperclip icon" /> - <span class="label">{{ - comment_form.attachment_file.value - ? comment_form.attachment_file.value - : "Sélectionner un fichier ..." - }}</span> - </label> - <input - id="attachment_file" - type="file" - accept="application/pdf, image/jpeg, image/png" - style="display: none" - name="attachment_file" - @change="onFileChange" - > - </div> - <div class="field"> - <input - id="title" - v-model="comment_form.attachment_file.title" - type="text" - name="title" - > - {{ comment_form.attachment_file.errors }} + <div class="content"> + <div class="summary"> + <div class="date"> + {{ event.created_on }} + </div> + Signalement mis à jour + <span v-if="user">par {{ event.display_user }}</span> </div> </div> + </div> + </div> + </div> + + <div + v-if="permissions && permissions.can_create_feature && isOnline" + class="ui segment" + > + <form + id="form-comment" + class="ui form" + > + <div class="required field"> + <label + :for="comment_form.comment.id_for_label" + >Ajouter un commentaire</label> <ul - v-if="comment_form.attachment_file.errors" + v-if="comment_form.comment.errors" class="errorlist" > <li> - {{ comment_form.attachment_file.errors }} + {{ comment_form.comment.errors }} </li> </ul> - <button - type="button" - class="ui compact green icon button" - @click="postComment" - > - <i class="plus icon" /> Poster le commentaire - </button> - </form> - </div> + <textarea + v-model="comment_form.comment.value" + :name="comment_form.comment.html_name" + rows="2" + /> + </div> + <label>Pièce jointe (facultative)</label> + <div class="two fields"> + <div class="field"> + <label + class="ui icon button" + for="attachment_file" + > + <i class="paperclip icon" /> + <span class="label">{{ + comment_form.attachment_file.value + ? comment_form.attachment_file.value + : "Sélectionner un fichier ..." + }}</span> + </label> + <input + id="attachment_file" + type="file" + accept="application/pdf, image/jpeg, image/png" + style="display: none" + name="attachment_file" + @change="onFileChange" + > + </div> + <div class="field"> + <input + id="title" + v-model="comment_form.attachment_file.title" + type="text" + name="title" + > + {{ comment_form.attachment_file.errors }} + </div> + </div> + <ul + v-if="comment_form.attachment_file.errors" + class="errorlist" + > + <li> + {{ comment_form.attachment_file.errors }} + </li> + </ul> + <button + type="button" + class="ui compact green icon button" + @click="postComment" + > + <i class="plus icon" /> Poster le commentaire + </button> + </form> </div> </div> + </div> + <div + v-if="isCanceling" + class="ui dimmer modals page transition visible active" + style="display: flex !important" + > <div - v-if="isCanceling" - class="ui dimmer modals page transition visible active" - style="display: flex !important" + :class="[ + 'ui mini modal subscription', + { 'active visible': isCanceling }, + ]" > - <div - :class="[ - 'ui mini modal subscription', - { 'active visible': isCanceling }, - ]" - > - <i - class="close icon" - @click="isCanceling = false" - /> - <div class="ui icon header"> - <i class="trash alternate icon" /> - Supprimer le signalement - </div> - <div class="actions"> - <button - type="button" - class="ui red compact fluid button" - @click="deleteFeature" - > - Confirmer la suppression - </button> - </div> + <i + class="close icon" + @click="isCanceling = false" + /> + <div class="ui icon header"> + <i class="trash alternate icon" /> + Supprimer le signalement + </div> + <div class="actions"> + <button + type="button" + class="ui red compact fluid button" + @click="deleteFeature" + > + Confirmer la suppression + </button> </div> </div> </div> <div - v-else - v-frag + v-if="!feature" > Pas de signalement correspondant trouvé </div> @@ -388,7 +391,7 @@ <script> import frag from 'vue-frag'; -import { mapGetters, mapState, mapActions } from 'vuex'; +import { mapGetters, mapState, mapActions, mapMutations } from 'vuex'; import { mapUtil } from '@/assets/js/map-util.js'; import featureAPI from '@/services/feature-api'; import axios from '@/axios-client.js'; @@ -442,19 +445,15 @@ export default { ...mapGetters([ 'permissions', ]), - ...mapState('feature', [ - 'linked_features', - 'statusChoices' - ]), + ...mapState('feature', { + linked_features: 'linked_features', + statusChoices: 'statusChoices', + feature: 'current_feature', + }), DJANGO_BASE_URL() { return this.$store.state.configuration.VUE_APP_DJANGO_BASE; }, - feature() { - const result = this.$store.state.feature.current_feature; - return result; - }, - isFeatureCreator() { if (this.feature && this.user) { return this.feature.creator === this.user.id; @@ -503,33 +502,32 @@ export default { }, mounted() { - this.$store.commit('DISPLAY_LOADER', 'Recherche du signalement'); + this.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('projects/GET_PROJECT', this.$route.params.slug), - this.$store - .dispatch('projects/GET_PROJECT_INFO', this.$route.params.slug), - this.$store.dispatch('feature/GET_PROJECT_FEATURE', { + this.GET_PROJECT(this.$route.params.slug), + this.GET_PROJECT_INFO(this.$route.params.slug), + this.GET_PROJECT_FEATURE({ project_slug: this.$route.params.slug, feature_id: this.$route.params.slug_signal })]) .then(() => { - this.$store.commit('DISCARD_LOADER'); + this.DISCARD_LOADER(); this.initMap(); }); - } if (!this.feature || this.feature.feature_id !== this.$route.params.slug_signal) { - this.$store.dispatch('feature/GET_PROJECT_FEATURE', { + } else if (!this.feature || this.feature.feature_id !== this.$route.params.slug_signal) { + this.GET_PROJECT_FEATURE({ project_slug: this.$route.params.slug, feature_id: this.$route.params.slug_signal }) .then(() => { - this.$store.commit('DISCARD_LOADER'); + this.DISCARD_LOADER(); this.initMap(); }); } else { - this.$store.commit('DISCARD_LOADER'); + this.DISCARD_LOADER(); this.initMap(); } }, @@ -539,11 +537,21 @@ export default { }, methods: { + ...mapMutations([ + 'DISCARD_LOADER', + 'DISPLAY_LOADER', + ]), + ...mapActions('projects', [ + 'GET_PROJECT', + 'GET_PROJECT_INFO' + ]), ...mapActions('feature', [ - 'GET_PROJECT_FEATURES' + 'GET_PROJECT_FEATURES', + 'GET_PROJECT_FEATURE' ]), pushNgo(link) { + this.DISPLAY_LOADER('Recherche du signalement'); this.$router.push({ name: 'details-signalement', params: { @@ -551,10 +559,16 @@ export default { slug_signal: link.feature_to.feature_id, }, }); + this.GET_PROJECT_FEATURE({ + project_slug: this.$route.params.slug, + feature_id: this.$route.params.slug_signal, + }).then(()=> { + this.addFeatureToMap(); + this.DISCARD_LOADER(); + }); this.getFeatureEvents(); this.getFeatureAttachments(); this.getLinkedFeatures(); - this.addFeatureToMap(); }, validateForm() {