@c8y/ng1-modules 1017.0.134 → 1017.0.135

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.
@@ -1 +1 @@
1
- "use strict";!function(){function t(c){t.$inject=["$injector","c8yModal"];var i,a=new WeakMap,f={},u={},p={};function s(t,e,r){var o=f[t],n=_.isArray(e)?e:e.$inject;void 0===n&&(n=c.annotate(e));var i=_.includes(n,"config");if(o)throw new Error('Computed property "'.concat(t,'" already registered'));if(i){if(p[t])throw new Error('Computed property factory "'.concat(t,'" already registered'));p[t]={config:r,property:e}}f[t]={config:r,property:e}}function e(o,t){var n=p[t];if(!n)throw new Error('Computed property factory "'.concat(t,'" is not registered'));return{create:function(t,e){if(u[t])throw new Error('Computed property "'.concat(t,'" already registered'));return u[t]={getter:o.invoke(n.property,void 0,{config:e}),config:n.config},!0},attach:function(t,e,r){d(t,e,{getter:o.invoke(n.property,void 0,{config:r})})}}}function r(r){_.forEach(f,function(e,t){u[t]||(u[t]={_lazy:!0,getter:function(){var t=this._getter;return t||(this._getter=r.invoke(e.property,void 0,{config:!1}),t=this._getter),t},config:e.config})})}function g(t,e){if(_.isArray(e))return function(e,t){var c=_.keys(p),a=_.union(_.keys(u),c);_(t).filter("computed").map(function(t){var e=_.last(t.id.split("!!")),r=(t.config||{})._id||String(Math.random()).substr(2),o=t.config||{},n=_.includes(a,e),i=e+(_.includes(c,e)?"_".concat(r):"");return(t.config=o)._id=r,n&&(t.keyPath=[i]),{key:e,keyPath:i,isFactory:_.includes(c,e),config:o,exists:n}}).filter("exists").forEach(function(t){t.isFactory?i(t.key).attach(e,t.keyPath,t.config):g(e,t.key)})}(t,e),t;var r=e;if(r){var o=u[r];if(!o)throw new Error('Computed property "'.concat(r,'" is not registered.'));d(t,r,o)}else!function(i){_.forEach(u,function(e,r){var t=function(t){return t&&d(i,r,e)},o=(e.config||{}).attachIf,n=(o=o||_.constant(!0))(i);_.isFunction(_.get(n,"then"))?n.then(t):t(n)})}(t);return t}function d(t,e,r){if(_.isObjectLike(t)){if(!_.has(t,e)){var o=r._lazy?r.getter():r.getter,n=o.detach||_.noop,i=a.get(t);i||(i=[],a.set(t,i)),i.push(function(t){n(t),delete t[e]}),Object.defineProperty(t,e,{enumerable:!1,configurable:!0,get:function(){return o(this)}})}}else console.warn("[Computed properties] Managed object is not an object")}function l(e){var r=this,t=a.get(e);_.forEach(t,function(t){try{t.call(r,e)}catch(t){console.error("Error detaching computed property",t)}}),a.delete(e)}function t(t,n){var o=_.partial(r,t);return{register:function(t,e,r){s(t,e,r),o()},attach:g,detach:l,factory:i=_.partial(e,t),init:o,edit:function(t){var e=_.last(t.id.split("!!")),r=p[e];if(!r)throw new Error("".concat(e," is not a factory computed property."));var o=_.get(r,"config.configTemplateUrl");return n({templateUrl:":::PLUGIN_PATH:::/ui/properties/computedPropertyConfigModal.html",controller:"ComputedPropertyConfigCtrl",size:"lg",resolve:{options:function(){return{configTemplateUrl:o,computedProperty:e,configSchema:_.isObjectLike(t.configSchema)&&t.configSchema,config:angular.copy(t.config)||{},prop:t}}}})},listFactories:function(){return _.map(p,function(t,e){return{id:e,config:_.clone(t.config)}})}}}return{register:s,$get:t}}function e(t){t.init()}e.$inject=["c8yComputedProperties"],t.$inject=["$injector"],angular.module("c8y.ui").provider("c8yComputedProperties",t).run(e)}();
1
+ "use strict";!function(){function t(c){t.$inject=["$injector","c8yModal"];var i,a=new WeakMap,f={},u={},p={};function s(t,e,r){var o=f[t],n=_.isArray(e)?e:e.$inject;void 0===n&&(n=c.annotate(e));var i=_.includes(n,"config");if(o)throw new Error('Computed property "'.concat(t,'" already registered'));if(i){if(p[t])throw new Error('Computed property factory "'.concat(t,'" already registered'));p[t]={config:r,property:e}}f[t]={config:r,property:e}}function e(o,t){var n=p[t];if(!n)throw new Error('Computed property factory "'.concat(t,'" is not registered'));return{create:function(t,e){if(u[t])throw new Error('Computed property "'.concat(t,'" already registered'));return u[t]={getter:o.invoke(n.property,void 0,{config:e}),config:n.config},!0},attach:function(t,e,r){d(t,e,{getter:o.invoke(n.property,void 0,{config:r})})}}}function r(r){_.forEach(f,function(e,t){u[t]||(u[t]={_lazy:!0,getter:function(){var t=this._getter;return t||(this._getter=r.invoke(e.property,void 0,{config:!1}),t=this._getter),t},config:e.config})})}function g(t,e){if(_.isArray(e))return function(e,t){var c=_.keys(p),a=_.union(_.keys(u),c);_(t).filter("computed").map(function(t){var e=_.last(t.id.split("!!")),r=(t.config||{})._id||String(Math.random()).substr(2),o=t.config||{},n=_.includes(a,e),i=e+(_.includes(c,e)?"_".concat(r):"");return(t.config=o)._id=r,n&&(t.keyPath=[i]),{key:e,keyPath:i,isFactory:_.includes(c,e),config:o,exists:n}}).filter("exists").forEach(function(t){t.isFactory?i(t.key).attach(e,t.keyPath,t.config):g(e,t.key)})}(t,e),t;var r=e;if(r){var o=u[r];if(!o)throw new Error('Computed property "'.concat(r,'" is not registered.'));d(t,r,o)}else!function(i){_.forEach(u,function(e,r){var t=function(t){return t&&d(i,r,e)},o=(e.config||{}).attachIf,n=(o=o||_.constant(!0))(i);_.isFunction(_.get(n,"then"))?n.then(t):t(n)})}(t);return t}function d(t,e,r){if(_.isObjectLike(t)){if(!_.has(t,e)){var o=r._lazy?r.getter():r.getter,n=o.detach||_.noop,i=a.get(t);i||(i=[],a.set(t,i)),i.push(function(t){n(t),delete t[e]}),Object.defineProperty(t,e,{enumerable:!1,configurable:!0,get:function(){return o(this)}})}}else console.warn("[Computed properties] Managed object is not an object")}function l(e){var r=this,t=a.get(e);_.forEach(t,function(t){try{t.call(r,e)}catch(t){console.error("Error detaching computed property",t)}}),a.delete(e)}function t(t,n){var o=_.partial(r,t);return{register:function(t,e,r){s(t,e,r),o()},attach:g,detach:l,factory:i=_.partial(e,t),init:o,edit:function(t){var e=_.last(t.id.split("!!")),r=p[e];if(!r)throw new Error("".concat(e," is not a factory computed property."));var o=_.get(r,"config.configTemplateUrl");return n({templateUrl:":::PLUGIN_PATH:::/ui/properties/computedPropertyConfigModal.html",controller:"ComputedPropertyConfigCtrl",size:"sm",resolve:{options:function(){return{configTemplateUrl:o,computedProperty:e,configSchema:_.isObjectLike(t.configSchema)&&t.configSchema,config:angular.copy(t.config)||{},prop:t}}}})},listFactories:function(){return _.map(p,function(t,e){return{id:e,config:_.clone(t.config)}})}}}return{register:s,$get:t}}function e(t){t.init()}e.$inject=["c8yComputedProperties"],t.$inject=["$injector"],angular.module("c8y.ui").provider("c8yComputedProperties",t).run(e)}();
@@ -1,38 +1,43 @@
1
- <div class="modal-header">
2
- <h3 id="modal-title" translate>Computed property configuration</h3>
3
- </div>
4
- <div class="modal-body" id="modal-body">
5
- <h4>
1
+ <div class="c8y-viewport-modal">
2
+ <div class="modal-header dialog-header">
6
3
  <i c8y-icon="bolt"></i>
