Newer
Older
Sébastien DA ROCHA
committed
<template>
<div v-frag>
v-frag
>
<div
id="message"
class="fullwidth"
>
<div
v-if="tempMessage"
class="ui positive message"
>
<p><i class="check icon" /> {{ tempMessage }}</p>
Sébastien DA ROCHA
committed
</div>
</div>
<div
id="message_info"
class="fullwidth"
>
<div
v-if="infoMessage"
class="ui info message"
style="text-align: left"
>
<div class="header">
<i class="info circle icon" /> Informations
<ul class="list">
{{
infoMessage
}}
</ul>
</div>
Sébastien DA ROCHA
committed
<div class="row">
<div class="four wide middle aligned column">
<img
class="ui small spaced image"
:src="
project.thumbnail.includes('default')
? require('@/assets/img/default.png')
: DJANGO_BASE_URL + project.thumbnail + refreshId()
"
>
<div class="ui hidden divider" />
<div
class="ui basic teal label"
data-tooltip="Membres"
>
<i class="user icon" />{{ project.nb_contributors }}
Sébastien DA ROCHA
committed
</div>
<div
class="ui basic teal label"
data-tooltip="Signalements publiés"
>
<i class="map marker icon" />{{ project.nb_published_features }}
Sébastien DA ROCHA
committed
</div>
<div
class="ui basic teal label"
data-tooltip="Commentaires"
>
<i class="comment icon" />{{
project.nb_published_features_comments
}}
Sébastien DA ROCHA
committed
</div>
</div>
<div class="ten wide column important-flex space-between">
<div>
<h1 class="ui header">
<div class="sub header">
{{ project.description }}
</div>
</div>
<div class="content flex flex-column-right">
<div class="flex flex-column-right">
<div class="ui icon right compact buttons flex-column-right">
<div>
<a
v-if="
user &&
permissions &&
permissions.can_view_project &&
isOffline() !== true
"
id="subscribe-button"
class="ui button button-hover-green"
data-tooltip="S'abonner au projet"
data-position="top center"
data-variation="mini"
@click="modalType = 'subscribe'"
</a>
<router-link
v-if="
permissions &&
:to="{ name: 'project_edit', params: { slug } }"
class="ui button button-hover-orange"
data-tooltip="Modifier le projet"
data-position="top center"
data-variation="mini"
>
v-if="isProjectAdmin && isOffline() !== true"
id="delete-button"
class="ui button button-hover-red"
data-tooltip="Supprimer le projet"
data-position="top center"
data-variation="mini"
@click="modalType = 'deleteProject'"
>
v-if="isProjectAdmin &&
!isSharedProject && project.generate_share_link"
class="ui teal left labeled icon button"
@click="copyLink"
Copier le lien de partage
<div v-if="confirmMsg">
<div class="ui positive tiny-margin message">
<span>
Le lien a été copié dans le presse-papier
</span>
Sébastien DA ROCHA
committed
</div>
</div>
</div>
</div>
<div v-if="arraysOffline.length > 0">
{{ arraysOffline.length }} modification<span v-if="arraysOffline.length>1">s</span> en attente
<button
:disabled="isOffline()"
class="ui fluid labeled teal icon button"
Envoyer au serveur
</button>
Sébastien DA ROCHA
committed
</div>
</div>
<div class="row">
<div class="seven wide column">
<h3 class="ui header">
Types de signalements
</h3>
Sébastien DA ROCHA
committed
<div class="ui middle aligned divided list">
class="ui inverted dimmer"
>
<div class="ui text loader">
Récupération des types de signalements en cours...
</div>
</div>
Florent
committed
<div
:class="{ active: featureTypeImporting }"
class="ui inverted dimmer"
>
<div class="ui text loader">
Traitement du fichier en cours ...
</div>
</div>
Sébastien DA ROCHA
committed
<div
v-for="(type, index) in feature_types"
Sébastien DA ROCHA
committed
class="item"
>
Florent
committed
<div class="feature-type-container">
:to="{
name: 'details-type-signalement',
params: { feature_type_slug: type.slug },
}"
Florent
committed
class="feature-type-title"
Florent
committed
<div class="middle aligned content">
<router-link
v-if="
project && permissions && permissions.can_create_feature
"
:to="{
name: 'ajouter-signalement',
params: { slug_type_signal: type.slug },
}"
class="
ui
compact
small
icon
right
floated
button button-hover-green
"
data-tooltip="Ajouter un signalement"
data-variation="mini"
>
</router-link>
<router-link
v-if="
project &&
permissions &&
permissions.can_create_feature_type &&
isOffline() !== true
"
:to="{
name: 'dupliquer-type-signalement',
params: { slug_type_signal: type.slug },
}"
class="
ui
compact
small
icon
right
floated
button button-hover-green
"
data-tooltip="Dupliquer un type de signalement"
data-variation="mini"
>
<i class="inverted grey copy alternate icon" />
</router-link>
<div
v-if="isImporting(type)"
class="import-message"
>
<i class="info circle icon" />
Import en cours
</div>
>
v-if="isProjectAdmin && isOffline() !== true"
class="
ui
compact
small
icon
right
floated
button button-hover-red
data-tooltip="Supprimer le type de signalement"
data-position="top center"
data-variation="mini"
v-if="
project &&
permissions &&
permissions.can_create_feature_type &&
:to="{
name: 'editer-symbologie-signalement',
params: { slug_type_signal: type.slug },
}"
class="
data-tooltip="Éditer la symbologie du type de signalement"
v-if="
project &&
type.is_editable &&
permissions &&
permissions.can_create_feature_type &&
isOffline() !== true
"
:to="{
name: 'editer-type-signalement',
params: { slug_type_signal: type.slug },
}"
class="
data-tooltip="Éditer le type de signalement"
data-variation="mini"
>
<i class="inverted grey pencil alternate icon" />
</router-link>
</div>
Florent
committed
</div>
Sébastien DA ROCHA
committed
</div>
</div>
<div v-if="feature_types.length === 0">
<i> Le projet ne contient pas encore de type de signalements. </i>
</div>
</div>
Sébastien DA ROCHA
committed
<router-link
permissions.can_update_project &&
isOffline() !== true
Sébastien DA ROCHA
committed
:to="{
name: 'ajouter-type-signalement',
params: { slug },
Sébastien DA ROCHA
committed
}"

Timothee P
committed
class="ui compact basic button"
Sébastien DA ROCHA
committed
>
<i class="ui plus icon" />Créer un nouveau type de signalement
Sébastien DA ROCHA
committed
</router-link>
</div>
<div class="nouveau-type-signalement">
permissions.can_update_project &&
isOffline() !== true

Timothee P
committed
button
<i class="ui plus icon" />
<label
class="ui"
for="json_file"
>
<span
class="label"
>Créer un nouveau type de signalement à partir d'un
GeoJSON</span>
type="file"
accept="application/json, .json, .geojson"
style="display: none"
name="json_file"
@change="onFileChange"
Sébastien DA ROCHA
committed
</div>
</div>
<div class="nouveau-type-signalement">
<router-link
v-if="
permissions &&
permissions.can_update_project &&
isOffline() !== true
feature_type_slug: 'create'
},

Timothee P
committed
class="ui compact basic button button-align-left"
<i class="ui plus icon" />
Créer un nouveau type de signalement à partir du catalogue {{ CATALOG_NAME|| 'IDGO' }}
<div
v-if="fileToImport.size > 0"
id="button-import"
>
<button
:disabled="fileToImport.size === 0"
class="ui fluid teal icon button"
{{ fileToImport.name }}
</button>
</div>
Sébastien DA ROCHA
committed
</div>
<div class="seven wide column">
class="ui inverted dimmer"
>
<div class="ui text loader">
Chargement de la carte...
</div>
</div>
Sébastien DA ROCHA
committed
</div>
</div>
<div class="row">
<div class="fourteen wide column">
<div class="ui two stackable cards">
<div class="red card">
<div class="content">
<div class="center aligned header">
Derniers signalements
</div>
Sébastien DA ROCHA
committed
<div class="center aligned description">
<div
:class="{ active: featuresLoading }"
class="ui inverted dimmer"
>
<div class="ui text loader">
Récupération des signalements en cours...
</div>
</div>
Sébastien DA ROCHA
committed
<div class="ui relaxed list">
<div
:key="item.properties.title + index"
Sébastien DA ROCHA
committed
class="item"
>
<div class="content">
<div>
<router-link
:to="{
name: 'details-signalement',
params: {
Sébastien DA ROCHA
committed
},
}"
>
{{ item.properties.title || item.id }}
</router-link>
Sébastien DA ROCHA
committed
</div>
<div class="description">
<span v-if="user && item.properties.creator">
, par
{{
item.properties.creator.full_name
? item.properties.creator.full_name
: item.properties.creator.username
Sébastien DA ROCHA
committed
</span>
Sébastien DA ROCHA
committed
</div>
</div>
</div>
<i
v-if="features.length === 0"
>Aucun signalement pour le moment.</i>
Sébastien DA ROCHA
committed
</div>
</div>
</div>
</div>
<div class="orange card">
<div class="content">
<div class="center aligned header">
Derniers commentaires
</div>
Sébastien DA ROCHA
committed
<div class="center aligned description">
<div
:class="{ active: projectInfoLoading }"
class="ui inverted dimmer"
>
<div class="ui text loader">
Sébastien DA ROCHA
committed
<div class="ui relaxed list">
<div
v-for="(item, index) in last_comments"
:key="'comment ' + index"
class="item"
>
<div class="content">
<div>
<router-link
:to="getRouteUrl(item.related_feature.feature_url)"
Sébastien DA ROCHA
committed
>
Sébastien DA ROCHA
committed
</div>
<div class="description">
<i>[ {{ item.created_on
}}<span
v-if="user && item.display_author"
>, par {{ item.display_author }}
</span>
]</i>
Sébastien DA ROCHA
committed
</div>
</div>
</div>
<i
v-if="!last_comments || last_comments.length === 0"
>Aucun commentaire pour le moment.</i>
Sébastien DA ROCHA
committed
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="fourteen wide column">
<div class="ui grey segment">
<h3 class="ui header">
Paramètres du projet
</h3>
Sébastien DA ROCHA
committed
<div class="ui five stackable cards">
<div class="card">
<div class="center aligned content">
<h4 class="ui center aligned icon header">
<i class="disabled grey archive icon" />
<div class="content">
Délai avant archivage automatique
</div>
Sébastien DA ROCHA
committed
</h4>
</div>
<div class="center aligned extra content">
{{ project.archive_feature }} jours
</div>
</div>
<div class="card">
<div class="content">
<h4 class="ui center aligned icon header">
<i class="disabled grey trash alternate icon" />
Sébastien DA ROCHA
committed
<div class="content">
Délai avant suppression automatique
</div>
</h4>
</div>
<div class="center aligned extra content">
{{ project.delete_feature }} jours
</div>
</div>
<div class="card">
<div class="content">
<h4 class="ui center aligned icon header">
Sébastien DA ROCHA
committed
<div class="content">
Visibilité des signalements publiés
</div>
</h4>
</div>
<div class="center aligned extra content">
{{ project.access_level_pub_feature }}
</div>
</div>
<div class="card">
<div class="content">
<h4 class="ui center aligned icon header">
Sébastien DA ROCHA
committed
<div class="content">
Visibilité des signalements archivés
</div>
</h4>
</div>
<div class="center aligned extra content">
{{ project.access_level_arch_feature }}
</div>
</div>
<div class="card">
<div class="content">
<h4 class="ui center aligned icon header">
<i class="disabled grey cogs icon" />
<div class="content">
Modération
</div>
Sébastien DA ROCHA
committed
</h4>
</div>
<div class="center aligned extra content">
{{ project.moderation ? "Oui" : "Non" }}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<i class="icon exclamation triangle" />
<span>Vous ne disposez pas des droits nécessaires pour consulter ce
projet.</span>
Sébastien DA ROCHA
committed
</span>
<div
Sébastien DA ROCHA
committed
class="ui dimmer modals page transition visible active"
style="display: flex !important"
>
<div
:class="[
'ui mini modal subscription',
Sébastien DA ROCHA
committed
]"
>
Sébastien DA ROCHA
committed
<div class="ui icon header">
<i :class="[modalType === 'subscribe' ? 'envelope' : 'trash', 'icon']" />
{{
modalType === 'subscribe' ? 'Notifications' : 'Suppression'
}} du {{
modalType === 'deleteFeatureType' ? 'type de signalement ' + featureTypeToDelete.title : 'projet'
}}
Sébastien DA ROCHA
committed
</div>
<div class="content">
<div v-if="modalType !== 'subscribe'">
<p class="centered-text">
Confirmez vous la suppression du {{
modalType === 'deleteProject' ?
'projet, ainsi que les types de signalements' :
'type de signalement'
}} et tous les signalements associés ?
</p>
<p class="centered-text alert">
Attention cette action est irreversible !
</p>
Sébastien DA ROCHA
committed
<button
:class="['ui compact fluid button', modalType === 'subscribe' && !is_suscriber ? 'green' : 'red']"
Sébastien DA ROCHA
committed
>
<span v-if="modalType === 'subscribe'">
{{
is_suscriber
? "Se désabonner de ce projet"
: "S'abonner à ce projet"
}}
</span>
<span v-else>
Supprimer le
{{
modalType === 'deleteProject'
? 'projet'
: 'type de signalement'
}}
</span>
Sébastien DA ROCHA
committed
</button>
</div>
</div>
</div>
Florent
committed
<div
:class="isFileSizeModalOpen ? 'active' : ''"
class="ui dimmer"
>
<div
:class="isFileSizeModalOpen ? 'active' : ''"
class="ui modal tiny"
style="top: 20%"
>
<div class="header">
Fichier trop grand!
</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).
Florent
committed
</p>
</div>
<div class="actions">
<div
class="ui button teal"
@click="closeFileSizeModal"
>
Fermer
</div>
</div>
</div>
</div>
Sébastien DA ROCHA
committed
</div>
</template>
<script>
import frag from 'vue-frag';
import { mapUtil } from '@/assets/js/map-util.js';
import { mapGetters, mapState, mapActions, mapMutations } from 'vuex';
import projectAPI from '@/services/project-api';
import featureTypeAPI from '@/services/featureType-api';
import featureAPI from '@/services/feature-api';
Sébastien DA ROCHA
committed
Florent
committed
import { fileConvertSizeToMo } from '@/assets/js/utils';
Sébastien DA ROCHA
committed
export default {
Sébastien DA ROCHA
committed
directives: {
frag,
},
filters: {
setDate(value) {
const date = new Date(value);
const d = date.toLocaleDateString('fr', {
year: '2-digit',
month: 'numeric',
day: 'numeric',
Sébastien DA ROCHA
committed
});
return d;
},
},
props: {
message: {
type: String,
default: ''
}
},
Sébastien DA ROCHA
committed
data() {
return {
importMessage: null,
Sébastien DA ROCHA
committed
geojsonImport: [],
Sébastien DA ROCHA
committed
slug: this.$route.params.slug,
Sébastien DA ROCHA
committed
is_suscriber: false,
tempMessage: null,
Florent
committed
featureTypeImporting: false,
Florent
committed
featuresLoading: true,
isFileSizeModalOpen: false,
mapLoading: true,
Sébastien DA ROCHA
committed
};
},
computed: {
...mapGetters([
'permissions'
]),
...mapState('projects', [
...mapState([
'configuration',
]),
...mapState('feature_type', [
'feature_types',
'importFeatureTypeData'
]),
...mapState('feature', [
'features'
]),
...mapState([
'last_comments',
'user',
'user_permissions',
'reloadIntervalId',
]),
...mapState('map', [
'map'
]),
return this.configuration.VUE_APP_DJANGO_BASE;
Sébastien DA ROCHA
committed
},
return this.configuration.VUE_APP_DJANGO_API_BASE;
},
CATALOG_NAME() {
return this.configuration.VUE_APP_CATALOG_NAME;
Florent
committed
},
IDGO() {
return this.$store.state.configuration.VUE_APP_IDGO;
Florent
committed
},
fileSize() {
return fileConvertSizeToMo(this.fileToImport.size);
},
isSharedProject() {
return this.$route.path.includes('projet-partage');
},
isProjectAdmin() {
return this.user_permissions && this.user_permissions[this.slug] &&
this.user_permissions[this.slug].is_project_administrator;
},
Sébastien DA ROCHA
committed
},
watch: {
feature_types: {
deep: true,
handler(newValue, oldValue) {
if (newValue && newValue !== oldValue) {
this.GET_IMPORTS({
});
}
},
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
) {
this.GET_PROJECT_FEATURE_TYPES(this.slug);
this.CLEAR_RELOAD_INTERVAL_ID();
}
},
created() {
if (this.user) {
projectAPI
.getProjectSubscription({
baseUrl: this.$store.state.configuration.VUE_APP_DJANGO_API_BASE,
projectSlug: this.$route.params.slug
})
this.$store.commit('feature/SET_FEATURES', []); //* empty features remaining in case they were in geojson format and will be fetch after map initialization anyway
this.$store.commit('feature_type/SET_FEATURE_TYPES', []); //* empty feature_types remaining from previous project
},
mounted() {
if (this.message) {
this.tempMessage = this.message;
document
.getElementById('message')
.scrollIntoView({ block: 'end', inline: 'nearest' });
setTimeout(() => (this.tempMessage = null), 5000); //* hide message after 5 seconds
}
},
destroyed() {
Sébastien DA ROCHA
committed
methods: {
...mapMutations([
'SET_RELOAD_INTERVAL_ID',
'CLEAR_RELOAD_INTERVAL_ID',
'DISPLAY_MESSAGE',
]),

Timothee P
committed
...mapActions('projects', [
'GET_PROJECT',
]),
...mapActions('feature_type', [
'GET_IMPORTS'
]),
...mapActions('feature', [
'GET_PROJECT_FEATURES'
]),
...mapActions('feature_type', [
'GET_PROJECT_FEATURE_TYPES'
]),
Sébastien DA ROCHA
committed
refreshId() {
Sébastien DA ROCHA
committed
},
if (this.isSharedProject) {
return url.replace(this.$store.state.configuration.BASE_URL, ''); //* remove duplicate /geocontrib
isImporting(type) {
if (this.importFeatureTypeData) {
const singleImportData = this.importFeatureTypeData.find(
(el) => el.feature_type_title === type.slug
);
return singleImportData && singleImportData.status === 'pending';
const sharedLink = window.location.href.replace('projet', 'projet-partage');
navigator.clipboard.writeText(sharedLink).then(()=> {
console.log('success');
this.confirmMsg = true;
}, () => {
console.log('failed');
}
);
this.$store.commit('DISPLAY_LOADER', 'Projet en cours de chargement.');
Promise.all([
this.GET_PROJECT(this.slug),
this.GET_PROJECT_INFO(this.slug)
])
setTimeout(() => {
let map = mapUtil.getMap();
if (map) map.remove();
this.initMap();
}, 1000);
this.projectInfoLoading = false;
});
},