qwc2 2026.4.2 → 2026.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,6 +1,5 @@
1
1
  Copyright (c) 2015-2016 GeoSolutions Sas
2
- Copyright (c) 2016-2024 Sourcepole AG
3
- Copyright (c) 2021 Oslandia SAS <infos+qwc2@oslandia.com>
2
+ Copyright (c) QWC Contributors <https://github.com/qgis/qwc2/graphs/contributors>
4
3
  All rights reserved.
5
4
 
6
5
  Redistribution and use in source and binary forms, with or without modification, are
@@ -22,7 +21,3 @@ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRU
22
21
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
23
22
  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
23
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
-
26
- The views and conclusions contained in the software and documentation are those
27
- of the authors and should not be interpreted as representing official policies,
28
- either expressed or implied, of the MapStore2 Project.
package/README.md CHANGED
@@ -8,18 +8,22 @@ The `qwc2` NPM package can be used as a dependency to build a custom QWC applica
8
8
 
9
9
  ![Screenshot](https://github.com/qgis/qwc2/blob/gh-pages/Screenshot.jpg?raw=true)
10
10
 
11
- ### Main Features
11
+ ## Homepage
12
+
13
+ See [qwc.app](https://qwc.app).
14
+
15
+ ## Main Features
12
16
 
13
17
  See [qwc.app/features](https://qwc.app/features).
14
18
 
15
19
  ## Quick start
16
20
 
17
- See [qwc-services.github.io/master/QuickStart/](https://qwc-services.github.io/master/QuickStart/)
21
+ See [docs.qwc.app/master/QuickStart/](https://docs.qwc.app/master/QuickStart/).
18
22
 
19
23
  ## Documentation
20
24
 
21
- * [qwc-services.github.io](https://qwc-services.github.io/)
22
- * [ChangeLog](https://qwc-services.github.io/master/release_notes/ChangeLog/)
25
+ * [docs.qwc.app](https://docs.qwc.app)
26
+ * [ChangeLog](https://docs.qwc.app/master/release_notes/ChangeLog/)
23
27
 
24
28
  ## Help
25
29
 
@@ -15,7 +15,7 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
15
15
  import axios from 'axios';
16
16
  import { applyStyle } from 'ol-mapbox-style';
17
17
  import ol from 'openlayers';
18
- export var createLayer = function createLayer(options) {
18
+ function createLayer(url, options) {
19
19
  return new ol.layer.VectorTile(_objectSpread({
20
20
  minResolution: options.minResolution,
21
21
  maxResolution: options.maxResolution,
@@ -23,37 +23,75 @@ export var createLayer = function createLayer(options) {
23
23
  source: new ol.source.VectorTile(_objectSpread({
24
24
  projection: options.projection,
25
25
  format: new ol.format.MVT({}),
26
- url: options.url,
26
+ url: url,
27
27
  tileGrid: options.tileGridConfig ? new ol.tilegrid.TileGrid(_objectSpread({}, options.tileGridConfig)) : undefined
28
28
  }, options.sourceConfig || {}))
29
29
  }, options.layerConfig || {}));
30
- };
30
+ }
31
+ export function createFromStyle(style, options, callback) {
32
+ axios.get(style).then(function (response) {
33
+ var _glStyle$sprite, _glStyle$glyphs;
34
+ var glStyle = response.data;
35
+ ((_glStyle$sprite = glStyle.sprite) === null || _glStyle$sprite === void 0 ? void 0 : _glStyle$sprite.startsWith(".")) && (glStyle.sprite = new URL(glStyle.sprite, options.style).href);
36
+ ((_glStyle$glyphs = glStyle.glyphs) === null || _glStyle$glyphs === void 0 ? void 0 : _glStyle$glyphs.startsWith(".")) && (glStyle.glyphs = new URL(glStyle.glyphs, options.style).href);
37
+ // Collect used sources
38
+ var usedSources = new Set(glStyle.layers.map(function (l) {
39
+ return l.source;
40
+ }).filter(Boolean));
41
+ // Create layer for each source
42
+ usedSources.forEach(function (sourceName) {
43
+ var _source$url, _source$tiles;
44
+ var source = glStyle.sources[sourceName];
45
+ if (source.type !== 'vector' && source.type !== 'geojson') {
46
+ return;
47
+ }
48
+ ((_source$url = source.url) === null || _source$url === void 0 ? void 0 : _source$url.startsWith(".")) && (source.url = new URL(source.url, options.style).href);
49
+ if ((_source$tiles = source.tiles) !== null && _source$tiles !== void 0 && _source$tiles.length) {
50
+ var layer = createLayer(source.tiles[0], options);
51
+ applyStyle(layer, style, sourceName, options.styleOptions).then(function () {
52
+ callback(layer);
53
+ })["catch"](function (e) {
54
+ /* eslint-disable-next-line */
55
+ console.warn("Unable to apply style " + sourceName + ": " + String(e));
56
+ });
57
+ } else if (source.url) {
58
+ axios.get(source.url).then(function (response2) {
59
+ var _response2$data;
60
+ if ((_response2$data = response2.data) !== null && _response2$data !== void 0 && (_response2$data = _response2$data.tiles) !== null && _response2$data !== void 0 && _response2$data.length) {
61
+ var _layer = createLayer(response2.data.tiles[0], options, callback);
62
+ applyStyle(_layer, style, sourceName, options.styleOptions).then(function () {
63
+ callback(_layer);
64
+ })["catch"](function (e) {
65
+ /* eslint-disable-next-line */
66
+ console.warn("Unable to apply style " + sourceName + ": " + String(e));
67
+ });
68
+ } else {
69
+ /* eslint-disable-next-line */
70
+ console.warn("Could not find source tile URL for style " + sourceName);
71
+ }
72
+ })["catch"](function () {
73
+ /* eslint-disable-next-line */
74
+ console.warn("Could not find source tile URL for style " + sourceName);
75
+ });
76
+ } else {
77
+ /* eslint-disable-next-line */
78
+ console.warn("Could not find source tile URL for style " + sourceName);
79
+ }
80
+ });
81
+ })["catch"](function (e) {
82
+ /* eslint-disable-next-line */
83
+ console.warn("Unable to load style " + options.style + ": " + String(e));
84
+ });
85
+ }
31
86
  export default {
32
87
  create: function create(options) {
33
88
  var group = new ol.layer.Group();
34
89
  if (options.style) {
35
- axios.get(options.style).then(function (response) {
36
- var _glStyle$sprite, _glStyle$glyphs;
37
- var glStyle = response.data;
38
- ((_glStyle$sprite = glStyle.sprite) === null || _glStyle$sprite === void 0 ? void 0 : _glStyle$sprite.startsWith(".")) && (glStyle.sprite = new URL(glStyle.sprite, options.style).href);
39
- ((_glStyle$glyphs = glStyle.glyphs) === null || _glStyle$glyphs === void 0 ? void 0 : _glStyle$glyphs.startsWith(".")) && (glStyle.glyphs = new URL(glStyle.glyphs, options.style).href);
40
- Object.keys(glStyle.sources).forEach(function (styleSource) {
41
- var _glStyle$sources$styl;
42
- ((_glStyle$sources$styl = glStyle.sources[styleSource].url) === null || _glStyle$sources$styl === void 0 ? void 0 : _glStyle$sources$styl.startsWith(".")) && (glStyle.sources[styleSource].url = new URL(glStyle.sources[styleSource].url, options.style).href);
43
- var layer = createLayer(options);
44
- applyStyle(layer, glStyle, styleSource, options.styleOptions).then(function () {
45
- group.getLayers().push(layer);
46
- })["catch"](function (e) {
47
- /* eslint-disable-next-line */
48
- console.warn("Unable to apply style " + options.style + ": " + String(e));
49
- });
50
- });
51
- })["catch"](function (e) {
52
- /* eslint-disable-next-line */
53
- console.warn("Unable to load style " + options.style + ": " + String(e));
90
+ createFromStyle(options.style, options, function (layer) {
91
+ group.getLayers().push(layer);
54
92
  });
55
93
  } else {
56
- group.getLayers().push(createLayer(options));
94
+ group.getLayers().push(createLayer(options.url, options));
57
95
  }
58
96
  return group;
59
97
  }
@@ -130,7 +130,8 @@ var ColorLayer3D = /*#__PURE__*/function (_React$Component) {
130
130
  value: function componentDidUpdate(prevProps) {
131
131
  var layerCreator = LayerRegistry3D[this.props.options.type];
132
132
  if (this.mapLayer && layerCreator) {
133
- layerCreator.update3d(this.mapLayer, this.props.options, prevProps.options, this.props.sceneContext.mapCrs);
133
+ var _layerCreator$update;
134
+ (_layerCreator$update = layerCreator.update3d) === null || _layerCreator$update === void 0 || _layerCreator$update.call(layerCreator, this.mapLayer, this.props.options, prevProps.options, this.props.sceneContext.mapCrs);
134
135
  this.applyLayerOptions(layerCreator, prevProps.options);
135
136
  }
136
137
  }
@@ -8,16 +8,14 @@
8
8
 
9
9
  import ColorLayer from '@giro3d/giro3d/core/layer/ColorLayer';
10
10
  import VectorTileSource from "@giro3d/giro3d/sources/VectorTileSource.js";
11
- import axios from 'axios';
12
- import { applyStyle } from 'ol-mapbox-style';
13
- import { createLayer } from '../../map/layers/MVTLayer';
11
+ import { createFromStyle } from '../../map/layers/MVTLayer';
14
12
  import { LayerGroup3D } from './Layer3D';
15
13
  export default {
16
14
  create3d: function create3d(options, projection) {
17
- var create3dLayer = function create3dLayer() {
18
- var style = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
15
+ var create3dLayer = function create3dLayer(url) {
16
+ var style = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
19
17
  var source = new VectorTileSource({
20
- url: options.url,
18
+ url: url,
21
19
  style: style,
22
20
  backgroundColor: "white"
23
21
  });
@@ -28,28 +26,11 @@ export default {
28
26
  };
29
27
  var group = new LayerGroup3D(options.id);
30
28
  if (options.style) {
31
- axios.get(options.style).then(function (response) {
32
- var _glStyle$sprite, _glStyle$glyphs;
33
- var glStyle = response.data;
34
- ((_glStyle$sprite = glStyle.sprite) === null || _glStyle$sprite === void 0 ? void 0 : _glStyle$sprite.startsWith(".")) && (glStyle.sprite = new URL(glStyle.sprite, options.style).href);
35
- ((_glStyle$glyphs = glStyle.glyphs) === null || _glStyle$glyphs === void 0 ? void 0 : _glStyle$glyphs.startsWith(".")) && (glStyle.glyphs = new URL(glStyle.glyphs, options.style).href);
36
- Object.keys(glStyle.sources).forEach(function (styleSource) {
37
- var _glStyle$sources$styl;
38
- ((_glStyle$sources$styl = glStyle.sources[styleSource].url) === null || _glStyle$sources$styl === void 0 ? void 0 : _glStyle$sources$styl.startsWith(".")) && (glStyle.sources[styleSource].url = new URL(glStyle.sources[styleSource].url, options.style).href);
39
- var olLayer = createLayer(options);
40
- applyStyle(olLayer, glStyle, styleSource, options.styleOptions).then(function () {
41
- group.addLayer(create3dLayer(olLayer.getStyle()));
42
- })["catch"](function (e) {
43
- /* eslint-disable-next-line */
44
- console.warn("Unable to apply style " + options.style + ": " + String(e));
45
- });
46
- });
47
- })["catch"](function (e) {
48
- /* eslint-disable-next-line */
49
- console.warn("Unable to load style " + options.style + ": " + String(e));
29
+ createFromStyle(options.style, options, function (olLayer) {
30
+ group.addLayer(create3dLayer(olLayer.getSource().getUrls()[0], olLayer.getStyle()));
50
31
  });
51
32
  } else {
52
- group.addLayer(create3dLayer());
33
+ group.addLayer(create3dLayer(options.url));
53
34
  }
54
35
  return group;
55
36
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qwc2",
3
- "version": "2026.04.02",
3
+ "version": "2026.04.03",
4
4
  "description": "QGIS Web Client",
5
5
  "author": "Sourcepole AG",
6
6
  "license": "BSD-2-Clause",
@@ -712,7 +712,7 @@ var SensorThingsTool = /*#__PURE__*/function (_React$Component) {
712
712
  }, datastream.description);
713
713
  })), /*#__PURE__*/React.createElement("button", {
714
714
  className: "button",
715
- onClick: _this.addDatastream,
715
+ onClick: _this.addSelectedDatastream,
716
716
  title: LocaleUtils.tr("sensorthingstool.addDatastream")
717
717
  }, /*#__PURE__*/React.createElement(Icon, {
718
718
  icon: "plus"
@@ -1079,8 +1079,13 @@ var SensorThingsTool = /*#__PURE__*/function (_React$Component) {
1079
1079
  };
1080
1080
  });
1081
1081
  });
1082
- _defineProperty(_this, "addDatastream", function () {
1082
+ _defineProperty(_this, "addSelectedDatastream", function () {
1083
1083
  if (_this.state.currentDatastreamId !== undefined) {
1084
+ _this.addDatastream(_this.state.currentDatastreamId);
1085
+ }
1086
+ });
1087
+ _defineProperty(_this, "addDatastream", function (datastreamId) {
1088
+ if (datastreamId !== undefined) {
1084
1089
  _this.setState(function (state) {
1085
1090
  // find next unused color
1086
1091
  var availableColors = new Set(state.graphColors.map(function (color, idx) {
@@ -1104,7 +1109,7 @@ var SensorThingsTool = /*#__PURE__*/function (_React$Component) {
1104
1109
  return {
1105
1110
  graph: _objectSpread(_objectSpread({}, state.graph), {}, {
1106
1111
  datastreams: [].concat(_toConsumableArray(state.graph.datastreams), [{
1107
- id: state.currentDatastreamId,
1112
+ id: datastreamId,
1108
1113
  observations: null,
1109
1114
  loading: false,
1110
1115
  colorIdx: colorIdx,
@@ -1116,7 +1121,7 @@ var SensorThingsTool = /*#__PURE__*/function (_React$Component) {
1116
1121
  }])
1117
1122
  }),
1118
1123
  datastreamOptions: [].concat(_toConsumableArray(state.datastreamOptions), [{
1119
- datastreamId: state.currentDatastreamId,
1124
+ datastreamId: datastreamId,
1120
1125
  showOnSecondYAxis: false,
1121
1126
  showArithmeticMean: false,
1122
1127
  percentilesInput: "",
@@ -1606,10 +1611,32 @@ var SensorThingsTool = /*#__PURE__*/function (_React$Component) {
1606
1611
  if (!_this.state.showDatastreamsFilterWindow || _this.state.currentSensorLocation === null) {
1607
1612
  return null;
1608
1613
  }
1614
+
1615
+ // group datastreams by thing
1616
+ var groupedDatastreams = {};
1617
+ var filteredThings = [];
1618
+ _this.state.currentSensorLocation.filteredDatastreams.forEach(function (datastreamId) {
1619
+ var datastreamInfo = _this.state.datastreams[datastreamId];
1620
+ var thingId = datastreamInfo.thing.id;
1621
+ if (groupedDatastreams[thingId] === undefined) {
1622
+ groupedDatastreams[thingId] = {
1623
+ thing: datastreamInfo.thing,
1624
+ datastreamIds: []
1625
+ };
1626
+ filteredThings.push(datastreamInfo.thing);
1627
+ }
1628
+ groupedDatastreams[thingId].datastreamIds.push(datastreamId);
1629
+ });
1630
+ // order thing IDs by name and description
1631
+ var thingIds = filteredThings.sort(function (a, b) {
1632
+ return a.name.localeCompare(b.name) || a.description.localeCompare(b.description);
1633
+ }).map(function (thing) {
1634
+ return thing.id;
1635
+ });
1609
1636
  return /*#__PURE__*/React.createElement(ResizeableWindow, {
1610
- fitHeight: "true",
1611
1637
  icon: "filter",
1612
- initialWidth: 500,
1638
+ initialHeight: 600,
1639
+ initialWidth: 800,
1613
1640
  initialX: _this.props.windowSize.width + 10,
1614
1641
  initialY: 0,
1615
1642
  key: "SensorThingsDatastreamsFilterWindow",
@@ -1624,7 +1651,9 @@ var SensorThingsTool = /*#__PURE__*/function (_React$Component) {
1624
1651
  role: "body"
1625
1652
  }, /*#__PURE__*/React.createElement("table", {
1626
1653
  className: "sensor-things-datastreams-filter"
1627
- }, /*#__PURE__*/React.createElement("tbody", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("sensorthingstool.datastreamsFilter.thing"), ":\xA0"), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("select", {
1654
+ }, /*#__PURE__*/React.createElement("tbody", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", {
1655
+ className: "sensor-things-datastreams-filter-location"
1656
+ }, LocaleUtils.tr("sensorthingstool.datastreamsFilter.location"), ":\xA0"), /*#__PURE__*/React.createElement("td", null, _this.state.currentSensorLocation.name, ": ", _this.state.currentSensorLocation.description)), /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("sensorthingstool.datastreamsFilter.thing"), ":\xA0"), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("select", {
1628
1657
  onChange: function onChange(ev) {
1629
1658
  return _this.updateDatastreamsFilter('thingId', ev.target.value);
1630
1659
  },
@@ -1660,7 +1689,41 @@ var SensorThingsTool = /*#__PURE__*/function (_React$Component) {
1660
1689
  key: "sensor-things-select-filter-observed-property-" + observedProperty.id,
1661
1690
  value: observedProperty.id
1662
1691
  }, observedProperty.optionText);
1663
- }))))))));
1692
+ })))))), /*#__PURE__*/React.createElement("div", {
1693
+ className: "sensor-things-datastreams-filter-table-wrapper"
1694
+ }, /*#__PURE__*/React.createElement("table", {
1695
+ className: "sensor-things-datastreams-filter-table"
1696
+ }, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("th", null, "ID"), /*#__PURE__*/React.createElement("th", null, LocaleUtils.tr("sensorthingstool.datastreamsFilter.datastream")), /*#__PURE__*/React.createElement("th", null, LocaleUtils.tr("sensorthingstool.datastreamTable.fullPeriod")), /*#__PURE__*/React.createElement("th", null, LocaleUtils.tr("sensorthingstool.datastreamInfo.observedProperty")), /*#__PURE__*/React.createElement("th", null, LocaleUtils.tr("sensorthingstool.datastreamInfo.unit")), /*#__PURE__*/React.createElement("th", null, LocaleUtils.tr("sensorthingstool.datastreamInfo.sensor")), /*#__PURE__*/React.createElement("th", null))), /*#__PURE__*/React.createElement("tbody", null, thingIds.map(function (thingId) {
1697
+ var thing = groupedDatastreams[thingId].thing;
1698
+ var datastreamIds = groupedDatastreams[thingId].datastreamIds;
1699
+ var thingRows = [/*#__PURE__*/React.createElement("tr", {
1700
+ className: "sensor-things-datastreams-filter-table-thing",
1701
+ key: "sensor-things-datastream-filter-list-thing-" + thingId
1702
+ }, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("sensorthingstool.datastreamInfo.thing"), ":"), /*#__PURE__*/React.createElement("td", {
1703
+ colSpan: "6"
1704
+ }, /*#__PURE__*/React.createElement("div", null, thing.name), /*#__PURE__*/React.createElement("div", null, thing.description)))];
1705
+ var datastreamRows = datastreamIds.map(function (datastreamId, idx) {
1706
+ var datastreamInfo = _this.state.datastreams[datastreamId];
1707
+ var periodInfo = "-";
1708
+ if (datastreamInfo.period.begin !== null && datastreamInfo.period.end !== null) {
1709
+ var fullPeriodBegin = dayjs(datastreamInfo.period.begin).format(_this.props.timeFormats.tooltip);
1710
+ var fullPeriodEnd = dayjs(datastreamInfo.period.end).format(_this.props.timeFormats.tooltip);
1711
+ periodInfo = /*#__PURE__*/React.createElement("div", null, fullPeriodBegin, /*#__PURE__*/React.createElement("br", null), "- ", fullPeriodEnd);
1712
+ }
1713
+ return /*#__PURE__*/React.createElement("tr", {
1714
+ key: "sensor-things-datastream-filter-list-" + idx
1715
+ }, /*#__PURE__*/React.createElement("td", null, datastreamInfo.id), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("div", null, datastreamInfo.name), /*#__PURE__*/React.createElement("div", null, datastreamInfo.description)), /*#__PURE__*/React.createElement("td", null, periodInfo), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("div", null, datastreamInfo.observedProperty.name), /*#__PURE__*/React.createElement("div", null, datastreamInfo.observedProperty.description)), /*#__PURE__*/React.createElement("td", null, datastreamInfo.unitOfMeasurement.symbol), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("div", null, datastreamInfo.sensor.name), /*#__PURE__*/React.createElement("div", null, datastreamInfo.sensor.description)), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("button", {
1716
+ className: "button",
1717
+ onClick: function onClick() {
1718
+ return _this.addDatastream(datastreamId);
1719
+ },
1720
+ title: LocaleUtils.tr("sensorthingstool.addDatastream")
1721
+ }, /*#__PURE__*/React.createElement(Icon, {
1722
+ icon: "plus"
1723
+ }))));
1724
+ });
1725
+ return thingRows.concat(datastreamRows);
1726
+ }))))));
1664
1727
  });
1665
1728
  _defineProperty(_this, "toggleDatastreamInfoWindow", function (datastreamIndex) {
1666
1729
  var datastreamInfoWindow = null;
@@ -177,8 +177,34 @@ table.sensor-things-datastreams-filter td select {
177
177
  width: 100%;
178
178
  text-overflow: ellipsis;
179
179
  }
180
+ table.sensor-things-datastreams-filter td.sensor-things-datastreams-filter-location {
181
+ height: 2em;
182
+ }
183
+ table.sensor-things-datastreams-filter-table {
184
+ width: 100%;
185
+ margin-top: 1em;
186
+ font-size: 85%;
187
+ }
188
+ table.sensor-things-datastreams-filter-table td {
189
+ vertical-align: top;
190
+ padding-top: 0.25em;
191
+ padding-bottom: 0.25em;
192
+ border-bottom: 1px solid var(--border-color);
193
+ }
194
+ table.sensor-things-datastreams-filter-table td div:nth-child(2) {
195
+ color: var(--text-color-disabled);
196
+ }
197
+ table.sensor-things-datastreams-filter-table td:last-child {
198
+ vertical-align: middle;
199
+ }
200
+ table.sensor-things-datastreams-filter-table tr.sensor-things-datastreams-filter-table-thing {
201
+ background-color: var(--button-bg-color);
202
+ }
203
+ table.sensor-things-datastreams-filter-table tr.sensor-things-datastreams-filter-table-thing td:nth-child(1) {
204
+ font-weight: bold;
205
+ }
180
206
 
181
- div.sensor-things-datastream-observations-table-wrapper {
207
+ div.sensor-things-datastream-observations-table-wrapper, div.sensor-things-datastreams-filter-table-wrapper {
182
208
  overflow: auto;
183
209
  margin-bottom: 0.25em;
184
210
  }
@@ -672,6 +672,8 @@
672
672
  "value": ""
673
673
  },
674
674
  "datastreamsFilter": {
675
+ "datastream": "",
676
+ "location": "",
675
677
  "observedProperty": "",
676
678
  "sensor": "",
677
679
  "thing": "",
@@ -672,6 +672,8 @@
672
672
  "value": ""
673
673
  },
674
674
  "datastreamsFilter": {
675
+ "datastream": "",
676
+ "location": "",
675
677
  "observedProperty": "",
676
678
  "sensor": "",
677
679
  "thing": "",
@@ -672,6 +672,8 @@
672
672
  "value": ""
673
673
  },
674
674
  "datastreamsFilter": {
675
+ "datastream": "",
676
+ "location": "",
675
677
  "observedProperty": "",
676
678
  "sensor": "",
677
679
  "thing": "",
@@ -672,6 +672,8 @@
672
672
  "value": "Wert"
673
673
  },
674
674
  "datastreamsFilter": {
675
+ "datastream": "Datastream",
676
+ "location": "Location",
675
677
  "observedProperty": "Observed Property",
676
678
  "sensor": "Sensor",
677
679
  "thing": "Thing",
@@ -672,6 +672,8 @@
672
672
  "value": "Wert"
673
673
  },
674
674
  "datastreamsFilter": {
675
+ "datastream": "Datastream",
676
+ "location": "Location",
675
677
  "observedProperty": "Observed Property",
676
678
  "sensor": "Sensor",
677
679
  "thing": "Thing",
@@ -672,6 +672,8 @@
672
672
  "value": "Value"
673
673
  },
674
674
  "datastreamsFilter": {
675
+ "datastream": "Datastream",
676
+ "location": "Location",
675
677
  "observedProperty": "Observed Property",
676
678
  "sensor": "Sensor",
677
679
  "thing": "Thing",
@@ -672,6 +672,8 @@
672
672
  "value": ""
673
673
  },
674
674
  "datastreamsFilter": {
675
+ "datastream": "",
676
+ "location": "",
675
677
  "observedProperty": "",
676
678
  "sensor": "",
677
679
  "thing": "",
@@ -672,6 +672,8 @@
672
672
  "value": ""
673
673
  },
674
674
  "datastreamsFilter": {
675
+ "datastream": "",
676
+ "location": "",
675
677
  "observedProperty": "",
676
678
  "sensor": "",
677
679
  "thing": "",
@@ -672,6 +672,8 @@
672
672
  "value": ""
673
673
  },
674
674
  "datastreamsFilter": {
675
+ "datastream": "",
676
+ "location": "",
675
677
  "observedProperty": "",
676
678
  "sensor": "",
677
679
  "thing": "",
@@ -672,6 +672,8 @@
672
672
  "value": ""
673
673
  },
674
674
  "datastreamsFilter": {
675
+ "datastream": "",
676
+ "location": "",
675
677
  "observedProperty": "",
676
678
  "sensor": "",
677
679
  "thing": "",
@@ -672,6 +672,8 @@
672
672
  "value": ""
673
673
  },
674
674
  "datastreamsFilter": {
675
+ "datastream": "",
676
+ "location": "",
675
677
  "observedProperty": "",
676
678
  "sensor": "",
677
679
  "thing": "",
@@ -672,6 +672,8 @@
672
672
  "value": ""
673
673
  },
674
674
  "datastreamsFilter": {
675
+ "datastream": "",
676
+ "location": "",
675
677
  "observedProperty": "",
676
678
  "sensor": "",
677
679
  "thing": "",
@@ -672,6 +672,8 @@
672
672
  "value": ""
673
673
  },
674
674
  "datastreamsFilter": {
675
+ "datastream": "",
676
+ "location": "",
675
677
  "observedProperty": "",
676
678
  "sensor": "",
677
679
  "thing": "",
@@ -672,6 +672,8 @@
672
672
  "value": ""
673
673
  },
674
674
  "datastreamsFilter": {
675
+ "datastream": "",
676
+ "location": "",
675
677
  "observedProperty": "",
676
678
  "sensor": "",
677
679
  "thing": "",
@@ -672,6 +672,8 @@
672
672
  "value": ""
673
673
  },
674
674
  "datastreamsFilter": {
675
+ "datastream": "",
676
+ "location": "",
675
677
  "observedProperty": "",
676
678
  "sensor": "",
677
679
  "thing": "",
@@ -672,6 +672,8 @@
672
672
  "value": ""
673
673
  },
674
674
  "datastreamsFilter": {
675
+ "datastream": "",
676
+ "location": "",
675
677
  "observedProperty": "",
676
678
  "sensor": "",
677
679
  "thing": "",
@@ -672,6 +672,8 @@
672
672
  "value": ""
673
673
  },
674
674
  "datastreamsFilter": {
675
+ "datastream": "",
676
+ "location": "",
675
677
  "observedProperty": "",
676
678
  "sensor": "",
677
679
  "thing": "",
@@ -672,6 +672,8 @@
672
672
  "value": ""
673
673
  },
674
674
  "datastreamsFilter": {
675
+ "datastream": "",
676
+ "location": "",
675
677
  "observedProperty": "",
676
678
  "sensor": "",
677
679
  "thing": "",
@@ -672,6 +672,8 @@
672
672
  "value": ""
673
673
  },
674
674
  "datastreamsFilter": {
675
+ "datastream": "",
676
+ "location": "",
675
677
  "observedProperty": "",
676
678
  "sensor": "",
677
679
  "thing": "",
@@ -672,6 +672,8 @@
672
672
  "value": ""
673
673
  },
674
674
  "datastreamsFilter": {
675
+ "datastream": "",
676
+ "location": "",
675
677
  "observedProperty": "",
676
678
  "sensor": "",
677
679
  "thing": "",
@@ -672,6 +672,8 @@
672
672
  "value": ""
673
673
  },
674
674
  "datastreamsFilter": {
675
+ "datastream": "",
676
+ "location": "",
675
677
  "observedProperty": "",
676
678
  "sensor": "",
677
679
  "thing": "",
@@ -580,6 +580,8 @@
580
580
  "sensorthingstool.datastreamTable.title",
581
581
  "sensorthingstool.datastreamTable.unit",
582
582
  "sensorthingstool.datastreamTable.value",
583
+ "sensorthingstool.datastreamsFilter.datastream",
584
+ "sensorthingstool.datastreamsFilter.location",
583
585
  "sensorthingstool.datastreamsFilter.observedProperty",
584
586
  "sensorthingstool.datastreamsFilter.sensor",
585
587
  "sensorthingstool.datastreamsFilter.thing",
@@ -672,6 +672,8 @@
672
672
  "value": ""
673
673
  },
674
674
  "datastreamsFilter": {
675
+ "datastream": "",
676
+ "location": "",
675
677
  "observedProperty": "",
676
678
  "sensor": "",
677
679
  "thing": "",