Browse Source

Action Rule nodes config UI

pull/725/head
Igor Kulikov 9 years ago
parent
commit
4024e42324
  1. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java
  2. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTelemetryNode.java
  3. 2
      rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.css
  4. 2
      rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js
  5. 10
      ui/src/app/components/details-sidenav.scss
  6. 175
      ui/src/app/components/json-content.directive.js
  7. 35
      ui/src/app/components/json-content.scss
  8. 31
      ui/src/app/components/json-content.tpl.html
  9. 4
      ui/src/app/layout/index.js

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java

@ -48,7 +48,9 @@ import static org.thingsboard.rule.engine.DonAsynchron.withCallback;
configClazz = TbMsgGeneratorNodeConfiguration.class,
nodeDescription = "Periodically generates messages",
nodeDetails = "Generates messages with configurable period. ",
inEnabled = false
inEnabled = false,
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbActionNodeGeneratorConfig"
)
public class TbMsgGeneratorNode implements TbNode {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTelemetryNode.java

@ -43,7 +43,9 @@ import java.util.Map;
name = "save timeseries data",
configClazz = TbMsgTelemetryNodeConfiguration.class,
nodeDescription = "Saves timeseries data",
nodeDetails = "Saves timeseries telemetry data based on configurable TTL parameter. Expects messages with 'POST_TELEMETRY' message type"
nodeDetails = "Saves timeseries telemetry data based on configurable TTL parameter. Expects messages with 'POST_TELEMETRY' message type",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbActionNodeTelemetryConfig"
)
public class TbMsgTelemetryNode implements TbNode {

2
rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.css

@ -1,2 +1,2 @@
.tb-message-type-autocomplete .tb-not-found{display:block;line-height:1.5;height:48px}.tb-message-type-autocomplete .tb-not-found .tb-no-entries{line-height:48px}.tb-message-type-autocomplete li{height:auto!important;white-space:normal!important}.tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}.tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}.tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}.tb-kv-map-config .body .row{padding-top:5px;max-height:40px}.tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}.tb-kv-map-config .body md-input-container.cell{margin:0;max-height:40px}.tb-kv-map-config .body .md-button{margin:0}
.tb-message-type-autocomplete .tb-not-found{display:block;line-height:1.5;height:48px}.tb-message-type-autocomplete .tb-not-found .tb-no-entries{line-height:48px}.tb-message-type-autocomplete li{height:auto!important;white-space:normal!important}.tb-generator-config tb-json-content.tb-message-body,.tb-generator-config tb-json-object-edit.tb-metadata-json{height:200px;display:block}.tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}.tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}.tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}.tb-kv-map-config .body .row{padding-top:5px;max-height:40px}.tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}.tb-kv-map-config .body md-input-container.cell{margin:0;max-height:40px}.tb-kv-map-config .body .md-button{margin:0}
/*# sourceMappingURL=rulenode-core-config.css.map*/

2
rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js

File diff suppressed because one or more lines are too long

10
ui/src/app/components/details-sidenav.scss

@ -59,4 +59,14 @@ md-sidenav.tb-sidenav-details {
background-color: $primary-hue-3;
}
}
md-tab-content.md-active > div {
height: 100%;
& > *:first-child {
height: 100%;
}
md-content {
height: 100%;
}
}
}

175
ui/src/app/components/json-content.directive.js

