diff --git a/ui/src/app/api/widget.service.js b/ui/src/app/api/widget.service.js
index 206d3c3d14..4b706e827d 100644
--- a/ui/src/app/api/widget.service.js
+++ b/ui/src/app/api/widget.service.js
@@ -29,6 +29,8 @@ import thingsboardWebCameraInputWidget from '../widget/lib/web-camera-input-widg
import thingsboardRpcWidgets from '../widget/lib/rpc';
+import thingsboardJsonToString from '../components/tb-json-to-string.directive';
+
import TbFlot from '../widget/lib/flot-widget';
import TbAnalogueLinearGauge from '../widget/lib/analogue-linear-gauge';
import TbAnalogueRadialGauge from '../widget/lib/analogue-radial-gauge';
@@ -52,7 +54,7 @@ export default angular.module('thingsboard.api.widget', ['oc.lazyLoad', thingsbo
thingsboardTimeseriesTableWidget, thingsboardAlarmsTableWidget, thingsboardEntitiesTableWidget,
thingsboardEntitiesHierarchyWidget, thingsboardExtensionsTableWidget, thingsboardDateRangeNavigatorWidget,
thingsboardMultipleInputWidget, thingsboardWebCameraInputWidget, thingsboardRpcWidgets, thingsboardTypes,
- thingsboardUtils, TripAnimationWidget])
+ thingsboardUtils, thingsboardJsonToString, TripAnimationWidget])
.factory('widgetService', WidgetService)
.name;
diff --git a/ui/src/app/common/types.constant.js b/ui/src/app/common/types.constant.js
index 57ac8825f5..86bf952582 100644
--- a/ui/src/app/common/types.constant.js
+++ b/ui/src/app/common/types.constant.js
@@ -881,6 +881,11 @@ export default angular.module('thingsboard.types', [])
value: "boolean",
name: "value.boolean",
icon: "mdi:checkbox-marked-outline"
+ },
+ json: {
+ value: "json",
+ name: "value.json",
+ icon: "mdi:json"
}
},
widgetType: {
diff --git a/ui/src/app/components/json-content.directive.js b/ui/src/app/components/json-content.directive.js
index 0788216db9..c4281b15c2 100644
--- a/ui/src/app/components/json-content.directive.js
+++ b/ui/src/app/components/json-content.directive.js
@@ -57,9 +57,12 @@ function JsonContent($compile, $templateCache, toast, types, utils) {
updateEditorSize();
};
- scope.beautifyJson = function () {
- var res = js_beautify(scope.contentBody, {indent_size: 4, wrap_line_length: 60});
- scope.contentBody = res;
+ scope.beautifyJSON = function () {
+ scope.contentBody = js_beautify(scope.contentBody, {indent_size: 4, wrap_line_length: 60});
+ };
+
+ scope.minifyJSON = function () {
+ scope.contentBody = angular.toJson(angular.fromJson(scope.contentBody));
};
function updateEditorSize() {
@@ -116,7 +119,7 @@ function JsonContent($compile, $templateCache, toast, types, utils) {
scope.$watch('contentBody', function (newContent, oldContent) {
ngModelCtrl.$setViewValue(scope.contentBody);
if (!angular.equals(newContent, oldContent)) {
- scope.contentValid = true;
+ scope.contentValid = scope.validate();
}
scope.updateValidity();
});
@@ -139,15 +142,17 @@ function JsonContent($compile, $templateCache, toast, types, utils) {
}
return true;
} catch (e) {
- var details = utils.parseException(e);
- var errorInfo = 'Error:';
- if (details.name) {
- errorInfo += ' ' + details.name + ':';
- }
- if (details.message) {
- errorInfo += ' ' + details.message;
+ if (!scope.hideErrorToast) {
+ var details = utils.parseException(e);
+ var errorInfo = 'Error:';
+ if (details.name) {
+ errorInfo += ' ' + details.name + ':';
+ }
+ if (details.message) {
+ errorInfo += ' ' + details.message;
+ }
+ scope.showError(errorInfo);
}
- scope.showError(errorInfo);
return false;
}
};
@@ -169,7 +174,7 @@ function JsonContent($compile, $templateCache, toast, types, utils) {
});
$compile(element.contents())(scope);
- }
+ };
return {
restrict: "E",
@@ -177,6 +182,7 @@ function JsonContent($compile, $templateCache, toast, types, utils) {
scope: {
contentType: '=',
validateContent: '=?',
+ hideErrorToast: '=?',
readonly:'=ngReadonly',
fillHeight:'=?'
},
diff --git a/ui/src/app/components/json-content.scss b/ui/src/app/components/json-content.scss
index 86937c3af4..d444f8051f 100644
--- a/ui/src/app/components/json-content.scss
+++ b/ui/src/app/components/json-content.scss
@@ -27,7 +27,7 @@ tb-json-content {
min-height: 15px;
padding: 4px;
margin: 0 5px 0 0;
- font-size: .8rem;
+ font-size: 12px;
line-height: 15px;
color: #7b7b7b;
background: rgba(220, 220, 220, .35);
diff --git a/ui/src/app/components/json-content.tpl.html b/ui/src/app/components/json-content.tpl.html
index 5b847f1af6..2b7670942d 100644
--- a/ui/src/app/components/json-content.tpl.html
+++ b/ui/src/app/components/json-content.tpl.html
@@ -17,11 +17,15 @@
-->
-
+
- {{
+ {{
'js-func.tidy' | translate }}
+ {{
+ 'js-func.mini' | translate }}
+
diff --git a/ui/src/app/components/json-object-edit.directive.js b/ui/src/app/components/json-object-edit.directive.js
index 61b54faab7..538b1cfc41 100644
--- a/ui/src/app/components/json-object-edit.directive.js
+++ b/ui/src/app/components/json-object-edit.directive.js
@@ -50,6 +50,14 @@ function JsonObjectEdit($compile, $templateCache, $document, toast, utils) {
updateEditorSize();
};
+ scope.beautifyJSON = function () {
+ scope.contentBody = angular.toJson(scope.object, 4);
+ };
+
+ scope.minifyJSON = function () {
+ scope.contentBody = angular.toJson(scope.object);
+ };
+
function updateEditorSize() {
if (scope.json_editor) {
scope.json_editor.resize();
@@ -169,7 +177,7 @@ function JsonObjectEdit($compile, $templateCache, $document, toast, utils) {
});
$compile(element.contents())(scope);
- }
+ };
return {
restrict: "E",
diff --git a/ui/src/app/components/json-object-edit.scss b/ui/src/app/components/json-object-edit.scss
index d58d9f4b23..9c9cdc7e44 100644
--- a/ui/src/app/components/json-object-edit.scss
+++ b/ui/src/app/components/json-object-edit.scss
@@ -21,6 +21,19 @@ tb-json-object-edit {
}
}
+.tb-json-object-edit-toolbar {
+ .md-button.tidy {
+ min-width: 32px;
+ min-height: 15px;
+ padding: 4px;
+ margin: 0 5px 0 0;
+ font-size: 12px;
+ line-height: 15px;
+ color: #7b7b7b;
+ background: rgba(220, 220, 220, .35);
+ }
+}
+
.tb-json-object-panel {
height: 100%;
margin-left: 15px;
diff --git a/ui/src/app/components/json-object-edit.tpl.html b/ui/src/app/components/json-object-edit.tpl.html
index aa6c867555..86f2a55650 100644
--- a/ui/src/app/components/json-object-edit.tpl.html
+++ b/ui/src/app/components/json-object-edit.tpl.html
@@ -16,12 +16,18 @@
-->
-
+
+
+ {{'js-func.tidy' | translate }}
+
+
+ {{'js-func.mini' | translate }}
+
diff --git a/ui/src/app/components/tb-json-to-string.directive.js b/ui/src/app/components/tb-json-to-string.directive.js
new file mode 100644
index 0000000000..79bfadb540
--- /dev/null
+++ b/ui/src/app/components/tb-json-to-string.directive.js
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2016-2020 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export default angular.module('tbJsonToString', [])
+ .directive('tbJsonToString', InputJson)
+ .name;
+
+function InputJson() {
+ return {
+ restrict: 'A',
+ require: 'ngModel',
+ link: function(scope, element, attr, ngModelCtrl) {
+ function into(input) {
+ try {
+ ngModelCtrl.$setValidity('invalidJSON', true);
+ return angular.fromJson(input);
+ } catch (e) {
+ ngModelCtrl.$setValidity('invalidJSON', false);
+ }
+ }
+ function out(data) {
+ try {
+ ngModelCtrl.$setValidity('invalidJSON', true);
+ return angular.toJson(data);
+ } catch (e) {
+ ngModelCtrl.$setValidity('invalidJSON', false);
+ }
+ }
+ ngModelCtrl.$parsers.push(into);
+ ngModelCtrl.$formatters.push(out);
+ }
+ };
+}
diff --git a/ui/src/app/entity/attribute/add-attribute-dialog.controller.js b/ui/src/app/entity/attribute/add-attribute-dialog.controller.js
index 6b277f08ef..e1c711ba66 100644
--- a/ui/src/app/entity/attribute/add-attribute-dialog.controller.js
+++ b/ui/src/app/entity/attribute/add-attribute-dialog.controller.js
@@ -13,10 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/* eslint-disable import/no-unresolved, import/default */
+
+import attributeDialogEditJsonTemplate from './attribute-dialog-edit-json.tpl.html';
+
+/* eslint-enable import/no-unresolved, import/default */
+
+import AttributeDialogEditJsonController from './attribute-dialog-edit-json.controller';
+
/*@ngInject*/
export default function AddAttributeDialogController($scope, $mdDialog, types, attributeService, entityType, entityId, attributeScope) {
- var vm = this;
+ let vm = this;
vm.attribute = {};
@@ -40,11 +48,37 @@ export default function AddAttributeDialogController($scope, $mdDialog, types, a
);
}
- $scope.$watch('vm.valueType', function() {
+ $scope.$watch('vm.valueType', function () {
if (vm.valueType === types.valueType.boolean) {
vm.attribute.value = false;
+ } else if (vm.valueType === types.valueType.json) {
+ vm.attribute.value = {};
} else {
vm.attribute.value = null;
}
});
+
+ vm.addJSON = ($event) => {
+ showJsonDialog($event, vm.attribute.value, false).then((response) => {
+ vm.attribute.value = response;
+ })
+ };
+
+ function showJsonDialog($event, jsonValue, readOnly) {
+ if ($event) {
+ $event.stopPropagation();
+ }
+ return $mdDialog.show({
+ controller: AttributeDialogEditJsonController,
+ controllerAs: 'vm',
+ templateUrl: attributeDialogEditJsonTemplate,
+ locals: {
+ jsonValue: jsonValue,
+ readOnly: readOnly
+ },
+ targetEvent: $event,
+ fullscreen: true,
+ multiple: true,
+ });
+ }
}
diff --git a/ui/src/app/entity/attribute/add-attribute-dialog.tpl.html b/ui/src/app/entity/attribute/add-attribute-dialog.tpl.html
index f13e31eee9..6520d7a541 100644
--- a/ui/src/app/entity/attribute/add-attribute-dialog.tpl.html
+++ b/ui/src/app/entity/attribute/add-attribute-dialog.tpl.html
@@ -26,7 +26,8 @@
-
+
@@ -58,7 +59,8 @@
-
+
attribute.value-required
value.invalid-integer-value
@@ -71,11 +73,31 @@
attribute.value-required
-
-
+
+
{{ (vm.attribute.value ? 'value.true' : 'value.false') | translate }}
+
+
+
+
+
+
attribute.value-required
+
+
+
+
+ {{ 'action.edit' | translate }}
+
+
+
+
@@ -87,8 +109,8 @@
class="md-raised md-primary">
{{ 'action.add' | translate }}
- {{ 'action.cancel' |
- translate }}
+
+ {{ 'action.cancel' | translate }}
diff --git a/ui/src/app/entity/attribute/add-widget-to-dashboard-dialog.controller.js b/ui/src/app/entity/attribute/add-widget-to-dashboard-dialog.controller.js
index 173132a4b3..076bee89d5 100644
--- a/ui/src/app/entity/attribute/add-widget-to-dashboard-dialog.controller.js
+++ b/ui/src/app/entity/attribute/add-widget-to-dashboard-dialog.controller.js
@@ -151,5 +151,4 @@ export default function AddWidgetToDashboardDialogController($scope, $mdDialog,
}
);
}
-
}
diff --git a/ui/src/app/entity/attribute/add-widget-to-dashboard-dialog.tpl.html b/ui/src/app/entity/attribute/add-widget-to-dashboard-dialog.tpl.html
index 10d7e4ce55..b6c1746b41 100644
--- a/ui/src/app/entity/attribute/add-widget-to-dashboard-dialog.tpl.html
+++ b/ui/src/app/entity/attribute/add-widget-to-dashboard-dialog.tpl.html
@@ -26,7 +26,8 @@
-
+
@@ -37,10 +38,10 @@
dashboard.select-existing
+ ng-disabled="$root.loading || vm.addToDashboardType != 0"
+ tb-required="vm.addToDashboardType === 0"
+ ng-model="vm.dashboardId"
+ select-first-dashboard="false">
@@ -49,7 +50,8 @@
dashboard.create-new
-
+
@@ -66,15 +68,15 @@
+ style="margin-bottom: 0; padding-right: 20px;">
{{ 'dashboard.open-dashboard' | translate }}
{{ 'action.add' | translate }}
- {{ 'action.cancel' |
- translate }}
+
+ {{ 'action.cancel' | translate }}
diff --git a/ui/src/app/entity/attribute/attribute-dialog-edit-json.controller.js b/ui/src/app/entity/attribute/attribute-dialog-edit-json.controller.js
new file mode 100644
index 0000000000..e53d168a68
--- /dev/null
+++ b/ui/src/app/entity/attribute/attribute-dialog-edit-json.controller.js
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2016-2020 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* eslint-enable import/no-unresolved, import/default */
+
+import './attribute-dialog-edit-json.scss';
+
+/*@ngInject*/
+export default function AttributeDialogEditJsonController($mdDialog, types, jsonValue, readOnly) {
+
+ let vm = this;
+ vm.json = angular.toJson(jsonValue, 4);
+ vm.readOnly = readOnly;
+ vm.contentType = types.contentType.JSON.value;
+
+ vm.save = () => {
+ $mdDialog.hide(angular.fromJson(vm.json));
+ };
+
+ vm.cancel = () => {
+ $mdDialog.cancel();
+ };
+}
diff --git a/ui/src/app/entity/attribute/attribute-dialog-edit-json.scss b/ui/src/app/entity/attribute/attribute-dialog-edit-json.scss
new file mode 100644
index 0000000000..84219ac11a
--- /dev/null
+++ b/ui/src/app/entity/attribute/attribute-dialog-edit-json.scss
@@ -0,0 +1,24 @@
+/**
+ * Copyright © 2016-2020 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+.attribute-edit-json-dialog{
+ min-width: 400px;
+}
+
+@media (max-width: 425px){
+ .attribute-edit-json-dialog {
+ min-width: 200px;
+ }
+}
diff --git a/ui/src/app/entity/attribute/attribute-dialog-edit-json.tpl.html b/ui/src/app/entity/attribute/attribute-dialog-edit-json.tpl.html
new file mode 100644
index 0000000000..1c801edc10
--- /dev/null
+++ b/ui/src/app/entity/attribute/attribute-dialog-edit-json.tpl.html
@@ -0,0 +1,54 @@
+
+
+
+
diff --git a/ui/src/app/entity/attribute/attribute-table.directive.js b/ui/src/app/entity/attribute/attribute-table.directive.js
index 3ba1f51744..59ea4fe91d 100644
--- a/ui/src/app/entity/attribute/attribute-table.directive.js
+++ b/ui/src/app/entity/attribute/attribute-table.directive.js
@@ -39,7 +39,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
element.html(template);
- var getAttributeScopeByValue = function(attributeScopeValue) {
+ var getAttributeScopeByValue = function (attributeScopeValue) {
if (scope.types.latestTelemetry.value === attributeScopeValue) {
return scope.types.latestTelemetry;
}
@@ -48,7 +48,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
return scope.attributeScopes[attrScope];
}
}
- }
+ };
scope.types = types;
@@ -87,14 +87,14 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
search: null
};
- scope.$watch("entityId", function(newVal) {
+ scope.$watch("entityId", function (newVal) {
if (newVal) {
scope.resetFilter();
scope.getEntityAttributes(false, true);
}
});
- scope.$watch("attributeScope", function(newVal, prevVal) {
+ scope.$watch("attributeScope", function (newVal, prevVal) {
if (newVal && !angular.equals(newVal, prevVal)) {
scope.mode = 'default';
scope.query.search = null;
@@ -103,30 +103,30 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
}
});
- scope.resetFilter = function() {
+ scope.resetFilter = function () {
scope.mode = 'default';
scope.query.search = null;
scope.selectedAttributes = [];
scope.attributeScope = getAttributeScopeByValue(attrs.defaultAttributeScope);
- }
+ };
- scope.enterFilterMode = function(event) {
+ scope.enterFilterMode = function (event) {
let $button = angular.element(event.currentTarget);
let $toolbarsContainer = $button.closest('.toolbarsContainer');
scope.query.search = '';
- $timeout(()=>{
+ $timeout(() => {
$toolbarsContainer.find('.searchInput').focus();
})
- }
+ };
- scope.exitFilterMode = function() {
+ scope.exitFilterMode = function () {
scope.query.search = null;
scope.getEntityAttributes();
- }
+ };
- scope.$watch("query.search", function(newVal, prevVal) {
+ scope.$watch("query.search", function (newVal, prevVal) {
if (!angular.equals(newVal, prevVal) && scope.query.search != null) {
scope.getEntityAttributes();
}
@@ -142,15 +142,15 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
}
}
- scope.onReorder = function() {
+ scope.onReorder = function () {
scope.getEntityAttributes(false, false);
- }
+ };
- scope.onPaginate = function() {
+ scope.onPaginate = function () {
scope.getEntityAttributes(false, false);
- }
+ };
- scope.getEntityAttributes = function(forceUpdate, reset) {
+ scope.getEntityAttributes = function (forceUpdate, reset) {
if (scope.attributesDeferred) {
scope.attributesDeferred.resolve();
}
@@ -163,7 +163,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
}
scope.checkSubscription();
scope.attributesDeferred = attributeService.getEntityAttributes(scope.entityType, scope.entityId, scope.attributeScope.value,
- scope.query, function(attributes, update, apply) {
+ scope.query, function (attributes, update, apply) {
success(attributes, update || forceUpdate, apply);
}
);
@@ -176,9 +176,9 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
});
deferred.resolve();
}
- }
+ };
- scope.checkSubscription = function() {
+ scope.checkSubscription = function () {
var newSubscriptionId = null;
if (scope.entityId && scope.entityType && scope.attributeScope.clientSide && scope.mode != 'widget') {
newSubscriptionId = attributeService.subscribeForEntityAttributes(scope.entityType, scope.entityId, scope.attributeScope.value);
@@ -187,36 +187,38 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
attributeService.unsubscribeForEntityAttributes(scope.subscriptionId);
}
scope.subscriptionId = newSubscriptionId;
- }
+ };
- scope.$on('$destroy', function() {
+ scope.$on('$destroy', function () {
if (scope.subscriptionId) {
attributeService.unsubscribeForEntityAttributes(scope.subscriptionId);
}
});
- scope.editAttribute = function($event, attribute) {
+ scope.editAttribute = function ($event, attribute) {
if (!scope.attributeScope.clientSide) {
$event.stopPropagation();
$mdEditDialog.show({
controller: EditAttributeValueController,
templateUrl: editAttributeValueTemplate,
- locals: {attributeValue: attribute.value,
- save: function (model) {
- var updatedAttribute = angular.copy(attribute);
- updatedAttribute.value = model.value;
- attributeService.saveEntityAttributes(scope.entityType, scope.entityId, scope.attributeScope.value, [updatedAttribute]).then(
- function success() {
- scope.getEntityAttributes();
- }
- );
- }},
+ locals: {
+ attributeValue: attribute.value,
+ save: function (model) {
+ var updatedAttribute = angular.copy(attribute);
+ updatedAttribute.value = model.value;
+ attributeService.saveEntityAttributes(scope.entityType, scope.entityId, scope.attributeScope.value, [updatedAttribute]).then(
+ function success() {
+ scope.getEntityAttributes();
+ }
+ );
+ }
+ },
targetEvent: $event
});
}
- }
+ };
- scope.addAttribute = function($event) {
+ scope.addAttribute = function ($event) {
if (!scope.attributeScope.clientSide) {
$event.stopPropagation();
$mdDialog.show({
@@ -224,16 +226,20 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
controllerAs: 'vm',
templateUrl: addAttributeDialogTemplate,
parent: angular.element($document[0].body),
- locals: {entityType: scope.entityType, entityId: scope.entityId, attributeScope: scope.attributeScope.value},
+ locals: {
+ entityType: scope.entityType,
+ entityId: scope.entityId,
+ attributeScope: scope.attributeScope.value
+ },
fullscreen: true,
targetEvent: $event
}).then(function () {
scope.getEntityAttributes();
});
}
- }
+ };
- scope.deleteAttributes = function($event) {
+ scope.deleteAttributes = function ($event) {
if (!scope.attributeScope.clientSide) {
$event.stopPropagation();
var confirm = $mdDialog.confirm()
@@ -244,33 +250,33 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
.cancel($translate.instant('action.no'))
.ok($translate.instant('action.yes'));
$mdDialog.show(confirm).then(function () {
- attributeService.deleteEntityAttributes(scope.entityType, scope.entityId, scope.attributeScope.value, scope.selectedAttributes).then(
- function success() {
- scope.selectedAttributes = [];
- scope.getEntityAttributes();
- }
- )
+ attributeService.deleteEntityAttributes(scope.entityType, scope.entityId, scope.attributeScope.value, scope.selectedAttributes).then(
+ function success() {
+ scope.selectedAttributes = [];
+ scope.getEntityAttributes();
+ }
+ )
});
}
- }
+ };
- scope.nextWidget = function() {
+ scope.nextWidget = function () {
$mdUtil.nextTick(function () {
if (scope.widgetsCarousel.index < scope.widgetsList.length - 1) {
scope.widgetsCarousel.index++;
}
});
- }
+ };
- scope.prevWidget = function() {
+ scope.prevWidget = function () {
$mdUtil.nextTick(function () {
if (scope.widgetsCarousel.index > 0) {
scope.widgetsCarousel.index--;
}
});
- }
+ };
- scope.enterWidgetMode = function() {
+ scope.enterWidgetMode = function () {
if (scope.widgetsIndexWatch) {
scope.widgetsIndexWatch();
@@ -303,7 +309,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
entitiAliases[entityAlias.id] = entityAlias;
var stateController = {
- getStateParams: function() {
+ getStateParams: function () {
return {};
}
};
@@ -317,9 +323,9 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
type: types.datasourceType.entity,
entityAliasId: entityAlias.id,
dataKeys: []
- }
+ };
var i = 0;
- for (var attr =0; attr < scope.selectedAttributes.length;attr++) {
+ for (var attr = 0; attr < scope.selectedAttributes.length; attr++) {
var attribute = scope.selectedAttributes[attr];
var dataKey = {
name: attribute.key,
@@ -328,12 +334,12 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
color: utils.getMaterialColor(i),
settings: {},
_hash: Math.random()
- }
+ };
datasource.dataKeys.push(dataKey);
i++;
}
- scope.widgetsIndexWatch = scope.$watch('widgetsCarousel.index', function(newVal, prevVal) {
+ scope.widgetsIndexWatch = scope.$watch('widgetsCarousel.index', function (newVal, prevVal) {
if (scope.mode === 'widget' && (newVal != prevVal)) {
var index = scope.widgetsCarousel.index;
for (var i = 0; i < scope.widgetsList.length; i++) {
@@ -345,7 +351,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
}
});
- scope.widgetsBundleWatch = scope.$watch('widgetsBundle', function(newVal, prevVal) {
+ scope.widgetsBundleWatch = scope.$watch('widgetsBundle', function (newVal, prevVal) {
if (scope.mode === 'widget' && (scope.firstBundle === true || newVal != prevVal)) {
scope.widgetsList = [];
scope.widgetsListCache = [];
@@ -358,7 +364,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
widgetService.getBundleWidgetTypes(scope.widgetsBundle.alias, isSystem).then(
function success(widgetTypes) {
- widgetTypes = $filter('orderBy')(widgetTypes, ['-descriptor.type','-createdTime']);
+ widgetTypes = $filter('orderBy')(widgetTypes, ['-descriptor.type', '-createdTime']);
for (var i = 0; i < widgetTypes.length; i++) {
var widgetType = widgetTypes[i];
@@ -398,9 +404,9 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
}
}
});
- }
+ };
- scope.exitWidgetMode = function() {
+ scope.exitWidgetMode = function () {
if (scope.widgetsBundleWatch) {
scope.widgetsBundleWatch();
scope.widgetsBundleWatch = null;
@@ -412,9 +418,9 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
scope.selectedWidgetsBundleAlias = null;
scope.mode = 'default';
scope.getEntityAttributes(true);
- }
+ };
- scope.addWidgetToDashboard = function($event) {
+ scope.addWidgetToDashboard = function ($event) {
if (scope.mode === 'widget' && scope.widgetsListCache.length > 0) {
var widget = scope.widgetsListCache[scope.widgetsCarousel.index][0];
$event.stopPropagation();
@@ -423,21 +429,26 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
controllerAs: 'vm',
templateUrl: addWidgetToDashboardDialogTemplate,
parent: angular.element($document[0].body),
- locals: {entityId: scope.entityId, entityType: scope.entityType, entityName: scope.entityName, widget: angular.copy(widget)},
+ locals: {
+ entityId: scope.entityId,
+ entityType: scope.entityType,
+ entityName: scope.entityName,
+ widget: angular.copy(widget)
+ },
fullscreen: true,
targetEvent: $event
}).then(function () {
});
}
- }
+ };
- scope.loading = function() {
+ scope.loading = function () {
return $rootScope.loading;
- }
+ };
$compile(element.contents())(scope);
- }
+ };
return {
restrict: "E",
diff --git a/ui/src/app/entity/attribute/attribute-table.scss b/ui/src/app/entity/attribute/attribute-table.scss
index dd48a5d4b5..5a0bde0c68 100644
--- a/ui/src/app/entity/attribute/attribute-table.scss
+++ b/ui/src/app/entity/attribute/attribute-table.scss
@@ -58,3 +58,11 @@ md-toolbar.md-table-toolbar.alternate {
}
}
}
+
+md-edit-dialog.tb-edit-dialog{
+ z-index: 78;
+}
+
+md-backdrop.md-edit-dialog-backdrop{
+ z-index: 77;
+}
diff --git a/ui/src/app/entity/attribute/attribute-table.tpl.html b/ui/src/app/entity/attribute/attribute-table.tpl.html
index e6a8b12d3d..8844891e62 100644
--- a/ui/src/app/entity/attribute/attribute-table.tpl.html
+++ b/ui/src/app/entity/attribute/attribute-table.tpl.html
@@ -77,9 +77,7 @@
-
diff --git a/ui/src/app/entity/attribute/edit-attribute-value.controller.js b/ui/src/app/entity/attribute/edit-attribute-value.controller.js
index 208ad9a678..7cb550d4c1 100644
--- a/ui/src/app/entity/attribute/edit-attribute-value.controller.js
+++ b/ui/src/app/entity/attribute/edit-attribute-value.controller.js
@@ -13,14 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/* eslint-enable import/no-unresolved, import/default */
+
+import AttributeDialogEditJsonController from "./attribute-dialog-edit-json.controller";
+import attributeDialogEditJsonTemplate from "./attribute-dialog-edit-json.tpl.html";
+
/*@ngInject*/
-export default function EditAttributeValueController($scope, $q, $element, types, attributeValue, save) {
+export default function EditAttributeValueController($scope, $mdDialog, $q, $element, $document, types, attributeValue, save) {
$scope.valueTypes = types.valueType;
- $scope.model = {};
-
- $scope.model.value = attributeValue;
+ $scope.model = {
+ value: attributeValue
+ };
if ($scope.model.value === true || $scope.model.value === false) {
$scope.valueType = types.valueType.boolean;
@@ -30,26 +35,27 @@ export default function EditAttributeValueController($scope, $q, $element, types
} else {
$scope.valueType = types.valueType.double;
}
+ } else if (angular.isObject($scope.model.value)) {
+ $scope.valueType = types.valueType.json;
} else {
$scope.valueType = types.valueType.string;
}
$scope.submit = submit;
$scope.dismiss = dismiss;
+ $scope.editJSON = editJSON;
function dismiss() {
$element.remove();
}
function update() {
- if($scope.editDialog.$invalid) {
+ if ($scope.editDialog.$invalid) {
return $q.reject();
}
-
- if(angular.isFunction(save)) {
+ if (angular.isFunction(save)) {
return $q.when(save($scope.model));
}
-
return $q.resolve();
}
@@ -59,13 +65,45 @@ export default function EditAttributeValueController($scope, $q, $element, types
});
}
- $scope.$watch('valueType', function(newVal, prevVal) {
- if (newVal != prevVal) {
+
+ $scope.$watch('valueType', function (newVal, prevVal) {
+ if (newVal !== prevVal) {
if ($scope.valueType === types.valueType.boolean) {
$scope.model.value = false;
+ } else if ($scope.valueType === types.valueType.json) {
+ $scope.model.value = {};
} else {
$scope.model.value = null;
}
}
});
+
+ function editJSON($event) {
+ $scope.hideDialog = true;
+ showJsonDialog($event, $scope.model.value, false).then((response) => {
+ $scope.hideDialog = false;
+ if (!angular.equals(response, $scope.model.value)) {
+ $scope.editDialog.$setDirty();
+ }
+ $scope.model.value = response;
+ })
+ }
+
+ function showJsonDialog($event, jsonValue, readOnly) {
+ if ($event) {
+ $event.stopPropagation();
+ }
+ return $mdDialog.show({
+ controller: AttributeDialogEditJsonController,
+ controllerAs: 'vm',
+ templateUrl: attributeDialogEditJsonTemplate,
+ locals: {
+ jsonValue: jsonValue,
+ readOnly: readOnly
+ },
+ targetEvent: $event,
+ fullscreen: true,
+ multiple: true
+ });
+ }
}
diff --git a/ui/src/app/entity/attribute/edit-attribute-value.tpl.html b/ui/src/app/entity/attribute/edit-attribute-value.tpl.html
index ca4f8181f1..35abe746aa 100644
--- a/ui/src/app/entity/attribute/edit-attribute-value.tpl.html
+++ b/ui/src/app/entity/attribute/edit-attribute-value.tpl.html
@@ -15,8 +15,8 @@
limitations under the License.
-->
-
-
diff --git a/ui/src/app/locale/locale.constant-el_GR.json b/ui/src/app/locale/locale.constant-el_GR.json
index 1d81f7ea19..8d4951f28f 100644
--- a/ui/src/app/locale/locale.constant-el_GR.json
+++ b/ui/src/app/locale/locale.constant-el_GR.json
@@ -2232,7 +2232,7 @@
"last": "Τελευταίος",
"time-period": "Χρονική Περίοδος"
},
- "user": {
+ "user": {
"user": "Χρήστης",
"users": "Χρήστες",
"management": "Διαχείριση Χρηστών",
diff --git a/ui/src/app/locale/locale.constant-en_US.json b/ui/src/app/locale/locale.constant-en_US.json
index d9e33e4488..f0dc673f84 100644
--- a/ui/src/app/locale/locale.constant-en_US.json
+++ b/ui/src/app/locale/locale.constant-en_US.json
@@ -607,6 +607,7 @@
},
"details": {
"edit-mode": "Edit mode",
+ "edit-json": "Edit JSON",
"toggle-edit-mode": "Toggle edit mode"
},
"device": {
@@ -1270,7 +1271,8 @@
"js-func": {
"no-return-error": "Function must return value!",
"return-type-mismatch": "Function must return value of '{{type}}' type!",
- "tidy": "Tidy"
+ "tidy": "Tidy",
+ "mini": "Mini"
},
"key-val": {
"key": "Key",
@@ -1593,7 +1595,9 @@
"boolean-value": "Boolean value",
"false": "False",
"true": "True",
- "long": "Long"
+ "long": "Long",
+ "json": "JSON",
+ "json-value": "JSON value"
},
"widget": {
"widget-library": "Widgets Library",
diff --git a/ui/src/app/locale/locale.constant-ru_RU.json b/ui/src/app/locale/locale.constant-ru_RU.json
index d5284ebd1a..47c70da48a 100644
--- a/ui/src/app/locale/locale.constant-ru_RU.json
+++ b/ui/src/app/locale/locale.constant-ru_RU.json
@@ -607,6 +607,7 @@
},
"details": {
"edit-mode": "Режим редактирования",
+ "edit-json": "Редактировать JSON",
"toggle-edit-mode": "Режим редактирования"
},
"device": {
@@ -1191,8 +1192,7 @@
},
"js-func": {
"no-return-error": "Функция должна возвращать значение!",
- "return-type-mismatch": "Функция должна возвращать значение типа '{{type}}'!",
- "tidy": "Tidy"
+ "return-type-mismatch": "Функция должна возвращать значение типа '{{type}}'!"
},
"key-val": {
"key": "Ключ",
diff --git a/ui/src/app/locale/locale.constant-uk_UA.json b/ui/src/app/locale/locale.constant-uk_UA.json
index 75124022dd..7b882423ed 100644
--- a/ui/src/app/locale/locale.constant-uk_UA.json
+++ b/ui/src/app/locale/locale.constant-uk_UA.json
@@ -724,6 +724,7 @@
"details": {
"details": "Деталі",
"edit-mode": "Режим редагування",
+ "edit-json": "Редагувати JSON",
"toggle-edit-mode": "Перемкнути режим редагування"
},
"device": {
@@ -1606,8 +1607,7 @@
},
"js-func": {
"no-return-error": "Функція повинна повертати значення!",
- "return-type-mismatch": "Функція повинна повернути значення типу '{{type}}'!",
- "tidy": "Tidy"
+ "return-type-mismatch": "Функція повинна повернути значення типу '{{type}}'!"
},
"key-val": {
"key": "Ключ",