Mercurial > gemma
changeset 1470:c89a18f8027d bulkreview
Merged back default into bulkreview branch.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Fri, 30 Nov 2018 09:17:03 +0100 |
parents | 286a3306f6bf (current diff) 7fa030127b05 (diff) |
children | 9a0231e6749d |
files | client/src/store/imports.js |
diffstat | 26 files changed, 1047 insertions(+), 402 deletions(-) [+] |
line wrap: on
line diff
--- a/client/docs/developer.md Fri Nov 30 09:15:47 2018 +0100 +++ b/client/docs/developer.md Fri Nov 30 09:17:03 2018 +0100 @@ -101,6 +101,7 @@ - [xgettext fails with some .vue files](https://github.com/Polyconseil/vue-gettext/issues/28) which forces us to use `(`, `)` around templates - [translations in attributes](https://github.com/Polyconseil/vue-gettext/issues/9) which leaves us with either interpolating in templates with `<translate></translate>` or use computed properties in Vue components (cf. Login component). + - [inconsistent white space handling](https://github.com/Polyconseil/vue-gettext/issues/80) if you need a white space preserved before the translated tag, use `<span v-translate class="fix-trans-space">to be translated</a>` (see `src/assets/application.sass`). - Is dependend on external (=non JS) tools (`xgettext`) which are not able to consume `.vue`-files directly, which in turn leads to unexpected behaviour. -
--- a/client/src/assets/application.sass Fri Nov 30 09:15:47 2018 +0100 +++ b/client/src/assets/application.sass Fri Nov 30 09:17:03 2018 +0100 @@ -77,4 +77,15 @@ max-width: 999px margin-left: 0.5rem margin-right: 0.5rem - margin-bottom: 0.5rem + margin-bottom: 1rem + +// needed to fix the whitespace problem of +// https://github.com/Polyconseil/vue-gettext/issues/80 +// use like +// <a href="..">link</a> +// <span v-translate class="fix-trans-space">contributors.</span> +// +// done centrally, so we can fix it centrally for better vue-gettext version +.fix-trans-space + &:before + content: " "
--- a/client/src/components/Sidebar.vue Fri Nov 30 09:15:47 2018 +0100 +++ b/client/src/components/Sidebar.vue Fri Nov 30 09:17:03 2018 +0100 @@ -9,7 +9,7 @@ <div class="menu text-nowrap text-left"> <router-link to="/"> <font-awesome-icon icon="map-marked-alt" fixed-width></font-awesome-icon> - <translate>Map</translate> + <span v-translate class="fix-trans-space">Map</span> </router-link> <a href="#" @@ -17,7 +17,7 @@ :class="['secondary', { active: isActive('bottlenecks') }]" > <font-awesome-icon icon="ship" fixed-width></font-awesome-icon> - <translate>Bottlenecks</translate> + <span v-translate class="fix-trans-space">Bottlenecks</span> </a> <div v-if="isWaterwayAdmin"> <a @@ -26,7 +26,7 @@ :class="['secondary', { active: isActive('imports') }]" > <font-awesome-icon icon="upload" fixed-width></font-awesome-icon> - <translate>Import soundingresults</translate> + <span v-translate class="fix-trans-space">Import soundingresults</span> </a> <a href="#" @@ -34,33 +34,40 @@ :class="['secondary', { active: isActive('staging') }]" > <font-awesome-icon icon="clipboard-check" fixed-width></font-awesome-icon> - <translate>Staging area</translate> + <span v-translate class="fix-trans-space">Staging area</span> </a> - <small class="text-muted pl-3"><translate>Systemadministration</translate></small> + <small class="text-muted pl-3"> + <translate>Systemadministration</translate> + </small> <hr class="m-0"> <router-link to="usermanagement"> <font-awesome-icon icon="users-cog" fixed-width></font-awesome-icon> - <translate>Users</translate> + <span v-translate class="fix-trans-space">Users</span> </router-link> </div> <div v-if="isSysAdmin"> <router-link to="systemconfiguration"> <font-awesome-icon icon="wrench" fixed-width></font-awesome-icon> - <translate>Systemconfiguration</translate> + <span v-translate class="fix-trans-space">Configuration</span> </router-link> <router-link to="logs"> <font-awesome-icon icon="book" fixed-width></font-awesome-icon> - <translate>Logs</translate> + <span v-translate class="fix-trans-space">Logs</span> </router-link> <router-link to="importqueue"> <font-awesome-icon icon="tasks" fixed-width></font-awesome-icon> - <translate>Importqueue</translate> + <span v-translate class="fix-trans-space">Importqueue</span> + </router-link> + <router-link v-if="this.$options.IMPORTSCHEDULE" to="importschedule"> + <font-awesome-icon icon="clock" fixed-width></font-awesome-icon> + <translate>Importschedule</translate> </router-link> </div> <hr class="m-0"> <a href="#" @click="logoff"> <font-awesome-icon icon="power-off" fixed-width></font-awesome-icon> - <translate>Logout</translate> {{ user }} + <span v-translate class="fix-trans-space">Logout</span> + {{ user }} </a> </div> </div> @@ -105,6 +112,7 @@ ]; } }, + IMPORTSCHEDULE: process.env.VUE_APP_FEATURE_IMPORTSCHEDULE, methods: { logoff() { this.$store.commit("reset"); @@ -143,10 +151,8 @@ padding: 0.5rem 1rem color: #333 text-decoration: none - svg - margin-right: 0.5rem - path - fill: #666 + svg path + fill: #666 &:hover background-color: #f8f8f8 &.router-link-exact-active
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/src/components/admin/importschedule/Importschedule.vue Fri Nov 30 09:17:03 2018 +0100 @@ -0,0 +1,157 @@ +<template> + <div class="d-flex flex-row"> + <div :class="spacerStyle"></div> + <div class="mt-3"> + <div class="card schedulecard"> + <div class="card-header shadow-sm text-white bg-info mb-3"> + <translate>Importschedule</translate> + </div> + <div class="card-body schedulecardbody"> + <div class="card-body schedulecardbody"> + <div class="searchandfilter d-flex flex-row"> + <div class="searchgroup input-group"> + <div class="input-group-prepend"> + <span class="input-group-text" id="search"> + <font-awesome-icon icon="search"></font-awesome-icon> + </span> + </div> + <input + v-model="searchQuery" + type="text" + class="form-control" + placeholder + aria-label="Search" + aria-describedby="search" + > + </div> + </div> + <table v-if="schedules.length" class="table"> + <thead> + <tr> + <th> + <translate>Import</translate> + </th> + <th> + <translate>Type</translate> + </th> + <th> + <translate>Author</translate> + </th> + <th> + <translate>Schedule</translate> + </th> + <th> + <translate>Email</translate> + </th> + <th> </th> + <th> </th> + </tr> + </thead> + <tbody> + <tr v-for="(schedule, index) in schedules" :key="index"> + <td></td> + <td></td> + <td></td> + <td></td> + <td></td> + <td> + <font-awesome-icon icon="pencil-alt" fixed-width></font-awesome-icon> + </td> + <td> + <font-awesome-icon @click="deleteSchedule" icon="trash" fixed-width></font-awesome-icon> + </td> + </tr> + </tbody> + </table> + <div v-else class="mt-4 small text-center py-3"> + <translate>No schedules</translate> + </div> + <button @click="newImport" class="btn btn-info position-absolute newbutton"> + <translate>New Import</translate> + </button> + </div> + </div> + </div> + </div> + <Importscheduledetail></Importscheduledetail> + </div> +</template> + +<script> +/* This is Free Software under GNU Affero General Public License v >= 3.0 + * without warranty, see README.md and license for details. + * + * SPDX-License-Identifier: AGPL-3.0-or-later + * License-Filename: LICENSES/AGPL-3.0.txt + * + * Copyright (C) 2018 by via donau + * – Österreichische Wasserstraßen-Gesellschaft mbH + * Software engineering by Intevation GmbH + * + * Author(s): + * Thomas Junk <thomas.junk@intevation.de> + */ + +import { mapState } from "vuex"; +import Importscheduledetail from "./Importscheduledetail"; +//import { SCHEDULES } from "../../store/imports.js"; + +export default { + name: "importschedule", + components: { + Importscheduledetail + }, + data() { + return { + searchQuery: "" + }; + }, + methods: { + newImport() { + this.$store.commit("imports/setImportScheduleDetailVisible"); + }, + deleteSchedule(index) { + this.$store.commit("imports/deleteSchedule", index); + } + }, + computed: { + ...mapState("application", ["showSidebar"]), + ...mapState("imports", ["schedules"]), + spacerStyle() { + return [ + "spacer ml-3", + { + "spacer-expanded": this.showSidebar, + "spacer-collapsed": !this.showSidebar + } + ]; + } + } +}; +</script> + +<style lang="sass" scoped> +.spacer + height: 100vh + +.spacer-collapsed + min-width: $icon-width + $offset + transition: $transition-fast + +.spacer-expanded + min-width: $sidebar-width + $offset + +.schedulecard + width: 40vw + min-height: 20rem + +.schedulecard-body + width: 100% + margin-left: auto + margin-right: aut + +.newbutton + position:absolute + bottom: $offset + right: $offset +</style>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/src/components/admin/importschedule/Importscheduledetail.vue Fri Nov 30 09:17:03 2018 +0100 @@ -0,0 +1,35 @@ +<template> + <div v-if="importScheduleDetailVisible"> + <div class="card"> + <div class="card-header shadow-sm text-white bg-info mb-3"> + <span @click="closeDetailview" class="pull-right"> + <font-awesome-icon icon="times"></font-awesome-icon> + </span> + </div> + <div class="card-body"> + <h1>lalala</h1> + <form @submit.prevent="save" class="ml-3"></form> + </div> + </div> + </div> +</template> + +<script> +import { mapState } from "vuex"; + +export default { + name: "importscheduledetail", + computed: { + ...mapState("imports", ["importScheduleDetailVisible"]) + }, + methods: { + closeDetailview() { + this.$store.commit("imports/clearImportScheduleDetail"); + this.$store.commit("imports/setImportScheduleDetailInvisible"); + } + } +}; +</script> + +<style> +</style>
--- a/client/src/components/admin/usermanagement/Userdetail.vue Fri Nov 30 09:15:47 2018 +0100 +++ b/client/src/components/admin/usermanagement/Userdetail.vue Fri Nov 30 09:17:03 2018 +0100 @@ -11,7 +11,9 @@ <form @submit.prevent="save" class="ml-3"> <div class="formfields"> <div v-if="currentUser.isNew" class="form-group row"> - <label for="user">Username</label> + <label for="user"> + <translate>Username</translate> + </label> <input type="user" :placeholder="userNamePlaceholder" @@ -28,13 +30,17 @@ </div> </div> <div class="form-group row"> - <label for="country">Country</label> + <label for="country"> + <translate>Country</translate> + </label> <select class="form-control form-control-sm" v-on:change="validateCountry" v-model="currentUser.country" > - <option disabled value>Please select one</option> + <option disabled value> + <translate>Please select one</translate> + </option> <option v-for="country in countries" v-bind:value="country" @@ -49,7 +55,9 @@ </div> </div> <div class="form-group row"> - <label for="email">Email address</label> + <label for="email"> + <translate>Email address</translate> + </label> <input type="email" v-on:change="validateEmailaddress" @@ -66,16 +74,26 @@ </div> </div> <div class="form-group row"> - <label for="role">Role</label> + <label for="role"> + <translate>Role</translate> + </label> <select class="form-control form-control-sm" v-on:change="validateRole" v-model="currentUser.role" > - <option disabled value>Please select one</option> - <option value="sys_admin">Sysadmin</option> - <option value="waterway_admin">Waterway Admin</option> - <option value="waterway_user">Waterway User</option> + <option disabled value> + <translate>Please select one</translate> + </option> + <option value="sys_admin"> + <translate>Sysadmin</translate> + </option> + <option value="waterway_admin"> + <translate>Waterway Admin</translate> + </option> + <option value="waterway_user"> + <translate>Waterway User</translate> + </option> </select> <div v-show="errors.role" class="text-danger"> <small> @@ -102,20 +120,21 @@ </div> </div> <div> - <button - type="submit" - :disabled="submitted" - class="shadow-sm btn btn-info pull-right" - >Submit</button> + <button type="submit" :disabled="submitted" class="shadow-sm btn btn-info pull-right"> + <translate>Submit</translate> + </button> </div> <div v-if="currentUser.role !='waterway_user' " class="form-group row d-flex flex-row justify-content-start mailbutton" > <a @click="sendTestMail" class="btn btn-light"> - <font-awesome-icon icon="paper-plane"></font-awesome-icon>Send testmail + <font-awesome-icon icon="paper-plane"></font-awesome-icon> + <translate>Send testmail</translate> </a> - <div v-if="mailsent">Mail was sent</div> + <div v-if="mailsent"> + <translate>Mail was sent</translate> + </div> </div> </form> </div>
--- a/client/src/components/admin/usermanagement/Usermanagement.vue Fri Nov 30 09:15:47 2018 +0100 +++ b/client/src/components/admin/usermanagement/Usermanagement.vue Fri Nov 30 09:17:03 2018 +0100 @@ -5,7 +5,9 @@ <div class="d-flex flex-row"> <div :class="userlistStyle"> <div class="card"> - <div class="card-header shadow-sm text-white bg-info mb-3">Users</div> + <div class="card-header shadow-sm text-white bg-info mb-3"> + <translate>Users</translate> + </div> <div class="card-body"> <table id="datatable" :class="tableStyle"> <thead> @@ -66,7 +68,9 @@ </button> </div> <div class="mr-3 pb-3"> - <button @click="addUser " class="btn btn-info pull-right shadow-sm">Add User</button> + <button @click="addUser " class="btn btn-info pull-right shadow-sm"> + <translate>Add User</translate> + </button> </div> </div> </div>
--- a/client/src/components/map/Identify.vue Fri Nov 30 09:15:47 2018 +0100 +++ b/client/src/components/map/Identify.vue Fri Nov 30 09:17:03 2018 +0100 @@ -1,54 +1,59 @@ <template> - <div :class="['box ui-element rounded bg-white text-nowrap', { expanded: showIdentify }]"> - <div style="width: 20rem"> - <h6 class="mb-0 py-2 px-3 border-bottom d-flex align-items-center"> - <font-awesome-icon icon="info" class="mr-2"></font-awesome-icon> - <translate>Identified</translate> - <font-awesome-icon - icon="times" - class="ml-auto text-muted" - @click="$store.commit('application/showIdentify', false)" - ></font-awesome-icon> - </h6> - <div class="d-flex flex-column features p-3 flex-grow-1 text-left"> - <div v-if="currentMeasurement"> - <b> - {{ currentMeasurement.quantity }} - ({{ currentMeasurement.unitSymbol }}): - </b><br> - <small>{{ currentMeasurement.value }}</small> - </div> - <div v-for="(feature, i) of identifiedFeatures" :key="feature.getId()" > - <div v-if="feature.getId()" :class="{ 'mt-2': i }"> - <b>{{ feature.getId().replace(/[.][^.]*$/,"") /* cut away everything from the last . to the end */}}:</b> - <small - v-for="(value, key) in prepareProperties(feature)" - :key="key" - > - <div v-if="value">{{key}}:{{value}}</div> - </small> - </div> - </div> - <div v-if="!currentMeasurement && !identifiedFeatures.length" class="text-muted small text-center my-auto"> - <translate>No features identified.</translate> - </div> - </div> - <div class="versioninfo border-top p-3 text-left"> - <translate>This app uses </translate><i>gemma</i>,<translate> which is Free Software under</translate> - <br> - AGPL-3.0-or-later - <translate> without warranty, see docs for details.</translate><br> + <div :class="['box ui-element rounded bg-white text-nowrap', { expanded: showIdentify }]"> + <div style="width: 20rem"> + <h6 class="mb-0 py-2 px-3 border-bottom d-flex align-items-center"> + <font-awesome-icon icon="info" class="mr-2"></font-awesome-icon> + <translate>Identified</translate> + <font-awesome-icon + icon="times" + class="ml-auto text-muted" + @click="$store.commit('application/showIdentify', false)" + ></font-awesome-icon> + </h6> + <div class="d-flex flex-column features p-3 flex-grow-1 text-left"> + <div v-if="currentMeasurement"> + <b> + {{ currentMeasurement.quantity }} + ({{ currentMeasurement.unitSymbol }}): + </b> + <br> + <small>{{ currentMeasurement.value }}</small> + </div> + <div v-for="(feature, i) of identifiedFeatures" :key="feature.getId()"> + <div v-if="feature.getId()" :class="{ 'mt-2': i }"> + <b>{{ feature.getId().replace(/[.][^.]*$/,"") /* cut away everything from the last . to the end */}}:</b> + <small v-for="(value, key) in prepareProperties(feature)" :key="key"> + <div v-if="value">{{key}}:{{value}}</div> + </small> + </div> + </div> + <div + v-if="!currentMeasurement && !identifiedFeatures.length" + class="text-muted small text-center my-auto" + > + <translate>No features identified.</translate> + </div> + </div> + <div class="versioninfo border-top p-3 text-left"> + <translate>This app uses</translate> + <i>gemma</i>, + <translate>which is Free Software under</translate> + <br>AGPL-3.0-or-later + <translate>without warranty, see docs for details.</translate> + <br> - <a href="https://hg.intevation.de/gemma/file/tip"><translate>source-code</translate></a> - {{ versionStr }} - <br> - © via donau. ⓔ Intevation. - <br><translate>Some data </translate>© - <a href="https://www.openstreetmap.org/copyright">OpenSteetMap</a> - <translate>contributors.</translate> - </div> - </div> + <a href="https://hg.intevation.de/gemma/file/tip"> + <translate>source-code</translate> + </a> + {{ versionStr }} + <br>© via donau. ⓔ Intevation. + <br> + <translate>Some data</translate>© + <a href="https://www.openstreetmap.org/copyright">OpenSteetMap</a> + <span v-translate class="fix-trans-space">contributors.</span> + </div> </div> + </div> </template> <style lang="sass" scoped> @@ -58,7 +63,7 @@ .versioninfo font-size: 60% - white-space:normal + white-space: normal </style> <script>
--- a/client/src/components/map/Maplayer.vue Fri Nov 30 09:15:47 2018 +0100 +++ b/client/src/components/map/Maplayer.vue Fri Nov 30 09:17:03 2018 +0100 @@ -43,7 +43,6 @@ import { Map, View } from "ol"; import { WFS, GeoJSON } from "ol/format.js"; import { Stroke, Style, Fill } from "ol/style.js"; -import { getCenter } from "ol/extent"; /* for the sake of debugging */ /* eslint-disable no-console */ @@ -55,7 +54,7 @@ }; }, computed: { - ...mapGetters("map", ["getLayerByName"]), + ...mapGetters("map", ["getLayerByName", "getVSourceByName"]), ...mapState("map", [ "extent", "layers", @@ -82,68 +81,6 @@ } }, methods: { - identify(coordinate, pixel) { - if (!this.hasActiveInteractions) { - this.$store.commit("map/setIdentifiedFeatures", []); - // checking our WFS layers - var features = this.openLayersMap.getFeaturesAtPixel(pixel); - if (features) { - this.$store.commit("map/setIdentifiedFeatures", features); - - // get selected bottleneck from identified features - for (let feature of features) { - let id = feature.getId(); - // RegExp.prototype.test() works with number, str and undefined - if (/^bottlenecks\./.test(id)) { - this.$store.dispatch( - "bottlenecks/setSelectedBottleneck", - feature.get("objnam") - ); - this.$store.commit("map/moveMap", { - coordinates: getCenter( - feature - .getGeometry() - .clone() - .transform("EPSG:3857", "EPSG:4326") - .getExtent() - ), - zoom: 17, - preventZoomOut: true - }); - } - } - } - - // DEBUG output and example how to remove the GeometryName - /* - for (let feature of features) { - console.log("Identified:", feature.getId()); - for (let key of feature.getKeys()) { - if (key != feature.getGeometryName()) { - console.log(key, feature.get(key)); - } - } - } - */ - - // trying the GetFeatureInfo way for WMS - var wmsSource = this.getLayerByName( - "Inland ECDIS chart Danube" - ).data.getSource(); - var url = wmsSource.getGetFeatureInfoUrl( - coordinate, - 100 /* resolution */, - "EPSG:3857", - // { INFO_FORMAT: "application/vnd.ogc.gml" } // not allowed by d4d - { INFO_FORMAT: "text/plain" } - ); - - if (url) { - // cannot directly query here because of SOP - console.log("GetFeatureInfo url:", url); - } - } - }, buildVectorLoader(featureRequestOptions, endpoint, vectorSource) { // build a function to be used for VectorSource.setLoader() // make use of WFS().writeGetFeature to build the request @@ -189,10 +126,11 @@ }, updateBottleneckFilter(bottleneck_id, datestr) { console.log("updating filter with", bottleneck_id, datestr); - var layer = this.getLayerByName("Bottleneck isolines"); - var wmsSrc = layer.data.getSource(); + const layer = this.getLayerByName("Bottleneck isolines"); + const wmsSrc = layer.data.getSource(); + const exists = bottleneck_id != "does_not_exist"; - if (bottleneck_id != "does_not_exist") { + if (exists) { wmsSrc.updateParams({ cql_filter: "date_info='" + @@ -201,12 +139,9 @@ bottleneck_id + "'" }); - layer.isVisible = true; - layer.data.setVisible(true); - } else { - layer.isVisible = false; - layer.data.setVisible(false); } + layer.isVisible = exists; + layer.data.setVisible(exists); }, onBeforePrint(/* evt */) { // console.log("onBeforePrint(", evt ,")"); @@ -300,11 +235,9 @@ } } ).then(response => { - var features = new GeoJSON().readFeatures(JSON.stringify(response.data)); - var vectorSrc = this.getLayerByName( - "Fairway Dimensions" - ).data.getSource(); - vectorSrc.addFeatures(features); + this.getVSourceByName("Fairway Dimensions").addFeatures( + new GeoJSON().readFeatures(JSON.stringify(response.data)) + ); // would scale to the extend of all resulting features // this.openLayersMap.getView().fit(vectorSrc.getExtent()); }); @@ -430,9 +363,7 @@ // so none is shown this.updateBottleneckFilter("does_not_exist", "1999-10-01"); - this.openLayersMap.on(["singleclick", "dblclick"], event => { - this.identify(event.coordinate, event.pixel); - }); + this.$store.dispatch("map/enableIdentifyTool"); this.$store.dispatch("bottlenecks/loadBottlenecks"); } };
--- a/client/src/components/map/Pdftool.vue Fri Nov 30 09:15:47 2018 +0100 +++ b/client/src/components/map/Pdftool.vue Fri Nov 30 09:17:03 2018 +0100 @@ -23,7 +23,7 @@ v-model="form.downloadType" selected > - <label for="pdfexport-downloadtype-download" class="ml-1 mr-2"><translate>Dvownload</translate></label> + <label for="pdfexport-downloadtype-download" class="ml-1 mr-2"><translate>Download</translate></label> <input type="radio" id="pdfexport-downloadtype-open"
--- a/client/src/components/map/Search.vue Fri Nov 30 09:15:47 2018 +0100 +++ b/client/src/components/map/Search.vue Fri Nov 30 09:17:03 2018 +0100 @@ -5,7 +5,7 @@ <font-awesome-icon icon="search"></font-awesome-icon> </span> </div> - <div :class="['searchgroup', {'searchgroup-collapsed': !showSearchbar}]"> + <div :class="['searchgroup', {'searchgroup-collapsed': !showSearchbar, big: showContextBox && ['bottlenecks', 'staging'].indexOf(contextBoxContent) !== -1 }]"> <input @keyup.enter="takeFirstSearchresult" id="search" @@ -40,8 +40,10 @@ .searchgroup margin-left: -3px transition: width 0.3s - width: 571px + width: 300px overflow: hidden + &.big + width: 571px .searchgroup-collapsed width: 0
--- a/client/src/components/map/contextbox/Bottlenecks.vue Fri Nov 30 09:15:47 2018 +0100 +++ b/client/src/components/map/contextbox/Bottlenecks.vue Fri Nov 30 09:17:03 2018 +0100 @@ -28,32 +28,36 @@ <div v-for="bottleneck in filteredAndSortedBottlenecks()" :key="bottleneck.properties.name" - class="border-top row mx-0 py-2" + class="border-top row bottleneck-row mx-0" > - <div class="col-5 text-left"> + <div class="col-5 py-2 text-left"> <a href="#" - class="d-block" - @click="moveToBottleneck(bottleneck)" + @click="selectBottleneck(bottleneck)" >{{ bottleneck.properties.name }}</a> </div> - <div class="col-2">{{ displayCurrentSurvey(bottleneck.properties.current) }}</div> - <div - class="col-3" - >{{ displayCurrentChainage(bottleneck.properties.from, bottleneck.properties.from) }}</div> - <div class="col-2 text-right"> + <div class="col-2 py-2"> + {{ displayCurrentSurvey(bottleneck.properties.current) }} + </div> + <div class="col-3 py-2"> + {{ displayCurrentChainage(bottleneck.properties.from, bottleneck.properties.from) }} + </div> + <div class="col-2 pr-0 text-right"> <button type="button" - class="btn btn-sm btn-info" - @click="toggleBottleneck(bottleneck.properties.name)" + class="btn btn-sm btn-info rounded-0 h-100" + @click="loadSurveys(bottleneck.properties.name)" + v-if="bottleneck.properties.current" > - <font-awesome-icon icon="angle-down"></font-awesome-icon> + <font-awesome-icon icon="spinner" fixed-width spin v-if="loading === bottleneck.properties.name"></font-awesome-icon> + <font-awesome-icon icon="angle-down" fixed-width v-if="loading !== bottleneck.properties.name && openBottleneck !== bottleneck.properties.name"></font-awesome-icon> + <font-awesome-icon icon="angle-up" fixed-width v-if="loading !== bottleneck.properties.name && openBottleneck === bottleneck.properties.name"></font-awesome-icon> </button> </div> - <div :class="['col-12', 'surveys', {open: openBottleneck === bottleneck.properties.name}]"> + <div :class="['col-12 p-0', 'surveys', {open: openBottleneck === bottleneck.properties.name}]"> <a href="#" - class="d-block p-2" + class="d-block px-3 py-2" v-for="(survey, index) in openBottleneckSurveys" :key="index" @click="selectSurvey(survey, bottleneck)" @@ -90,7 +94,8 @@ sortColumn: "name", sortDirection: "ASC", openBottleneck: null, - openBottleneckSurveys: null + openBottleneckSurveys: null, + loading: null }; }, computed: { @@ -154,14 +159,14 @@ }); }, selectSurvey(survey, bottleneck) { + this.selectBottleneck(bottleneck); + this.$store.commit("bottlenecks/selectedSurvey", survey); + }, + selectBottleneck(bottleneck) { this.$store.dispatch( "bottlenecks/setSelectedBottleneck", bottleneck.properties.name ); - this.$store.commit("bottlenecks/selectedSurvey", survey); - this.moveToBottleneck(bottleneck); - }, - moveToBottleneck(bottleneck) { this.$store.commit("map/moveMap", { coordinates: bottleneck.geometry.coordinates, zoom: 17, @@ -172,12 +177,13 @@ this.sortColumn = column; this.sortDirection = this.sortDirection === "ASC" ? "DESC" : "ASC"; }, - toggleBottleneck(name) { + loadSurveys(name) { this.openBottleneckSurveys = null; if (name === this.openBottleneck) { this.openBottleneck = null; } else { this.openBottleneck = name; + this.loading = name; HTTP.get("/surveys/" + name, { headers: { @@ -186,7 +192,9 @@ } }) .then(response => { - this.openBottleneckSurveys = response.data.surveys; + this.openBottleneckSurveys = response.data.surveys.sort( + (a, b) => (a.date_info < b.date_info ? 1 : -1) + ); }) .catch(error => { const { status, data } = error.response; @@ -194,7 +202,8 @@ title: "Backend Error", message: `${status}: ${data.message || data}` }); - }); + }) + .finally(() => (this.loading = null)); } }, displayCurrentSurvey(current) { @@ -213,14 +222,23 @@ <style lang="sass" scoped> .bottleneck-list overflow-y: auto + .bottleneck-row + a + text-decoration: none + &:hover + background: #fbfbfb .surveys max-height: 0 + min-height: 0 overflow: hidden - transition: max-height 0.3s ease + a + &:hover + background: #f3f3f3 .surveys.open - max-height: 999px + max-height: 250px + overflow: auto .sort-link color: #444
--- a/client/src/components/map/fairway/Fairwayprofile.vue Fri Nov 30 09:15:47 2018 +0100 +++ b/client/src/components/map/fairway/Fairwayprofile.vue Fri Nov 30 09:17:03 2018 +0100 @@ -109,7 +109,6 @@ }; }, computed: { - ...mapGetters("map", ["getLayerByName"]), ...mapGetters("fairwayprofile", ["totalLength"]), ...mapState("application", ["showSplitscreen"]), ...mapState("fairwayprofile", [ @@ -122,7 +121,6 @@ "fairwayCoordinates", "waterLevels", "selectedWaterLevel", - "previousCuts", "profileLoading" ]), ...mapState("bottlenecks", [
--- a/client/src/components/map/fairway/Profiles.vue Fri Nov 30 09:15:47 2018 +0100 +++ b/client/src/components/map/fairway/Profiles.vue Fri Nov 30 09:17:03 2018 +0100 @@ -3,7 +3,7 @@ <div style="width: 20rem"> <h6 class="mb-0 py-2 px-3 border-bottom d-flex align-items-center"> <font-awesome-icon icon="chart-area" class="mr-2"></font-awesome-icon> - Profiles + <translate>Profiles</translate> <font-awesome-icon icon="times" class="ml-auto text-muted" @@ -11,11 +11,20 @@ ></font-awesome-icon> </h6> <div class="d-flex flex-column p-3 flex-grow-1 text-left position-relative"> - <div class="loading d-flex justify-content-center align-items-center" v-if="surveysLoading || profileLoading"> - <font-awesome-icon icon="spinner" spin /> + <div + class="loading d-flex justify-content-center align-items-center" + v-if="surveysLoading || profileLoading" + > + <font-awesome-icon icon="spinner" spin/> </div> - <select @click="moveToBottleneck" v-model="selectedBottleneck" class="form-control font-weight-bold"> - <option :value="null">Select Bottleneck</option> + <select + @click="moveToBottleneck" + v-model="selectedBottleneck" + class="form-control font-weight-bold" + > + <option :value="null"> + <translate>Select Bottleneck</translate> + </option> <option v-for="bn in bottlenecks" :key="bn.properties.name" @@ -25,7 +34,9 @@ <div v-if="selectedBottleneck"> <div class="d-flex mt-2"> <div class="flex-fill"> - <small class="text-muted">Sounding Result:</small> + <small class="text-muted"> + <translate>Sounding Result</translate>: + </small> <select v-model="selectedSurvey" class="form-control form-control-sm"> <option v-for="survey in surveys" @@ -35,7 +46,9 @@ </select> </div> <div class="flex-fill ml-3" v-if="selectedSurvey && surveys.length > 1"> - <small class="text-muted mt-1">Compare with:</small> + <small class="text-muted mt-1"> + <translate>Compare with</translate>: + </small> <select v-model="additionalSurvey" class="form-control form-control-sm"> <option :value="null">None</option> <option @@ -47,43 +60,62 @@ </div> </div> <hr class="w-100 mb-0"> - <small class="text-muted d-block mt-2">Saved cross profiles:</small> + <small class="text-muted d-block mt-2"> + <translate>Saved cross profiles</translate>: + </small> <div class="d-flex"> - <select :class="['form-control form-control-sm flex-fill', { 'rounded-left-only': selectedCut }]" v-model="selectedCut"> + <select + :class="['form-control form-control-sm flex-fill', { 'rounded-left-only': selectedCut }]" + v-model="selectedCut" + > <option></option> - <option v-for="(cut, index) in previousCuts" :value="cut" :key="index"> - {{ cut.label }} - </option> + <option v-for="(cut, index) in previousCuts" :value="cut" :key="index">{{ cut.label }}</option> </select> <button class="btn btn-sm btn-danger input-button-right" @click="confirmDeleteSelectedCut = true" v-if="selectedCut && !confirmDeleteSelectedCut" - ><font-awesome-icon icon="trash" /></button> + > + <font-awesome-icon icon="trash"/> + </button> <button class="btn btn-sm btn-info rounded-0" @click="confirmDeleteSelectedCut = false" v-if="selectedCut && confirmDeleteSelectedCut" - ><font-awesome-icon icon="times" /></button> + > + <font-awesome-icon icon="times"/> + </button> <button class="btn btn-sm btn-danger input-button-right" @click="deleteSelectedCut" v-if="selectedCut && confirmDeleteSelectedCut" - ><font-awesome-icon icon="check" /></button> + > + <font-awesome-icon icon="check"/> + </button> </div> - <small class="text-muted d-block mt-2">Enter coordinates manually:</small> + <small class="text-muted d-block mt-2"> + <translate>Enter coordinates manually</translate>: + </small> <div class="position-relative"> - <input class="form-control form-control-sm pr-5" placeholder="Lat,Lon,Lat,Lon" v-model="coordinatesInput" /> + <input + class="form-control form-control-sm pr-5" + placeholder="Lat,Lon,Lat,Lon" + v-model="coordinatesInput" + > <button - class="btn btn-sm btn-info position-absolute input-button-right" + class="btn btn-sm btn-info position-absolute input-button-right" @click="applyManualCoordinates" style="top: 0; right: 0;" v-if="coordinatesInputIsValid" - ><font-awesome-icon icon="check" /></button> + > + <font-awesome-icon icon="check"/> + </button> </div> <small class="d-flex text-left mt-2" v-if="startPoint && endPoint"> <div class="text-nowrap mr-3"> - <b>Start:</b> + <b> + <translate>Start</translate>: + </b> <br> Lat: {{ startPoint[1] }} <br> @@ -96,41 +128,42 @@ <br> Lon: {{ endPoint[0] }} </div> - <button v-clipboard:copy="coordinatesForClipboard" + <button + v-clipboard:copy="coordinatesForClipboard" v-clipboard:success="onCopyCoordinates" class="btn btn-info btn-sm ml-auto mt-auto" - ><font-awesome-icon icon="copy" /></button> + > + <font-awesome-icon icon="copy"/> + </button> </small> <div class="d-flex mt-3"> <div class="pr-3 w-50" v-if="startPoint && endPoint && !selectedCut"> - <button - class="btn btn-info btn-sm w-100" - @click="showLabelInput = !showLabelInput" - > - <font-awesome-icon :icon="showLabelInput ? 'times' : 'check'" /> + <button class="btn btn-info btn-sm w-100" @click="showLabelInput = !showLabelInput"> + <font-awesome-icon :icon="showLabelInput ? 'times' : 'check'"/> {{ showLabelInput ? "Cancel" : "Save" }} </button> </div> <div :class="startPoint && endPoint && !selectedCut ? 'w-50' : 'w-100'"> - <button - class="btn btn-info btn-sm w-100" - @click="toggleCutTool" - > + <button class="btn btn-info btn-sm w-100" @click="toggleCutTool"> <font-awesome-icon :icon="cutTool && cutTool.getActive() ? 'times' : 'plus'"></font-awesome-icon> {{ cutTool && cutTool.getActive() ? "Cancel" : "New" }} </button> </div> </div> <div v-if="showLabelInput" class="mt-2"> - <small class="text-muted">Enter label for cross profile:</small> + <small class="text-muted"> + <translate>Enter label for cross profile</translate>: + </small> <div class="position-relative"> - <input class="form-control form-control-sm pr-5" v-model="cutLabel" /> + <input class="form-control form-control-sm pr-5" v-model="cutLabel"> <button class="btn btn-sm btn-info position-absolute input-button-right" @click="saveCut" v-if="cutLabel" style="top: 0; right: 0;" - ><font-awesome-icon icon="check" /></button> + > + <font-awesome-icon icon="check"/> + </button> </div> </div> </div> @@ -160,7 +193,7 @@ border-bottom-right-radius: 0 !important border-top-left-radius: $border-radius border-bottom-left-radius: $border-radius - + </style> <script> @@ -170,7 +203,7 @@ * SPDX-License-Identifier: AGPL-3.0-or-later * License-Filename: LICENSES/AGPL-3.0.txt * - * Copyright (C) 2018 by via donau + * Copyright (C) 2018 by via donau * – Österreichische Wasserstraßen-Gesellschaft mbH * Software engineering by Intevation GmbH * @@ -299,6 +332,13 @@ this.lineTool.setActive(false); this.polygonTool.setActive(false); this.$store.commit("map/setCurrentMeasurement", null); + + // toggle identifyTool (map events singleclick and dblclick) + this.$store.dispatch( + this.cutTool.getActive() + ? "map/disableIdentifyTool" + : "map/enableIdentifyTool" + ); } }, onCopyCoordinates() {
--- a/client/src/components/map/toolbar/Identify.vue Fri Nov 30 09:15:47 2018 +0100 +++ b/client/src/components/map/toolbar/Identify.vue Fri Nov 30 09:17:03 2018 +0100 @@ -1,6 +1,9 @@ <template> <div @click="$store.commit('application/showIdentify', !showIdentify)" class="toolbar-button"> <font-awesome-icon icon="info" :class="{'text-info': showIdentify}"></font-awesome-icon> + <span :class="['indicator', { show: !showIdentify && (identifiedFeatures.length || currentMeasurement) }]"> + {{ badgeCount }} + </span> </div> </template> @@ -23,7 +26,11 @@ export default { name: "identify", computed: { - ...mapState("application", ["showIdentify"]) + ...mapState("application", ["showIdentify"]), + ...mapState("map", ["identifiedFeatures", "currentMeasurement"]), + badgeCount() { + return this.identifiedFeatures.length + !!this.currentMeasurement; + } } }; </script>
--- a/client/src/components/map/toolbar/Linetool.vue Fri Nov 30 09:15:47 2018 +0100 +++ b/client/src/components/map/toolbar/Linetool.vue Fri Nov 30 09:17:03 2018 +0100 @@ -32,9 +32,7 @@ this.polygonTool.setActive(false); this.cutTool.setActive(false); this.$store.commit("map/setCurrentMeasurement", null); - this.getLayerByName("Draw Tool") - .data.getSource() - .clear(); + this.getVSourceByName("Draw Tool").clear(); } } };
--- a/client/src/components/map/toolbar/Polygontool.vue Fri Nov 30 09:15:47 2018 +0100 +++ b/client/src/components/map/toolbar/Polygontool.vue Fri Nov 30 09:17:03 2018 +0100 @@ -32,9 +32,7 @@ this.lineTool.setActive(false); this.cutTool.setActive(false); this.$store.commit("map/setCurrentMeasurement", null); - this.getLayerByName("Draw Tool") - .data.getSource() - .clear(); + this.getVSourceByName("Draw Tool").clear(); } } };
--- a/client/src/components/map/toolbar/Profiles.vue Fri Nov 30 09:15:47 2018 +0100 +++ b/client/src/components/map/toolbar/Profiles.vue Fri Nov 30 09:17:03 2018 +0100 @@ -1,5 +1,5 @@ <template> - <div @click="$store.commit('application/showProfiles', !showProfiles)" class="toolbar-button"> + <div @click="$store.commit('application/showProfiles', !showProfiles)" class="toolbar-button border-0"> <font-awesome-icon icon="chart-area" :class="{ 'text-info': showProfiles }"></font-awesome-icon> </div> </template>
--- a/client/src/components/map/toolbar/Toolbar.vue Fri Nov 30 09:15:47 2018 +0100 +++ b/client/src/components/map/toolbar/Toolbar.vue Fri Nov 30 09:17:03 2018 +0100 @@ -1,28 +1,29 @@ <template> - <div class="ml-2"> - <div :class="'toolbar toolbar-' + (expandToolbar ? 'expanded' : 'collapsed')"> - <Identify></Identify> - <Layers></Layers> - <Profiles></Profiles> - <Linetool></Linetool> - <Polygontool></Polygontool> - <Pdftool></Pdftool> - </div> - <div @click="$store.commit('application/expandToolbar', !expandToolbar)" class="toolbar-button bg-info text-white"> - <font-awesome-icon :icon="expandToolbar ? 'angle-up' : 'angle-down'"></font-awesome-icon> - </div> - </div> + <div :class="'ml-2 toolbar toolbar-' + (expandToolbar ? 'expanded' : 'collapsed')"> + <Identify></Identify> + <Layers></Layers> + <Profiles></Profiles> + <div @click="$store.commit('application/expandToolbar', !expandToolbar)" class="toolbar-button toolbar-toggle bg-info text-white"> + <font-awesome-icon :icon="expandToolbar ? 'angle-up' : 'angle-down'"></font-awesome-icon> + </div> + <Linetool></Linetool> + <Polygontool></Polygontool> + <Pdftool></Pdftool> + </div> </template> <style lang="sass"> // not scoped to affect nested components // doen't work when put in application/assets/application.sass... why??? o_O .toolbar + box-shadow: $shadow-xs overflow: hidden transition: max-height 0.4s + margin-bottom: auto + border-radius: $border-radius .toolbar-collapsed - max-height: (3 * $icon-height) + (3 * $offset) + max-height: (3 * $icon-height) + 1.2rem .toolbar-expanded max-height: 100% @@ -36,15 +37,35 @@ justify-content: center display: flex background: #fff - margin-bottom: $offset - border-radius: $border-radius - box-shadow: $shadow-xs + border-bottom: 1px solid #dee2e6 z-index: 2 pointer-events: auto + position: relative + overflow: hidden + &:last-child + border-bottom: none .inverted color: $color-info .grey color: #ddd + .indicator + color: #fff + background: $color-info + position: absolute + bottom: -14px + left: -14px + padding: 2px 4px 1px + font-size: 11px + line-height: 11px + border-top-right-radius: $border-radius + transition: bottom 0.3s, left 0.3s + &.show + left: 0 + bottom: 0 + +.toolbar-toggle + height: 1.2rem + border-bottom: none </style> <script> @@ -74,7 +95,7 @@ Pdftool: () => import("./Pdftool.vue") }, computed: { - ...mapGetters("map", ["getLayerByName"]), + ...mapGetters("map", ["getVSourceByName"]), ...mapState("map", ["lineTool", "polygonTool", "cutTool"]), ...mapState("application", ["expandToolbar"]) }, @@ -86,9 +107,8 @@ this.polygonTool.setActive(false); this.cutTool.setActive(false); this.$store.commit("map/setCurrentMeasurement", null); - this.getLayerByName("Draw Tool") - .data.getSource() - .clear(); + this.$store.dispatch("map/enableIdentifyTool"); + this.getVSourceByName("Draw Tool").clear(); } }); }
--- a/client/src/locale/de_AT/LC_MESSAGES/app.po Fri Nov 30 09:15:47 2018 +0100 +++ b/client/src/locale/de_AT/LC_MESSAGES/app.po Fri Nov 30 09:17:03 2018 +0100 @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: wamosjs 0.1.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-28 17:09+0100\n" +"POT-Creation-Date: 2018-11-29 17:47+0100\n" "PO-Revision-Date: 2018-07-03 17:00+0200\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" @@ -26,11 +26,19 @@ msgid "Accesslog" msgstr "" +#: src/components/admin/usermanagement/Usermanagement.vue:71 +msgid "Add User" +msgstr "" + +#: src/components/admin/importschedule/Importschedule.vue:37 +msgid "Author" +msgstr "" + #: src/components/Login.vue:59 msgid "back to login" msgstr "" -#: src/components/map/contextbox/ImportSoundingresults.vue:9 +#: src/components/map/contextbox/ImportSoundingresults.vue:11 msgid "Bottleneck" msgstr "" @@ -47,7 +55,7 @@ msgid "Bottlenecks" msgstr "Engstellen" -#: src/components/map/contextbox/ImportSoundingresults.vue:87 +#: src/components/map/contextbox/ImportSoundingresults.vue:110 msgid "Cancel Upload" msgstr "" @@ -59,34 +67,62 @@ msgid "Chose format:" msgstr "" -#: src/components/map/contextbox/Staging.vue:54 +#: src/components/map/fairway/Profiles.vue:49 +msgid "Compare with" +msgstr "" + +#: src/components/Sidebar.vue:50 +msgid "Configuration" +msgstr "" + +#: src/components/map/contextbox/Staging.vue:65 msgid "Confirm" msgstr "" -#: src/components/map/Identify.vue:47 +#: src/components/map/Identify.vue:52 msgid "contributors." msgstr "" -#: src/components/map/contextbox/ImportSoundingresults.vue:22 +#: src/components/admin/usermanagement/Userdetail.vue:33 +msgid "Country" +msgstr "" + +#: src/components/map/contextbox/Staging.vue:16 msgid "Date" msgstr "" -#: src/components/map/contextbox/ImportSoundingresults.vue:39 +#: src/components/map/contextbox/ImportSoundingresults.vue:42 msgid "Depthreference" msgstr "" -#: src/components/map/contextbox/ImportSoundingresults.vue:81 +#: src/components/map/Pdftool.vue:25 msgid "Download" msgstr "" -#: src/components/map/Pdftool.vue:25 -msgid "Dvownload" +#: src/components/map/contextbox/ImportSoundingresults.vue:107 +msgid "Download Meta.json" +msgstr "" + +#: src/components/admin/importschedule/Importschedule.vue:43 +msgid "Email" +msgstr "" + +#: src/components/admin/usermanagement/Userdetail.vue:58 +msgid "Email address" msgstr "" #: src/components/admin/Importqueue.vue:35 msgid "Enqueued" msgstr "" +#: src/components/map/fairway/Profiles.vue:96 +msgid "Enter coordinates manually" +msgstr "" + +#: src/components/map/fairway/Profiles.vue:154 +msgid "Enter label for cross profile" +msgstr "" + #: src/components/Login.vue:141 msgid "Enter passphrase" msgstr "Passphrase" @@ -116,20 +152,31 @@ msgid "Identified" msgstr "" -#: src/components/map/contextbox/ImportSoundingresults.vue:3 -msgid "" -"Import\n" -" Soundingresults" +#: src/components/admin/importschedule/Importschedule.vue:31 +msgid "Import" msgstr "" #: src/components/Sidebar.vue:28 msgid "Import soundingresults" msgstr "" -#: src/components/Sidebar.vue:56 src/components/admin/Importqueue.vue:5 +#: src/components/map/contextbox/ImportSoundingresults.vue:4 +msgid "Import Soundingresults" +msgstr "" + +#: src/components/map/contextbox/Staging.vue:19 +msgid "Imported" +msgstr "" + +#: src/components/Sidebar.vue:58 src/components/admin/Importqueue.vue:5 msgid "Importqueue" msgstr "" +#: src/components/Sidebar.vue:62 +#: src/components/admin/importschedule/Importschedule.vue:6 +msgid "Importschedule" +msgstr "" + #: src/components/admin/Importqueue.vue:36 msgid "Kind" msgstr "" @@ -158,14 +205,18 @@ msgid "Login failed" msgstr "Login fehlgeschlagen" -#: src/components/Sidebar.vue:62 +#: src/components/Sidebar.vue:68 msgid "Logout" msgstr "" -#: src/components/Sidebar.vue:52 +#: src/components/Sidebar.vue:54 msgid "Logs" msgstr "" +#: src/components/admin/usermanagement/Userdetail.vue:135 +msgid "Mail was sent" +msgstr "" + #: src/components/Sidebar.vue:11 msgid "Map" msgstr "Karte" @@ -175,18 +226,27 @@ msgstr "" #: src/components/map/contextbox/Bottlenecks.vue:7 +#: src/components/map/contextbox/Staging.vue:10 msgid "Name" msgstr "" -#: src/components/map/Identify.vue:32 +#: src/components/admin/importschedule/Importschedule.vue:69 +msgid "New Import" +msgstr "" + +#: src/components/map/Identify.vue:33 msgid "No features identified." msgstr "" -#: src/components/map/contextbox/Bottlenecks.vue:63 -#: src/components/map/contextbox/Staging.vue:49 +#: src/components/map/contextbox/Bottlenecks.vue:67 +#: src/components/map/contextbox/Staging.vue:58 msgid "No results." msgstr "" +#: src/components/admin/importschedule/Importschedule.vue:66 +msgid "No schedules" +msgstr "" + #: src/components/map/Pdftool.vue:32 msgid "Open in new window" msgstr "" @@ -199,22 +259,39 @@ msgid "Pending" msgstr "" -#: src/components/map/contextbox/ImportSoundingresults.vue:35 +#: src/components/map/contextbox/ImportSoundingresults.vue:69 msgid "Please enter a date" msgstr "" -#: src/components/map/contextbox/ImportSoundingresults.vue:46 +#: src/components/map/contextbox/ImportSoundingresults.vue:34 +msgid "Please enter a projection" +msgstr "" + +#: src/components/map/contextbox/ImportSoundingresults.vue:52 msgid "Please enter a reference" msgstr "" -#: src/components/map/contextbox/ImportSoundingresults.vue:16 +#: src/components/map/contextbox/ImportSoundingresults.vue:18 msgid "Please select a bottleneck" msgstr "" +#: src/components/admin/usermanagement/Userdetail.vue:41 +#: src/components/admin/usermanagement/Userdetail.vue:85 +msgid "Please select one" +msgstr "" + #: src/components/map/Pdftool.vue:15 msgid "portrait" msgstr "" +#: src/components/map/fairway/Profiles.vue:5 +msgid "Profiles" +msgstr "" + +#: src/components/map/contextbox/ImportSoundingresults.vue:24 +msgid "Projection" +msgstr "" + #: src/components/admin/Importqueue.vue:51 src/components/admin/Logs.vue:32 msgid "Refresh" msgstr "" @@ -227,15 +304,40 @@ msgid "Request password reset!" msgstr "" +#: src/components/admin/usermanagement/Userdetail.vue:77 +msgid "Role" +msgstr "" + +#: src/components/map/fairway/Profiles.vue:63 +msgid "Saved cross profiles" +msgstr "" + +#: src/components/admin/importschedule/Importschedule.vue:40 +msgid "Schedule" +msgstr "" + +#: src/components/map/fairway/Profiles.vue:25 +#, fuzzy +msgid "Select Bottleneck" +msgstr "Engstellen" + #: src/components/admin/Systemconfiguration.vue:14 msgid "Send" msgstr "" -#: src/components/map/Identify.vue:45 +#: src/components/admin/usermanagement/Userdetail.vue:132 +msgid "Send testmail" +msgstr "" + +#: src/components/map/Identify.vue:50 msgid "Some data" msgstr "" -#: src/components/map/Identify.vue:41 +#: src/components/map/fairway/Profiles.vue:37 +msgid "Sounding Result" +msgstr "" + +#: src/components/map/Identify.vue:45 msgid "source-code" msgstr "" @@ -243,42 +345,74 @@ msgid "Staging area" msgstr "" -#: src/components/map/contextbox/Staging.vue:3 +#: src/components/map/contextbox/Staging.vue:4 msgid "Staging Area" msgstr "" +#: src/components/map/fairway/Profiles.vue:116 +msgid "Start" +msgstr "" + #: src/components/admin/Importqueue.vue:38 msgid "State" msgstr "" +#: src/components/admin/usermanagement/Userdetail.vue:123 +msgid "Submit" +msgstr "" + #: src/components/admin/Importqueue.vue:25 msgid "Successful" msgstr "" -#: src/components/Sidebar.vue:38 +#: src/components/admin/usermanagement/Userdetail.vue:88 +msgid "Sysadmin" +msgstr "" + +#: src/components/Sidebar.vue:39 msgid "Systemadministration" msgstr "" -#: src/components/Sidebar.vue:48 src/components/admin/Systemconfiguration.vue:3 +#: src/components/admin/Systemconfiguration.vue:3 msgid "Systemconfiguration" msgstr "" -#: src/components/map/Identify.vue:36 +#: src/components/map/Identify.vue:37 msgid "This app uses" msgstr "" +#: src/components/admin/importschedule/Importschedule.vue:34 +#: src/components/map/contextbox/Staging.vue:13 +msgid "Type" +msgstr "" + #: src/components/admin/Importqueue.vue:37 msgid "User" msgstr "" -#: src/components/Sidebar.vue:42 +#: src/components/admin/usermanagement/Userdetail.vue:14 +#: src/components/map/contextbox/Staging.vue:22 +#, fuzzy +msgid "Username" +msgstr "Passphrase" + +#: src/components/Sidebar.vue:44 +#: src/components/admin/usermanagement/Usermanagement.vue:8 msgid "Users" msgstr "" -#: src/components/map/Identify.vue:36 +#: src/components/admin/usermanagement/Userdetail.vue:91 +msgid "Waterway Admin" +msgstr "" + +#: src/components/admin/usermanagement/Userdetail.vue:94 +msgid "Waterway User" +msgstr "" + +#: src/components/map/Identify.vue:39 msgid "which is Free Software under" msgstr "" -#: src/components/map/Identify.vue:39 +#: src/components/map/Identify.vue:41 msgid "without warranty, see docs for details." msgstr ""
--- a/client/src/locale/en_GB/LC_MESSAGES/app.po Fri Nov 30 09:15:47 2018 +0100 +++ b/client/src/locale/en_GB/LC_MESSAGES/app.po Fri Nov 30 09:17:03 2018 +0100 @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: wamosjs 0.1.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-28 17:09+0100\n" +"POT-Creation-Date: 2018-11-29 17:47+0100\n" "PO-Revision-Date: 2018-07-03 17:18+0200\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" @@ -25,11 +25,19 @@ msgid "Accesslog" msgstr "" +#: src/components/admin/usermanagement/Usermanagement.vue:71 +msgid "Add User" +msgstr "" + +#: src/components/admin/importschedule/Importschedule.vue:37 +msgid "Author" +msgstr "" + #: src/components/Login.vue:59 msgid "back to login" msgstr "" -#: src/components/map/contextbox/ImportSoundingresults.vue:9 +#: src/components/map/contextbox/ImportSoundingresults.vue:11 msgid "Bottleneck" msgstr "" @@ -46,7 +54,7 @@ msgid "Bottlenecks" msgstr "" -#: src/components/map/contextbox/ImportSoundingresults.vue:87 +#: src/components/map/contextbox/ImportSoundingresults.vue:110 msgid "Cancel Upload" msgstr "" @@ -58,34 +66,62 @@ msgid "Chose format:" msgstr "" -#: src/components/map/contextbox/Staging.vue:54 +#: src/components/map/fairway/Profiles.vue:49 +msgid "Compare with" +msgstr "" + +#: src/components/Sidebar.vue:50 +msgid "Configuration" +msgstr "" + +#: src/components/map/contextbox/Staging.vue:65 msgid "Confirm" msgstr "" -#: src/components/map/Identify.vue:47 +#: src/components/map/Identify.vue:52 msgid "contributors." msgstr "" -#: src/components/map/contextbox/ImportSoundingresults.vue:22 +#: src/components/admin/usermanagement/Userdetail.vue:33 +msgid "Country" +msgstr "" + +#: src/components/map/contextbox/Staging.vue:16 msgid "Date" msgstr "" -#: src/components/map/contextbox/ImportSoundingresults.vue:39 +#: src/components/map/contextbox/ImportSoundingresults.vue:42 msgid "Depthreference" msgstr "" -#: src/components/map/contextbox/ImportSoundingresults.vue:81 +#: src/components/map/Pdftool.vue:25 msgid "Download" msgstr "" -#: src/components/map/Pdftool.vue:25 -msgid "Dvownload" +#: src/components/map/contextbox/ImportSoundingresults.vue:107 +msgid "Download Meta.json" +msgstr "" + +#: src/components/admin/importschedule/Importschedule.vue:43 +msgid "Email" +msgstr "" + +#: src/components/admin/usermanagement/Userdetail.vue:58 +msgid "Email address" msgstr "" #: src/components/admin/Importqueue.vue:35 msgid "Enqueued" msgstr "" +#: src/components/map/fairway/Profiles.vue:96 +msgid "Enter coordinates manually" +msgstr "" + +#: src/components/map/fairway/Profiles.vue:154 +msgid "Enter label for cross profile" +msgstr "" + #: src/components/Login.vue:141 msgid "Enter passphrase" msgstr "Enter passphrase" @@ -115,20 +151,31 @@ msgid "Identified" msgstr "" -#: src/components/map/contextbox/ImportSoundingresults.vue:3 -msgid "" -"Import\n" -" Soundingresults" +#: src/components/admin/importschedule/Importschedule.vue:31 +msgid "Import" msgstr "" #: src/components/Sidebar.vue:28 msgid "Import soundingresults" msgstr "" -#: src/components/Sidebar.vue:56 src/components/admin/Importqueue.vue:5 +#: src/components/map/contextbox/ImportSoundingresults.vue:4 +msgid "Import Soundingresults" +msgstr "" + +#: src/components/map/contextbox/Staging.vue:19 +msgid "Imported" +msgstr "" + +#: src/components/Sidebar.vue:58 src/components/admin/Importqueue.vue:5 msgid "Importqueue" msgstr "" +#: src/components/Sidebar.vue:62 +#: src/components/admin/importschedule/Importschedule.vue:6 +msgid "Importschedule" +msgstr "" + #: src/components/admin/Importqueue.vue:36 msgid "Kind" msgstr "" @@ -157,14 +204,18 @@ msgid "Login failed" msgstr "Login failed" -#: src/components/Sidebar.vue:62 +#: src/components/Sidebar.vue:68 msgid "Logout" msgstr "" -#: src/components/Sidebar.vue:52 +#: src/components/Sidebar.vue:54 msgid "Logs" msgstr "" +#: src/components/admin/usermanagement/Userdetail.vue:135 +msgid "Mail was sent" +msgstr "" + #: src/components/Sidebar.vue:11 msgid "Map" msgstr "" @@ -174,18 +225,27 @@ msgstr "" #: src/components/map/contextbox/Bottlenecks.vue:7 +#: src/components/map/contextbox/Staging.vue:10 msgid "Name" msgstr "" -#: src/components/map/Identify.vue:32 +#: src/components/admin/importschedule/Importschedule.vue:69 +msgid "New Import" +msgstr "" + +#: src/components/map/Identify.vue:33 msgid "No features identified." msgstr "" -#: src/components/map/contextbox/Bottlenecks.vue:63 -#: src/components/map/contextbox/Staging.vue:49 +#: src/components/map/contextbox/Bottlenecks.vue:67 +#: src/components/map/contextbox/Staging.vue:58 msgid "No results." msgstr "" +#: src/components/admin/importschedule/Importschedule.vue:66 +msgid "No schedules" +msgstr "" + #: src/components/map/Pdftool.vue:32 msgid "Open in new window" msgstr "" @@ -198,22 +258,39 @@ msgid "Pending" msgstr "" -#: src/components/map/contextbox/ImportSoundingresults.vue:35 +#: src/components/map/contextbox/ImportSoundingresults.vue:69 msgid "Please enter a date" msgstr "" -#: src/components/map/contextbox/ImportSoundingresults.vue:46 +#: src/components/map/contextbox/ImportSoundingresults.vue:34 +msgid "Please enter a projection" +msgstr "" + +#: src/components/map/contextbox/ImportSoundingresults.vue:52 msgid "Please enter a reference" msgstr "" -#: src/components/map/contextbox/ImportSoundingresults.vue:16 +#: src/components/map/contextbox/ImportSoundingresults.vue:18 msgid "Please select a bottleneck" msgstr "" +#: src/components/admin/usermanagement/Userdetail.vue:41 +#: src/components/admin/usermanagement/Userdetail.vue:85 +msgid "Please select one" +msgstr "" + #: src/components/map/Pdftool.vue:15 msgid "portrait" msgstr "" +#: src/components/map/fairway/Profiles.vue:5 +msgid "Profiles" +msgstr "" + +#: src/components/map/contextbox/ImportSoundingresults.vue:24 +msgid "Projection" +msgstr "" + #: src/components/admin/Importqueue.vue:51 src/components/admin/Logs.vue:32 msgid "Refresh" msgstr "" @@ -226,15 +303,39 @@ msgid "Request password reset!" msgstr "" +#: src/components/admin/usermanagement/Userdetail.vue:77 +msgid "Role" +msgstr "" + +#: src/components/map/fairway/Profiles.vue:63 +msgid "Saved cross profiles" +msgstr "" + +#: src/components/admin/importschedule/Importschedule.vue:40 +msgid "Schedule" +msgstr "" + +#: src/components/map/fairway/Profiles.vue:25 +msgid "Select Bottleneck" +msgstr "" + #: src/components/admin/Systemconfiguration.vue:14 msgid "Send" msgstr "" -#: src/components/map/Identify.vue:45 +#: src/components/admin/usermanagement/Userdetail.vue:132 +msgid "Send testmail" +msgstr "" + +#: src/components/map/Identify.vue:50 msgid "Some data" msgstr "" -#: src/components/map/Identify.vue:41 +#: src/components/map/fairway/Profiles.vue:37 +msgid "Sounding Result" +msgstr "" + +#: src/components/map/Identify.vue:45 msgid "source-code" msgstr "" @@ -242,42 +343,74 @@ msgid "Staging area" msgstr "" -#: src/components/map/contextbox/Staging.vue:3 +#: src/components/map/contextbox/Staging.vue:4 msgid "Staging Area" msgstr "" +#: src/components/map/fairway/Profiles.vue:116 +msgid "Start" +msgstr "" + #: src/components/admin/Importqueue.vue:38 msgid "State" msgstr "" +#: src/components/admin/usermanagement/Userdetail.vue:123 +msgid "Submit" +msgstr "" + #: src/components/admin/Importqueue.vue:25 msgid "Successful" msgstr "" -#: src/components/Sidebar.vue:38 +#: src/components/admin/usermanagement/Userdetail.vue:88 +msgid "Sysadmin" +msgstr "" + +#: src/components/Sidebar.vue:39 msgid "Systemadministration" msgstr "" -#: src/components/Sidebar.vue:48 src/components/admin/Systemconfiguration.vue:3 +#: src/components/admin/Systemconfiguration.vue:3 msgid "Systemconfiguration" msgstr "" -#: src/components/map/Identify.vue:36 +#: src/components/map/Identify.vue:37 msgid "This app uses" msgstr "" +#: src/components/admin/importschedule/Importschedule.vue:34 +#: src/components/map/contextbox/Staging.vue:13 +msgid "Type" +msgstr "" + #: src/components/admin/Importqueue.vue:37 msgid "User" msgstr "" -#: src/components/Sidebar.vue:42 +#: src/components/admin/usermanagement/Userdetail.vue:14 +#: src/components/map/contextbox/Staging.vue:22 +#, fuzzy +msgid "Username" +msgstr "Enter passphrase" + +#: src/components/Sidebar.vue:44 +#: src/components/admin/usermanagement/Usermanagement.vue:8 msgid "Users" msgstr "" -#: src/components/map/Identify.vue:36 +#: src/components/admin/usermanagement/Userdetail.vue:91 +msgid "Waterway Admin" +msgstr "" + +#: src/components/admin/usermanagement/Userdetail.vue:94 +msgid "Waterway User" +msgstr "" + +#: src/components/map/Identify.vue:39 msgid "which is Free Software under" msgstr "" -#: src/components/map/Identify.vue:39 +#: src/components/map/Identify.vue:41 msgid "without warranty, see docs for details." msgstr ""
--- a/client/src/main.js Fri Nov 30 09:15:47 2018 +0100 +++ b/client/src/main.js Fri Nov 30 09:17:03 2018 +0100 @@ -29,91 +29,95 @@ import VTooltip from "v-tooltip"; import { library } from "@fortawesome/fontawesome-svg-core"; import { + faAngleDown, + faAngleLeft, + faAngleRight, + faAngleUp, + faBars, + faBook, + faChartArea, + faCheck, + faCity, + faClipboardCheck, + faClock, + faCopy, + faDrawPolygon, + faExclamationTriangle, faEye, faEyeSlash, - faCopy, - faCheck, - faTimes, + faFilePdf, + faFolderPlus, faInfo, faLayerGroup, - faChartArea, + faMapMarkedAlt, + faMinus, + faPaperPlane, + faPencilAlt, + faPlus, + faPowerOff, faRuler, - faDrawPolygon, - faAngleDown, - faAngleUp, - faAngleLeft, - faAngleRight, - faFolderPlus, - faFilePdf, - faBars, faSearch, faShip, - faUpload, - faTasks, - faUsersCog, - faMapMarkedAlt, - faClipboardCheck, - faWrench, - faBook, - faPowerOff, - faTrash, + faSortAmountDown, + faSortAmountUp, + faSpinner, faStar, + faTasks, + faTimes, + faTrash, + faUpload, faUser, - faExclamationTriangle, - faPaperPlane, - faPlus, - faMinus, - faSortAmountUp, - faSortAmountDown, - faSpinner, - faCity, - faWater + faUsersCog, + faWater, + faWrench } from "@fortawesome/free-solid-svg-icons"; import { faAdn } from "@fortawesome/free-brands-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; import VueClipboard from "vue-clipboard2"; library.add( + faAdn, + faAngleDown, + faAngleLeft, + faAngleRight, + faAngleUp, + faBars, + faBook, + faChartArea, + faCheck, + faCity, + faClipboardCheck, + faClock, + faCopy, + faDrawPolygon, + faExclamationTriangle, faEye, faEyeSlash, - faCopy, - faCheck, - faTimes, + faFilePdf, + faFolderPlus, faInfo, faLayerGroup, - faChartArea, + faMapMarkedAlt, + faMinus, + faPaperPlane, + faPencilAlt, + faPlus, + faPowerOff, faRuler, - faDrawPolygon, - faAngleDown, - faAngleUp, - faAngleLeft, - faAngleRight, - faFolderPlus, - faFilePdf, - faBars, faSearch, faShip, - faUpload, - faTasks, - faUsersCog, - faMapMarkedAlt, - faClipboardCheck, - faWrench, - faBook, - faPowerOff, - faTrash, + faSortAmountDown, + faSortAmountUp, + faSpinner, faStar, - faAdn, + faTasks, + faTimes, + faTrash, + faUpload, faUser, - faExclamationTriangle, - faPaperPlane, - faPlus, - faMinus, - faSortAmountUp, - faSortAmountDown, - faSpinner, - faCity, - faWater + faUsersCog, + faWater, + faWrench ); Vue.component("font-awesome-icon", FontAwesomeIcon);
--- a/client/src/router.js Fri Nov 30 09:15:47 2018 +0100 +++ b/client/src/router.js Fri Nov 30 09:17:03 2018 +0100 @@ -25,6 +25,8 @@ import("./components/admin/usermanagement/Usermanagement.vue"); const Logs = () => import("./components/admin/Logs.vue"); const Importqueue = () => import("./components/admin/Importqueue.vue"); +const Importschedule = () => + import("./components/admin/importschedule/Importschedule.vue"); const Systemconfiguration = () => import("./components/admin/Systemconfiguration.vue"); @@ -93,7 +95,23 @@ requiresAuth: true }, beforeEnter: (to, from, next) => { - const isWaterwayAdmin = store.getters["user/isSysAdmin"]; + const isWaterwayAdmin = store.getters["user/isWaterwayAdmin"]; + if (!isWaterwayAdmin) { + next("/"); + } else { + next(); + } + } + }, + { + path: "/importschedule", + name: "importschedule", + component: Importschedule, + meta: { + requiresAuth: true + }, + beforeEnter: (to, from, next) => { + const isWaterwayAdmin = store.getters["user/isWaterwayAdmin"]; if (!isWaterwayAdmin) { next("/"); } else {
--- a/client/src/store/fairway.js Fri Nov 30 09:15:47 2018 +0100 +++ b/client/src/store/fairway.js Fri Nov 30 09:17:03 2018 +0100 @@ -118,12 +118,11 @@ actions: { clearSelection({ commit, dispatch, rootGetters, rootState }) { dispatch("bottlenecks/setSelectedBottleneck", null, { root: true }); + dispatch("map/enableIdentifyTool", null, { root: true }); commit("clearCurrentProfile"); commit("application/showSplitscreen", false, { root: true }); rootState.map.cutTool.setActive(false); - rootGetters["map/getLayerByName"]("Cut Tool") - .data.getSource() - .clear(); + rootGetters["map/getVSourceByName"]("Cut Tool").clear(); }, loadProfile({ commit, state }, survey) { if (state.startPoint && state.endPoint) { @@ -190,6 +189,7 @@ commit("profileLoading", true); Promise.all(profileLoaders) .then(() => { + dispatch("map/enableIdentifyTool", null, { root: true }); rootState.map.cutTool.setActive(false); rootGetters["map/getVSourceByName"]( "Fairway Dimensions"
--- a/client/src/store/imports.js Fri Nov 30 09:15:47 2018 +0100 +++ b/client/src/store/imports.js Fri Nov 30 09:17:03 2018 +0100 @@ -22,11 +22,29 @@ REJECTED: "rejected" }; +const SCHEDULES = { + DAILY: "daily", + MONTHLY: "monthly" +}; + // initial state const init = () => { return { imports: [], - staging: [] + staging: [], + schedules: [], + importScheduleDetail: null, + importScheduleDetailVisible: false + }; +}; + +const newImportScheduleDetail = () => { + return { + import: "", + type: "", + author: "", + schedule: "", + emailNotification: null }; }; @@ -35,6 +53,21 @@ namespaced: true, state: init(), mutations: { + clearImportScheduleDetail: state => { + state.importScheduleDetail = newImportScheduleDetail(); + }, + deleteSchedule: (state, index) => { + state.schedules.splice(index, 1); + }, + setImportScheduleDetailInvisible: state => { + state.importScheduleDetailVisible = false; + }, + setImportScheduleDetailVisible: state => { + state.importScheduleDetailVisible = true; + }, + setSchedules: (state, schedules) => { + state.schedules = schedules; + }, setImports: (state, imports) => { state.imports = imports; }, @@ -58,6 +91,21 @@ } }, actions: { + getSchedules({ commit }) { + throw new Error("Not Implemented!"); + return new Promise((resolve, reject) => { + HTTP.get("/imports", { + headers: { "X-Gemma-Auth": localStorage.getItem("token") } + }) + .then(response => { + commit("setImports", response.data.imports); + resolve(response); + }) + .catch(error => { + reject(error); + }); + }); + }, getImports({ commit }) { return new Promise((resolve, reject) => { HTTP.get("/imports", { @@ -85,23 +133,8 @@ reject(error); }); }); - }, - setStaging({ commit }, results) { - return new Promise((resolve, reject) => { - throw "Not implemented!"; - HTTP.get("/imports?states=pending", { - headers: { "X-Gemma-Auth": localStorage.getItem("token") } - }) - .then(response => { - commit("setStaging", response.data.imports); - resolve(response); - }) - .catch(error => { - reject(error); - }); - }); } } }; -export { imports, STATES }; +export { imports, STATES, SCHEDULES };
--- a/client/src/store/map.js Fri Nov 30 09:15:47 2018 +0100 +++ b/client/src/store/map.js Fri Nov 30 09:17:03 2018 +0100 @@ -26,6 +26,8 @@ import { HTTP } from "../lib/http"; import { fromLonLat } from "ol/proj"; import { getLength, getArea } from "ol/sphere.js"; +import { unByKey } from "ol/Observable"; +import { getCenter } from "ol/extent"; // initial state const init = () => { @@ -36,6 +38,7 @@ lon: 1819178, zoom: 11 }, + identifyTool: null, // event binding (singleclick, dblclick) identifiedFeatures: [], // map features identified by clicking on the map currentMeasurement: null, // distance or area from line-/polygon-/cutTool lineTool: null, // open layers interaction object (Draw) @@ -362,6 +365,9 @@ openLayersMap: (state, map) => { state.openLayersMap = map; }, + identifyTool: (state, events) => { + state.identifyTool = events; + }, setIdentifiedFeatures: (state, identifiedFeatures) => { state.identifiedFeatures = identifiedFeatures; }, @@ -471,6 +477,73 @@ commit("polygonTool", polygonTool); commit("cutTool", cutTool); commit("openLayersMap", map); + }, + disableIdentifyTool({ state }) { + unByKey(state.identifyTool); + }, + enableIdentifyTool({ state, commit, dispatch, getters }) { + state.identifyTool = state.openLayersMap.on( + ["singleclick", "dblclick"], + event => { + commit("setIdentifiedFeatures", []); + // checking our WFS layers + var features = state.openLayersMap.getFeaturesAtPixel(event.pixel); + if (features) { + commit("setIdentifiedFeatures", features); + + // get selected bottleneck from identified features + for (let feature of features) { + let id = feature.getId(); + // RegExp.prototype.test() works with number, str and undefined + if (/^bottlenecks\./.test(id)) { + dispatch( + "bottlenecks/setSelectedBottleneck", + feature.get("objnam"), + { root: true } + ); + commit("moveMap", { + coordinates: getCenter( + feature + .getGeometry() + .clone() + .transform("EPSG:3857", "EPSG:4326") + .getExtent() + ), + zoom: 17, + preventZoomOut: true + }); + } + } + } + + // DEBUG output and example how to remove the GeometryName + /* + for (let feature of features) { + console.log("Identified:", feature.getId()); + for (let key of feature.getKeys()) { + if (key != feature.getGeometryName()) { + console.log(key, feature.get(key)); + } + } + } + */ + + // trying the GetFeatureInfo way for WMS + var wmsSource = getters.getVSourceByName("Inland ECDIS chart Danube"); + var url = wmsSource.getGetFeatureInfoUrl( + event.coordinate, + 100 /* resolution */, + "EPSG:3857", + // { INFO_FORMAT: "application/vnd.ogc.gml" } // not allowed by d4d + { INFO_FORMAT: "text/plain" } + ); + + if (url) { + // cannot directly query here because of SOP + console.log("GetFeatureInfo url:", url); + } + } + ); } } };