@ -0,0 +1,175 @@
/*
* Copyright © 2016-2018 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.
*/
import './json-content.scss';
import 'brace/ext/language_tools';
import 'brace/mode/json';
import 'brace/mode/text';
import 'ace-builds/src-min-noconflict/snippets/json';
import 'ace-builds/src-min-noconflict/snippets/text';
import fixAceEditor from './ace-editor-fix';
/* eslint-disable import/no-unresolved, import/default */
import jsonContentTemplate from './json-content.tpl.html';
/* eslint-enable import/no-unresolved, import/default */
export default angular.module('thingsboard.directives.jsonContent', [])
.directive('tbJsonContent', JsonContent)
.name;
/*@ngInject*/
function JsonContent($compile, $templateCache, toast, types, utils) {
var linker = function (scope, element, attrs, ngModelCtrl) {
var template = $templateCache.get(jsonContentTemplate);
element.html(template);
scope.label = attrs.label;
scope.validationTriggerArg = attrs.validationTriggerArg;
scope.contentValid = true;
scope.json_editor;
scope.onFullscreenChanged = function () {
updateEditorSize();
};
function updateEditorSize() {
if (scope.json_editor) {
scope.json_editor.resize();
scope.json_editor.renderer.updateFull();
}
}
var mode;
if (scope.contentType) {
mode = types.contentType[scope.contentType].code;
} else {
mode = 'text';
}
scope.jsonEditorOptions = {
useWrapMode: true,
mode: mode,
advanced: {
enableSnippets: true,
enableBasicAutocompletion: true,
enableLiveAutocompletion: true
},
onLoad: function (_ace) {
scope.json_editor = _ace;
scope.json_editor.session.on("change", function () {
scope.cleanupJsonErrors();
});
fixAceEditor(_ace);
}
};
scope.$watch('contentType', () => {
var mode;
if (scope.contentType) {
mode = types.contentType[scope.contentType].code;
} else {
mode = 'text';
}
if (scope.json_editor) {
scope.json_editor.session.setMode('ace/mode/' + mode);
}
});
scope.cleanupJsonErrors = function () {
toast.hide();
};
scope.updateValidity = function () {
ngModelCtrl.$setValidity('contentBody', scope.contentValid);
};
scope.$watch('contentBody', function (newContent, oldContent) {
ngModelCtrl.$setViewValue(scope.contentBody);
if (!angular.equals(newContent, oldContent)) {
scope.contentValid = true;
}
scope.updateValidity();
});
ngModelCtrl.$render = function () {
scope.contentBody = ngModelCtrl.$viewValue;
};
scope.showError = function (error) {
var toastParent = angular.element('#tb-json-panel', element);
toast.showError(error, toastParent, 'bottom left');
};
scope.validate = function () {
try {
if (scope.validateContent) {
if (scope.contentType == types.contentType.JSON.value) {
angular.fromJson(scope.contentBody);
}
}
return true;
} catch (e) {
var details = utils.parseException(e);
var errorInfo = 'Error:';
if (details.name) {
errorInfo += ' ' + details.name + ':';
}
if (details.message) {
errorInfo += ' ' + details.message;
}
scope.showError(errorInfo);
return false;
}
};
scope.$on('form-submit', function (event, args) {
if (!scope.readonly) {
if (!args || scope.validationTriggerArg && scope.validationTriggerArg == args) {
scope.cleanupJsonErrors();
scope.contentValid = true;
scope.updateValidity();
scope.contentValid = scope.validate();
scope.updateValidity();
}
}
});
scope.$on('update-ace-editor-size', function () {
updateEditorSize();
});
$compile(element.contents())(scope);
}
return {
restrict: "E",
require: "^ngModel",
scope: {
contentType: '=',
validateContent: '=?',
readonly:'=ngReadonly',
fillHeight:'=?'
},
link: linker
};
}

35
ui/src/app/components/json-content.scss

@ -0,0 +1,35 @@
/**
* Copyright © 2016-2018 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.
*/
tb-json-content {
position: relative;
.fill-height {
height: 100%;
}
}
.tb-json-content-panel {
margin-left: 15px;
border: 1px solid #C0C0C0;
height: 100%;
#tb-json-input {
min-width: 200px;
width: 100%;
height: 100%;
&:not(.fill-height) {
min-height: 200px;
}
}
}

31
ui/src/app/components/json-content.tpl.html

@ -0,0 +1,31 @@
<!--
Copyright © 2016-2018 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.
-->
<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">
<div layout="row" layout-align="start center">
<label class="tb-title no-padding">{{ label }}</label>
<span flex></span>
<md-button id="expand-button" aria-label="Fullscreen" class="md-icon-button tb-md-32 tb-fullscreen-button-style"></md-button>
</div>
<div flex id="tb-json-panel" class="tb-json-content-panel" layout="column">
<div flex id="tb-json-input" ng-class="{'fill-height': fillHeight}"
ng-readonly="readonly"
ui-ace="jsonEditorOptions"
ng-model="contentBody">
</div>
</div>
</div>

4
ui/src/app/layout/index.js

@ -30,6 +30,7 @@ import thingsboardOnFinishRender from '../components/finish-render.directive';
import thingsboardSideMenu from '../components/side-menu.directive';
import thingsboardDashboardAutocomplete from '../components/dashboard-autocomplete.directive';
import thingsboardJsonObjectEdit from '../components/json-object-edit.directive';
import thingsboardJsonContent from '../components/json-content.directive';
import thingsboardUserMenu from './user-menu.directive';
@ -92,7 +93,8 @@ export default angular.module('thingsboard.home', [
thingsboardOnFinishRender,
thingsboardSideMenu,
thingsboardDashboardAutocomplete,
thingsboardJsonObjectEdit
thingsboardJsonObjectEdit,
thingsboardJsonContent
])
.config(HomeRoutes)
.controller('HomeController', HomeController)

Loading…
Cancel
Save