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,6 +29,8 @@ import thingsboardWebCameraInputWidget from '../widget/lib/web-camera-input-widg | ||
29 | 29 | ||
30 | import thingsboardRpcWidgets from '../widget/lib/rpc'; | 30 | import thingsboardRpcWidgets from '../widget/lib/rpc'; |
31 | 31 | ||
32 | +import thingsboardJsonToString from '../components/tb-json-to-string.directive'; | ||
33 | + | ||
32 | import TbFlot from '../widget/lib/flot-widget'; | 34 | import TbFlot from '../widget/lib/flot-widget'; |
33 | import TbAnalogueLinearGauge from '../widget/lib/analogue-linear-gauge'; | 35 | import TbAnalogueLinearGauge from '../widget/lib/analogue-linear-gauge'; |
34 | import TbAnalogueRadialGauge from '../widget/lib/analogue-radial-gauge'; | 36 | import TbAnalogueRadialGauge from '../widget/lib/analogue-radial-gauge'; |
@@ -52,7 +54,7 @@ export default angular.module('thingsboard.api.widget', ['oc.lazyLoad', thingsbo | @@ -52,7 +54,7 @@ export default angular.module('thingsboard.api.widget', ['oc.lazyLoad', thingsbo | ||
52 | thingsboardTimeseriesTableWidget, thingsboardAlarmsTableWidget, thingsboardEntitiesTableWidget, | 54 | thingsboardTimeseriesTableWidget, thingsboardAlarmsTableWidget, thingsboardEntitiesTableWidget, |
53 | thingsboardEntitiesHierarchyWidget, thingsboardExtensionsTableWidget, thingsboardDateRangeNavigatorWidget, | 55 | thingsboardEntitiesHierarchyWidget, thingsboardExtensionsTableWidget, thingsboardDateRangeNavigatorWidget, |
54 | thingsboardMultipleInputWidget, thingsboardWebCameraInputWidget, thingsboardRpcWidgets, thingsboardTypes, | 56 | thingsboardMultipleInputWidget, thingsboardWebCameraInputWidget, thingsboardRpcWidgets, thingsboardTypes, |
55 | - thingsboardUtils, TripAnimationWidget]) | 57 | + thingsboardUtils, thingsboardJsonToString, TripAnimationWidget]) |
56 | .factory('widgetService', WidgetService) | 58 | .factory('widgetService', WidgetService) |
57 | .name; | 59 | .name; |
58 | 60 |
@@ -881,6 +881,11 @@ export default angular.module('thingsboard.types', []) | @@ -881,6 +881,11 @@ export default angular.module('thingsboard.types', []) | ||
881 | value: "boolean", | 881 | value: "boolean", |
882 | name: "value.boolean", | 882 | name: "value.boolean", |
883 | icon: "mdi:checkbox-marked-outline" | 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 | widgetType: { | 891 | widgetType: { |
@@ -57,9 +57,12 @@ function JsonContent($compile, $templateCache, toast, types, utils) { | @@ -57,9 +57,12 @@ function JsonContent($compile, $templateCache, toast, types, utils) { | ||
57 | updateEditorSize(); | 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 | function updateEditorSize() { | 68 | function updateEditorSize() { |
@@ -116,7 +119,7 @@ function JsonContent($compile, $templateCache, toast, types, utils) { | @@ -116,7 +119,7 @@ function JsonContent($compile, $templateCache, toast, types, utils) { | ||
116 | scope.$watch('contentBody', function (newContent, oldContent) { | 119 | scope.$watch('contentBody', function (newContent, oldContent) { |
117 | ngModelCtrl.$setViewValue(scope.contentBody); | 120 | ngModelCtrl.$setViewValue(scope.contentBody); |
118 | if (!angular.equals(newContent, oldContent)) { | 121 | if (!angular.equals(newContent, oldContent)) { |
119 | - scope.contentValid = true; | 122 | + scope.contentValid = scope.validate(); |
120 | } | 123 | } |
121 | scope.updateValidity(); | 124 | scope.updateValidity(); |
122 | }); | 125 | }); |
@@ -139,15 +142,17 @@ function JsonContent($compile, $templateCache, toast, types, utils) { | @@ -139,15 +142,17 @@ function JsonContent($compile, $templateCache, toast, types, utils) { | ||
139 | } | 142 | } |
140 | return true; | 143 | return true; |
141 | } catch (e) { | 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 | return false; | 156 | return false; |
152 | } | 157 | } |
153 | }; | 158 | }; |
@@ -169,7 +174,7 @@ function JsonContent($compile, $templateCache, toast, types, utils) { | @@ -169,7 +174,7 @@ function JsonContent($compile, $templateCache, toast, types, utils) { | ||
169 | }); | 174 | }); |
170 | 175 | ||
171 | $compile(element.contents())(scope); | 176 | $compile(element.contents())(scope); |
172 | - } | 177 | + }; |
173 | 178 | ||
174 | return { | 179 | return { |
175 | restrict: "E", | 180 | restrict: "E", |
@@ -177,6 +182,7 @@ function JsonContent($compile, $templateCache, toast, types, utils) { | @@ -177,6 +182,7 @@ function JsonContent($compile, $templateCache, toast, types, utils) { | ||
177 | scope: { | 182 | scope: { |
178 | contentType: '=', | 183 | contentType: '=', |
179 | validateContent: '=?', | 184 | validateContent: '=?', |
185 | + hideErrorToast: '=?', | ||
180 | readonly:'=ngReadonly', | 186 | readonly:'=ngReadonly', |
181 | fillHeight:'=?' | 187 | fillHeight:'=?' |
182 | }, | 188 | }, |
@@ -27,7 +27,7 @@ tb-json-content { | @@ -27,7 +27,7 @@ tb-json-content { | ||
27 | min-height: 15px; | 27 | min-height: 15px; |
28 | padding: 4px; | 28 | padding: 4px; |
29 | margin: 0 5px 0 0; | 29 | margin: 0 5px 0 0; |
30 | - font-size: .8rem; | 30 | + font-size: 12px; |
31 | line-height: 15px; | 31 | line-height: 15px; |
32 | color: #7b7b7b; | 32 | color: #7b7b7b; |
33 | background: rgba(220, 220, 220, .35); | 33 | background: rgba(220, 220, 220, .35); |
@@ -17,11 +17,15 @@ | @@ -17,11 +17,15 @@ | ||
17 | --> | 17 | --> |
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"> | 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" style="height: 40px;" class="tb-json-content-toolbar"> | 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 | <span flex></span> | 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 | 'js-func.tidy' | translate }} | 24 | 'js-func.tidy' | translate }} |
24 | </md-button> | 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 | <md-button id="expand-button" aria-label="Fullscreen" class="md-icon-button tb-md-32 tb-fullscreen-button-style"></md-button> | 29 | <md-button id="expand-button" aria-label="Fullscreen" class="md-icon-button tb-md-32 tb-fullscreen-button-style"></md-button> |
26 | </div> | 30 | </div> |
27 | <div flex id="tb-json-panel" class="tb-json-content-panel" layout="column"> | 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,6 +50,14 @@ function JsonObjectEdit($compile, $templateCache, $document, toast, utils) { | ||
50 | updateEditorSize(); | 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 | function updateEditorSize() { | 61 | function updateEditorSize() { |
54 | if (scope.json_editor) { | 62 | if (scope.json_editor) { |
55 | scope.json_editor.resize(); | 63 | scope.json_editor.resize(); |
@@ -169,7 +177,7 @@ function JsonObjectEdit($compile, $templateCache, $document, toast, utils) { | @@ -169,7 +177,7 @@ function JsonObjectEdit($compile, $templateCache, $document, toast, utils) { | ||
169 | }); | 177 | }); |
170 | 178 | ||
171 | $compile(element.contents())(scope); | 179 | $compile(element.contents())(scope); |
172 | - } | 180 | + }; |
173 | 181 | ||
174 | return { | 182 | return { |
175 | restrict: "E", | 183 | restrict: "E", |
@@ -21,6 +21,19 @@ tb-json-object-edit { | @@ -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 | .tb-json-object-panel { | 37 | .tb-json-object-panel { |
25 | height: 100%; | 38 | height: 100%; |
26 | margin-left: 15px; | 39 | margin-left: 15px; |
@@ -16,12 +16,18 @@ | @@ -16,12 +16,18 @@ | ||
16 | 16 | ||
17 | --> | 17 | --> |
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"> | 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 | <label class="tb-title no-padding" | 20 | <label class="tb-title no-padding" |
21 | ng-class="{'tb-required': required, | 21 | ng-class="{'tb-required': required, |
22 | 'tb-readonly': readonly, | 22 | 'tb-readonly': readonly, |
23 | 'tb-error': !objectValid}">{{ label }}</label> | 23 | 'tb-error': !objectValid}">{{ label }}</label> |
24 | <span flex></span> | 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 | <md-button id="expand-button" aria-label="Fullscreen" class="md-icon-button tb-md-32 tb-fullscreen-button-style"></md-button> | 31 | <md-button id="expand-button" aria-label="Fullscreen" class="md-icon-button tb-md-32 tb-fullscreen-button-style"></md-button> |
26 | </div> | 32 | </div> |
27 | <div flex id="tb-json-panel" class="tb-json-object-panel" layout="column"> | 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,10 +13,18 @@ | ||
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 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 | /*@ngInject*/ | 24 | /*@ngInject*/ |
17 | export default function AddAttributeDialogController($scope, $mdDialog, types, attributeService, entityType, entityId, attributeScope) { | 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 | vm.attribute = {}; | 29 | vm.attribute = {}; |
22 | 30 | ||
@@ -40,11 +48,37 @@ export default function AddAttributeDialogController($scope, $mdDialog, types, a | @@ -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 | if (vm.valueType === types.valueType.boolean) { | 52 | if (vm.valueType === types.valueType.boolean) { |
45 | vm.attribute.value = false; | 53 | vm.attribute.value = false; |
54 | + } else if (vm.valueType === types.valueType.json) { | ||
55 | + vm.attribute.value = {}; | ||
46 | } else { | 56 | } else { |
47 | vm.attribute.value = null; | 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,7 +26,8 @@ | ||
26 | </md-button> | 26 | </md-button> |
27 | </div> | 27 | </div> |
28 | </md-toolbar> | 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 | <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span> | 31 | <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span> |
31 | <md-dialog-content> | 32 | <md-dialog-content> |
32 | <div class="md-dialog-content"> | 33 | <div class="md-dialog-content"> |
@@ -58,7 +59,8 @@ | @@ -58,7 +59,8 @@ | ||
58 | </md-input-container> | 59 | </md-input-container> |
59 | <md-input-container ng-if="vm.valueType===vm.valueTypes.integer" flex="60" class="md-block"> | 60 | <md-input-container ng-if="vm.valueType===vm.valueTypes.integer" flex="60" class="md-block"> |
60 | <label translate>value.integer-value</label> | 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 | <div ng-messages="theForm.value.$error"> | 64 | <div ng-messages="theForm.value.$error"> |
63 | <div translate ng-message="required">attribute.value-required</div> | 65 | <div translate ng-message="required">attribute.value-required</div> |
64 | <div translate ng-message="pattern">value.invalid-integer-value</div> | 66 | <div translate ng-message="pattern">value.invalid-integer-value</div> |
@@ -71,11 +73,31 @@ | @@ -71,11 +73,31 @@ | ||
71 | <div translate ng-message="required">attribute.value-required</div> | 73 | <div translate ng-message="required">attribute.value-required</div> |
72 | </div> | 74 | </div> |
73 | </md-input-container> | 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 | {{ (vm.attribute.value ? 'value.true' : 'value.false') | translate }} | 79 | {{ (vm.attribute.value ? 'value.true' : 'value.false') | translate }} |
77 | </md-checkbox> | 80 | </md-checkbox> |
78 | </div> | 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 | </section> | 101 | </section> |
80 | </fieldset> | 102 | </fieldset> |
81 | </md-content> | 103 | </md-content> |
@@ -87,8 +109,8 @@ | @@ -87,8 +109,8 @@ | ||
87 | class="md-raised md-primary"> | 109 | class="md-raised md-primary"> |
88 | {{ 'action.add' | translate }} | 110 | {{ 'action.add' | translate }} |
89 | </md-button> | 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 | </md-button> | 114 | </md-button> |
93 | </md-dialog-actions> | 115 | </md-dialog-actions> |
94 | </form> | 116 | </form> |
@@ -26,7 +26,8 @@ | @@ -26,7 +26,8 @@ | ||
26 | </md-button> | 26 | </md-button> |
27 | </div> | 27 | </div> |
28 | </md-toolbar> | 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 | <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span> | 31 | <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span> |
31 | <md-dialog-content> | 32 | <md-dialog-content> |
32 | <div class="md-dialog-content"> | 33 | <div class="md-dialog-content"> |
@@ -37,10 +38,10 @@ | @@ -37,10 +38,10 @@ | ||
37 | <section flex layout="column" style="width: 300px;"> | 38 | <section flex layout="column" style="width: 300px;"> |
38 | <span translate style="padding-bottom: 10px;">dashboard.select-existing</span> | 39 | <span translate style="padding-bottom: 10px;">dashboard.select-existing</span> |
39 | <tb-dashboard-autocomplete the-form="theForm" | 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 | </tb-dashboard-autocomplete> | 45 | </tb-dashboard-autocomplete> |
45 | </section> | 46 | </section> |
46 | </md-radio-button> | 47 | </md-radio-button> |
@@ -49,7 +50,8 @@ | @@ -49,7 +50,8 @@ | ||
49 | <span translate>dashboard.create-new</span> | 50 | <span translate>dashboard.create-new</span> |
50 | <md-input-container class="md-block"> | 51 | <md-input-container class="md-block"> |
51 | <label translate>dashboard.new-dashboard-title</label> | 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 | <div ng-messages="theForm.title.$error"> | 55 | <div ng-messages="theForm.title.$error"> |
54 | <div translate ng-message="required">dashboard.title-required</div> | 56 | <div translate ng-message="required">dashboard.title-required</div> |
55 | </div> | 57 | </div> |
@@ -66,15 +68,15 @@ | @@ -66,15 +68,15 @@ | ||
66 | <md-checkbox | 68 | <md-checkbox |
67 | ng-model="vm.openDashboard" | 69 | ng-model="vm.openDashboard" |
68 | aria-label="{{ 'dashboard.open-dashboard' | translate }}" | 70 | aria-label="{{ 'dashboard.open-dashboard' | translate }}" |
69 | - style="margin-bottom: 0px; padding-right: 20px;"> | 71 | + style="margin-bottom: 0; padding-right: 20px;"> |
70 | {{ 'dashboard.open-dashboard' | translate }} | 72 | {{ 'dashboard.open-dashboard' | translate }} |
71 | </md-checkbox> | 73 | </md-checkbox> |
72 | <md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit" | 74 | <md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit" |
73 | class="md-raised md-primary"> | 75 | class="md-raised md-primary"> |
74 | {{ 'action.add' | translate }} | 76 | {{ 'action.add' | translate }} |
75 | </md-button> | 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 | </md-button> | 80 | </md-button> |
79 | </md-dialog-actions> | 81 | </md-dialog-actions> |
80 | </form> | 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,7 +39,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | ||
39 | 39 | ||
40 | element.html(template); | 40 | element.html(template); |
41 | 41 | ||
42 | - var getAttributeScopeByValue = function(attributeScopeValue) { | 42 | + var getAttributeScopeByValue = function (attributeScopeValue) { |
43 | if (scope.types.latestTelemetry.value === attributeScopeValue) { | 43 | if (scope.types.latestTelemetry.value === attributeScopeValue) { |
44 | return scope.types.latestTelemetry; | 44 | return scope.types.latestTelemetry; |
45 | } | 45 | } |
@@ -48,7 +48,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | @@ -48,7 +48,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | ||
48 | return scope.attributeScopes[attrScope]; | 48 | return scope.attributeScopes[attrScope]; |
49 | } | 49 | } |
50 | } | 50 | } |
51 | - } | 51 | + }; |
52 | 52 | ||
53 | scope.types = types; | 53 | scope.types = types; |
54 | 54 | ||
@@ -87,14 +87,14 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | @@ -87,14 +87,14 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | ||
87 | search: null | 87 | search: null |
88 | }; | 88 | }; |
89 | 89 | ||
90 | - scope.$watch("entityId", function(newVal) { | 90 | + scope.$watch("entityId", function (newVal) { |
91 | if (newVal) { | 91 | if (newVal) { |
92 | scope.resetFilter(); | 92 | scope.resetFilter(); |
93 | scope.getEntityAttributes(false, true); | 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 | if (newVal && !angular.equals(newVal, prevVal)) { | 98 | if (newVal && !angular.equals(newVal, prevVal)) { |
99 | scope.mode = 'default'; | 99 | scope.mode = 'default'; |
100 | scope.query.search = null; | 100 | scope.query.search = null; |
@@ -103,30 +103,30 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | @@ -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 | scope.mode = 'default'; | 107 | scope.mode = 'default'; |
108 | scope.query.search = null; | 108 | scope.query.search = null; |
109 | scope.selectedAttributes = []; | 109 | scope.selectedAttributes = []; |
110 | scope.attributeScope = getAttributeScopeByValue(attrs.defaultAttributeScope); | 110 | scope.attributeScope = getAttributeScopeByValue(attrs.defaultAttributeScope); |
111 | - } | 111 | + }; |
112 | 112 | ||
113 | - scope.enterFilterMode = function(event) { | 113 | + scope.enterFilterMode = function (event) { |
114 | let $button = angular.element(event.currentTarget); | 114 | let $button = angular.element(event.currentTarget); |
115 | let $toolbarsContainer = $button.closest('.toolbarsContainer'); | 115 | let $toolbarsContainer = $button.closest('.toolbarsContainer'); |
116 | 116 | ||
117 | scope.query.search = ''; | 117 | scope.query.search = ''; |
118 | 118 | ||
119 | - $timeout(()=>{ | 119 | + $timeout(() => { |
120 | $toolbarsContainer.find('.searchInput').focus(); | 120 | $toolbarsContainer.find('.searchInput').focus(); |
121 | }) | 121 | }) |
122 | - } | 122 | + }; |
123 | 123 | ||
124 | - scope.exitFilterMode = function() { | 124 | + scope.exitFilterMode = function () { |
125 | scope.query.search = null; | 125 | scope.query.search = null; |
126 | scope.getEntityAttributes(); | 126 | scope.getEntityAttributes(); |
127 | - } | 127 | + }; |
128 | 128 | ||
129 | - scope.$watch("query.search", function(newVal, prevVal) { | 129 | + scope.$watch("query.search", function (newVal, prevVal) { |
130 | if (!angular.equals(newVal, prevVal) && scope.query.search != null) { | 130 | if (!angular.equals(newVal, prevVal) && scope.query.search != null) { |
131 | scope.getEntityAttributes(); | 131 | scope.getEntityAttributes(); |
132 | } | 132 | } |
@@ -142,15 +142,15 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | @@ -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 | scope.getEntityAttributes(false, false); | 146 | scope.getEntityAttributes(false, false); |
147 | - } | 147 | + }; |
148 | 148 | ||
149 | - scope.onPaginate = function() { | 149 | + scope.onPaginate = function () { |
150 | scope.getEntityAttributes(false, false); | 150 | scope.getEntityAttributes(false, false); |
151 | - } | 151 | + }; |
152 | 152 | ||
153 | - scope.getEntityAttributes = function(forceUpdate, reset) { | 153 | + scope.getEntityAttributes = function (forceUpdate, reset) { |
154 | if (scope.attributesDeferred) { | 154 | if (scope.attributesDeferred) { |
155 | scope.attributesDeferred.resolve(); | 155 | scope.attributesDeferred.resolve(); |
156 | } | 156 | } |
@@ -163,7 +163,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | @@ -163,7 +163,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | ||
163 | } | 163 | } |
164 | scope.checkSubscription(); | 164 | scope.checkSubscription(); |
165 | scope.attributesDeferred = attributeService.getEntityAttributes(scope.entityType, scope.entityId, scope.attributeScope.value, | 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 | success(attributes, update || forceUpdate, apply); | 167 | success(attributes, update || forceUpdate, apply); |
168 | } | 168 | } |
169 | ); | 169 | ); |
@@ -176,9 +176,9 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | @@ -176,9 +176,9 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | ||
176 | }); | 176 | }); |
177 | deferred.resolve(); | 177 | deferred.resolve(); |
178 | } | 178 | } |
179 | - } | 179 | + }; |
180 | 180 | ||
181 | - scope.checkSubscription = function() { | 181 | + scope.checkSubscription = function () { |
182 | var newSubscriptionId = null; | 182 | var newSubscriptionId = null; |
183 | if (scope.entityId && scope.entityType && scope.attributeScope.clientSide && scope.mode != 'widget') { | 183 | if (scope.entityId && scope.entityType && scope.attributeScope.clientSide && scope.mode != 'widget') { |
184 | newSubscriptionId = attributeService.subscribeForEntityAttributes(scope.entityType, scope.entityId, scope.attributeScope.value); | 184 | newSubscriptionId = attributeService.subscribeForEntityAttributes(scope.entityType, scope.entityId, scope.attributeScope.value); |
@@ -187,36 +187,38 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | @@ -187,36 +187,38 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | ||
187 | attributeService.unsubscribeForEntityAttributes(scope.subscriptionId); | 187 | attributeService.unsubscribeForEntityAttributes(scope.subscriptionId); |
188 | } | 188 | } |
189 | scope.subscriptionId = newSubscriptionId; | 189 | scope.subscriptionId = newSubscriptionId; |
190 | - } | 190 | + }; |
191 | 191 | ||
192 | - scope.$on('$destroy', function() { | 192 | + scope.$on('$destroy', function () { |
193 | if (scope.subscriptionId) { | 193 | if (scope.subscriptionId) { |
194 | attributeService.unsubscribeForEntityAttributes(scope.subscriptionId); | 194 | attributeService.unsubscribeForEntityAttributes(scope.subscriptionId); |
195 | } | 195 | } |
196 | }); | 196 | }); |
197 | 197 | ||
198 | - scope.editAttribute = function($event, attribute) { | 198 | + scope.editAttribute = function ($event, attribute) { |
199 | if (!scope.attributeScope.clientSide) { | 199 | if (!scope.attributeScope.clientSide) { |
200 | $event.stopPropagation(); | 200 | $event.stopPropagation(); |
201 | $mdEditDialog.show({ | 201 | $mdEditDialog.show({ |
202 | controller: EditAttributeValueController, | 202 | controller: EditAttributeValueController, |
203 | templateUrl: editAttributeValueTemplate, | 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 | targetEvent: $event | 216 | targetEvent: $event |
215 | }); | 217 | }); |
216 | } | 218 | } |
217 | - } | 219 | + }; |
218 | 220 | ||
219 | - scope.addAttribute = function($event) { | 221 | + scope.addAttribute = function ($event) { |
220 | if (!scope.attributeScope.clientSide) { | 222 | if (!scope.attributeScope.clientSide) { |
221 | $event.stopPropagation(); | 223 | $event.stopPropagation(); |
222 | $mdDialog.show({ | 224 | $mdDialog.show({ |
@@ -224,16 +226,20 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | @@ -224,16 +226,20 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | ||
224 | controllerAs: 'vm', | 226 | controllerAs: 'vm', |
225 | templateUrl: addAttributeDialogTemplate, | 227 | templateUrl: addAttributeDialogTemplate, |
226 | parent: angular.element($document[0].body), | 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 | fullscreen: true, | 234 | fullscreen: true, |
229 | targetEvent: $event | 235 | targetEvent: $event |
230 | }).then(function () { | 236 | }).then(function () { |
231 | scope.getEntityAttributes(); | 237 | scope.getEntityAttributes(); |
232 | }); | 238 | }); |
233 | } | 239 | } |
234 | - } | 240 | + }; |
235 | 241 | ||
236 | - scope.deleteAttributes = function($event) { | 242 | + scope.deleteAttributes = function ($event) { |
237 | if (!scope.attributeScope.clientSide) { | 243 | if (!scope.attributeScope.clientSide) { |
238 | $event.stopPropagation(); | 244 | $event.stopPropagation(); |
239 | var confirm = $mdDialog.confirm() | 245 | var confirm = $mdDialog.confirm() |
@@ -244,33 +250,33 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | @@ -244,33 +250,33 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | ||
244 | .cancel($translate.instant('action.no')) | 250 | .cancel($translate.instant('action.no')) |
245 | .ok($translate.instant('action.yes')); | 251 | .ok($translate.instant('action.yes')); |
246 | $mdDialog.show(confirm).then(function () { | 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 | $mdUtil.nextTick(function () { | 264 | $mdUtil.nextTick(function () { |
259 | if (scope.widgetsCarousel.index < scope.widgetsList.length - 1) { | 265 | if (scope.widgetsCarousel.index < scope.widgetsList.length - 1) { |
260 | scope.widgetsCarousel.index++; | 266 | scope.widgetsCarousel.index++; |
261 | } | 267 | } |
262 | }); | 268 | }); |
263 | - } | 269 | + }; |
264 | 270 | ||
265 | - scope.prevWidget = function() { | 271 | + scope.prevWidget = function () { |
266 | $mdUtil.nextTick(function () { | 272 | $mdUtil.nextTick(function () { |
267 | if (scope.widgetsCarousel.index > 0) { | 273 | if (scope.widgetsCarousel.index > 0) { |
268 | scope.widgetsCarousel.index--; | 274 | scope.widgetsCarousel.index--; |
269 | } | 275 | } |
270 | }); | 276 | }); |
271 | - } | 277 | + }; |
272 | 278 | ||
273 | - scope.enterWidgetMode = function() { | 279 | + scope.enterWidgetMode = function () { |
274 | 280 | ||
275 | if (scope.widgetsIndexWatch) { | 281 | if (scope.widgetsIndexWatch) { |
276 | scope.widgetsIndexWatch(); | 282 | scope.widgetsIndexWatch(); |
@@ -303,7 +309,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | @@ -303,7 +309,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | ||
303 | entitiAliases[entityAlias.id] = entityAlias; | 309 | entitiAliases[entityAlias.id] = entityAlias; |
304 | 310 | ||
305 | var stateController = { | 311 | var stateController = { |
306 | - getStateParams: function() { | 312 | + getStateParams: function () { |
307 | return {}; | 313 | return {}; |
308 | } | 314 | } |
309 | }; | 315 | }; |
@@ -317,9 +323,9 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | @@ -317,9 +323,9 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | ||
317 | type: types.datasourceType.entity, | 323 | type: types.datasourceType.entity, |
318 | entityAliasId: entityAlias.id, | 324 | entityAliasId: entityAlias.id, |
319 | dataKeys: [] | 325 | dataKeys: [] |
320 | - } | 326 | + }; |
321 | var i = 0; | 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 | var attribute = scope.selectedAttributes[attr]; | 329 | var attribute = scope.selectedAttributes[attr]; |
324 | var dataKey = { | 330 | var dataKey = { |
325 | name: attribute.key, | 331 | name: attribute.key, |
@@ -328,12 +334,12 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | @@ -328,12 +334,12 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | ||
328 | color: utils.getMaterialColor(i), | 334 | color: utils.getMaterialColor(i), |
329 | settings: {}, | 335 | settings: {}, |
330 | _hash: Math.random() | 336 | _hash: Math.random() |
331 | - } | 337 | + }; |
332 | datasource.dataKeys.push(dataKey); | 338 | datasource.dataKeys.push(dataKey); |
333 | i++; | 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 | if (scope.mode === 'widget' && (newVal != prevVal)) { | 343 | if (scope.mode === 'widget' && (newVal != prevVal)) { |
338 | var index = scope.widgetsCarousel.index; | 344 | var index = scope.widgetsCarousel.index; |
339 | for (var i = 0; i < scope.widgetsList.length; i++) { | 345 | for (var i = 0; i < scope.widgetsList.length; i++) { |
@@ -345,7 +351,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | @@ -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 | if (scope.mode === 'widget' && (scope.firstBundle === true || newVal != prevVal)) { | 355 | if (scope.mode === 'widget' && (scope.firstBundle === true || newVal != prevVal)) { |
350 | scope.widgetsList = []; | 356 | scope.widgetsList = []; |
351 | scope.widgetsListCache = []; | 357 | scope.widgetsListCache = []; |
@@ -358,7 +364,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | @@ -358,7 +364,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | ||
358 | widgetService.getBundleWidgetTypes(scope.widgetsBundle.alias, isSystem).then( | 364 | widgetService.getBundleWidgetTypes(scope.widgetsBundle.alias, isSystem).then( |
359 | function success(widgetTypes) { | 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 | for (var i = 0; i < widgetTypes.length; i++) { | 369 | for (var i = 0; i < widgetTypes.length; i++) { |
364 | var widgetType = widgetTypes[i]; | 370 | var widgetType = widgetTypes[i]; |
@@ -398,9 +404,9 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | @@ -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 | if (scope.widgetsBundleWatch) { | 410 | if (scope.widgetsBundleWatch) { |
405 | scope.widgetsBundleWatch(); | 411 | scope.widgetsBundleWatch(); |
406 | scope.widgetsBundleWatch = null; | 412 | scope.widgetsBundleWatch = null; |
@@ -412,9 +418,9 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | @@ -412,9 +418,9 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | ||
412 | scope.selectedWidgetsBundleAlias = null; | 418 | scope.selectedWidgetsBundleAlias = null; |
413 | scope.mode = 'default'; | 419 | scope.mode = 'default'; |
414 | scope.getEntityAttributes(true); | 420 | scope.getEntityAttributes(true); |
415 | - } | 421 | + }; |
416 | 422 | ||
417 | - scope.addWidgetToDashboard = function($event) { | 423 | + scope.addWidgetToDashboard = function ($event) { |
418 | if (scope.mode === 'widget' && scope.widgetsListCache.length > 0) { | 424 | if (scope.mode === 'widget' && scope.widgetsListCache.length > 0) { |
419 | var widget = scope.widgetsListCache[scope.widgetsCarousel.index][0]; | 425 | var widget = scope.widgetsListCache[scope.widgetsCarousel.index][0]; |
420 | $event.stopPropagation(); | 426 | $event.stopPropagation(); |
@@ -423,21 +429,26 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | @@ -423,21 +429,26 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | ||
423 | controllerAs: 'vm', | 429 | controllerAs: 'vm', |
424 | templateUrl: addWidgetToDashboardDialogTemplate, | 430 | templateUrl: addWidgetToDashboardDialogTemplate, |
425 | parent: angular.element($document[0].body), | 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 | fullscreen: true, | 438 | fullscreen: true, |
428 | targetEvent: $event | 439 | targetEvent: $event |
429 | }).then(function () { | 440 | }).then(function () { |
430 | 441 | ||
431 | }); | 442 | }); |
432 | } | 443 | } |
433 | - } | 444 | + }; |
434 | 445 | ||
435 | - scope.loading = function() { | 446 | + scope.loading = function () { |
436 | return $rootScope.loading; | 447 | return $rootScope.loading; |
437 | - } | 448 | + }; |
438 | 449 | ||
439 | $compile(element.contents())(scope); | 450 | $compile(element.contents())(scope); |
440 | - } | 451 | + }; |
441 | 452 | ||
442 | return { | 453 | return { |
443 | restrict: "E", | 454 | restrict: "E", |
@@ -77,9 +77,7 @@ | @@ -77,9 +77,7 @@ | ||
77 | </md-toolbar> | 77 | </md-toolbar> |
78 | <md-toolbar class="md-table-toolbar alternate" ng-show="mode==='default' && selectedAttributes.length"> | 78 | <md-toolbar class="md-table-toolbar alternate" ng-show="mode==='default' && selectedAttributes.length"> |
79 | <div class="md-toolbar-tools"> | 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 | translate-values="{count: selectedAttributes.length}" | 81 | translate-values="{count: selectedAttributes.length}" |
84 | translate-interpolation="messageformat"></span> | 82 | translate-interpolation="messageformat"></span> |
85 | <span flex></span> | 83 | <span flex></span> |
@@ -13,14 +13,19 @@ | @@ -13,14 +13,19 @@ | ||
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 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 | /*@ngInject*/ | 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 | $scope.valueTypes = types.valueType; | 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 | if ($scope.model.value === true || $scope.model.value === false) { | 30 | if ($scope.model.value === true || $scope.model.value === false) { |
26 | $scope.valueType = types.valueType.boolean; | 31 | $scope.valueType = types.valueType.boolean; |
@@ -30,26 +35,27 @@ export default function EditAttributeValueController($scope, $q, $element, types | @@ -30,26 +35,27 @@ export default function EditAttributeValueController($scope, $q, $element, types | ||
30 | } else { | 35 | } else { |
31 | $scope.valueType = types.valueType.double; | 36 | $scope.valueType = types.valueType.double; |
32 | } | 37 | } |
38 | + } else if (angular.isObject($scope.model.value)) { | ||
39 | + $scope.valueType = types.valueType.json; | ||
33 | } else { | 40 | } else { |
34 | $scope.valueType = types.valueType.string; | 41 | $scope.valueType = types.valueType.string; |
35 | } | 42 | } |
36 | 43 | ||
37 | $scope.submit = submit; | 44 | $scope.submit = submit; |
38 | $scope.dismiss = dismiss; | 45 | $scope.dismiss = dismiss; |
46 | + $scope.editJSON = editJSON; | ||
39 | 47 | ||
40 | function dismiss() { | 48 | function dismiss() { |
41 | $element.remove(); | 49 | $element.remove(); |
42 | } | 50 | } |
43 | 51 | ||
44 | function update() { | 52 | function update() { |
45 | - if($scope.editDialog.$invalid) { | 53 | + if ($scope.editDialog.$invalid) { |
46 | return $q.reject(); | 54 | return $q.reject(); |
47 | } | 55 | } |
48 | - | ||
49 | - if(angular.isFunction(save)) { | 56 | + if (angular.isFunction(save)) { |
50 | return $q.when(save($scope.model)); | 57 | return $q.when(save($scope.model)); |
51 | } | 58 | } |
52 | - | ||
53 | return $q.resolve(); | 59 | return $q.resolve(); |
54 | } | 60 | } |
55 | 61 | ||
@@ -59,13 +65,45 @@ export default function EditAttributeValueController($scope, $q, $element, types | @@ -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 | if ($scope.valueType === types.valueType.boolean) { | 71 | if ($scope.valueType === types.valueType.boolean) { |
65 | $scope.model.value = false; | 72 | $scope.model.value = false; |
73 | + } else if ($scope.valueType === types.valueType.json) { | ||
74 | + $scope.model.value = {}; | ||
66 | } else { | 75 | } else { |
67 | $scope.model.value = null; | 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,8 +15,8 @@ | ||
15 | limitations under the License. | 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 | <div layout="column" class="md-content" style="width: 400px;"> | 20 | <div layout="column" class="md-content" style="width: 400px;"> |
21 | <fieldset> | 21 | <fieldset> |
22 | <section layout="row"> | 22 | <section layout="row"> |
@@ -38,7 +38,8 @@ | @@ -38,7 +38,8 @@ | ||
38 | </md-input-container> | 38 | </md-input-container> |
39 | <md-input-container ng-if="valueType===valueTypes.integer" flex="60" class="md-block"> | 39 | <md-input-container ng-if="valueType===valueTypes.integer" flex="60" class="md-block"> |
40 | <label translate>value.integer-value</label> | 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 | <div ng-messages="editDialog.value.$error"> | 43 | <div ng-messages="editDialog.value.$error"> |
43 | <div translate ng-message="required">attribute.value-required</div> | 44 | <div translate ng-message="required">attribute.value-required</div> |
44 | <div translate ng-message="pattern">value.invalid-integer-value</div> | 45 | <div translate ng-message="pattern">value.invalid-integer-value</div> |
@@ -52,16 +53,31 @@ | @@ -52,16 +53,31 @@ | ||
52 | </div> | 53 | </div> |
53 | </md-input-container> | 54 | </md-input-container> |
54 | <div layout="column" layout-align="center" flex="60" ng-if="valueType===valueTypes.boolean"> | 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 | {{ (model.value ? 'value.true' : 'value.false') | translate }} | 57 | {{ (model.value ? 'value.true' : 'value.false') | translate }} |
57 | </md-checkbox> | 58 | </md-checkbox> |
58 | </div> | 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 | </section> | 76 | </section> |
60 | </fieldset> | 77 | </fieldset> |
61 | </div> | 78 | </div> |
62 | <div layout="row" layout-align="end" class="md-actions"> | 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 | </md-button> | 81 | </md-button> |
66 | <md-button ng-disabled="editDialog.$invalid || !editDialog.$dirty" type="submit" | 82 | <md-button ng-disabled="editDialog.$invalid || !editDialog.$dirty" type="submit" |
67 | class="md-raised md-primary"> | 83 | class="md-raised md-primary"> |
@@ -69,4 +85,4 @@ | @@ -69,4 +85,4 @@ | ||
69 | </md-button> | 85 | </md-button> |
70 | </div> | 86 | </div> |
71 | </form> | 87 | </form> |
72 | -</md-edit-dialog> | ||
88 | +</md-edit-dialog> |
@@ -2232,7 +2232,7 @@ | @@ -2232,7 +2232,7 @@ | ||
2232 | "last": "Τελευταίος", | 2232 | "last": "Τελευταίος", |
2233 | "time-period": "Χρονική Περίοδος" | 2233 | "time-period": "Χρονική Περίοδος" |
2234 | }, | 2234 | }, |
2235 | - "user": { | 2235 | + "user": { |
2236 | "user": "Χρήστης", | 2236 | "user": "Χρήστης", |
2237 | "users": "Χρήστες", | 2237 | "users": "Χρήστες", |
2238 | "management": "Διαχείριση Χρηστών", | 2238 | "management": "Διαχείριση Χρηστών", |
@@ -607,6 +607,7 @@ | @@ -607,6 +607,7 @@ | ||
607 | }, | 607 | }, |
608 | "details": { | 608 | "details": { |
609 | "edit-mode": "Edit mode", | 609 | "edit-mode": "Edit mode", |
610 | + "edit-json": "Edit JSON", | ||
610 | "toggle-edit-mode": "Toggle edit mode" | 611 | "toggle-edit-mode": "Toggle edit mode" |
611 | }, | 612 | }, |
612 | "device": { | 613 | "device": { |
@@ -1270,7 +1271,8 @@ | @@ -1270,7 +1271,8 @@ | ||
1270 | "js-func": { | 1271 | "js-func": { |
1271 | "no-return-error": "Function must return value!", | 1272 | "no-return-error": "Function must return value!", |
1272 | "return-type-mismatch": "Function must return value of '{{type}}' type!", | 1273 | "return-type-mismatch": "Function must return value of '{{type}}' type!", |
1273 | - "tidy": "Tidy" | 1274 | + "tidy": "Tidy", |
1275 | + "mini": "Mini" | ||
1274 | }, | 1276 | }, |
1275 | "key-val": { | 1277 | "key-val": { |
1276 | "key": "Key", | 1278 | "key": "Key", |
@@ -1593,7 +1595,9 @@ | @@ -1593,7 +1595,9 @@ | ||
1593 | "boolean-value": "Boolean value", | 1595 | "boolean-value": "Boolean value", |
1594 | "false": "False", | 1596 | "false": "False", |
1595 | "true": "True", | 1597 | "true": "True", |
1596 | - "long": "Long" | 1598 | + "long": "Long", |
1599 | + "json": "JSON", | ||
1600 | + "json-value": "JSON value" | ||
1597 | }, | 1601 | }, |
1598 | "widget": { | 1602 | "widget": { |
1599 | "widget-library": "Widgets Library", | 1603 | "widget-library": "Widgets Library", |
@@ -607,6 +607,7 @@ | @@ -607,6 +607,7 @@ | ||
607 | }, | 607 | }, |
608 | "details": { | 608 | "details": { |
609 | "edit-mode": "Режим редактирования", | 609 | "edit-mode": "Режим редактирования", |
610 | + "edit-json": "Редактировать JSON", | ||
610 | "toggle-edit-mode": "Режим редактирования" | 611 | "toggle-edit-mode": "Режим редактирования" |
611 | }, | 612 | }, |
612 | "device": { | 613 | "device": { |
@@ -1191,8 +1192,7 @@ | @@ -1191,8 +1192,7 @@ | ||
1191 | }, | 1192 | }, |
1192 | "js-func": { | 1193 | "js-func": { |
1193 | "no-return-error": "Функция должна возвращать значение!", | 1194 | "no-return-error": "Функция должна возвращать значение!", |
1194 | - "return-type-mismatch": "Функция должна возвращать значение типа '{{type}}'!", | ||
1195 | - "tidy": "Tidy" | 1195 | + "return-type-mismatch": "Функция должна возвращать значение типа '{{type}}'!" |
1196 | }, | 1196 | }, |
1197 | "key-val": { | 1197 | "key-val": { |
1198 | "key": "Ключ", | 1198 | "key": "Ключ", |
@@ -724,6 +724,7 @@ | @@ -724,6 +724,7 @@ | ||
724 | "details": { | 724 | "details": { |
725 | "details": "Деталі", | 725 | "details": "Деталі", |
726 | "edit-mode": "Режим редагування", | 726 | "edit-mode": "Режим редагування", |
727 | + "edit-json": "Редагувати JSON", | ||
727 | "toggle-edit-mode": "Перемкнути режим редагування" | 728 | "toggle-edit-mode": "Перемкнути режим редагування" |
728 | }, | 729 | }, |
729 | "device": { | 730 | "device": { |
@@ -1606,8 +1607,7 @@ | @@ -1606,8 +1607,7 @@ | ||
1606 | }, | 1607 | }, |
1607 | "js-func": { | 1608 | "js-func": { |
1608 | "no-return-error": "Функція повинна повертати значення!", | 1609 | "no-return-error": "Функція повинна повертати значення!", |
1609 | - "return-type-mismatch": "Функція повинна повернути значення типу '{{type}}'!", | ||
1610 | - "tidy": "Tidy" | 1610 | + "return-type-mismatch": "Функція повинна повернути значення типу '{{type}}'!" |
1611 | }, | 1611 | }, |
1612 | "key-val": { | 1612 | "key-val": { |
1613 | "key": "Ключ", | 1613 | "key": "Ключ", |