7
- {{ computedProperty }}
8
- </h4>
4
+ <div id="modal-title-property" class="h4" translate>Computed property configuration</div>
5
+ </div>
6
+ <div class="modal-inner-scroll">
7
+ <p class="text-center bg-level-0 text-medium text-16 p-t-16 p-b-16 sticky-top separator-bottom"
8
+ style="z-index: 110;">
9
+ {{ computedProperty}}
10
+ </p>
11
+ <div class="modal-body no-card-context p-t-16" id="modal-body-property">
9
12
 
10
- <form name="configForm" novalidate>
11
- <div ng-if="configTemplateUrl" ng-include="configTemplateUrl"></div>
12
- <c8y-schema-form
13
- ng-if="configSchema"
14
- schema="configSchema"
15
- form="['*']"
16
- model="config"
17
- ></c8y-schema-form>
18
- </form>
19
- </div>
20
- <div class="modal-footer">
21
- <button
22
- title="{{ 'Cancel' | translate }}"
23
- type="button"
24
- class="btn btn-default"
25
- ng-click="$dismiss()"
26
- >
27
- {{ 'Cancel' | translate }}
28
- </button>
29
- <button
30
- title="{{ 'Save' | translate }}"
31
- type="button"
32
- class="btn btn-primary"
33
- ng-click="$close(config)"
34
- ng-disabled="configForm.$invalid"
35
- >
36
- {{ 'Save' | translate }}
37
- </button>
13
+ <form name="configForm" novalidate>
14
+ <div ng-if="configTemplateUrl" ng-include="configTemplateUrl"></div>
15
+ <c8y-schema-form
16
+ ng-if="configSchema"
17
+ schema="configSchema"
18
+ form="['*']"
19
+ model="config"
20
+ ></c8y-schema-form>
21
+ </form>
22
+ </div>
23
+ </div>
24
+ <div class="modal-footer">
25
+ <button
26
+ class="btn btn-default"
27
+ type="button"
28
+ title="{{ 'Cancel' | translate }}"
29
+ ng-click="$dismiss()"
30
+ >
31
+ {{ 'Cancel' | translate }}
32
+ </button>
33
+ <button
34
+ class="btn btn-primary"
35
+ type="button"
36
+ title="{{ 'Save' | translate }}"
37
+ ng-click="$close(config)"
38
+ ng-disabled="configForm.$invalid"
39
+ >
40
+ {{ 'Save' | translate }}
41
+ </button>
42
+ </div>
38
43
  </div>
@@ -22,13 +22,14 @@
22
22
 
23
23
  <div class="form-group">
24
24
  <label for="returnTypeField" translate>Return type</label>
25
- <select
26
- id="returnTypeField"
27
- class="form-control"
28
- ng-model="config.resultType"
29
- ng-options="resultType.value as (resultType.label | translate) for resultType in resultTypes.values()"
30
- >
31
- </select>
25
+ <div class="c8y-select-wrapper">
26
+ <select
27
+ id="returnTypeField"
28
+ class="form-control"
29
+ ng-model="config.resultType"
30
+ ng-options="resultType.value as (resultType.label | translate) for resultType in resultTypes.values()"
31
+ ></select>
32
+ </div>
32
33
  </div>
33
34
  </ng-form>
34
35
  </div>
@@ -6,18 +6,18 @@
6
6
  <div class="form-group m-16">
7
7
  <div class="input-group input-group-search">
8
8
  <input
9
- type="search"
10
9
  class="form-control"
11
- placeholder="{{ 'Filter properties' | translate }}"
10
+ type="search"
12
11
  ng-model="search"
12
+ placeholder="{{ 'Filter properties' | translate }}"
13
13
  />
14
14
  <span class="input-group-addon">
15
15
  <i c8y-icon="search" ng-show="search.length === 0 || !search"></i>
16
16
  <i
17
17
  c8y-icon="times"
18
18
  class="text-muted"
19
- ng-show="search.length > 0"
20
19
  ng-click="search = ''"
20
+ ng-show="search.length > 0"
21
21
  ></i>
22
22
  </span>
23
23
  </div>
@@ -39,8 +39,8 @@
39
39
 
40
40
  <div
41
41
  class="modal-inner-scroll container-fluid"
42
- id="modal-body"
43
42
  style="max-height: calc(100vh - 340px)"
43
+ id="modal-body"
44
44
  >
45
45
  <div class="row">
46
46
  <div
@@ -49,21 +49,24 @@
49
49
  >
50
50
  <div class="col-xs-2">
51
51
  <span ng-switch="selectSingle">
52
- <label ng-switch-when="true" class="c8y-radio">
52
+ <label class="c8y-radio" ng-switch-when="true">
53
53
  <input
54
- name="property"
55
54
  type="radio"
55
+ aria-label="{{ property.label }}"
56
+ id="radio-{{ property.keyPath.join('.') }}"
57
+ name="property"
56
58
  ng-model="properties.selected"
57
59
  ng-value="property"
58
60
  />
59
61
  <span></span>
60
62
  </label>
61
- <label ng-switch-default class="c8y-checkbox">
63
+ <label class="c8y-checkbox" ng-switch-default>
62
64
  <input
63
65
  type="checkbox"
64
- ng-model="property.__active"
66
+ aria-label="{{ property.label }}"
67
+ id="checkbox-{{ property.keyPath.join('.') }}"
65
68
  ng-change="onSelectProperty(property)"
66
- aria-label="{{ 'Complex property' | translate }}"
69
+ ng-model="property.__active"
67
70
  />
68
71
  <span></span>
69
72
  </label>
@@ -71,21 +74,24 @@
71
74
  </div>
72
75
  <div
73
76
  class="col-xs-5 text-truncate"
74
- title="{{ property.label | translate }}"
75
77
  ng-class="{ strong: isComplexProperty(property) }"
78
+ title="{{ property.label | translate }}"
76
79
  >
77
80
  <span>
78
81
  <button
79
82
  aria-label="{{ 'Complex property' | translate }}"
80
83
  class="btn btn-dot"
81
84
  type="button"
82
- ng-if="isComplexProperty(property) && isAtLeastOneSubpropertyListed(property)"
83
85
  uib-tooltip="{{
84
86
  'Complex property. Subproperties are listed below.`tooltip`' | translate
85
87
  }}"
86
- tooltip-placement="auto"
87
- tooltip-popup-delay="500"
88
88
  tooltip-append-to-body="true"
89
+ tooltip-placement="right"
90
+ tooltip-popup-delay="500"
91
+ aria-label="{{
92
+ 'Complex property. Subproperties are listed below.`tooltip`' | translate
93
+ }}"
94
+ ng-if="isComplexProperty(property) && isAtLeastOneSubpropertyListed(property)"
89
95
  >
90
96
  <i c8y-icon="tags" class="text-info"></i>
91
97
  </button>
@@ -93,27 +99,29 @@
93
99
  aria-label="{{ 'Complex property' | translate }}"
94
100
  class="btn btn-dot"
95
101
  type="button"
96
- ng-if="isComplexProperty(property) && !isAtLeastOneSubpropertyListed(property)"
97
102
  uib-tooltip="{{ 'Complex property.`tooltip`' | translate }}"
98
- tooltip-placement="auto"
99
103
  tooltip-append-to-body="true"
104
+ tooltip-placement="right"
105
+ aria-label="{{ 'Complex property.`tooltip`' | translate }}"
106
+ ng-if="isComplexProperty(property) && !isAtLeastOneSubpropertyListed(property)"
100
107
  >
101
- <i class="text-info" c8y-icon="tag"></i>
108
+ <i c8y-icon="tag" class="text-info"></i>
102
109
  </button>
103
110
  <button
104
111
  aria-label="{{ 'Computed property' | translate }}"
105
112
  class="btn btn-dot"
106
113
  type="button"
107
- ng-show="property.computed"
108
114
  uib-tooltip="{{ 'Computed property.`tooltip`' | translate }}"
115
+ tooltip-append-to-body="true"
109
116
  tooltip-placement="right"
110
117
  tooltip-popup-delay="500"
111
- tooltip-append-to-body="true"
118
+ aria-label="{{ 'Computed property.`tooltip`' | translate }}"
119
+ ng-show="property.computed"
112
120
  >
113
- <i class="text-primary-light" c8y-icon="bolt"></i>
121
+ <i c8y-icon="bolt" class="text-primary-light"></i>
114
122
  </button>
115
123
  </span>
116
- {{ property.label | translate }}
124
+ {{ property.label | translate }}
117
125
  </div>
118
126
  <div class="col-xs-5 text-truncate" title="{{ property.keyPath.join('.') }}">
119
127
  {{ property.keyPath.join('.') }}
@@ -133,10 +141,9 @@
133
141
  </button>
134
142
  <button
135
143
  title="{{ 'Select' | translate }}"
136
- type="button"
144
+ ng-click="close()"
137
145
  ng-disabled="selectIsDisabled()"
138
146
  class="btn btn-primary"
139
- ng-click="close()"
140
147
  >
141
148
  {{ 'Select' | translate }}
142
149
  </button>
@@ -1,85 +1,143 @@
1
- <div ng-controller="DataPointWidgetConfigCtrl" ng-init="disableLocalStorage = true">
2
- <div class="data-point-explorer" ng-controller="c8yDataPointExplorerCtrl">
3
- <div class="pull-right m-b-4">
4
- <c8y-realtime-button
5
- class="top-right-control"
6
- channel="{{ channel }}"
7
- state="data.realtime"
8
- on-data="onData($data)"
9
- ></c8y-realtime-button>
10
- <c8y-realtime-button
11
- ng-show="false"
12
- channel="{{ alarmsChannel }}"
13
- state="data.realtime"
14
- on-data="onAlarm($data)"
15
- on-data-update="onAlarm($data)"
16
- ></c8y-realtime-button>
17
- <c8y-realtime-button
18
- ng-show="false"
19
- channel="{{ eventsChannel }}"
20
- state="data.realtime"
21
- on-data="onEvent($data)"
22
- ></c8y-realtime-button>
23
- <c8y-aggregation
24
- class="top-right-control"
25
- date-from="data.dateFrom"
26
- date-to="data.dateTo"
27
- aggregation="data.aggregation"
28
- realtime="data.realtime"
29
- auto="true"
30
- ></c8y-aggregation>
31
- <c8y-interval
32
- class="top-right-control"
33
- date-from="data.dateFrom"
34
- date-to="data.dateTo"
35
- interval="data.interval"
36
- ></c8y-interval>
1
+ <div
2
+ ng-controller="DataPointWidgetConfigCtrl"
3
+ ng-init="disableLocalStorage = true"
4
+ class="row no-card-context d-flex"
5
+ style="height: calc(100vh - 422px);"
6
+ >
7
+ <div class="col-md-5 bg-level-1 a-s-stretch inner-scroll">
8
+ <div class="p-l-24 bg-inherit p-t-8">
9
+ <div class="form-group m-b-0 p-b-16 separator-bottom">
10
+ <label for="dateSelection">
11
+ {{ 'Date selection' | translate }}
12
+ <button
13
+ type="button"
14
+ class="btn-help btn-help--sm"
15
+ aria-label="{{ 'Help' | translate }}"
16
+ uib-popover-html="dateSelectionHelpPopoverText | translate"
17
+ popover-placement="right"
18
+ popover-trigger="'focus'"
19
+ popover-append-to-body="true"
20
+ ></button>
21
+ </label>
22
+ <div class="c8y-select-wrapper">
23
+ <select
24
+ id="dateSelection"
25
+ class="form-control"
26
+ title="{{ 'Date selection' | translate }}"
27
+ aria-label="{{ 'Date selection' | translate }}"
28
+ ng-model="dateSelection"
29
+ >
30
+ <option
31
+ title="{{ 'Widget configuration' | translate }}"
32
+ value="{{ 'config' }}"
33
+ >
34
+ {{ 'Widget configuration' | translate }}
35
+ </option>
36
+ <option
37
+ title="{{ 'Widget and widget configuration' | translate }}"
38
+ value="{{ 'view_and_config' }}"
39
+ >
40
+ {{ 'Widget and widget configuration' | translate }}
41
+ </option>
42
+ <option
43
+ title="{{ 'Dashboard time range' | translate }}"
44
+ value="{{ 'dashboard_context' }}"
45
+ >
46
+ {{ 'Dashboard time range' | translate }}
47
+ </option>
48
+ </select>
49
+ </div>
50
+ </div>
51
+
52
+ <c8y-data-point-list
53
+ datapoints="data.datapoints"
54
+ allow-adding-data-points-from-context-mo-only="dashboard.deviceType && dashboard.deviceTypeValue"
55
+ dont-save="true"
56
+ no-target
57
+ no-yellow-range
58
+ no-red-range
59
+ class="bg-inherit separator-bottom"
60
+ ></c8y-data-point-list>
61
+ <c8y-alarms-events-timelines-config
62
+ configs="data.alarmsEventsConfigs"
63
+ allow-alarms-events-from-context-mo-only="dashboard.deviceType && dashboard.deviceTypeValue"
64
+ class="d-block bg-inherit separator-top"
65
+ style="padding-top: 1px;"
66
+ ></c8y-alarms-events-timelines-config>
37
67
  </div>
38
- <div class="c8yGraphFill" style="height: 340px; clear: both">
39
- <c8y-chart
40
- datapoints="data.graphDataPoints"
41
- date-from="data.dateFrom"
42
- date-to="data.dateTo"
43
- realtime="data.realtime"
44
- aggregation="data.aggregation"
45
- show-time="true"
46
- on-data="(onData)"
47
- on-update-dates="onUpdateDates($dateFrom, $dateTo)"
48
- on-update-displayed-dates="onUpdateDisplayedDates($dateFrom, $dateTo)"
49
- on-box-changed="onBoxChanged(box)"
50
- ></c8y-chart>
68
+ </div>
69
+
70
+ <div class="col-md-7 sticky-top">
71
+ <div class="p-r-24 p-t-8">
72
+ <div
73
+ class="data-point-explorer d-flex d-col"
74
+ ng-controller="c8yDataPointExplorerCtrl"
75
+ >
76
+ <div class="m-b-4 m-t-4 d-flex j-c-end gap-8">
77
+ <c8y-realtime-button
78
+ ng-show="!data.widgetInstanceGlobalTimeContext"
79
+ class="top-right-control"
80
+ channel="{{ channel }}"
81
+ state="data.realtime"
82
+ on-data="onData($data)"
83
+ ></c8y-realtime-button>
84
+ <c8y-realtime-button
85
+ ng-show="false"
86
+ channel="{{ alarmsChannel }}"
87
+ state="data.realtime"
88
+ on-data="onAlarm($data)"
89
+ on-data-update="onAlarm($data)"
90
+ ></c8y-realtime-button>
91
+ <c8y-realtime-button
92
+ ng-show="false"
93
+ channel="{{ eventsChannel }}"
94
+ state="data.realtime"
95
+ on-data="onEvent($data)"
96
+ ></c8y-realtime-button>
97
+ <c8y-aggregation
98
+ class="top-right-control"
99
+ date-from="data.dateFrom"
100
+ date-to="data.dateTo"
101
+ aggregation="data.aggregation"
102
+ realtime="data.realtime"
103
+ auto="true"
104
+ ></c8y-aggregation>
105
+ <c8y-interval
106
+ ng-show="!data.widgetInstanceGlobalTimeContext"
107
+ class="top-right-control"
108
+ date-from="data.dateFrom"
109
+ date-to="data.dateTo"
110
+ interval="data.interval"
111
+ ></c8y-interval>
112
+ </div>
113
+ <div
114
+ class="c8yGraphFill"
115
+ style="height: calc(100vh - 520px);"
116
+ >
117
+ <c8y-chart
118
+ datapoints="data.graphDataPoints"
119
+ date-from="data.dateFrom"
120
+ date-to="data.dateTo"
121
+ realtime="data.realtime"
122
+ aggregation="data.aggregation"
123
+ show-time="!data.widgetInstanceGlobalTimeContext"
124
+ on-data="(onData)"
125
+ on-update-dates="onUpdateDates($dateFrom, $dateTo)"
126
+ on-update-displayed-dates="onUpdateDisplayedDates($dateFrom, $dateTo)"
127
+ on-box-changed="onBoxChanged(box)"
128
+ ></c8y-chart>
129
+ </div>
130
+ <c8y-alarms-events-timelines-chart
131
+ alarms-events-configs="data.graphAlarmsEventsConfigs"
132
+ date-from="data.displayedDateFrom"
133
+ date-to="data.displayedDateTo"
134
+ on-update-dates="onUpdateDates($dateFrom, $dateTo)"
135
+ realtime="data.realtime"
136
+ on-realtime-alarm-fn="onRealtimeAlarmFn(onRealtimeAlarm)"
137
+ on-realtime-event-fn="onRealtimeEventFn(onRealtimeEvent)"
138
+ chart-box="chartBox"
139
+ ></c8y-alarms-events-timelines-chart>
140
+ </div>
51
141
  </div>
52
- <c8y-alarms-events-timelines-chart
53
- alarms-events-configs="data.graphAlarmsEventsConfigs"
54
- date-from="data.displayedDateFrom"
55
- date-to="data.displayedDateTo"
56
- on-update-dates="onUpdateDates($dateFrom, $dateTo)"
57
- realtime="data.realtime"
58
- on-realtime-alarm-fn="onRealtimeAlarmFn(onRealtimeAlarm)"
59
- on-realtime-event-fn="onRealtimeEventFn(onRealtimeEvent)"
60
- chart-box="chartBox"
61
- ></c8y-alarms-events-timelines-chart>
62
- <c8y-data-point-list
63
- datapoints="data.datapoints"
64
- allow-adding-data-points-from-context-mo-only="dashboard.deviceType && dashboard.deviceTypeValue"
65
- dont-save="true"
66
- no-target
67
- no-yellow-range
68
- no-red-range
69
- class="bg-level-0"
70
- ></c8y-data-point-list>
71
- <c8y-alarms-events-timelines-config
72
- configs="data.alarmsEventsConfigs"
73
- allow-alarms-events-from-context-mo-only="dashboard.deviceType && dashboard.deviceTypeValue"
74
- class="bg-level-0"
75
- ></c8y-alarms-events-timelines-config>
76
- <label
77
- title="{{ 'Show date selection' | translate }}"
78
- class="checkbox-inline c8y-checkbox m-t-16"
79
- >
80
- <input type="checkbox" ng-model="data.displayDateSelection" />
81
- <span></span>
82
- <span>{{ 'Show date selection' | translate }}</span>
83
- </label>
84
142
  </div>
85
143
  </div>
@@ -1,54 +1,111 @@
1
- <div ng-controller="DataPointWidgetConfigCtrl" ng-init="disableLocalStorage = true">
2
- <div class="data-point-explorer" ng-controller="c8yDataPointExplorerCtrl">
3
- <div class="pull-right m-b-4">
4
- <c8y-realtime-button
5
- class="top-right-control"
6
- channel="{{ channel }}"
7
- state="data.realtime"
8
- on-data="onData($data)"
9
- ></c8y-realtime-button>
10
- <c8y-aggregation
11
- class="top-right-control"
12
- date-from="data.dateFrom"
13
- date-to="data.dateTo"
14
- aggregation="data.aggregation"
15
- realtime="data.realtime"
16
- auto="true"
17
- ></c8y-aggregation>
18
- <c8y-interval
19
- class="top-right-control"
20
- date-from="data.dateFrom"
21
- date-to="data.dateTo"
22
- interval="data.interval"
23
- ></c8y-interval>
24
- </div>
25
- <div class="c8yGraphFill" style="height: 340px; clear: both">
26
- <c8y-chart
27
- datapoints="data.graphDataPoints"
28
- date-from="data.dateFrom"
29
- date-to="data.dateTo"
30
- realtime="data.realtime"
31
- aggregation="data.aggregation"
32
- show-time="true"
33
- on-data="(onData)"
34
- on-update-dates="onUpdateDates($dateFrom, $dateTo)"
35
- on-update-displayed-dates="onUpdateDisplayedDates($dateFrom, $dateTo)"
36
- on-box-changed="onBoxChanged(box)"
37
- ></c8y-chart>
38
- </div>
39
- <c8y-data-point-list
40
- datapoints="data.datapoints"
41
- allow-adding-data-points-from-context-mo-only="dashboard.deviceType && dashboard.deviceTypeValue"
42
- dont-save="true"
43
- class="bg-level-0"
44
- ></c8y-data-point-list>
45
- <label
46
- class="checkbox-inline c8y-checkbox m-t-24"
47
- title="{{ 'Show date selection' | translate }}"
48
- >
49
- <input type="checkbox" ng-model="data.displayDateSelection" />
50
- <span></span>
51
- <span>{{ 'Show date selection' | translate }}</span>
52
- </label>
53
- </div>
54
- </div>
1
+ <div
2
+ ng-controller="DataPointWidgetConfigCtrl"
3
+ ng-init="disableLocalStorage = true"
4
+ class="row no-card-context d-flex"
5
+ style="height: calc(100vh - 422px);"
6
+ >
7
+ <div class="col-md-5 bg-level-1 a-s-stretch inner-scroll">
8
+ <div class="p-l-24 bg-inherit p-t-8">
9
+ <div class="form-group m-b-0 p-b-16 separator-bottom">
10
+ <label for="dateSelection">
11
+ {{ 'Date selection' | translate }}
12
+ <button
13
+ type="button"
14
+ class="btn-help btn-help--sm"
15
+ aria-label="{{ 'Help' | translate }}"
16
+ uib-popover-html="dateSelectionHelpPopoverText | translate"
17
+ popover-placement="right"
18
+ popover-trigger="'focus'"
19
+ popover-append-to-body="true"
20
+ ></button>
21
+ </label>
22
+ <div class="c8y-select-wrapper">
23
+ <select
24
+ id="dateSelection"
25
+ class="form-control"
26
+ title="{{ 'Date selection' | translate }}"
27
+ aria-label="{{ 'Date selection' | translate }}"
28
+ ng-model="dateSelection"
29
+ >
30
+ <option
31
+ title="{{ 'Widget configuration' | translate }}"
32
+ value="{{ 'config' }}"
33
+ >
34
+ {{ 'Widget configuration' | translate }}
35
+ </option>
36
+ <option
37
+ title="{{ 'Widget and widget configuration' | translate }}"
38
+ value="{{ 'view_and_config' }}"
39
+ >
40
+ {{ 'Widget and widget configuration' | translate }}
41
+ </option>
42
+ <option
43
+ title="{{ 'Dashboard time range' | translate }}"
44
+ value="{{ 'dashboard_context' }}"
45
+ >
46
+ {{ 'Dashboard time range' | translate }}
47
+ </option>
48
+ </select>
49
+ </div>
50
+ </div>
51
+
52
+ <c8y-data-point-list
53
+ datapoints="data.datapoints"
54
+ allow-adding-data-points-from-context-mo-only="dashboard.deviceType && dashboard.deviceTypeValue"
55
+ dont-save="true"
56
+ class="bg-inherit separator-bottom"
57
+ ></c8y-data-point-list>
58
+ </div>
59
+ </div>
60
+
61
+ <div class="col-md-7 sticky-top">
62
+ <div class="p-r-24 p-t-8">
63
+ <div
64
+ class="data-point-explorer d-flex d-col"
65
+ ng-controller="c8yDataPointExplorerCtrl"
66
+ >
67
+ <div class="m-b-4 m-t-4 d-flex j-c-end gap-8">
68
+ <c8y-realtime-button
69
+ ng-show="!data.widgetInstanceGlobalTimeContext"
70
+ class="top-right-control"
71
+ channel="{{ channel }}"
72
+ state="data.realtime"
73
+ on-data="onData($data)"
74
+ ></c8y-realtime-button>
75
+ <c8y-aggregation
76
+ class="top-right-control"
77
+ date-from="data.dateFrom"
78
+ date-to="data.dateTo"
79
+ aggregation="data.aggregation"
80
+ realtime="data.realtime"
81
+ auto="true"
82
+ ></c8y-aggregation>
83
+ <c8y-interval
84
+ ng-show="!data.widgetInstanceGlobalTimeContext"
85
+ class="top-right-control"
86
+ date-from="data.dateFrom"
87
+ date-to="data.dateTo"
88
+ interval="data.interval"
89
+ ></c8y-interval>
90
+ </div>
91
+ <div
92
+ class="c8yGraphFill"
93
+ style="height: calc(100vh - 520px);"
94
+ >
95
+ <c8y-chart
96
+ datapoints="data.graphDataPoints"
97
+ date-from="data.dateFrom"
98
+ date-to="data.dateTo"
99
+ realtime="data.realtime"
100
+ aggregation="data.aggregation"
101
+ show-time="!data.widgetInstanceGlobalTimeContext"
102
+ on-data="(onData)"
103
+ on-update-dates="onUpdateDates($dateFrom, $dateTo)"
104
+ on-update-displayed-dates="onUpdateDisplayedDates($dateFrom, $dateTo)"
105
+ on-box-changed="onBoxChanged(box)"
106
+ ></c8y-chart>
107
+ </div>
108
+ </div>
109
+ </div>
110
+ </div>
111
+ </div>
@@ -1,7 +1,10 @@
1
1
  <div ng-controller="kpiConfigCtrl">
2
- <div ng-controller="listConfigCtrl">
3
- <div class="form-group">
4
- <label translate>Data point</label>
2
+ <div
3
+ ng-controller="listConfigCtrl"
4
+ class="no-card-context row m-l-0 m-r-0"
5
+ style="height: calc(100vh - 422px)"
6
+ >
7
+ <div class="col-md-6 p-l-24 inner-scroll bg-level-1">
5
8
  <c8y-data-point-list
6
9
  ng-model="config"
7
10
  datapoints="config.options.dataPoints"
@@ -10,28 +13,60 @@
10
13
  allow-adding-data-points-from-context-mo-only="dashboard.deviceType && dashboard.deviceTypeValue"
11
14
  ></c8y-data-point-list>
12
15
  </div>
13
- <label translate>Column visibility</label>
14
-
15
- <div class="form-group">
16
- <label class="checkbox-inline">
17
- <input type="checkbox" ng-model="config.options.kpi" /> <translate>Label</translate>
18
- </label>
19
- <label class="checkbox-inline">
20
- <input type="checkbox" ng-model="config.options.target" /> <translate>Target</translate>
21
- </label>
22
- <label class="checkbox-inline">
23
- <input type="checkbox" ng-model="config.options.current" /> <translate>Current</translate>
24
- </label>
25
- <label class="checkbox-inline">
26
- <input type="checkbox" ng-model="config.options.diff" /> <translate>Diff</translate>
27
- </label>
28
- <label class="checkbox-inline">
29
- <input type="checkbox" ng-model="config.options.diffPercentage" />
30
- <translate>Diff %</translate>
31
- </label>
32
- <label class="checkbox-inline">
33
- <input type="checkbox" ng-model="config.options.asset" /> <translate>Asset</translate>
34
- </label>
16
+ <div class="col-md-6 p-r-24 inner-scroll">
17
+ <div class="card-header separator sticky-top bg-level-0">
18
+ <span class="card-title">{{ 'Column visibility' | translate }}</span>
19
+ </div>
20
+ <div class="form-group p-t-8">
21
+ <label class="c8y-checkbox">
22
+ <input
23
+ type="checkbox"
24
+ ng-model="config.options.kpi"
25
+ />
26
+ <span></span>
27
+ <span>{{ 'Label' | translate }}</span>
28
+ </label>
29
+ <label class="c8y-checkbox">
30
+ <input
31
+ type="checkbox"
32
+ ng-model="config.options.target"
33
+ />
34
+ <span></span>
35
+ <span>{{ 'Target' | translate }}</span>
36
+ </label>
37
+ <label class="c8y-checkbox">
38
+ <input
39
+ type="checkbox"
40
+ ng-model="config.options.current"
41
+ />
42
+ <span></span>
43
+ <span>{{ 'Current' | translate }}</span>
44
+ </label>
45
+ <label class="c8y-checkbox">
46
+ <input
47
+ type="checkbox"
48
+ ng-model="config.options.diff"
49
+ />
50
+ <span></span>
51
+ <span>{{ 'Diff' | translate }}</span>
52
+ </label>
53
+ <label class="c8y-checkbox">
54
+ <input
55
+ type="checkbox"
56
+ ng-model="config.options.diffPercentage"
57
+ />
58
+ <span></span>
59
+ <span>{{ 'Diff %' | translate }}</span>
60
+ </label>
61
+ <label class="c8y-checkbox">
62
+ <input
63
+ type="checkbox"
64
+ ng-model="config.options.asset"
65
+ />
66
+ <span></span>
67
+ <span>{{ 'Asset' | translate }}</span>
68
+ </label>
69
+ </div>
35
70
  </div>
36
71
  </div>
37
72
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c8y/ng1-modules",
3
- "version": "1017.0.134",
3
+ "version": "1017.0.135",
4
4
  "license": "Apache-2.0",
5
5
  "author": "Cumulocity",
6
6
  "description": "AngularJS modules for Cumulocity IoT applications.",
@@ -1,5 +1,8 @@
1
- <div ng-controller="ScadaWidgetConfigCtrl as ctrl">
2
- <div class="form-group">
1
+ <div
2
+ ng-controller="ScadaWidgetConfigCtrl as ctrl"
3
+ class="p-t-8"
4
+ >
5
+ <div>
3
6
  <label>
4
7
  <span translate>SVG</span>
5
8
  <button
@@ -14,7 +17,10 @@
14
17
  ></button>
15
18
  </label>
16
19
 
17
- <div class="alert alert-info text-left" ng-show="svgTooltipVisible">
20
+ <div
21
+ class="alert alert-info text-left"
22
+ ng-show="svgTooltipVisible"
23
+ >
18
24
  <p translate>
19
25
  For placeholder to be recognized it needs to be used at least once in curly braces with no
20
26
  other expression, for example,
@@ -59,32 +65,54 @@
59
65
  </div>
60
66
 
61
67
  <div class="form-group">
62
- <label translate>Select code sanitization option</label>
63
- <select
64
- class="form-control"
65
- ng-model="config.sanitization"
66
- ng-init="config.sanitization = config.sanitization || 'strict'"
67
- >
68
- <option value="strict" translate>strict`code sanitization`</option>
69
- <option value="lax" translate>lax`code sanitization`</option>
70
- <option value="none" translate>none`code sanitization`</option>
71
- </select>
68
+ <label for="sanitization" translate>Select code sanitization option</label>
69
+ <div class="c8y-select-wrapper">
70
+ <select
71
+ class="form-control"
72
+ id="sanitization"
73
+ ng-model="config.sanitization"
74
+ ng-init="config.sanitization = config.sanitization || 'strict'"
75
+ >
76
+ <option
77
+ value="strict"
78
+ translate
79
+ >strict`code sanitization`</option>
80
+ <option
81
+ value="lax"
82
+ translate
83
+ >lax`code sanitization`</option>
84
+ <option
85
+ value="none"
86
+ translate
87
+ >none`code sanitization`</option>
88
+ </select>
89
+ </div>
90
+ </div>
91
+ <div class="form-group">
92
+ <file-picker
93
+ files="ctrl.files"
94
+ multiple="false"
95
+ display-drop-zone="false"
96
+ on-file-selected="ctrl.onSelectFile(ctrl.files[0].file)"
97
+ ></file-picker>
98
+ <input type="hidden" />
72
99
  </div>
73
-
74
- <file-picker
75
- files="ctrl.files"
76
- multiple="false"
77
- display-drop-zone="false"
78
- on-file-selected="ctrl.onSelectFile(ctrl.files[0].file)"
79
- ></file-picker>
80
- <input type="hidden" />
81
- <span id="helpBlock" class="help-block m-b-16" translate>SVG content will be sanitized.</span>
82
100
  </div>
83
-
84
- <div class="form-group">
85
- <label>{{ 'Preview' | translate }}</label>
86
- <span ng-show="ctrl.loading" class="m-l-4">
87
- <i c8y-icon="spinner" class="icon-spin"></i>
101
+ <div class="form-group p-t-16">
102
+ <label class="input-group">{{ 'Preview' | translate }}</label>
103
+ <span
104
+ id="helpBlock"
105
+ class="help-block m-b-8"
106
+ translate
107
+ >SVG content will be sanitized.</span>
108
+ <span
109
+ ng-show="ctrl.loading"
110
+ class="m-l-4"
111
+ >
112
+ <i
113
+ c8y-icon="spinner"
114
+ class="icon-spin"
115
+ ></i>
88
116
  </span>
89
117
  <div ng-switch="!!(ctrl.device && forms.componentForm.mapping.$valid && config.mapping)">
90
118
  <div
@@ -95,14 +123,16 @@
95
123
  device="ctrl.device"
96
124
  devices="ctrl.devices"
97
125
  device-ids="config.deviceIds"
98
- style="height: 200px"
99
126
  ></div>
100
- <div ng-switch-default class="alert alert-info" translate>
101
- You need to select a device and fill all mappings to be able to preview an SVG.
127
+ <div
128
+ ng-switch-default
129
+ class="alert alert-info"
130
+ translate
131
+ >
132
+ Select a device and fill all mappings to preview an SVG.
102
133
  </div>
103
134
  </div>
104
135
  </div>
105
-
106
136
  <div
107
137
  c8y-scada-mapping
108
138
  name="mapping"
@@ -111,6 +141,6 @@
111
141
  devices="ctrl.devices"
112
142
  device-ids="config.deviceIds"
113
143
  on-device-ids-change="ctrl.onDeviceIdsChange()"
114
- class="table-responsive"
115
144
  ></div>
145
+
116
146
  </div>
@@ -1,102 +1,113 @@
1
- <table class="table">
2
- <colgroup>
3
- <col width="20%">
4
- <col width="20%">
5
- <col width="20%">
6
- <col width="20%">
7
- <col width="148px">
8
- </colgroup>
9
- <thead>
10
- <tr>
11
- <th>
12
- <label translate>Placeholder</label>
13
- </th>
14
- <th>
15
- <label translate>Target</label>
16
- </th>
17
- <th>
18
- <label translate>Mapped to</label>
19
- </th>
20
- <th>
21
- <label translate>Current value</label>
22
- </th>
23
- <th></th>
24
- </tr>
25
- </thead>
26
- <tbody>
27
- <tr
28
- ng-repeat="mapping in mappings | orderBy:'placeholder'"
29
- class="property"
30
- ng-class="{ danger: hasError[mapping.placeholder] }"
31
- >
32
- <td class="text-truncate" title="{{ mapping.placeholder }}">
33
- {{ mapping.placeholder }}
34
- </td>
35
- <td class="form-group-sm">
36
- <span ng-show="devices.length == 1">
37
- {{ devices[0].name }}
38
- </span>
39
- <div class="c8y-select-wrapper" ng-show="devices.length > 1">
40
- <select
41
- class="form-control"
42
- ng-options="device.id as device.name for device in devices"
43
- ng-model="deviceIds[mapping.placeholder]"
44
- ng-change="onDeviceIdsChange()"
45
- required
46
- >
47
- </select>
48
- <span></span>
1
+ <div class="svg-mappings">
2
+ <label>{{ 'Mappings' | translate }}</label>
3
+ <ul class="c8y-list__group c8y-list__group--strip">
4
+ <li class="c8y-list__item" ng-repeat="mapping in mappings | orderBy:'placeholder'">
5
+ <div class="c8y-list__item__block d-block">
6
+ <div class="c8y-list__item__body">
7
+ <div class="row">
8
+ <div class="col-md-4">
9
+ <label class="text-label-small d-block" translate>Placeholder</label>
10
+ <div class="text-medium">
11
+ <i
12
+ c8y-icon="exclamation-circle"
13
+ class="m-r-4 text-danger"
14
+ ng-show="hasError[mapping.placeholder]"
15
+ ></i>
16
+ <span title="{{ mapping.placeholder }}">
17
+ {{ mapping.placeholder }}
18
+ </span>
19
+ </div>
20
+ </div>
21
+ <div class="col-md-8">
22
+ <label class="text-label-small d-block" translate>Target</label>
23
+ <div class="form-group-sm form-group">
24
+ <span ng-show="!devices.length">---</span>
25
+ <span
26
+ class="text-truncate"
27
+ title="{{ devices[0].name }}"
28
+ ng-show="devices.length == 1"
29
+ >
30
+ {{ devices[0].name }}
31
+ </span>
32
+ <div class="c8y-select-wrapper" ng-show="devices.length > 1">
33
+ <select
34
+ class="form-control"
35
+ ng-change="onDeviceIdsChange()"
36
+ ng-model="deviceIds[mapping.placeholder]"
37
+ ng-options="device.id as device.name for device in devices"
38
+ required
39
+ ></select>
40
+ </div>
41
+ </div>
42
+ </div>
43
+ <div class="col-md-4" ng-switch="!!mapping.config.configSchema">
44
+ <label class="text-label-small d-block" translate>Mapped to</label>
45
+ <button
46
+ class="btn btn-sm btn-default text-truncate"
47
+ type="button"
48
+ title=" {{ humanizeValue(mapping) }}"
49
+ ng-click="editComputedProperty(mapping)"
50
+ ng-switch-when="true"
51
+ >
52
+ <i c8y-icon="bolt"></i>
53
+ <span>
54
+ {{ humanizeValue(mapping) }}
55
+ </span>
56
+ </button>
57
+ <div class="form-control-static">
58
+ <span class="text-truncate" title="{{ humanizeValue(mapping) }}" ng-switch-default>
59
+ {{ humanizeValue(mapping) }}
60
+ </span>
61
+ </div>
62
+ </div>
63
+ <div class="col-md-4">
64
+ <label class="text-label-small d-block" translate>Current value</label>
65
+ <div class="form-control-static" title="{{ propertyValueFor(mapping) }}">
66
+ <span class="text-truncate text-monospace">
67
+ {{ propertyValueFor(mapping) }}
68
+ </span>
69
+ </div>
70
+ </div>
71
+ <div class="col-md-4">
72
+ <label class="text-label-small d-block" translate>Actions</label>
73
+ <button
74
+ class="btn btn-default btn-sm"
75
+ type="button"
76
+ uib-tooltip="{{ 'Clear mapping' | translate }}"
77
+ tooltip-append-to-body="true"
78
+ tooltip-popup-delay="500"
79
+ aria-label="{{ 'Clear mapping' | translate }}"
80
+ ng-click="clearMapping(mapping)"
81
+ ng-disabled="!mapping.config"
82
+ >
83
+ <i c8y-icon="delete-document"></i>
84
+ </button>
85
+ <button
86
+ class="btn btn-default btn-sm"
87
+ type="button"
88
+ uib-tooltip="{{ 'Assign fieldbus property' | translate }}"
89
+ tooltip-append-to-body="true"
90
+ tooltip-popup-delay="500"
91
+ aria-label="{{ 'Assign fieldbus property' | translate }}"
92
+ ng-click="setFieldbusMapping(mapping)"
93
+ >
94
+ <i c8y-icon="tasks"></i>
95
+ </button>
96
+ <button
97
+ class="btn btn-default btn-sm"
98
+ type="button"
99
+ uib-tooltip="{{ 'Assign device property' | translate }}"
100
+ tooltip-append-to-body="true"
101
+ tooltip-popup-delay="500"
102
+ aria-label="{{ 'Assign device property' | translate }}"
103
+ ng-click="setMapping(mapping)"
104
+ >
105
+ <i c8y-icon="edit"></i>
106
+ </button>
107
+ </div>
108
+ </div>
49
109
  </div>
50
- </td>
51
- <td
52
- ng-switch="!!mapping.config.configSchema"
53
- class="text-truncate"
54
- title="{{ humanizeValue(mapping) }}"
55
- >
56
- <a
57
- ng-switch-when="true"
58
- class="btn btn-xs btn-default"
59
- href=""
60
- ng-click="editComputedProperty(mapping)"
61
- >
62
- <i c8y-icon="bolt"></i>
63
- {{ humanizeValue(mapping) }}
64
- </a>
65
- <span ng-switch-default>{{ humanizeValue(mapping) }}</span>
66
- </td>
67
- <td class="text-truncate">
68
- <span title=" {{ propertyValueFor(mapping) }}">
69
- {{ propertyValueFor(mapping) }}
70
- </span>
71
- </td>
72
- <td>
73
- <div class="d-flex flex-end">
74
- <button
75
- type="button"
76
- class="btn btn-danger btn-xs showOnHover pull-right"
77
- title="{{ 'Clear mapping' | translate }}"
78
- ng-click="clearMapping(mapping)"
79
- >
80
- <i c8y-icon="scissors"></i>
81
- </button>
82
- <button
83
- type="button"
84
- class="btn btn-primary btn-xs showOnHover pull-right"
85
- title="{{ 'Assign fieldbus property' | translate }}"
86
- ng-click="setFieldbusMapping(mapping)"
87
- >
88
- <i c8y-icon="tasks"></i>
89
- </button>
90
- <button
91
- type="button"
92
- class="btn btn-primary btn-xs showOnHover pull-right"
93
- title="{{ 'Assign device property' | translate }}"
94
- ng-click="setMapping(mapping)"
95
- >
96
- <i c8y-icon="pencil"></i>
97
- </button>
98
- </div>
99
- </td>
100
- </tr>
101
- </tbody>
102
- </table>
110
+ </div>
111
+ </li>
112
+ </ul>
113
+ </div>