Commit 25ba81394dee5afe6d63e4c9db18a6a6d5036bae
Merge branch 'master' of github.com:thingsboard/thingsboard into develop/3.0
Showing
25 changed files
with
464 additions
and
130 deletions
... | ... | @@ -29,6 +29,8 @@ import thingsboardWebCameraInputWidget from '../widget/lib/web-camera-input-widg |
29 | 29 | |
30 | 30 | import thingsboardRpcWidgets from '../widget/lib/rpc'; |
31 | 31 | |
32 | +import thingsboardJsonToString from '../components/tb-json-to-string.directive'; | |
33 | + | |
32 | 34 | import TbFlot from '../widget/lib/flot-widget'; |
33 | 35 | import TbAnalogueLinearGauge from '../widget/lib/analogue-linear-gauge'; |
34 | 36 | import TbAnalogueRadialGauge from '../widget/lib/analogue-radial-gauge'; |
... | ... | @@ -52,7 +54,7 @@ export default angular.module('thingsboard.api.widget', ['oc.lazyLoad', thingsbo |
52 | 54 | thingsboardTimeseriesTableWidget, thingsboardAlarmsTableWidget, thingsboardEntitiesTableWidget, |
53 | 55 | thingsboardEntitiesHierarchyWidget, thingsboardExtensionsTableWidget, thingsboardDateRangeNavigatorWidget, |
54 | 56 | thingsboardMultipleInputWidget, thingsboardWebCameraInputWidget, thingsboardRpcWidgets, thingsboardTypes, |
55 | - thingsboardUtils, TripAnimationWidget]) | |
57 | + thingsboardUtils, thingsboardJsonToString, TripAnimationWidget]) | |
56 | 58 | .factory('widgetService', WidgetService) |
57 | 59 | .name; |
58 | 60 | ... | ... |
... | ... | @@ -881,6 +881,11 @@ export default angular.module('thingsboard.types', []) |
881 | 881 | value: "boolean", |
882 | 882 | name: "value.boolean", |
883 | 883 | icon: "mdi:checkbox-marked-outline" |
884 | + }, | |
885 | + json: { | |
886 | + value: "json", | |
887 | + name: "value.json", | |
888 | + icon: "mdi:json" | |
884 | 889 | } |
885 | 890 | }, |
886 | 891 | widgetType: { | ... | ... |
... | ... | @@ -57,9 +57,12 @@ function JsonContent($compile, $templateCache, toast, types, utils) { |
57 | 57 | updateEditorSize(); |
58 | 58 | }; |
59 | 59 | |
60 | - scope.beautifyJson = function () { | |
61 | - var res = js_beautify(scope.contentBody, {indent_size: 4, wrap_line_length: 60}); | |
62 | - scope.contentBody = res; | |
60 | + scope.beautifyJSON = function () { | |
61 | + scope.contentBody = js_beautify(scope.contentBody, {indent_size: 4, wrap_line_length: 60}); | |
62 | + }; | |
63 | + | |
64 | + scope.minifyJSON = function () { | |
65 | + scope.contentBody = angular.toJson(angular.fromJson(scope.contentBody)); | |
63 | 66 | }; |
64 | 67 | |
65 | 68 | function updateEditorSize() { |
... | ... | @@ -116,7 +119,7 @@ function JsonContent($compile, $templateCache, toast, types, utils) { |
116 | 119 | scope.$watch('contentBody', function (newContent, oldContent) { |
117 | 120 | ngModelCtrl.$setViewValue(scope.contentBody); |
118 | 121 | if (!angular.equals(newContent, oldContent)) { |
119 | - scope.contentValid = true; | |
122 | + scope.contentValid = scope.validate(); | |
120 | 123 | } |
121 | 124 | scope.updateValidity(); |
122 | 125 | }); |
... | ... | @@ -139,15 +142,17 @@ function JsonContent($compile, $templateCache, toast, types, utils) { |
139 | 142 | } |
140 | 143 | return true; |
141 | 144 | } catch (e) { |
142 | - var details = utils.parseException(e); | |
143 | - var errorInfo = 'Error:'; | |
144 | - if (details.name) { | |
145 | - errorInfo += ' ' + details.name + ':'; | |
146 | - } | |
147 | - if (details.message) { | |
148 | - errorInfo += ' ' + details.message; | |
145 | + if (!scope.hideErrorToast) { | |
146 | + var details = utils.parseException(e); | |
147 | + var errorInfo = 'Error:'; | |
148 | + if (details.name) { | |
149 | + errorInfo += ' ' + details.name + ':'; | |
150 | + } | |
151 | + if (details.message) { | |
152 | + errorInfo += ' ' + details.message; | |
153 | + } | |
154 | + scope.showError(errorInfo); | |
149 | 155 | } |
150 | - scope.showError(errorInfo); | |
151 | 156 | return false; |
152 | 157 | } |
153 | 158 | }; |
... | ... | @@ -169,7 +174,7 @@ function JsonContent($compile, $templateCache, toast, types, utils) { |
169 | 174 | }); |
170 | 175 | |
171 | 176 | $compile(element.contents())(scope); |
172 | - } | |
177 | + }; | |
173 | 178 | |
174 | 179 | return { |
175 | 180 | restrict: "E", |
... | ... | @@ -177,6 +182,7 @@ function JsonContent($compile, $templateCache, toast, types, utils) { |
177 | 182 | scope: { |
178 | 183 | contentType: '=', |
179 | 184 | validateContent: '=?', |
185 | + hideErrorToast: '=?', | |
180 | 186 | readonly:'=ngReadonly', |
181 | 187 | fillHeight:'=?' |
182 | 188 | }, | ... | ... |
... | ... | @@ -17,11 +17,15 @@ |
17 | 17 | --> |
18 | 18 | <div style="background: #fff;" ng-class="{'fill-height': fillHeight}" tb-expand-fullscreen fullscreen-zindex="100" expand-button-id="expand-button" on-fullscreen-changed="onFullscreenChanged()" layout="column"> |
19 | 19 | <div layout="row" layout-align="start center" style="height: 40px;" class="tb-json-content-toolbar"> |
20 | - <label class="tb-title no-padding">{{ label }}</label> | |
20 | + <label class="tb-title no-padding" | |
21 | + ng-class="{'tb-error': !contentValid}">{{ label }}</label> | |
21 | 22 | <span flex></span> |
22 | - <md-button ng-if="!readonly" class="tidy" aria-label="{{ 'js-func.tidy' | translate }}" ng-click="beautifyJson()">{{ | |
23 | + <md-button ng-if="!readonly" class="tidy" aria-label="{{ 'js-func.tidy' | translate }}" ng-click="beautifyJSON()">{{ | |
23 | 24 | 'js-func.tidy' | translate }} |
24 | 25 | </md-button> |
26 | + <md-button ng-if="!readonly" class="tidy" aria-label="{{ 'js-func.mini' | translate }}" ng-click="minifyJSON()">{{ | |
27 | + 'js-func.mini' | translate }} | |
28 | + </md-button> | |
25 | 29 | <md-button id="expand-button" aria-label="Fullscreen" class="md-icon-button tb-md-32 tb-fullscreen-button-style"></md-button> |
26 | 30 | </div> |
27 | 31 | <div flex id="tb-json-panel" class="tb-json-content-panel" layout="column"> | ... | ... |
... | ... | @@ -50,6 +50,14 @@ function JsonObjectEdit($compile, $templateCache, $document, toast, utils) { |
50 | 50 | updateEditorSize(); |
51 | 51 | }; |
52 | 52 | |
53 | + scope.beautifyJSON = function () { | |
54 | + scope.contentBody = angular.toJson(scope.object, 4); | |
55 | + }; | |
56 | + | |
57 | + scope.minifyJSON = function () { | |
58 | + scope.contentBody = angular.toJson(scope.object); | |
59 | + }; | |
60 | + | |
53 | 61 | function updateEditorSize() { |
54 | 62 | if (scope.json_editor) { |
55 | 63 | scope.json_editor.resize(); |
... | ... | @@ -169,7 +177,7 @@ function JsonObjectEdit($compile, $templateCache, $document, toast, utils) { |
169 | 177 | }); |
170 | 178 | |
171 | 179 | $compile(element.contents())(scope); |
172 | - } | |
180 | + }; | |
173 | 181 | |
174 | 182 | return { |
175 | 183 | restrict: "E", | ... | ... |
... | ... | @@ -21,6 +21,19 @@ tb-json-object-edit { |
21 | 21 | } |
22 | 22 | } |
23 | 23 | |
24 | +.tb-json-object-edit-toolbar { | |
25 | + .md-button.tidy { | |
26 | + min-width: 32px; | |
27 | + min-height: 15px; | |
28 | + padding: 4px; | |
29 | + margin: 0 5px 0 0; | |
30 | + font-size: 12px; | |
31 | + line-height: 15px; | |
32 | + color: #7b7b7b; | |
33 | + background: rgba(220, 220, 220, .35); | |
34 | + } | |
35 | +} | |
36 | + | |
24 | 37 | .tb-json-object-panel { |
25 | 38 | height: 100%; |
26 | 39 | margin-left: 15px; | ... | ... |
... | ... | @@ -16,12 +16,18 @@ |
16 | 16 | |
17 | 17 | --> |
18 | 18 | <div style="background: #fff;" ng-class="{'fill-height': fillHeight}" tb-expand-fullscreen fullscreen-zindex="100" expand-button-id="expand-button" on-fullscreen-changed="onFullscreenChanged()" layout="column"> |
19 | - <div layout="row" layout-align="start center"> | |
19 | + <div layout="row" layout-align="start center" class="tb-json-object-edit-toolbar"> | |
20 | 20 | <label class="tb-title no-padding" |
21 | 21 | ng-class="{'tb-required': required, |
22 | 22 | 'tb-readonly': readonly, |
23 | 23 | 'tb-error': !objectValid}">{{ label }}</label> |
24 | 24 | <span flex></span> |
25 | + <md-button ng-if="!readonly" class="tidy" aria-label="{{ 'js-func.tidy' | translate }}" ng-click="beautifyJSON()"> | |
26 | + {{'js-func.tidy' | translate }} | |
27 | + </md-button> | |
28 | + <md-button ng-if="!readonly" class="tidy" aria-label="{{ 'js-func.mini' | translate }}" ng-click="minifyJSON()"> | |
29 | + {{'js-func.mini' | translate }} | |
30 | + </md-button> | |
25 | 31 | <md-button id="expand-button" aria-label="Fullscreen" class="md-icon-button tb-md-32 tb-fullscreen-button-style"></md-button> |
26 | 32 | </div> |
27 | 33 | <div flex id="tb-json-panel" class="tb-json-object-panel" layout="column"> | ... | ... |
1 | +/* | |
2 | + * Copyright © 2016-2020 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +export default angular.module('tbJsonToString', []) | |
17 | + .directive('tbJsonToString', InputJson) | |
18 | + .name; | |
19 | + | |
20 | +function InputJson() { | |
21 | + return { | |
22 | + restrict: 'A', | |
23 | + require: 'ngModel', | |
24 | + link: function(scope, element, attr, ngModelCtrl) { | |
25 | + function into(input) { | |
26 | + try { | |
27 | + ngModelCtrl.$setValidity('invalidJSON', true); | |
28 | + return angular.fromJson(input); | |
29 | + } catch (e) { | |
30 | + ngModelCtrl.$setValidity('invalidJSON', false); | |
31 | + } | |
32 | + } | |
33 | + function out(data) { | |
34 | + try { | |
35 | + ngModelCtrl.$setValidity('invalidJSON', true); | |
36 | + return angular.toJson(data); | |
37 | + } catch (e) { | |
38 | + ngModelCtrl.$setValidity('invalidJSON', false); | |
39 | + } | |
40 | + } | |
41 | + ngModelCtrl.$parsers.push(into); | |
42 | + ngModelCtrl.$formatters.push(out); | |
43 | + } | |
44 | + }; | |
45 | +} | ... | ... |
... | ... | @@ -13,10 +13,18 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | +/* eslint-disable import/no-unresolved, import/default */ | |
17 | + | |
18 | +import attributeDialogEditJsonTemplate from './attribute-dialog-edit-json.tpl.html'; | |
19 | + | |
20 | +/* eslint-enable import/no-unresolved, import/default */ | |
21 | + | |
22 | +import AttributeDialogEditJsonController from './attribute-dialog-edit-json.controller'; | |
23 | + | |
16 | 24 | /*@ngInject*/ |
17 | 25 | export default function AddAttributeDialogController($scope, $mdDialog, types, attributeService, entityType, entityId, attributeScope) { |
18 | 26 | |
19 | - var vm = this; | |
27 | + let vm = this; | |
20 | 28 | |
21 | 29 | vm.attribute = {}; |
22 | 30 | |
... | ... | @@ -40,11 +48,37 @@ export default function AddAttributeDialogController($scope, $mdDialog, types, a |
40 | 48 | ); |
41 | 49 | } |
42 | 50 | |
43 | - $scope.$watch('vm.valueType', function() { | |
51 | + $scope.$watch('vm.valueType', function () { | |
44 | 52 | if (vm.valueType === types.valueType.boolean) { |
45 | 53 | vm.attribute.value = false; |
54 | + } else if (vm.valueType === types.valueType.json) { | |
55 | + vm.attribute.value = {}; | |
46 | 56 | } else { |
47 | 57 | vm.attribute.value = null; |
48 | 58 | } |
49 | 59 | }); |
60 | + | |
61 | + vm.addJSON = ($event) => { | |
62 | + showJsonDialog($event, vm.attribute.value, false).then((response) => { | |
63 | + vm.attribute.value = response; | |
64 | + }) | |
65 | + }; | |
66 | + | |
67 | + function showJsonDialog($event, jsonValue, readOnly) { | |
68 | + if ($event) { | |
69 | + $event.stopPropagation(); | |
70 | + } | |
71 | + return $mdDialog.show({ | |
72 | + controller: AttributeDialogEditJsonController, | |
73 | + controllerAs: 'vm', | |
74 | + templateUrl: attributeDialogEditJsonTemplate, | |
75 | + locals: { | |
76 | + jsonValue: jsonValue, | |
77 | + readOnly: readOnly | |
78 | + }, | |
79 | + targetEvent: $event, | |
80 | + fullscreen: true, | |
81 | + multiple: true, | |
82 | + }); | |
83 | + } | |
50 | 84 | } | ... | ... |
... | ... | @@ -26,7 +26,8 @@ |
26 | 26 | </md-button> |
27 | 27 | </div> |
28 | 28 | </md-toolbar> |
29 | - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear> | |
29 | + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" | |
30 | + ng-show="$root.loading"></md-progress-linear> | |
30 | 31 | <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span> |
31 | 32 | <md-dialog-content> |
32 | 33 | <div class="md-dialog-content"> |
... | ... | @@ -58,7 +59,8 @@ |
58 | 59 | </md-input-container> |
59 | 60 | <md-input-container ng-if="vm.valueType===vm.valueTypes.integer" flex="60" class="md-block"> |
60 | 61 | <label translate>value.integer-value</label> |
61 | - <input required name="value" type="number" step="1" ng-pattern="/^-?[0-9]+$/" ng-model="vm.attribute.value"> | |
62 | + <input required name="value" type="number" step="1" ng-pattern="/^-?[0-9]+$/" | |
63 | + ng-model="vm.attribute.value"> | |
62 | 64 | <div ng-messages="theForm.value.$error"> |
63 | 65 | <div translate ng-message="required">attribute.value-required</div> |
64 | 66 | <div translate ng-message="pattern">value.invalid-integer-value</div> |
... | ... | @@ -71,11 +73,31 @@ |
71 | 73 | <div translate ng-message="required">attribute.value-required</div> |
72 | 74 | </div> |
73 | 75 | </md-input-container> |
74 | - <div layout="column" layout-align="center" flex="60" ng-if="vm.valueType===vm.valueTypes.boolean"> | |
75 | - <md-checkbox ng-model="vm.attribute.value" style="margin-bottom: 0px;"> | |
76 | + <div layout="column" layout-align="center" flex="60" | |
77 | + ng-if="vm.valueType===vm.valueTypes.boolean"> | |
78 | + <md-checkbox ng-model="vm.attribute.value" style="margin-bottom: 0;"> | |
76 | 79 | {{ (vm.attribute.value ? 'value.true' : 'value.false') | translate }} |
77 | 80 | </md-checkbox> |
78 | 81 | </div> |
82 | + <div layout="row" layout-align="center" flex="60" | |
83 | + ng-if="vm.valueType===vm.valueTypes.json" class="md-block"> | |
84 | + <md-input-container flex class="md-block"> | |
85 | + <label translate>value.json-value</label> | |
86 | + <input required tb-json-to-string name="value" ng-model="vm.attribute.value"> | |
87 | + <div ng-messages="theForm.value.$error"> | |
88 | + <div translate ng-message="required">attribute.value-required</div> | |
89 | + </div> | |
90 | + </md-input-container> | |
91 | + <md-button class="md-icon-button" | |
92 | + ng-click="vm.addJSON($event)" | |
93 | + style="margin: 18px 0;" | |
94 | + aria-label="{{ 'action.edit' | translate }}"> | |
95 | + <md-tooltip md-direction="top"> | |
96 | + {{ 'action.edit' | translate }} | |
97 | + </md-tooltip> | |
98 | + <ng-md-icon size="20" icon="open_in_new"></ng-md-icon> | |
99 | + </md-button> | |
100 | + </div> | |
79 | 101 | </section> |
80 | 102 | </fieldset> |
81 | 103 | </md-content> |
... | ... | @@ -87,8 +109,8 @@ |
87 | 109 | class="md-raised md-primary"> |
88 | 110 | {{ 'action.add' | translate }} |
89 | 111 | </md-button> |
90 | - <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | | |
91 | - translate }} | |
112 | + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;"> | |
113 | + {{ 'action.cancel' | translate }} | |
92 | 114 | </md-button> |
93 | 115 | </md-dialog-actions> |
94 | 116 | </form> | ... | ... |
... | ... | @@ -26,7 +26,8 @@ |
26 | 26 | </md-button> |
27 | 27 | </div> |
28 | 28 | </md-toolbar> |
29 | - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear> | |
29 | + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" | |
30 | + ng-show="$root.loading"></md-progress-linear> | |
30 | 31 | <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span> |
31 | 32 | <md-dialog-content> |
32 | 33 | <div class="md-dialog-content"> |
... | ... | @@ -37,10 +38,10 @@ |
37 | 38 | <section flex layout="column" style="width: 300px;"> |
38 | 39 | <span translate style="padding-bottom: 10px;">dashboard.select-existing</span> |
39 | 40 | <tb-dashboard-autocomplete the-form="theForm" |
40 | - ng-disabled="$root.loading || vm.addToDashboardType != 0" | |
41 | - tb-required="vm.addToDashboardType === 0" | |
42 | - ng-model="vm.dashboardId" | |
43 | - select-first-dashboard="false"> | |
41 | + ng-disabled="$root.loading || vm.addToDashboardType != 0" | |
42 | + tb-required="vm.addToDashboardType === 0" | |
43 | + ng-model="vm.dashboardId" | |
44 | + select-first-dashboard="false"> | |
44 | 45 | </tb-dashboard-autocomplete> |
45 | 46 | </section> |
46 | 47 | </md-radio-button> |
... | ... | @@ -49,7 +50,8 @@ |
49 | 50 | <span translate>dashboard.create-new</span> |
50 | 51 | <md-input-container class="md-block"> |
51 | 52 | <label translate>dashboard.new-dashboard-title</label> |
52 | - <input ng-required="vm.addToDashboardType === 1" name="title" ng-model="vm.newDashboard.title"> | |
53 | + <input ng-required="vm.addToDashboardType === 1" name="title" | |
54 | + ng-model="vm.newDashboard.title"> | |
53 | 55 | <div ng-messages="theForm.title.$error"> |
54 | 56 | <div translate ng-message="required">dashboard.title-required</div> |
55 | 57 | </div> |
... | ... | @@ -66,15 +68,15 @@ |
66 | 68 | <md-checkbox |
67 | 69 | ng-model="vm.openDashboard" |
68 | 70 | aria-label="{{ 'dashboard.open-dashboard' | translate }}" |
69 | - style="margin-bottom: 0px; padding-right: 20px;"> | |
71 | + style="margin-bottom: 0; padding-right: 20px;"> | |
70 | 72 | {{ 'dashboard.open-dashboard' | translate }} |
71 | 73 | </md-checkbox> |
72 | 74 | <md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit" |
73 | 75 | class="md-raised md-primary"> |
74 | 76 | {{ 'action.add' | translate }} |
75 | 77 | </md-button> |
76 | - <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | | |
77 | - translate }} | |
78 | + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;"> | |
79 | + {{ 'action.cancel' | translate }} | |
78 | 80 | </md-button> |
79 | 81 | </md-dialog-actions> |
80 | 82 | </form> | ... | ... |
1 | +/* | |
2 | + * Copyright © 2016-2020 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +/* eslint-enable import/no-unresolved, import/default */ | |
17 | + | |
18 | +import './attribute-dialog-edit-json.scss'; | |
19 | + | |
20 | +/*@ngInject*/ | |
21 | +export default function AttributeDialogEditJsonController($mdDialog, types, jsonValue, readOnly) { | |
22 | + | |
23 | + let vm = this; | |
24 | + vm.json = angular.toJson(jsonValue, 4); | |
25 | + vm.readOnly = readOnly; | |
26 | + vm.contentType = types.contentType.JSON.value; | |
27 | + | |
28 | + vm.save = () => { | |
29 | + $mdDialog.hide(angular.fromJson(vm.json)); | |
30 | + }; | |
31 | + | |
32 | + vm.cancel = () => { | |
33 | + $mdDialog.cancel(); | |
34 | + }; | |
35 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2020 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +.attribute-edit-json-dialog{ | |
17 | + min-width: 400px; | |
18 | +} | |
19 | + | |
20 | +@media (max-width: 425px){ | |
21 | + .attribute-edit-json-dialog { | |
22 | + min-width: 200px; | |
23 | + } | |
24 | +} | ... | ... |
1 | +<!-- | |
2 | + | |
3 | + Copyright © 2016-2020 The Thingsboard Authors | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + | |
17 | +--> | |
18 | +<md-dialog class="attribute-edit-json-dialog"> | |
19 | + <form name="theForm" ng-submit="vm.save()"> | |
20 | + <md-toolbar> | |
21 | + <div class="md-toolbar-tools"> | |
22 | + <h2>{{ 'details.edit-json' | translate }}</h2> | |
23 | + <span flex></span> | |
24 | + <md-button class="md-icon-button" | |
25 | + ng-click="vm.cancel()" | |
26 | + aria-label="{{'action.close'|translate}}"> | |
27 | + <ng-md-icon icon="close" aria-label="Close"></ng-md-icon> | |
28 | + </md-button> | |
29 | + </div> | |
30 | + </md-toolbar> | |
31 | + <md-dialog-content> | |
32 | + <div class="md-dialog-content"> | |
33 | + <tb-json-content | |
34 | + ng-model="vm.json" | |
35 | + label="{{ 'value.json-value' | translate }}" | |
36 | + content-type="vm.contentType" | |
37 | + validate-content="true" | |
38 | + hide-error-toast="true" | |
39 | + fill-height="false" | |
40 | + ng-readonly="vm.readOnly"> | |
41 | + </tb-json-content> | |
42 | + </div> | |
43 | + </md-dialog-content> | |
44 | + <md-dialog-actions layout="row" layout-align="end center" class="action-buttons"> | |
45 | + <md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit" | |
46 | + class="md-raised md-primary"> | |
47 | + {{'action.save'|translate}} | |
48 | + </md-button> | |
49 | + <md-button id="cancel-btn" ng-disabled="$root.loading" ng-click="vm.cancel()"> | |
50 | + {{'action.cancel'|translate }} | |
51 | + </md-button> | |
52 | + </md-dialog-actions> | |
53 | + </form> | |
54 | +</md-dialog> | ... | ... |
... | ... | @@ -39,7 +39,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS |
39 | 39 | |
40 | 40 | element.html(template); |
41 | 41 | |
42 | - var getAttributeScopeByValue = function(attributeScopeValue) { | |
42 | + var getAttributeScopeByValue = function (attributeScopeValue) { | |
43 | 43 | if (scope.types.latestTelemetry.value === attributeScopeValue) { |
44 | 44 | return scope.types.latestTelemetry; |
45 | 45 | } |
... | ... | @@ -48,7 +48,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS |
48 | 48 | return scope.attributeScopes[attrScope]; |
49 | 49 | } |
50 | 50 | } |
51 | - } | |
51 | + }; | |
52 | 52 | |
53 | 53 | scope.types = types; |
54 | 54 | |
... | ... | @@ -87,14 +87,14 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS |
87 | 87 | search: null |
88 | 88 | }; |
89 | 89 | |
90 | - scope.$watch("entityId", function(newVal) { | |
90 | + scope.$watch("entityId", function (newVal) { | |
91 | 91 | if (newVal) { |
92 | 92 | scope.resetFilter(); |
93 | 93 | scope.getEntityAttributes(false, true); |
94 | 94 | } |
95 | 95 | }); |
96 | 96 | |
97 | - scope.$watch("attributeScope", function(newVal, prevVal) { | |
97 | + scope.$watch("attributeScope", function (newVal, prevVal) { | |
98 | 98 | if (newVal && !angular.equals(newVal, prevVal)) { |
99 | 99 | scope.mode = 'default'; |
100 | 100 | scope.query.search = null; |
... | ... | @@ -103,30 +103,30 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS |
103 | 103 | } |
104 | 104 | }); |
105 | 105 | |
106 | - scope.resetFilter = function() { | |
106 | + scope.resetFilter = function () { | |
107 | 107 | scope.mode = 'default'; |
108 | 108 | scope.query.search = null; |
109 | 109 | scope.selectedAttributes = []; |
110 | 110 | scope.attributeScope = getAttributeScopeByValue(attrs.defaultAttributeScope); |
111 | - } | |
111 | + }; | |
112 | 112 | |
113 | - scope.enterFilterMode = function(event) { | |
113 | + scope.enterFilterMode = function (event) { | |
114 | 114 | let $button = angular.element(event.currentTarget); |
115 | 115 | let $toolbarsContainer = $button.closest('.toolbarsContainer'); |
116 | 116 | |
117 | 117 | scope.query.search = ''; |
118 | 118 | |
119 | - $timeout(()=>{ | |
119 | + $timeout(() => { | |
120 | 120 | $toolbarsContainer.find('.searchInput').focus(); |
121 | 121 | }) |
122 | - } | |
122 | + }; | |
123 | 123 | |
124 | - scope.exitFilterMode = function() { | |
124 | + scope.exitFilterMode = function () { | |
125 | 125 | scope.query.search = null; |
126 | 126 | scope.getEntityAttributes(); |
127 | - } | |
127 | + }; | |
128 | 128 | |
129 | - scope.$watch("query.search", function(newVal, prevVal) { | |
129 | + scope.$watch("query.search", function (newVal, prevVal) { | |
130 | 130 | if (!angular.equals(newVal, prevVal) && scope.query.search != null) { |
131 | 131 | scope.getEntityAttributes(); |
132 | 132 | } |
... | ... | @@ -142,15 +142,15 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS |
142 | 142 | } |
143 | 143 | } |
144 | 144 | |
145 | - scope.onReorder = function() { | |
145 | + scope.onReorder = function () { | |
146 | 146 | scope.getEntityAttributes(false, false); |
147 | - } | |
147 | + }; | |
148 | 148 | |
149 | - scope.onPaginate = function() { | |
149 | + scope.onPaginate = function () { | |
150 | 150 | scope.getEntityAttributes(false, false); |
151 | - } | |
151 | + }; | |
152 | 152 | |
153 | - scope.getEntityAttributes = function(forceUpdate, reset) { | |
153 | + scope.getEntityAttributes = function (forceUpdate, reset) { | |
154 | 154 | if (scope.attributesDeferred) { |
155 | 155 | scope.attributesDeferred.resolve(); |
156 | 156 | } |
... | ... | @@ -163,7 +163,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS |
163 | 163 | } |
164 | 164 | scope.checkSubscription(); |
165 | 165 | scope.attributesDeferred = attributeService.getEntityAttributes(scope.entityType, scope.entityId, scope.attributeScope.value, |
166 | - scope.query, function(attributes, update, apply) { | |
166 | + scope.query, function (attributes, update, apply) { | |
167 | 167 | success(attributes, update || forceUpdate, apply); |
168 | 168 | } |
169 | 169 | ); |
... | ... | @@ -176,9 +176,9 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS |
176 | 176 | }); |
177 | 177 | deferred.resolve(); |
178 | 178 | } |
179 | - } | |
179 | + }; | |
180 | 180 | |
181 | - scope.checkSubscription = function() { | |
181 | + scope.checkSubscription = function () { | |
182 | 182 | var newSubscriptionId = null; |
183 | 183 | if (scope.entityId && scope.entityType && scope.attributeScope.clientSide && scope.mode != 'widget') { |
184 | 184 | newSubscriptionId = attributeService.subscribeForEntityAttributes(scope.entityType, scope.entityId, scope.attributeScope.value); |
... | ... | @@ -187,36 +187,38 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS |
187 | 187 | attributeService.unsubscribeForEntityAttributes(scope.subscriptionId); |
188 | 188 | } |
189 | 189 | scope.subscriptionId = newSubscriptionId; |
190 | - } | |
190 | + }; | |
191 | 191 | |
192 | - scope.$on('$destroy', function() { | |
192 | + scope.$on('$destroy', function () { | |
193 | 193 | if (scope.subscriptionId) { |
194 | 194 | attributeService.unsubscribeForEntityAttributes(scope.subscriptionId); |
195 | 195 | } |
196 | 196 | }); |
197 | 197 | |
198 | - scope.editAttribute = function($event, attribute) { | |
198 | + scope.editAttribute = function ($event, attribute) { | |
199 | 199 | if (!scope.attributeScope.clientSide) { |
200 | 200 | $event.stopPropagation(); |
201 | 201 | $mdEditDialog.show({ |
202 | 202 | controller: EditAttributeValueController, |
203 | 203 | templateUrl: editAttributeValueTemplate, |
204 | - locals: {attributeValue: attribute.value, | |
205 | - save: function (model) { | |
206 | - var updatedAttribute = angular.copy(attribute); | |
207 | - updatedAttribute.value = model.value; | |
208 | - attributeService.saveEntityAttributes(scope.entityType, scope.entityId, scope.attributeScope.value, [updatedAttribute]).then( | |
209 | - function success() { | |
210 | - scope.getEntityAttributes(); | |
211 | - } | |
212 | - ); | |
213 | - }}, | |
204 | + locals: { | |
205 | + attributeValue: attribute.value, | |
206 | + save: function (model) { | |
207 | + var updatedAttribute = angular.copy(attribute); | |
208 | + updatedAttribute.value = model.value; | |
209 | + attributeService.saveEntityAttributes(scope.entityType, scope.entityId, scope.attributeScope.value, [updatedAttribute]).then( | |
210 | + function success() { | |
211 | + scope.getEntityAttributes(); | |
212 | + } | |
213 | + ); | |
214 | + } | |
215 | + }, | |
214 | 216 | targetEvent: $event |
215 | 217 | }); |
216 | 218 | } |
217 | - } | |
219 | + }; | |
218 | 220 | |
219 | - scope.addAttribute = function($event) { | |
221 | + scope.addAttribute = function ($event) { | |
220 | 222 | if (!scope.attributeScope.clientSide) { |
221 | 223 | $event.stopPropagation(); |
222 | 224 | $mdDialog.show({ |
... | ... | @@ -224,16 +226,20 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS |
224 | 226 | controllerAs: 'vm', |
225 | 227 | templateUrl: addAttributeDialogTemplate, |
226 | 228 | parent: angular.element($document[0].body), |
227 | - locals: {entityType: scope.entityType, entityId: scope.entityId, attributeScope: scope.attributeScope.value}, | |
229 | + locals: { | |
230 | + entityType: scope.entityType, | |
231 | + entityId: scope.entityId, | |
232 | + attributeScope: scope.attributeScope.value | |
233 | + }, | |
228 | 234 | fullscreen: true, |
229 | 235 | targetEvent: $event |
230 | 236 | }).then(function () { |
231 | 237 | scope.getEntityAttributes(); |
232 | 238 | }); |
233 | 239 | } |
234 | - } | |
240 | + }; | |
235 | 241 | |
236 | - scope.deleteAttributes = function($event) { | |
242 | + scope.deleteAttributes = function ($event) { | |
237 | 243 | if (!scope.attributeScope.clientSide) { |
238 | 244 | $event.stopPropagation(); |
239 | 245 | var confirm = $mdDialog.confirm() |
... | ... | @@ -244,33 +250,33 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS |
244 | 250 | .cancel($translate.instant('action.no')) |
245 | 251 | .ok($translate.instant('action.yes')); |
246 | 252 | $mdDialog.show(confirm).then(function () { |
247 | - attributeService.deleteEntityAttributes(scope.entityType, scope.entityId, scope.attributeScope.value, scope.selectedAttributes).then( | |
248 | - function success() { | |
249 | - scope.selectedAttributes = []; | |
250 | - scope.getEntityAttributes(); | |
251 | - } | |
252 | - ) | |
253 | + attributeService.deleteEntityAttributes(scope.entityType, scope.entityId, scope.attributeScope.value, scope.selectedAttributes).then( | |
254 | + function success() { | |
255 | + scope.selectedAttributes = []; | |
256 | + scope.getEntityAttributes(); | |
257 | + } | |
258 | + ) | |
253 | 259 | }); |
254 | 260 | } |
255 | - } | |
261 | + }; | |
256 | 262 | |
257 | - scope.nextWidget = function() { | |
263 | + scope.nextWidget = function () { | |
258 | 264 | $mdUtil.nextTick(function () { |
259 | 265 | if (scope.widgetsCarousel.index < scope.widgetsList.length - 1) { |
260 | 266 | scope.widgetsCarousel.index++; |
261 | 267 | } |
262 | 268 | }); |
263 | - } | |
269 | + }; | |
264 | 270 | |
265 | - scope.prevWidget = function() { | |
271 | + scope.prevWidget = function () { | |
266 | 272 | $mdUtil.nextTick(function () { |
267 | 273 | if (scope.widgetsCarousel.index > 0) { |
268 | 274 | scope.widgetsCarousel.index--; |
269 | 275 | } |
270 | 276 | }); |
271 | - } | |
277 | + }; | |
272 | 278 | |
273 | - scope.enterWidgetMode = function() { | |
279 | + scope.enterWidgetMode = function () { | |
274 | 280 | |
275 | 281 | if (scope.widgetsIndexWatch) { |
276 | 282 | scope.widgetsIndexWatch(); |
... | ... | @@ -303,7 +309,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS |
303 | 309 | entitiAliases[entityAlias.id] = entityAlias; |
304 | 310 | |
305 | 311 | var stateController = { |
306 | - getStateParams: function() { | |
312 | + getStateParams: function () { | |
307 | 313 | return {}; |
308 | 314 | } |
309 | 315 | }; |
... | ... | @@ -317,9 +323,9 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS |
317 | 323 | type: types.datasourceType.entity, |
318 | 324 | entityAliasId: entityAlias.id, |
319 | 325 | dataKeys: [] |
320 | - } | |
326 | + }; | |
321 | 327 | var i = 0; |
322 | - for (var attr =0; attr < scope.selectedAttributes.length;attr++) { | |
328 | + for (var attr = 0; attr < scope.selectedAttributes.length; attr++) { | |
323 | 329 | var attribute = scope.selectedAttributes[attr]; |
324 | 330 | var dataKey = { |
325 | 331 | name: attribute.key, |
... | ... | @@ -328,12 +334,12 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS |
328 | 334 | color: utils.getMaterialColor(i), |
329 | 335 | settings: {}, |
330 | 336 | _hash: Math.random() |
331 | - } | |
337 | + }; | |
332 | 338 | datasource.dataKeys.push(dataKey); |
333 | 339 | i++; |
334 | 340 | } |
335 | 341 | |
336 | - scope.widgetsIndexWatch = scope.$watch('widgetsCarousel.index', function(newVal, prevVal) { | |
342 | + scope.widgetsIndexWatch = scope.$watch('widgetsCarousel.index', function (newVal, prevVal) { | |
337 | 343 | if (scope.mode === 'widget' && (newVal != prevVal)) { |
338 | 344 | var index = scope.widgetsCarousel.index; |
339 | 345 | for (var i = 0; i < scope.widgetsList.length; i++) { |
... | ... | @@ -345,7 +351,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS |
345 | 351 | } |
346 | 352 | }); |
347 | 353 | |
348 | - scope.widgetsBundleWatch = scope.$watch('widgetsBundle', function(newVal, prevVal) { | |
354 | + scope.widgetsBundleWatch = scope.$watch('widgetsBundle', function (newVal, prevVal) { | |
349 | 355 | if (scope.mode === 'widget' && (scope.firstBundle === true || newVal != prevVal)) { |
350 | 356 | scope.widgetsList = []; |
351 | 357 | scope.widgetsListCache = []; |
... | ... | @@ -358,7 +364,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS |
358 | 364 | widgetService.getBundleWidgetTypes(scope.widgetsBundle.alias, isSystem).then( |
359 | 365 | function success(widgetTypes) { |
360 | 366 | |
361 | - widgetTypes = $filter('orderBy')(widgetTypes, ['-descriptor.type','-createdTime']); | |
367 | + widgetTypes = $filter('orderBy')(widgetTypes, ['-descriptor.type', '-createdTime']); | |
362 | 368 | |
363 | 369 | for (var i = 0; i < widgetTypes.length; i++) { |
364 | 370 | var widgetType = widgetTypes[i]; |
... | ... | @@ -398,9 +404,9 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS |
398 | 404 | } |
399 | 405 | } |
400 | 406 | }); |
401 | - } | |
407 | + }; | |
402 | 408 | |
403 | - scope.exitWidgetMode = function() { | |
409 | + scope.exitWidgetMode = function () { | |
404 | 410 | if (scope.widgetsBundleWatch) { |
405 | 411 | scope.widgetsBundleWatch(); |
406 | 412 | scope.widgetsBundleWatch = null; |
... | ... | @@ -412,9 +418,9 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS |
412 | 418 | scope.selectedWidgetsBundleAlias = null; |
413 | 419 | scope.mode = 'default'; |
414 | 420 | scope.getEntityAttributes(true); |
415 | - } | |
421 | + }; | |
416 | 422 | |
417 | - scope.addWidgetToDashboard = function($event) { | |
423 | + scope.addWidgetToDashboard = function ($event) { | |
418 | 424 | if (scope.mode === 'widget' && scope.widgetsListCache.length > 0) { |
419 | 425 | var widget = scope.widgetsListCache[scope.widgetsCarousel.index][0]; |
420 | 426 | $event.stopPropagation(); |
... | ... | @@ -423,21 +429,26 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS |
423 | 429 | controllerAs: 'vm', |
424 | 430 | templateUrl: addWidgetToDashboardDialogTemplate, |
425 | 431 | parent: angular.element($document[0].body), |
426 | - locals: {entityId: scope.entityId, entityType: scope.entityType, entityName: scope.entityName, widget: angular.copy(widget)}, | |
432 | + locals: { | |
433 | + entityId: scope.entityId, | |
434 | + entityType: scope.entityType, | |
435 | + entityName: scope.entityName, | |
436 | + widget: angular.copy(widget) | |
437 | + }, | |
427 | 438 | fullscreen: true, |
428 | 439 | targetEvent: $event |
429 | 440 | }).then(function () { |
430 | 441 | |
431 | 442 | }); |
432 | 443 | } |
433 | - } | |
444 | + }; | |
434 | 445 | |
435 | - scope.loading = function() { | |
446 | + scope.loading = function () { | |
436 | 447 | return $rootScope.loading; |
437 | - } | |
448 | + }; | |
438 | 449 | |
439 | 450 | $compile(element.contents())(scope); |
440 | - } | |
451 | + }; | |
441 | 452 | |
442 | 453 | return { |
443 | 454 | restrict: "E", | ... | ... |
... | ... | @@ -77,9 +77,7 @@ |
77 | 77 | </md-toolbar> |
78 | 78 | <md-toolbar class="md-table-toolbar alternate" ng-show="mode==='default' && selectedAttributes.length"> |
79 | 79 | <div class="md-toolbar-tools"> |
80 | - <span translate="{{attributeScope === types.latestTelemetry | |
81 | - ? 'attribute.selected-telemetry' | |
82 | - : 'attribute.selected-attributes'}}" | |
80 | + <span translate="{{(attributeScope === types.latestTelemetry) ? 'attribute.selected-telemetry' : 'attribute.selected-attributes'}}" | |
83 | 81 | translate-values="{count: selectedAttributes.length}" |
84 | 82 | translate-interpolation="messageformat"></span> |
85 | 83 | <span flex></span> | ... | ... |
... | ... | @@ -13,14 +13,19 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | +/* eslint-enable import/no-unresolved, import/default */ | |
17 | + | |
18 | +import AttributeDialogEditJsonController from "./attribute-dialog-edit-json.controller"; | |
19 | +import attributeDialogEditJsonTemplate from "./attribute-dialog-edit-json.tpl.html"; | |
20 | + | |
16 | 21 | /*@ngInject*/ |
17 | -export default function EditAttributeValueController($scope, $q, $element, types, attributeValue, save) { | |
22 | +export default function EditAttributeValueController($scope, $mdDialog, $q, $element, $document, types, attributeValue, save) { | |
18 | 23 | |
19 | 24 | $scope.valueTypes = types.valueType; |
20 | 25 | |
21 | - $scope.model = {}; | |
22 | - | |
23 | - $scope.model.value = attributeValue; | |
26 | + $scope.model = { | |
27 | + value: attributeValue | |
28 | + }; | |
24 | 29 | |
25 | 30 | if ($scope.model.value === true || $scope.model.value === false) { |
26 | 31 | $scope.valueType = types.valueType.boolean; |
... | ... | @@ -30,26 +35,27 @@ export default function EditAttributeValueController($scope, $q, $element, types |
30 | 35 | } else { |
31 | 36 | $scope.valueType = types.valueType.double; |
32 | 37 | } |
38 | + } else if (angular.isObject($scope.model.value)) { | |
39 | + $scope.valueType = types.valueType.json; | |
33 | 40 | } else { |
34 | 41 | $scope.valueType = types.valueType.string; |
35 | 42 | } |
36 | 43 | |
37 | 44 | $scope.submit = submit; |
38 | 45 | $scope.dismiss = dismiss; |
46 | + $scope.editJSON = editJSON; | |
39 | 47 | |
40 | 48 | function dismiss() { |
41 | 49 | $element.remove(); |
42 | 50 | } |
43 | 51 | |
44 | 52 | function update() { |
45 | - if($scope.editDialog.$invalid) { | |
53 | + if ($scope.editDialog.$invalid) { | |
46 | 54 | return $q.reject(); |
47 | 55 | } |
48 | - | |
49 | - if(angular.isFunction(save)) { | |
56 | + if (angular.isFunction(save)) { | |
50 | 57 | return $q.when(save($scope.model)); |
51 | 58 | } |
52 | - | |
53 | 59 | return $q.resolve(); |
54 | 60 | } |
55 | 61 | |
... | ... | @@ -59,13 +65,45 @@ export default function EditAttributeValueController($scope, $q, $element, types |
59 | 65 | }); |
60 | 66 | } |
61 | 67 | |
62 | - $scope.$watch('valueType', function(newVal, prevVal) { | |
63 | - if (newVal != prevVal) { | |
68 | + | |
69 | + $scope.$watch('valueType', function (newVal, prevVal) { | |
70 | + if (newVal !== prevVal) { | |
64 | 71 | if ($scope.valueType === types.valueType.boolean) { |
65 | 72 | $scope.model.value = false; |
73 | + } else if ($scope.valueType === types.valueType.json) { | |
74 | + $scope.model.value = {}; | |
66 | 75 | } else { |
67 | 76 | $scope.model.value = null; |
68 | 77 | } |
69 | 78 | } |
70 | 79 | }); |
80 | + | |
81 | + function editJSON($event) { | |
82 | + $scope.hideDialog = true; | |
83 | + showJsonDialog($event, $scope.model.value, false).then((response) => { | |
84 | + $scope.hideDialog = false; | |
85 | + if (!angular.equals(response, $scope.model.value)) { | |
86 | + $scope.editDialog.$setDirty(); | |
87 | + } | |
88 | + $scope.model.value = response; | |
89 | + }) | |
90 | + } | |
91 | + | |
92 | + function showJsonDialog($event, jsonValue, readOnly) { | |
93 | + if ($event) { | |
94 | + $event.stopPropagation(); | |
95 | + } | |
96 | + return $mdDialog.show({ | |
97 | + controller: AttributeDialogEditJsonController, | |
98 | + controllerAs: 'vm', | |
99 | + templateUrl: attributeDialogEditJsonTemplate, | |
100 | + locals: { | |
101 | + jsonValue: jsonValue, | |
102 | + readOnly: readOnly | |
103 | + }, | |
104 | + targetEvent: $event, | |
105 | + fullscreen: true, | |
106 | + multiple: true | |
107 | + }); | |
108 | + } | |
71 | 109 | } | ... | ... |
... | ... | @@ -15,8 +15,8 @@ |
15 | 15 | limitations under the License. |
16 | 16 | |
17 | 17 | --> |
18 | -<md-edit-dialog> | |
19 | - <form name="editDialog" ng-submit="submit()"> | |
18 | +<md-edit-dialog class="tb-edit-dialog"> | |
19 | + <form name="editDialog" ng-submit="submit()" > | |
20 | 20 | <div layout="column" class="md-content" style="width: 400px;"> |
21 | 21 | <fieldset> |
22 | 22 | <section layout="row"> |
... | ... | @@ -38,7 +38,8 @@ |
38 | 38 | </md-input-container> |
39 | 39 | <md-input-container ng-if="valueType===valueTypes.integer" flex="60" class="md-block"> |
40 | 40 | <label translate>value.integer-value</label> |
41 | - <input required name="value" type="number" step="1" ng-pattern="/^-?[0-9]+$/" ng-model="model.value"> | |
41 | + <input required name="value" type="number" step="1" ng-pattern="/^-?[0-9]+$/" | |
42 | + ng-model="model.value"> | |
42 | 43 | <div ng-messages="editDialog.value.$error"> |
43 | 44 | <div translate ng-message="required">attribute.value-required</div> |
44 | 45 | <div translate ng-message="pattern">value.invalid-integer-value</div> |
... | ... | @@ -52,16 +53,31 @@ |
52 | 53 | </div> |
53 | 54 | </md-input-container> |
54 | 55 | <div layout="column" layout-align="center" flex="60" ng-if="valueType===valueTypes.boolean"> |
55 | - <md-checkbox ng-model="model.value" style="margin-bottom: 0px;"> | |
56 | + <md-checkbox ng-model="model.value" style="margin-bottom: 0;"> | |
56 | 57 | {{ (model.value ? 'value.true' : 'value.false') | translate }} |
57 | 58 | </md-checkbox> |
58 | 59 | </div> |
60 | + <div layout="row" layout-align="center" ng-if="valueType===valueTypes.json" flex="60"> | |
61 | + <md-input-container class="md-block"> | |
62 | + <label translate>value.json-value</label> | |
63 | + <input required tb-json-to-string name="value" ng-model="model.value"> | |
64 | + <div ng-messages="editDialog.value.$error"> | |
65 | + <div translate ng-message="required">attribute.value-required</div> | |
66 | + </div> | |
67 | + </md-input-container> | |
68 | + <md-button class="md-icon-button" style="margin: 18px 0;" | |
69 | + ng-click="editJSON($event)" aria-label="{{ 'action.edit' | translate }}"> | |
70 | + <md-tooltip md-direction="top"> | |
71 | + {{ 'action.edit' | translate }} | |
72 | + </md-tooltip> | |
73 | + <ng-md-icon size="20" icon="open_in_new"></ng-md-icon> | |
74 | + </md-button> | |
75 | + </div> | |
59 | 76 | </section> |
60 | 77 | </fieldset> |
61 | 78 | </div> |
62 | 79 | <div layout="row" layout-align="end" class="md-actions"> |
63 | - <md-button ng-click="dismiss()">{{ 'action.cancel' | | |
64 | - translate }} | |
80 | + <md-button ng-click="dismiss()">{{ 'action.cancel' | translate }} | |
65 | 81 | </md-button> |
66 | 82 | <md-button ng-disabled="editDialog.$invalid || !editDialog.$dirty" type="submit" |
67 | 83 | class="md-raised md-primary"> |
... | ... | @@ -69,4 +85,4 @@ |
69 | 85 | </md-button> |
70 | 86 | </div> |
71 | 87 | </form> |
72 | -</md-edit-dialog> | |
\ No newline at end of file | ||
88 | +</md-edit-dialog> | ... | ... |
... | ... | @@ -607,6 +607,7 @@ |
607 | 607 | }, |
608 | 608 | "details": { |
609 | 609 | "edit-mode": "Edit mode", |
610 | + "edit-json": "Edit JSON", | |
610 | 611 | "toggle-edit-mode": "Toggle edit mode" |
611 | 612 | }, |
612 | 613 | "device": { |
... | ... | @@ -1270,7 +1271,8 @@ |
1270 | 1271 | "js-func": { |
1271 | 1272 | "no-return-error": "Function must return value!", |
1272 | 1273 | "return-type-mismatch": "Function must return value of '{{type}}' type!", |
1273 | - "tidy": "Tidy" | |
1274 | + "tidy": "Tidy", | |
1275 | + "mini": "Mini" | |
1274 | 1276 | }, |
1275 | 1277 | "key-val": { |
1276 | 1278 | "key": "Key", |
... | ... | @@ -1593,7 +1595,9 @@ |
1593 | 1595 | "boolean-value": "Boolean value", |
1594 | 1596 | "false": "False", |
1595 | 1597 | "true": "True", |
1596 | - "long": "Long" | |
1598 | + "long": "Long", | |
1599 | + "json": "JSON", | |
1600 | + "json-value": "JSON value" | |
1597 | 1601 | }, |
1598 | 1602 | "widget": { |
1599 | 1603 | "widget-library": "Widgets Library", | ... | ... |
... | ... | @@ -607,6 +607,7 @@ |
607 | 607 | }, |
608 | 608 | "details": { |
609 | 609 | "edit-mode": "Режим редактирования", |
610 | + "edit-json": "Редактировать JSON", | |
610 | 611 | "toggle-edit-mode": "Режим редактирования" |
611 | 612 | }, |
612 | 613 | "device": { |
... | ... | @@ -1191,8 +1192,7 @@ |
1191 | 1192 | }, |
1192 | 1193 | "js-func": { |
1193 | 1194 | "no-return-error": "Функция должна возвращать значение!", |
1194 | - "return-type-mismatch": "Функция должна возвращать значение типа '{{type}}'!", | |
1195 | - "tidy": "Tidy" | |
1195 | + "return-type-mismatch": "Функция должна возвращать значение типа '{{type}}'!" | |
1196 | 1196 | }, |
1197 | 1197 | "key-val": { |
1198 | 1198 | "key": "Ключ", | ... | ... |
... | ... | @@ -724,6 +724,7 @@ |
724 | 724 | "details": { |
725 | 725 | "details": "Деталі", |
726 | 726 | "edit-mode": "Режим редагування", |
727 | + "edit-json": "Редагувати JSON", | |
727 | 728 | "toggle-edit-mode": "Перемкнути режим редагування" |
728 | 729 | }, |
729 | 730 | "device": { |
... | ... | @@ -1606,8 +1607,7 @@ |
1606 | 1607 | }, |
1607 | 1608 | "js-func": { |
1608 | 1609 | "no-return-error": "Функція повинна повертати значення!", |
1609 | - "return-type-mismatch": "Функція повинна повернути значення типу '{{type}}'!", | |
1610 | - "tidy": "Tidy" | |
1610 | + "return-type-mismatch": "Функція повинна повернути значення типу '{{type}}'!" | |
1611 | 1611 | }, |
1612 | 1612 | "key-val": { |
1613 | 1613 | "key": "Ключ", | ... | ... |