Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • geocontrib/geocontrib-frontend
  • ext_matthieu/geocontrib-frontend
  • fnecas/geocontrib-frontend
  • MatthieuE/geocontrib-frontend
4 results
Show changes
Commits on Source (63)
Showing
with 541 additions and 421 deletions
...@@ -25,16 +25,14 @@ build testing docker image: ...@@ -25,16 +25,14 @@ build testing docker image:
only: only:
- develop - develop
tags: tags:
- build - build_docker
image: variables:
name: gcr.io/kaniko-project/executor:debug DOCKER_TAG: testing
entrypoint: [""]
script: script:
- mkdir -p /kaniko/.docker - cat $DOCKER_PASSWORD | docker login --username $DOCKER_LOGIN --password-stdin
- export - docker-compose build geocontrib-front
- echo "{\"auths\":{\"https://index.docker.io/v1/\":{\"auth\":\"$DOCKER_AUTH\"}}}" > /kaniko/.docker/config.json - docker-compose push geocontrib-front
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination neogeo/geocontrib-front:testing - echo Image docker neogeo/geocontrib-front:${DOCKER_TAG} livrée
- echo Image docker neogeo/geocontrib-front:testing livrée
deploy testing docker image: deploy testing docker image:
stage: deploy stage: deploy
...@@ -52,36 +50,30 @@ build stable docker image: ...@@ -52,36 +50,30 @@ build stable docker image:
only: only:
- master - master
tags: tags:
- build - build_docker
image: variables:
name: gcr.io/kaniko-project/executor:debug DOCKER_TAG: latest
entrypoint: [""]
script: script:
- mkdir -p /kaniko/.docker - cat $DOCKER_PASSWORD | docker login --username $DOCKER_LOGIN --password-stdin
- echo "{\"auths\":{\"https://index.docker.io/v1/\":{\"auth\":\"$DOCKER_AUTH\"}}}" > /kaniko/.docker/config.json - docker-compose build geocontrib-front
- docker-compose push geocontrib-front
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination neogeo/geocontrib-front:latest - echo Image docker neogeo/geocontrib-front:${DOCKER_TAG} livrée
- echo Image docker neogeo/geocontrib:latest livrée
build tagged docker image: build tagged docker image:
stage: build stage: build
only: only:
- tags - tags
tags: tags:
- build - build_docker
image: variables:
name: gcr.io/kaniko-project/executor:debug DOCKER_TAG: $CI_COMMIT_TAG
entrypoint: [""]
script: script:
# Don't build tag id package.json as wrong version # Don't build tag id package.json as wrong version
- grep "\"version\":.\"$CI_COMMIT_TAG\"" package.json - grep "\"version\":.\"$CI_COMMIT_TAG\"" package.json
- mkdir -p /kaniko/.docker - cat $DOCKER_PASSWORD | docker login --username $DOCKER_LOGIN --password-stdin
- echo "{\"auths\":{\"https://index.docker.io/v1/\":{\"auth\":\"$DOCKER_AUTH\"}}}" > /kaniko/.docker/config.json - docker-compose build geocontrib-front
- docker-compose push geocontrib-front
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination neogeo/geocontrib-front:$CI_COMMIT_TAG - echo Image docker neogeo/geocontrib-front:${DOCKER_TAG} livrée
- echo Image docker neogeo/geocontrib-front:$CI_COMMIT_TAG livrée
sonarqube-check: sonarqube-check:
image: image:
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
version: "3" version: "3"
services: services:
geocontrib-front: geocontrib-front:
image: neogeo/geocontrib-front:geocontrib-latest image: neogeo/geocontrib-front:${DOCKER_TAG:-testing}
build: . build: .
environment: environment:
- BASE_URL=${BASE_URL} - BASE_URL=${BASE_URL}
......
{ {
"name": "geocontrib-frontend", "name": "geocontrib-frontend",
"version": "3.0.2", "version": "3.1.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
...@@ -2562,6 +2562,16 @@ ...@@ -2562,6 +2562,16 @@
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
"dev": true "dev": true
}, },
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"optional": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"array-union": { "array-union": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
...@@ -2571,6 +2581,34 @@ ...@@ -2571,6 +2581,34 @@
"array-uniq": "^1.0.1" "array-uniq": "^1.0.1"
} }
}, },
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"optional": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"optional": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true,
"optional": true
},
"dir-glob": { "dir-glob": {
"version": "2.2.2", "version": "2.2.2",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz",
...@@ -2642,6 +2680,13 @@ ...@@ -2642,6 +2680,13 @@
"slash": "^2.0.0" "slash": "^2.0.0"
} }
}, },
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"optional": true
},
"ignore": { "ignore": {
"version": "4.0.6", "version": "4.0.6",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
...@@ -2679,6 +2724,28 @@ ...@@ -2679,6 +2724,28 @@
"requires": { "requires": {
"minipass": "^3.1.1" "minipass": "^3.1.1"
} }
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"optional": true,
"requires": {
"has-flag": "^4.0.0"
}
},
"vue-loader-v16": {
"version": "npm:vue-loader@16.8.3",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.3.tgz",
"integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
"dev": true,
"optional": true,
"requires": {
"chalk": "^4.1.0",
"hash-sum": "^2.0.0",
"loader-utils": "^2.0.0"
}
} }
} }
}, },
...@@ -3561,8 +3628,7 @@ ...@@ -3561,8 +3628,7 @@
"bluebird": { "bluebird": {
"version": "3.7.2", "version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
"dev": true
}, },
"bn.js": { "bn.js": {
"version": "5.2.0", "version": "5.2.0",
...@@ -5207,6 +5273,16 @@ ...@@ -5207,6 +5273,16 @@
} }
} }
}, },
"csvtojson": {
"version": "2.0.10",
"resolved": "https://registry.npmjs.org/csvtojson/-/csvtojson-2.0.10.tgz",
"integrity": "sha512-lUWFxGKyhraKCW8Qghz6Z0f2l/PqB1W3AO0HKJzGIQ5JRSlR651ekJDiGJbBT4sRNNv5ddnSGVEnsxP9XRCVpQ==",
"requires": {
"bluebird": "^3.5.1",
"lodash": "^4.17.3",
"strip-bom": "^2.0.0"
}
},
"cyclist": { "cyclist": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz",
...@@ -8321,6 +8397,11 @@ ...@@ -8321,6 +8397,11 @@
"integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
"dev": true "dev": true
}, },
"is-utf8": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
"integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q=="
},
"is-weakref": { "is-weakref": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
...@@ -12273,6 +12354,14 @@ ...@@ -12273,6 +12354,14 @@
} }
} }
}, },
"strip-bom": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
"integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==",
"requires": {
"is-utf8": "^0.2.0"
}
},
"strip-comments": { "strip-comments": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-1.0.2.tgz", "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-1.0.2.tgz",
...@@ -13257,75 +13346,6 @@ ...@@ -13257,75 +13346,6 @@
} }
} }
}, },
"vue-loader-v16": {
"version": "npm:vue-loader@16.8.3",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.3.tgz",
"integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
"dev": true,
"optional": true,
"requires": {
"chalk": "^4.1.0",
"hash-sum": "^2.0.0",
"loader-utils": "^2.0.0"
},
"dependencies": {
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"optional": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"optional": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"optional": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true,
"optional": true
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"optional": true
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"optional": true,
"requires": {
"has-flag": "^4.0.0"
}
}
}
},
"vue-multiselect": { "vue-multiselect": {
"version": "2.1.6", "version": "2.1.6",
"resolved": "https://registry.npmjs.org/vue-multiselect/-/vue-multiselect-2.1.6.tgz", "resolved": "https://registry.npmjs.org/vue-multiselect/-/vue-multiselect-2.1.6.tgz",
......
{ {
"name": "geocontrib-frontend", "name": "geocontrib-frontend",
"version": "3.1.0", "version": "3.2.0",
"private": true, "private": true,
"scripts": { "scripts": {
"serve": "npm run init-proxy & npm run init-serve", "serve": "npm run init-proxy & npm run init-serve",
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
"@turf/helpers": "^6.5.0", "@turf/helpers": "^6.5.0",
"axios": "^0.21.1", "axios": "^0.21.1",
"core-js": "^3.20.2", "core-js": "^3.20.2",
"csvtojson": "^2.0.10",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"ol": "6.8.1", "ol": "6.8.1",
"ol-mapbox-style": "^6.8.3", "ol-mapbox-style": "^6.8.3",
......
...@@ -12,30 +12,4 @@ export function fileConvertSizeToMo(aSize){ ...@@ -12,30 +12,4 @@ export function fileConvertSizeToMo(aSize){
aSize = Math.abs(parseInt(aSize, 10)); aSize = Math.abs(parseInt(aSize, 10));
const def = [1024*1024, 'Mo', 1]; const def = [1024*1024, 'Mo', 1];
return (aSize/def[0]).toFixed(def[2]); return (aSize/def[0]).toFixed(def[2]);
} }
\ No newline at end of file
export function csvToJson(csv, delimiter) {
const result = [];
const allLines = csv.split('\n');
const headers = allLines[0].split(delimiter).map(el => {
return el.replace('\r', '');
});
const [, ...lines] = allLines;
for (const line of lines) {
if (line) {
const obj = {};
const currentLine = line.split(delimiter).map(el => {
return el.replace('\r', '');
});
for (let i = 0; i < headers.length; i++) {
obj[headers[i]] = currentLine[i];
}
result.push(obj);
}
}
return JSON.parse(JSON.stringify(result));
}
...@@ -47,11 +47,11 @@ ...@@ -47,11 +47,11 @@
<div class="description"> <div class="description">
<p>{{ project.description }}</p> <p>{{ project.description }}</p>
</div> </div>
<div class="meta"> <div class="meta top">
<span <span
class="right floated" class="right floated"
> >
Projet {{ project.moderation ? "" : "non" }} modéré <strong>Projet {{ project.moderation ? "" : "non" }} modéré</strong>
</span> </span>
<span> <span>
Niveau d'autorisation requis : {{ project.access_level_pub_feature }} Niveau d'autorisation requis : {{ project.access_level_pub_feature }}
...@@ -228,6 +228,12 @@ export default { ...@@ -228,6 +228,12 @@ export default {
} }
} }
.description {
p {
text-align: justify;
}
}
@media only screen and (min-width: 767px) { @media only screen and (min-width: 767px) {
.item-content-wrapper { .item-content-wrapper {
align-items: flex-start; align-items: flex-start;
...@@ -235,6 +241,12 @@ export default { ...@@ -235,6 +241,12 @@ export default {
.middle.aligned.content { .middle.aligned.content {
width: 100%; width: 100%;
padding: 0 0 0 1.5em; padding: 0 0 0 1.5em;
.meta.top {
span {
line-height: 1.2em;
}
}
} }
} }
} }
...@@ -244,8 +256,25 @@ export default { ...@@ -244,8 +256,25 @@ export default {
align-items: center; align-items: center;
.middle.aligned.content { .middle.aligned.content {
width: 70%; width: 80%;
padding: 1.5em 0 0; padding: 1.5em 0 0;
.meta.top {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
.right.floated {
float: none !important;
margin-left: 0 !important;
margin-bottom: 0.5em;
}
span {
margin: 0.15em 0;
}
}
} }
} }
} }
......
...@@ -207,10 +207,12 @@ export default { ...@@ -207,10 +207,12 @@ export default {
'user', 'user',
'isOnline', 'isOnline',
]), ]),
...mapGetters([ ...mapGetters([
'permissions', 'permissions',
]), ]),
...mapState('feature', [
'currentFeature',
]),
DJANGO_BASE_URL() { DJANGO_BASE_URL() {
return this.$store.state.configuration.VUE_APP_DJANGO_BASE; return this.$store.state.configuration.VUE_APP_DJANGO_BASE;
...@@ -231,14 +233,14 @@ export default { ...@@ -231,14 +233,14 @@ export default {
if (this.validateForm()) { if (this.validateForm()) {
featureAPI featureAPI
.postComment({ .postComment({
featureId: this.$route.params.slug_signal, featureId: this.currentFeature.feature_id,
comment: this.comment_form.comment.value, comment: this.comment_form.comment.value,
}) })
.then((response) => { .then((response) => {
if (response && this.comment_form.attachment_file.file) { if (response && this.comment_form.attachment_file.file) {
featureAPI featureAPI
.postCommentAttachment({ .postCommentAttachment({
featureId: this.$route.params.slug_signal, featureId: this.currentFeature.feature_id,
file: this.comment_form.attachment_file.file, file: this.comment_form.attachment_file.file,
fileName: this.comment_form.attachment_file.fileName, fileName: this.comment_form.attachment_file.fileName,
title: this.comment_form.attachment_file.title, title: this.comment_form.attachment_file.title,
......
...@@ -2,152 +2,163 @@ ...@@ -2,152 +2,163 @@
<div> <div>
<h1 class="ui header"> <h1 class="ui header">
<div class="content"> <div class="content">
<span <div class="two-block">
v-if="fastEditionMode && form" <div
class="form ui half-block" v-if="fastEditionMode && form && canEditFeature"
> 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"
id="feature-detail-to-features-list"
:to="{
name: 'liste-signalements',
params: { slug: $route.params.slug },
}"
custom
>
<div class="ui button tiny-margin teal">
<i class="ui icon arrow right" />
Retour à la liste des signalements
</div>
</router-link>
<span
v-if="featuresCount"
id="feature-count"
class="ui button tiny-margin basic"
>
{{ parseInt($route.query.offset) + 1 }} sur {{ featuresCount }}
</span>
<button
v-if="queryparams"
id="previous-feature"
:class="['ui button button-hover-green tiny-margin', { disabled: queryparams.previous < 0 }]"
data-tooltip="Voir le précédent signalement"
data-position="bottom center"
@click="toFeature('previous')"
> >
<i <input
class="angle left fitted icon" id="feature_detail_title_input"
aria-hidden="true" :value="form.title"
/> type="text"
</button> required
<button maxlength="128"
v-if="queryparams" name="title"
id="next-feature" @blur="updateTitle"
:class="[ >
'ui button button-hover-green tiny-margin', </div>
{ disabled: queryparams.next >= featuresCount } <div
]" v-else
data-tooltip="Voir le prochain signalement" class="ellipsis"
data-position="bottom center"
@click="toFeature('next')"
> >
<i {{ currentFeature.title || currentFeature.feature_id }}
class="angle right fitted icon" </div>
aria-hidden="true"
/>
</button>
<button <div
v-if="fastEditionMode && userCanFastEdit" id="feature-actions"
id="previous-feature" class="ui icon compact buttons"
: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 <div>
class="save fitted icon" <router-link
aria-hidden="true" v-if="displayToListButton"
/> id="feature-detail-to-features-list"
</button> :to="{
name: 'liste-signalements',
params: { slug: $route.params.slug },
}"
custom
>
<div class="ui button tiny-margin teal">
<i class="ui icon arrow right" />
Retour à la liste des signalements
</div>
</router-link>
</div>
<div>
<span
v-if="featuresCount"
id="feature-count"
class="ui button tiny-margin basic disabled no-opacity"
>
{{ parseInt($route.query.offset) + 1 }} sur {{ featuresCount }}
</span>
<button
v-if="queryparams"
id="previous-feature"
:class="['ui button button-hover-green tiny-margin', { disabled: queryparams.previous < 0 }]"
data-tooltip="Voir le précédent signalement"
data-position="bottom center"
@click="toFeature('previous')"
>
<i
class="angle left fitted icon"
aria-hidden="true"
/>
</button>
<button
v-if="queryparams"
id="next-feature"
:class="[
'ui button button-hover-green tiny-margin',
{ disabled: queryparams.next >= featuresCount }
]"
data-tooltip="Voir le prochain signalement"
data-position="bottom center"
@click="toFeature('next')"
>
<i
class="angle right fitted icon"
aria-hidden="true"
/>
</button>
</div>
<div>
<button
v-if="fastEditionMode && canEditFeature"
id="save-fast-edit"
:class="['ui button button-hover-orange tiny-margin', { disabled: false }]"
data-tooltip="Enregistrer les modifications"
data-position="bottom center"
@click="validateFastEdition"
>
<i
class="save fitted icon"
aria-hidden="true"
/>
</button>
<router-link <router-link
v-if="permissions && permissions.can_create_feature" v-if="permissions && permissions.can_create_feature"
id="add-feature" id="add-feature"
:to="{ :to="{
name: 'ajouter-signalement', name: 'ajouter-signalement',
params: { params: {
slug_type_signal: $route.params.slug_type_signal || featureType.slug, slug_type_signal: $route.params.slug_type_signal || featureType.slug,
}, },
}" }"
class="ui button button-hover-green tiny-margin" class="ui button button-hover-green tiny-margin"
data-tooltip="Ajouter un signalement" data-tooltip="Ajouter un signalement"
data-position="bottom center" data-position="bottom center"
> >
<i <i
class="plus icon" class="plus icon"
aria-hidden="true" aria-hidden="true"
/> />
</router-link> </router-link>
<router-link <router-link
v-if="slugSignal && v-if="slugSignal && canEditFeature"
((permissions && permissions.can_update_feature) || id="edit-feature"
isFeatureCreator || :to="{
isModerator) name: 'editer-signalement',
" params: {
id="edit-feature" slug_signal: slugSignal,
:to="{ slug_type_signal: $route.params.slug_type_signal || featureType.slug,
name: 'editer-signalement', },
params: { query: $route.query
slug_signal: slugSignal, }"
slug_type_signal: $route.params.slug_type_signal || featureType.slug, class="ui button button-hover-orange tiny-margin"
}, data-tooltip="Éditer le signalement"
query: $route.query data-position="bottom center"
}" >
class="ui button button-hover-orange tiny-margin" <i
data-tooltip="Éditer le signalement" class="inverted grey pencil alternate icon"
data-position="bottom center" aria-hidden="true"
> />
<i </router-link>
class="inverted grey pencil alternate icon"
aria-hidden="true"
/>
</router-link>
<a <a
v-if="((permissions && permissions.can_update_feature) || isFeatureCreator) && isOnline" v-if="canDeleteFeature && isOnline"
id="currentFeature-delete" id="currentFeature-delete"
class="ui button button-hover-red tiny-margin" class="ui button button-hover-red tiny-margin"
data-tooltip="Supprimer le signalement" data-tooltip="Supprimer le signalement"
data-position="bottom right" data-position="bottom right"
@click="$emit('setIsCancelling')" @click="$emit('setIsDeleting')"
> >
<i <i
class="inverted grey trash alternate icon" class="inverted grey trash alternate icon"
aria-hidden="true" aria-hidden="true"
/> />
</a> </a>
</div>
</div>
</div> </div>
<div class="ui hidden divider" />
<!-- <div class="ui hidden divider" /> -->
<div class="sub header prewrap"> <div class="sub header prewrap">
<span <span
v-if="fastEditionMode && form" v-if="fastEditionMode && canEditFeature && form"
class="form ui half-block" class="form ui half-block"
> >
<textarea <textarea
...@@ -196,12 +207,23 @@ export default { ...@@ -196,12 +207,23 @@ export default {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
isFeatureCreator: {
type: Boolean,
default: false,
},
canEditFeature: {
type: Boolean,
default: false,
},
canDeleteFeature: {
type: Boolean,
default: false,
},
}, },
computed: { computed: {
...mapState([ ...mapState([
'user', 'user',
'USER_LEVEL_PROJECTS',
'isOnline', 'isOnline',
]), ]),
...mapState('feature', [ ...mapState('feature', [
...@@ -212,24 +234,6 @@ export default { ...@@ -212,24 +234,6 @@ export default {
'permissions', 'permissions',
]), ]),
isFeatureCreator() {
if (this.currentFeature && this.user) {
return this.currentFeature.creator === this.user.id;
}
return false;
},
isModerator() {
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() { queryparams() {
return this.$route.query.offset >= 0 ? { return this.$route.query.offset >= 0 ? {
previous: parseInt(this.$route.query.offset) - 1, previous: parseInt(this.$route.query.offset) - 1,
...@@ -258,26 +262,45 @@ export default { ...@@ -258,26 +262,45 @@ export default {
updateDescription(e) { updateDescription(e) {
this.$store.commit('feature/UPDATE_FORM_FIELD', { name: 'description', value: e.target.value }); this.$store.commit('feature/UPDATE_FORM_FIELD', { name: 'description', value: e.target.value });
},
validateFastEdition() {
this.$store.dispatch('feature/SEND_FEATURE', this.$route.name)
.then(() => this.$emit('updateEvents'));
} }
} }
}; };
</script> </script>
<style> <style>
#next-feature {
margin-right: .5rem !important;
}
#feature-detail-to-features-list { #feature-detail-to-features-list {
line-height: 0; line-height: 0;
margin-right: 5px; margin-right: 5px;
} }
.half-block {
display: inline-block;
width: 50%;
}
#feature_detail_title_input { #feature_detail_title_input {
font-weight: bold; font-weight: bold;
font-size: 2em; font-size: 2em;
padding: .25em; padding: .25em;
} }
.two-block {
display: flex;
justify-content: space-between;
margin-bottom: .5em;
}
#feature-actions > div {
margin-left: .5rem;
}
#feature-actions .no-opacity {
opacity: 1 !important; /* overide disabled low opacity to customize button style */
}
@media screen and (max-width: 700px) {
.two-block {
flex-direction: column-reverse;
}
#feature-actions.ui.buttons {
flex-direction: column;
align-items: flex-end;
}
}
</style> </style>
\ No newline at end of file
...@@ -23,7 +23,8 @@ ...@@ -23,7 +23,8 @@
<td> <td>
<strong class="ui form"> <strong class="ui form">
<span <span
v-if="fastEditionMode && extra_forms.length > 0" v-if="fastEditionMode && canEditFeature && extra_forms.length > 0"
:id="field.label"
> >
<FeatureExtraForm <FeatureExtraForm
:field="getExtraForm(field)" :field="getExtraForm(field)"
...@@ -60,7 +61,7 @@ ...@@ -60,7 +61,7 @@
aria-hidden="true" aria-hidden="true"
/> />
<FeatureEditStatusField <FeatureEditStatusField
v-if="fastEditionMode && form" v-if="fastEditionMode && canEditFeature && form"
:status="form.status.value" :status="form.status.value"
class="inline" class="inline"
/> />
...@@ -115,6 +116,13 @@ ...@@ -115,6 +116,13 @@
{{ link.feature_to.created_on }}) {{ link.feature_to.created_on }})
</td> </td>
</tr> </tr>
<tr v-if="linked_features.length === 0">
<td>
<em>
Aucune liaison associée au signalement.
</em>
</td>
</tr>
</tbody> </tbody>
</table> </table>
</div> </div>
...@@ -154,7 +162,11 @@ export default { ...@@ -154,7 +162,11 @@ export default {
fastEditionMode: { fastEditionMode: {
type: Boolean, type: Boolean,
default: false, default: false,
} },
canEditFeature: {
type: Boolean,
default: false,
},
}, },
computed: { computed: {
......
<template> <template>
<div <div v-if="field && field.field_type === 'char'">
v-if="field && field.field_type === 'char'"
>
<label <label
v-if="$route.name === 'editer-signalement'" v-if="displayLabels"
:for="field.name" :for="field.name"
> >
{{ field.label }} {{ field.label }}
...@@ -17,11 +15,9 @@ ...@@ -17,11 +15,9 @@
> >
</div> </div>
<div <div v-else-if="field && field.field_type === 'list'">
v-else-if="field && field.field_type === 'list'"
>
<label <label
v-if="$route.name === 'editer-signalement'" v-if="displayLabels"
:for="field.name" :for="field.name"
> >
{{ field.label }} {{ field.label }}
...@@ -32,11 +28,9 @@ ...@@ -32,11 +28,9 @@
:selection.sync="selected_extra_form_list" :selection.sync="selected_extra_form_list"
/> />
</div> </div>
<div <div v-else-if="field && field.field_type === 'integer'">
v-else-if="field && field.field_type === 'integer'"
>
<label <label
v-if="$route.name === 'editer-signalement'" v-if="displayLabels"
:for="field.name" :for="field.name"
> >
{{ field.label }} {{ field.label }}
...@@ -52,9 +46,7 @@ ...@@ -52,9 +46,7 @@
> >
</div> </div>
</div> </div>
<div <div v-else-if="field && field.field_type === 'boolean'">
v-else-if="field && field.field_type === 'boolean'"
>
<div class="ui checkbox"> <div class="ui checkbox">
<input <input
:id="field.name" :id="field.name"
...@@ -63,19 +55,14 @@ ...@@ -63,19 +55,14 @@
:name="field.name" :name="field.name"
@change="updateStore_extra_form" @change="updateStore_extra_form"
> >
<label <label :for="field.name">
v-if="$route.name === 'editer-signalement'" {{ displayLabels ? field.label : '' }}
:for="field.name"
>
{{ field.label }}
</label> </label>
</div> </div>
</div> </div>
<div <div v-else-if="field && field.field_type === 'date'">
v-else-if="field && field.field_type === 'date'"
>
<label <label
v-if="$route.name === 'editer-signalement'" v-if="displayLabels"
:for="field.name" :for="field.name"
> >
{{ field.label }} {{ field.label }}
...@@ -88,11 +75,9 @@ ...@@ -88,11 +75,9 @@
@blur="updateStore_extra_form" @blur="updateStore_extra_form"
> >
</div> </div>
<div <div v-else-if="field && field.field_type === 'decimal'">
v-else-if="field && field.field_type === 'decimal'"
>
<label <label
v-if="$route.name === 'editer-signalement'" v-if="displayLabels"
:for="field.name" :for="field.name"
> >
{{ field.label }} {{ field.label }}
...@@ -108,11 +93,9 @@ ...@@ -108,11 +93,9 @@
> >
</div> </div>
</div> </div>
<div <div v-else-if="field && field.field_type === 'text'">
v-else-if="field && field.field_type === 'text'"
>
<label <label
v-if="$route.name === 'editer-signalement'" v-if="displayLabels"
:for="field.name" :for="field.name"
> >
{{ field.label }} {{ field.label }}
...@@ -155,6 +138,10 @@ export default { ...@@ -155,6 +138,10 @@ export default {
this.$store.commit('feature/UPDATE_EXTRA_FORM', newExtraForm); this.$store.commit('feature/UPDATE_EXTRA_FORM', newExtraForm);
}, },
}, },
displayLabels() {
return this.$route.name === 'editer-signalement' || this.$route.name === 'ajouter-signalement';
}
}, },
methods: { methods: {
......
<template> <template>
<div class="field"> <div
id="status"
class="field"
>
<Dropdown <Dropdown
v-if="selectedStatus" v-if="selectedStatus"
:options="allowedStatusChoices" :options="allowedStatusChoices"
...@@ -56,7 +59,7 @@ export default { ...@@ -56,7 +59,7 @@ export default {
allowedStatusChoices() { allowedStatusChoices() {
if (this.project && this.currentFeature && this.user) { if (this.project && this.currentFeature && this.user) {
const isModerate = this.project.moderation; const isModerate = this.project.moderation;
const userStatus = this.USER_LEVEL_PROJECTS[this.project.slug]; const userStatus = this.USER_LEVEL_PROJECTS && this.USER_LEVEL_PROJECTS[this.project.slug];
const isOwnFeature = this.currentFeature.creator === this.user.id; //* si le contributeur est l'auteur du signalement 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 allowedStatus2change(this.user, isModerate, userStatus, isOwnFeature, /* this.currentRouteName */);
} }
......
...@@ -312,7 +312,7 @@ export default { ...@@ -312,7 +312,7 @@ export default {
fillCustomFormData(customFormData) { fillCustomFormData(customFormData) {
for (const el in customFormData) { for (const el in customFormData) {
if (el && this.form[el] && customFormData[el]) { if (el && this.form[el] && customFormData[el] !== undefined && customFormData[el] !== null) {
//* check if is an object, because data from api is a string, while import from django is an object //* check if is an object, because data from api is a string, while import from django is an object
this.form[el].value = customFormData[el].value this.form[el].value = customFormData[el].value
? customFormData[el].value ? customFormData[el].value
...@@ -365,53 +365,46 @@ export default { ...@@ -365,53 +365,46 @@ export default {
return occurences.length === 1; return occurences.length === 1;
}, },
checkFilledOptions() { checkListOptions() {
if (this.form.field_type.value === 'list') { if (this.form.field_type.value !== 'list') return true;
if (this.form.options.value.length < 1) { return this.form.options.value.length >= 2 && !this.form.options.value.includes('');
return false;
} else if (
this.form.options.value.length === 1 &&
this.form.options.value[0] === ''
) {
return false;
}
}
return true;
}, },
checkCustomForm() { checkCustomForm() {
this.form.label.errors = []; this.form.label.errors = [];
this.form.name.errors = []; this.form.name.errors = [];
this.form.options.errors = []; this.form.options.errors = [];
let isValid = true;
if (!this.form.label.value) { if (!this.form.label.value) {
//* vérifier que le label est renseigné //* vérifier que le label est renseigné
this.form.label.errors = ['Veuillez compléter ce champ.']; this.form.label.errors = ['Veuillez compléter ce champ.'];
return false; isValid = false;
} else if (!this.form.name.value) { } else if (!this.form.name.value) {
//* vérifier que le nom est renseigné //* vérifier que le nom est renseigné
this.form.name.errors = ['Veuillez compléter ce champ.']; this.form.name.errors = ['Veuillez compléter ce champ.'];
return false; isValid = false;
} else if (!this.hasRegularCharacters(this.form.name.value)) { } else if (!this.hasRegularCharacters(this.form.name.value)) {
//* vérifier qu'il n'y a pas de caractères spéciaux //* vérifier qu'il n'y a pas de caractères spéciaux
this.form.name.errors = [ this.form.name.errors = [
'Veuillez utiliser seulement les caratères autorisés.', 'Veuillez utiliser seulement les caratères autorisés.',
]; ];
return false; isValid = false;
} else if (!this.checkUniqueName()) { } else if (!this.checkUniqueName()) {
//* vérifier si les noms sont pas dupliqués //* vérifier si les noms sont pas dupliqués
this.form.name.errors = [ this.form.name.errors = [
'Les champs personnalisés ne peuvent pas avoir des noms similaires.', 'Les champs personnalisés ne peuvent pas avoir des noms similaires.',
]; ];
return false; isValid = false;
} else if (!this.checkFilledOptions()) { } else if (!this.checkListOptions()) {
//* s'il s'agit d'un type liste, vérifier que le champ option est bien renseigné //* s'il s'agit d'un type liste, vérifier que le champ option est bien renseigné
this.form.options.errors = ['Veuillez compléter ce champ.']; this.form.options.errors = ['Veuillez compléter ce champ.'];
return false; isValid = false;
} else if (this.hasDuplicateOptions()) { } else if (this.hasDuplicateOptions()) {
//* pour le cas d'options dupliqués //* pour le cas d'options dupliqués
return false; isValid = false;
} }
return true; if (!isValid) document.getElementById(`custom_form-${this.form.position.value}`).scrollIntoView({ block: 'start', inline: 'nearest' });
return isValid;
}, },
}, },
}; };
......
...@@ -26,7 +26,9 @@ ...@@ -26,7 +26,9 @@
<td> <td>
<h4 class="ui header align-right"> <h4 class="ui header align-right">
<div :data-tooltip="importFile.geojson_file_name"> <div :data-tooltip="importFile.geojson_file_name">
{{ importFile.geojson_file_name | subString }} <div class="ellipsis">
{{ importFile.geojson_file_name | subString }}
</div>
<div class="sub header"> <div class="sub header">
ajouté le {{ importFile.created_on | setDate }} ajouté le {{ importFile.created_on | setDate }}
</div> </div>
...@@ -234,5 +236,9 @@ and also iPads specifically. ...@@ -234,5 +236,9 @@ and also iPads specifically.
.margin-left { .margin-left {
margin-left: 94%; margin-left: 94%;
} }
h4.ui.header {
margin-left: 60px;
white-space: nowrap;
}
} }
</style> </style>
...@@ -426,10 +426,11 @@ ...@@ -426,10 +426,11 @@
</template> </template>
<script> <script>
import { csv } from 'csvtojson';
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'; import { mapState, mapGetters, mapMutations, mapActions } from 'vuex';
import { fileConvertSizeToMo, csvToJson } from '@/assets/js/utils'; import { fileConvertSizeToMo } from '@/assets/js/utils';
import FeatureTypeLink from '@/components/FeatureType/FeatureTypeLink'; import FeatureTypeLink from '@/components/FeatureType/FeatureTypeLink';
export default { export default {
...@@ -633,7 +634,6 @@ export default { ...@@ -633,7 +634,6 @@ export default {
try { try {
fr.readAsText(this.csvFileToImport); fr.readAsText(this.csvFileToImport);
fr.onloadend = () => { fr.onloadend = () => {
// Find csv delimiter // Find csv delimiter
const commaDelimited = fr.result.split('\n')[0].includes(','); const commaDelimited = fr.result.split('\n')[0].includes(',');
const semicolonDelimited = fr.result.split('\n')[0].includes(';'); const semicolonDelimited = fr.result.split('\n')[0].includes(';');
...@@ -644,19 +644,16 @@ export default { ...@@ -644,19 +644,16 @@ export default {
this.featureTypeImporting = false; this.featureTypeImporting = false;
return; return;
} }
// Check if file contains 'lat' and 'long' fields // Check if file contains 'lat' and 'long' fields
const headersLine = const headers = fr.result
fr.result .split('\n')[0]
.split('\n')[0] .split(delimiter)
.split(delimiter) .map(el => {
.map(el => { return el.replace('\r', '');
return el.replace('\r', ''); });
}) const headersCoord = headers.filter(el => {
.filter(el => { return el === 'lat' || el === 'lon';
return el === 'lat' || el === 'lon'; });
});
// Look for 2 decimal fields in first line of csv // Look for 2 decimal fields in first line of csv
// corresponding to lon and lat // corresponding to lon and lat
const sampleLine = const sampleLine =
...@@ -667,9 +664,13 @@ export default { ...@@ -667,9 +664,13 @@ export default {
return !isNaN(el) && el.indexOf('.') !== -1; return !isNaN(el) && el.indexOf('.') !== -1;
}) })
.filter(Boolean); .filter(Boolean);
if (sampleLine.length > 1 && headersLine.length === 2) { if (sampleLine.length > 1 && headersCoord.length === 2) {
this.csvError = null; this.csvError = null;
this.csvImport = csvToJson(fr.result, delimiter); csv()
.fromString(fr.result)
.then((jsonObj)=>{
this.csvImport = jsonObj;
});
this.featureTypeImporting = false; this.featureTypeImporting = false;
//* stock filename to import features afterward //* stock filename to import features afterward
this.SET_FILE_TO_IMPORT(this.csvFileToImport); this.SET_FILE_TO_IMPORT(this.csvFileToImport);
......
...@@ -207,6 +207,7 @@ ...@@ -207,6 +207,7 @@
feature_type_slug: feature.feature_type.slug, feature_type_slug: feature.feature_type.slug,
}, },
}" }"
class="ellipsis space-left"
> >
{{ feature.feature_type.title }} {{ feature.feature_type.title }}
</router-link> </router-link>
...@@ -220,6 +221,7 @@ ...@@ -220,6 +221,7 @@
}, },
query: { ...queryparams, offset: queryparams.offset + index } query: { ...queryparams, offset: queryparams.offset + index }
}" }"
class="ellipsis space-left"
> >
{{ feature.title || feature.feature_id }} {{ feature.title || feature.feature_id }}
</router-link> </router-link>
...@@ -465,7 +467,9 @@ export default { ...@@ -465,7 +467,9 @@ export default {
Contributeur : ['draft', 'pending', 'published'], Contributeur : ['draft', 'pending', 'published'],
}; };
if (this.userStatus === 'Contributeur' && feature.display_creator !== this.user.username) { if (this.user.is_superuser) {
return true;
} else if (this.userStatus === 'Contributeur' && feature.display_creator !== `${this.user.first_name} ${this.user.last_name}`) {
return false; return false;
} else if (permissions[this.userStatus]) { } else if (permissions[this.userStatus]) {
return permissions[this.userStatus].includes(feature.status); return permissions[this.userStatus].includes(feature.status);
...@@ -725,6 +729,11 @@ and also iPads specifically. ...@@ -725,6 +729,11 @@ and also iPads specifically.
text-align: center; text-align: center;
margin: .5em 0; margin: .5em 0;
} }
.space-left {
max-width: 100%;
display: inline-block;
padding-left: 3em;
}
} }
@media only screen and (max-width: 410px) { @media only screen and (max-width: 410px) {
.ui.table tr td { .ui.table tr td {
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
<div class="description"> <div class="description">
<p>{{ project.description }}</p> <p>{{ project.description }}</p>
</div> </div>
<div class="meta"> <div class="meta top">
<span class="right floated"> <span class="right floated">
<strong v-if="project.moderation">Projet modéré</strong> <strong v-if="project.moderation">Projet modéré</strong>
<strong v-else>Projet non modéré</strong> <strong v-else>Projet non modéré</strong>
...@@ -110,3 +110,36 @@ export default { ...@@ -110,3 +110,36 @@ export default {
}; };
</script> </script>
<style lang="less" scoped>
.description {
p {
text-align: justify;
}
}
@media screen and (max-width: 767px) {
.content {
width: 90% !important;
.meta.top {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
.right.floated {
float: none !important;
margin-left: 0 !important;
margin-bottom: 0.5em;
}
span {
margin: 0.15em 0;
}
}
}
}
</style>
<template> <template>
<div class="filters-container"> <div id="filters-container">
<div class="ui styled accordion"> <div
class="ui styled accordion"
@click="displayFilters = !displayFilters"
>
<div <div
id="filters" id="filters"
class="title collapsible-filters" class="title collapsible-filters"
> >
FILTRES FILTRES
<i <i
class="ui icon caret right down" :class="['ui icon customcaret', { 'collapsed': !displayFilters }]"
aria-hidden="true" aria-hidden="true"
/> />
</div> </div>
</div> </div>
<div class="ui menu filters hidden"> <div :class="['ui menu filters', { 'hidden': displayFilters }]">
<div class="item"> <div class="item">
<label> <label>
Niveau d'autorisation requis Niveau d'autorisation requis
...@@ -40,7 +43,7 @@ ...@@ -40,7 +43,7 @@
v-on="$listeners" v-on="$listeners"
/> />
</div> </div>
<div class="right item"> <div class="item">
<label> <label>
Recherche par nom Recherche par nom
</label> </label>
...@@ -69,6 +72,7 @@ export default { ...@@ -69,6 +72,7 @@ export default {
data() { data() {
return { return {
displayFilters: false,
moderationOptions: [ moderationOptions: [
{ {
label: 'Tous', label: 'Tous',
...@@ -157,26 +161,10 @@ export default { ...@@ -157,26 +161,10 @@ export default {
} }
}, },
mounted() {
const el = document.getElementsByClassName('collapsible-filters');
el[0].addEventListener('click', function() {
const icon = document.getElementsByClassName('caret');
icon[0].classList.toggle('right');
const content = document.getElementsByClassName('filters');
content[0].classList.toggle('hidden');
if (content[0].style.maxHeight){
content[0].style.maxHeight = null;
} else {
content[0].style.maxHeight = content[0].scrollHeight + 5 + 'px';
}
});
},
methods: { methods: {
...mapActions('projects', [ ...mapActions('projects', [
'SEARCH_PROJECTS' 'SEARCH_PROJECTS'
]) ]),
} }
}; };
</script> </script>
...@@ -189,7 +177,7 @@ export default { ...@@ -189,7 +177,7 @@ export default {
transition: @arguments; transition: @arguments;
} }
.filters-container { #filters-container {
width: 100%; width: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
...@@ -200,6 +188,23 @@ export default { ...@@ -200,6 +188,23 @@ export default {
.collapsible-filters { .collapsible-filters {
font-size: 1.25em; font-size: 1.25em;
padding-right: 0; padding-right: 0;
.customcaret{
transition: transform .2s ease;
&.collapsed {
transform: rotate(180deg);
}
&::before{
position: relative;
right: 0;
top: 65%;
color: #999;
margin-top: 4px;
border-color: #999 transparent transparent;
border-style: solid;
border-width: 5px 5px 0;
content: "";
}
}
} }
} }
.filters { .filters {
...@@ -207,16 +212,16 @@ export default { ...@@ -207,16 +212,16 @@ export default {
height:auto; height:auto;
min-height: 0; min-height: 0;
max-height:75px; max-height:75px;
opacity: 1;
margin: 0 0 1em 0; margin: 0 0 1em 0;
border: none; border: none;
box-shadow: none; box-shadow: none;
.transition-properties(max-height 0.2s ease-out;); .transition-properties(all 0.2s ease-out;);
.item { .item {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: flex-start !important; align-items: flex-start !important;
padding: 0.5em;
padding: 0.4em 0.6em 0.4em 0;
label { label {
margin-bottom: 0.2em; margin-bottom: 0.2em;
...@@ -230,20 +235,43 @@ export default { ...@@ -230,20 +235,43 @@ export default {
.item::before { .item::before {
width: 0; width: 0;
} }
.right.item { #search-projects {
padding-right: 0; width: 100%;
#search-projects {
width: 100%;
}
} }
.right.item::before {
width: 0;
}
} }
.filters.hidden { .filters.hidden {
max-height: 0;
overflow: hidden; overflow: hidden;
border: none; opacity: 0;
max-height: 0;
} }
} }
@media screen and (min-width: 701px) {
.item {
&:first-child {
padding-left: 0;
}
&:last-child {
padding-right: 0;
}
}
}
@media screen and (max-width: 700px) {
#filters-container {
.filters {
display: flex;
flex-direction: column;
max-height: 275px;
.transition-properties(all 0.2s ease-out;);
.item {
width: 100%;
padding-right: 0;
padding-left: 0;
}
}
}
}
</style> </style>
...@@ -44,7 +44,7 @@ const onConfigLoaded = function(config){ ...@@ -44,7 +44,7 @@ const onConfigLoaded = function(config){
store.commit('SET_CONFIG', config); store.commit('SET_CONFIG', config);
setInterval(() => { //* check if navigator is online setInterval(() => { //* check if navigator is online
store.commit('SET_IS_ONLINE', navigator.onLine); store.commit('SET_IS_ONLINE', navigator.onLine);
}, 10000); }, 2000);
// set title and favico // set title and favico
document.title = `${config.VUE_APP_APPLICATION_NAME} ${config.VUE_APP_APPLICATION_ABSTRACT}`; document.title = `${config.VUE_APP_APPLICATION_NAME} ${config.VUE_APP_APPLICATION_ABSTRACT}`;
......
...@@ -51,6 +51,7 @@ const mapService = { ...@@ -51,6 +51,7 @@ const mapService = {
lng, lng,
mapDefaultViewCenter, mapDefaultViewCenter,
mapDefaultViewZoom, mapDefaultViewZoom,
maxZoom,
zoom, zoom,
zoomControl = true, zoomControl = true,
interactions = { doubleClickZoom: false, mouseWheelZoom: false, dragPan: true }, interactions = { doubleClickZoom: false, mouseWheelZoom: false, dragPan: true },
...@@ -60,7 +61,7 @@ const mapService = { ...@@ -60,7 +61,7 @@ const mapService = {
el.innerHTML = ''; el.innerHTML = '';
} }
this.map = new Map({ const mapOptions = {
layers: [], layers: [],
target: el, target: el,
controls: [ controls: [
...@@ -70,14 +71,17 @@ const mapService = { ...@@ -70,14 +71,17 @@ const mapService = {
})], })],
interactions: defaults(interactions), interactions: defaults(interactions),
view: new View({ view: new View({
center: transform([ center: transform([ //* since 0 is considered false, check for number instead of just defined (though boolean will pass through)
!lng ? mapDefaultViewCenter[1] : lng, Number(lng) ? lng : mapDefaultViewCenter[1],
!lat ? mapDefaultViewCenter[0] : lat, Number(lat) ? lat : mapDefaultViewCenter[0],
], 'EPSG:4326', 'EPSG:3857'), ], 'EPSG:4326', 'EPSG:3857'),
zoom: !zoom ? mapDefaultViewZoom : zoom zoom: Number(mapDefaultViewZoom) ? mapDefaultViewZoom : zoom,
maxZoom
}), }),
}); };
this.map = new Map(mapOptions);
if (zoomControl) { if (zoomControl) {
this.map.addControl(new Zoom({ zoomInTipLabel: 'Zoomer', zoomOutTipLabel: 'Dézoomer' })); this.map.addControl(new Zoom({ zoomInTipLabel: 'Zoomer', zoomOutTipLabel: 'Dézoomer' }));
...@@ -557,7 +561,12 @@ const mapService = { ...@@ -557,7 +561,12 @@ const mapService = {
</div> </div>
${author} ${author}
`; `;
const featureId = feature.getProperties ? feature.getProperties().feature_id || feature.getId() : feature.id; //* feature.id was used with leaflet, with ol feature.getId replace it, but keeping it as fallback can prevent regression const featureId =
feature.getId() ?
feature.getId() :
feature.getProperties ?
feature.getProperties().feature_id :
feature.id;
return { html, feature_type, featureId }; return { html, feature_type, featureId };
}, },
......
...@@ -215,7 +215,6 @@ const feature = { ...@@ -215,7 +215,6 @@ const feature = {
params: { params: {
slug_type_signal: rootState['feature-type'].current_feature_type_slug, slug_type_signal: rootState['feature-type'].current_feature_type_slug,
slug_signal: featureId, slug_signal: featureId,
message: routeName === 'ajouter-signalement' ? 'Le signalement a été crée' : 'Le signalement a été mis à jour'
}, },
}); });
}); });
...@@ -232,7 +231,6 @@ const feature = { ...@@ -232,7 +231,6 @@ const feature = {
for (const field of state.extra_forms) { for (const field of state.extra_forms) {
extraFormObject[field.name] = field.value; extraFormObject[field.name] = field.value;
} }
//const feature = state.form || state.currentFeature;
return { return {
id: state.form.feature_id || state.currentFeature.feature_id, id: state.form.feature_id || state.currentFeature.feature_id,
type: 'Feature', type: 'Feature',
......