Skip to content
Snippets Groups Projects
Commit a63a2457 authored by Timothee P's avatar Timothee P :sunflower:
Browse files

Merge branch 'develop' into redmine-issues/12652

parents 94265050 7c20ca33
No related branches found
No related tags found
2 merge requests!2132.3.2-rc1,!203REDMINE_ISSUE-12652
{
"name": "geocontrib-frontend",
"version": "2.3.0",
"version": "2.3.1",
"private": true,
"scripts": {
"serve": "npm run init-proxy & npm run init-serve",
......
......@@ -151,6 +151,7 @@
</header>
<main>
<div id="content" class="ui stackable grid centered container">
<transition name="fadeDownUp">
<div v-if="messages && messages.length > 0" class="row">
<div class="fourteen wide column">
<div
......@@ -169,6 +170,7 @@
</div>
</div>
</div>
</transition>
<div :class="{ active: loader.isLoading }" class="ui inverted dimmer">
<div class="ui text loader">
{{ loader.message }}
......@@ -373,5 +375,54 @@ footer {
box-shadow: none !important;
transition: none !important;
}
.bounce-enter-active {
animation: bounce-in .5s;
}
.bounce-leave-active {
animation: bounce-in .5s reverse;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
.fadeDownUp-enter-active {
animation: fadeInDown .5s;
}
.fadeDownUp-leave-active {
animation: fadeOutUp .5s;
}
@keyframes fadeOutUp {
0% {
opacity: 1;
}
100% {
opacity: 0;
transform: translate3d(0, -100%, 0);
}
}
@keyframes fadeInDown {
from {
opacity: 0;
transform: translate3d(0, -100%, 0);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
</style>
\ No newline at end of file
......@@ -10,33 +10,33 @@
Statut
<i
:class="{
down: isSortedAsc('statut'),
up: isSortedDesc('statut'),
down: isSortedAsc('status'),
up: isSortedDesc('status'),
}"
class="icon sort"
@click="changeSort('statut')"
@click="changeSort('status')"
/>
</th>
<th class="center">
Type
<i
:class="{
down: isSortedAsc('type'),
up: isSortedDesc('type'),
down: isSortedAsc('feature_type'),
up: isSortedDesc('feature_type'),
}"
class="icon sort"
@click="changeSort('type')"
@click="changeSort('feature_type')"
/>
</th>
<th class="center">
Nom
<i
:class="{
down: isSortedAsc('nom'),
up: isSortedDesc('nom'),
down: isSortedAsc('title'),
up: isSortedDesc('title'),
}"
class="icon sort"
@click="changeSort('nom')"
@click="changeSort('title')"
/>
</th>
<th class="center">
......@@ -75,7 +75,7 @@
</tr>
</thead>
<tbody>
<tr v-for="(feature, index) in sortedFeatures" :key="index">
<tr v-for="(feature, index) in paginatedFeatures" :key="index">
<td class="center">
<div
class="ui checkbox"
......@@ -153,7 +153,6 @@
>
</td>
<td class="center">
<!-- |date:'Ymd' -->
{{ feature.properties.updated_on }}
</td>
<td class="center" v-if="user">
......@@ -187,7 +186,7 @@
class="dataTables_paginate paging_simple_numbers"
>
<a
@click="$emit('update:page', 'previous');"
@click="$emit('update:page', 'previous')"
id="table-features_previous"
:class="[
'paginate_button previous',
......@@ -199,8 +198,20 @@
>Précédent</a
>
<span>
<span v-if="pagination.currentPage >= 5">
<a
key="page1"
@click="$emit('update:page', 1)"
class="paginate_button"
aria-controls="table-features"
data-dt-idx="1"
tabindex="0"
>{{ 1 }}</a
>
<span class="ellipsis"></span>
</span>
<a
v-for="pageNumber in pageNumbers"
v-for="pageNumber in displayedPageNumbers"
:key="'page' + pageNumber"
@click="$emit('update:page', pageNumber)"
:class="[
......@@ -212,8 +223,19 @@
tabindex="0"
>{{ pageNumber }}</a
>
<span v-if="(lastPageNumber - pagination.currentPage) >= 4">
<span class="ellipsis"></span>
<a
:key="'page' + lastPageNumber"
@click="$emit('update:page', lastPageNumber)"
class="paginate_button"
aria-controls="table-features"
data-dt-idx="1"
tabindex="0"
>{{ lastPageNumber }}</a
>
</span>
</span>
<a
id="table-features_next"
:class="[
......@@ -223,7 +245,7 @@
aria-controls="table-features"
data-dt-idx="7"
tabindex="0"
@click="$emit('update:page', 'next');"
@click="$emit('update:page', 'next')"
>Suivant</a
>
</div>
......@@ -241,18 +263,9 @@ export default {
"checkedFeatures",
"featuresCount",
"pagination",
"pageNumbers",
"sort",
],
data() {
return {
sort: {
column: "",
ascending: true,
},
};
},
computed: {
...mapState(["user"]),
...mapGetters(["project", "permissions"]),
......@@ -261,50 +274,6 @@ export default {
return this.permissions.is_project_administrator;
},
sortedFeatures() {
let sortedFeatures = [...this.paginatedFeatures];
// Ajout du tri
if (this.sort.column !== "") {
sortedFeatures = sortedFeatures.sort((a, b) => {
let aProp = this.getFeatureDisplayName(a);
let bProp = this.getFeatureDisplayName(b);
if (this.sort.column === "statut") {
aProp = a.properties.status.value;
bProp = b.properties.status.value;
} else if (this.sort.column === "type") {
aProp = a.properties.feature_type.title;
bProp = b.properties.feature_type.title;
} else if (this.sort.column === "updated_on") {
aProp = a.properties.updated_on;
bProp = b.properties.updated_on;
} else if (this.sort.column === "display_creator") {
aProp = a.properties.display_creator;
bProp = b.properties.display_creator;
}
//ascending
if (this.sort.ascending) {
if (aProp < bProp) {
return -1;
}
if (aProp > bProp) {
return 1;
}
return 0;
} else {
//descending
if (aProp < bProp) {
return 1;
}
if (aProp > bProp) {
return -1;
}
return 0;
}
});
}
return sortedFeatures;
},
checked: {
get() {
return this.checkedFeatures;
......@@ -319,6 +288,36 @@ export default {
? this.featuresCount
: this.pagination.end;
},
pageNumbers() {
const totalPages = Math.ceil(
this.featuresCount / this.pagination.pagesize
);
return [...Array(totalPages).keys()].map((pageNumb) => {
++pageNumb;
return pageNumb;
});
},
lastPageNumber() {
return this.pageNumbers.slice(-1)[0];
},
displayedPageNumbers() {
//* si la page courante est inférieur à 5, la liste commence à l'index 0 et on retourne 5 pages
let firstPageInList = 0;
let pagesQuantity = 5;
//* à partir de la 5ième page et jusqu'à la 4ième page avant la fin : n'afficher que 3 page entre les ellipses et la page courante doit être au milieu
if (this.pagination.currentPage >= 5 && !(this.lastPageNumber - this.pagination.currentPage < 4)) {
firstPageInList = this.pagination.currentPage - 2;
pagesQuantity = 3
}
//* a partir de 4 résultat avant la fin afficher seulement les 5 derniers résultats
if (this.lastPageNumber - this.pagination.currentPage < 4) {
firstPageInList = this.lastPageNumber - 5;
}
return this.pageNumbers.slice(firstPageInList, firstPageInList + pagesQuantity);
},
},
methods: {
......@@ -342,10 +341,14 @@ export default {
changeSort(column) {
if (this.sort.column === column) {
//changer order
this.sort.ascending = !this.sort.ascending;
this.$emit("update:sort", {
column: this.sort.column,
ascending: !this.sort.ascending,
});
} else {
this.sort.column = column;
this.sort.ascending = true;
this.$emit("update:sort", { column, ascending: true });
}
},
},
......@@ -433,6 +436,10 @@ export default {
box-shadow: none;
}
.dataTables_wrapper .dataTables_paginate .ellipsis {
padding: 0 1em;
}
i.icon.sort:not(.down):not(.up) {
color: rgb(220, 220, 220);
}
......
......@@ -238,7 +238,7 @@
</div>
<div
v-if="permissions && permissions.can_create_feature"
v-if="permissions && permissions.can_create_feature && isOffline() !== true"
class="ui segment"
>
<form
......@@ -249,7 +249,11 @@
<label :for="comment_form.comment.id_for_label"
>Ajouter un commentaire</label
>
{{ comment_form.comment.errors }}
<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"
......@@ -292,7 +296,6 @@
</li>
</ul>
<button
v-if="isOffline() !== true"
@click="postComment"
type="button"
class="ui compact green icon button"
......@@ -371,7 +374,7 @@ export default {
comment: {
id_for_label: "add-comment",
html_name: "add-comment",
errors: null,
errors: "",
value: null,
},
},
......@@ -453,8 +456,18 @@ export default {
this.addFeatureToMap();
},
validateForm() {
this.comment_form.comment.errors = ""
if (!this.comment_form.comment.value) {
this.comment_form.comment.errors = "Le commentaire ne peut pas être vide"
return false;
}
return true;
},
postComment() {
featureAPI
if (this.validateForm()) {
featureAPI
.postComment({
featureId: this.$route.params.slug_signal,
comment: this.comment_form.comment.value,
......@@ -476,6 +489,7 @@ export default {
this.confirmComment();
}
});
}
},
confirmComment() {
......
......@@ -86,7 +86,6 @@
<div class="field wide four column no-margin-mobile">
<label>Type</label>
<Dropdown
v-on:update:selection="updateTypeFeatures"
:options="featureTypeChoices"
:selected="form.type.selected"
:selection.sync="form.type.selected"
......@@ -98,7 +97,6 @@
<label>Statut</label>
<!-- //* giving an object mapped on key name -->
<Dropdown
v-on:update:selection="updateStatusFeatures"
:options="statusChoices"
:selected="form.status.selected.name"
:selection.sync="form.status.selected"
......@@ -141,11 +139,12 @@
<FeatureListTable
v-show="!showMap"
v-on:update:page="handlePageChange"
v-on:update:sort="handleSortChange"
:paginatedFeatures="paginatedFeatures"
:checkedFeatures.sync="checkedFeatures"
:featuresCount="featuresCount"
:pagination="pagination"
:pageNumbers="pageNumbers"
:sort="sort"
/>
<!-- MODAL ALL DELETE FEATURE TYPE -->
......@@ -201,17 +200,12 @@ export default {
data() {
return {
modalAllDeleteOpen: false,
form: {
type: {
selected: null,
choices: [],
selected: "",
},
status: {
selected: {
name: null,
value: null,
},
selected: "",
choices: [
{
name: "Brouillon",
......@@ -233,26 +227,40 @@ export default {
},
title: null,
},
paginatedFeatures: [],
baseUrl: this.$store.state.configuration.BASE_URL,
modalAllDeleteOpen: false,
map: null,
zoom: null,
lat: null,
lng: null,
featuresCount: 0,
next: null,
previous: null,
paginatedFeatures: [],
pagination: {
currentPage: 1,
pagesize: 15,
start: 0,
end: 15,
},
previous: null,
next: null,
sort: {
column: "",
ascending: true,
},
showMap: true,
showAddFeature: false,
};
},
watch: {
"form.type.selected"() {
this.fetchPagedFeatures();
},
"form.status.selected.value"() {
this.fetchPagedFeatures();
},
},
computed: {
...mapGetters(["project", "permissions"]),
...mapState("feature", ["checkedFeatures"]),
......@@ -273,16 +281,6 @@ export default {
featureTypeChoices() {
return this.feature_types.map((el) => el.title);
},
pageNumbers() {
const totalPages = Math.ceil(
this.featuresCount / this.pagination.pagesize
);
return [...Array(totalPages).keys()].map((pageNumb) => {
++pageNumb;
return pageNumb;
});
},
},
methods: {
......@@ -349,7 +347,7 @@ export default {
mapDefaultViewZoom,
});
this.getBbox2FIt();
this.fetchBboxNfit();
document.addEventListener("change-layers-order", (event) => {
// Reverse is done because the first layer in order has to be added in the map in last.
......@@ -372,7 +370,7 @@ export default {
}, 1000);
},
getBbox2FIt(queryParams) {
fetchBboxNfit(queryParams) {
featureAPI
.getFeaturesBbox(this.project.slug, queryParams)
.then((bbox) => {
......@@ -388,86 +386,42 @@ export default {
return featureType ? featureType.slug : null;
},
buildFilterParams({ filterType, filterValue }) {
let params = "";
let typeFilter, statusFilter;
//*** feature type ***//
if (filterType === "featureType") {
if (filterValue === "" && !this.form.type.selected) {
//* s'il y n'avait pas de filtre et qu'il a été supprimé --> ne pas mettre à jour les features
return "abort";
} else if (filterValue !== undefined && filterValue !== null) {
//* s'il y a un nouveau filtre --> ajouter une params
typeFilter = this.getFeatureTypeSlug(filterValue);
} //* sinon il n'y a pas de param ajouté, ce qui supprime la query
//*** status ***//
} else if (filterType === "status") {
if (filterValue === "" && !this.form.status.selected.value) {
return "abort";
} else if (filterValue !== undefined && filterValue !== null) {
statusFilter = filterValue.value;
}
}
//* after possibilities of aborting features fetch, empty geojson to make sure even no result would update
if (
(filterType === undefined || filterType === "status") &&
this.form.type.selected
) {
//* s'il y a déjà un filtre sélectionné, maintenir le params
typeFilter = this.getFeatureTypeSlug(this.form.type.selected);
}
if (
(filterType === undefined || filterType === "featureType") &&
this.form.status.selected.value
) {
statusFilter = this.form.status.selected.value;
}
if (typeFilter) {
let typeParams = `&feature_type_slug=${typeFilter}`;
params += typeParams;
}
if (statusFilter) {
let statusParams = `&status__value=${statusFilter}`;
params += statusParams;
}
//*** title ***//
if (this.form.title) {
params += `&title=${this.form.title}`;
getAvalaibleField(orderField) {
let result = orderField;
if (orderField === "display_creator") {
result = "creator";
} else if (orderField === "display_last_editor") {
result = "last_editor";
}
this.getBbox2FIt(params);
return params;
},
updateTypeFeatures(filterValue) {
//* only update:selection custom event can trigger the filter update,
//* but it happens before the value is updated, thus using selected value from event to update query
this.fetchPagedFeatures({ filterType: "featureType", filterValue });
return result;
},
updateStatusFeatures(filterValue) {
this.fetchPagedFeatures({ filterType: "status", filterValue });
buildQueryString() {
let urlParams = "";
let typeFilter = this.getFeatureTypeSlug(this.form.type.selected);
let statusFilter = this.form.status.selected.value;
if (typeFilter) urlParams += `&feature_type_slug=${typeFilter}`;
if (statusFilter) urlParams += `&status__value=${statusFilter}`;
if (this.form.title) urlParams += `&title=${this.form.title}`;
if (this.sort.column) {
urlParams += `&ordering=${
this.sort.ascending ? "-" : ""
}${this.getAvalaibleField(this.sort.column)}`;
}
return urlParams;
},
fetchPagedFeatures(params) {
this.onFilterChange(); //* temporary, use paginated event to watch change in filters, to modify geojson on map
fetchPagedFeatures(newUrl) {
this.onFilterChange(); //* use paginated event to watch change in filters and modify features on map
let url = `${this.API_BASE_URL}projects/${this.$route.params.slug}/feature-paginated/?output=geojson&limit=${this.pagination.pagesize}&offset=${this.pagination.start}`;
if (params) {
if (typeof params === "object") {
const filterParams = this.buildFilterParams(params);
if (filterParams === "abort") return;
url += filterParams;
} else {
//console.error("ONLY FOR DEV !!!!!!!!!!!!!");
//params = params.replace("8000", "8010"); //* for dev uncomment to use proxy link
url = params;
}
if (newUrl && typeof newUrl === "string") {
//* if receiving next & previous url
//newUrl = newUrl.replace("8000", "8010"); //* for dev uncomment to use proxy link
url = newUrl;
}
const queryString = this.buildQueryString();
url += queryString;
this.$store.commit(
"DISPLAY_LOADER",
......@@ -480,6 +434,8 @@ export default {
this.next = data.next;
this.paginatedFeatures = data.results.features;
}
//* bbox needs to be updated with the same filters
if (queryString) this.fetchBboxNfit(queryString);
this.$store.commit("DISCARD_LOADER");
});
},
......@@ -497,6 +453,14 @@ export default {
}
},
handleSortChange(sort) {
this.sort = sort;
this.fetchPagedFeatures({
filterType: undefined,
filterValue: undefined,
});
},
toPage(pageNumber) {
const toAddOrRemove =
(pageNumber - this.pagination.currentPage) * this.pagination.pagesize;
......
......@@ -2,10 +2,7 @@
<div>
<div class="row">
<div class="fourteen wide column">
<img
class="ui centered small image"
:src="logo"
/>
<img class="ui centered small image" :src="logo" />
<h2 class="ui center aligned icon header">
<div class="content">
{{ APPLICATION_NAME }}
......@@ -60,7 +57,6 @@
</template>
<script>
export default {
name: "Login",
data() {
......@@ -101,5 +97,15 @@ export default {
.catch();
},
},
mounted() {
if (this.$store.state.user) {
this.$store.commit(
"DISPLAY_MESSAGE",
"Vous êtes déjà connecté, vous allez être rediriger vers la page d'accueil."
);
setTimeout(() => this.$router.push("/"), 3100);
}
},
};
</script>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment