23 changed files with 1761 additions and 121 deletions
@ -0,0 +1,48 @@ |
|||
<!-- |
|||
|
|||
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. |
|||
|
|||
--> |
|||
<md-dialog aria-label="{{ 'rulenode.add-link' | translate }}" tb-help="'rulechains'" help-container-id="help-container"> |
|||
<form name="theForm" ng-submit="vm.add()"> |
|||
<md-toolbar> |
|||
<div class="md-toolbar-tools"> |
|||
<h2 translate>rulenode.add-link</h2> |
|||
<span flex></span> |
|||
<div id="help-container"></div> |
|||
<md-button class="md-icon-button" ng-click="vm.cancel()"> |
|||
<ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon> |
|||
</md-button> |
|||
</div> |
|||
</md-toolbar> |
|||
<md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear> |
|||
<span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span> |
|||
<md-dialog-content> |
|||
<div class="md-dialog-content"> |
|||
<tb-rule-node-link link="vm.link" labels="vm.labels" is-edit="true" the-form="theForm"></tb-rule-node-link> |
|||
</div> |
|||
</md-dialog-content> |
|||
<md-dialog-actions layout="row"> |
|||
<span flex></span> |
|||
<md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit" |
|||
class="md-raised md-primary"> |
|||
{{ 'action.add' | translate }} |
|||
</md-button> |
|||
<md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | |
|||
translate }} |
|||
</md-button> |
|||
</md-dialog-actions> |
|||
</form> |
|||
</md-dialog> |
|||
@ -0,0 +1,48 @@ |
|||
<!-- |
|||
|
|||
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. |
|||
|
|||
--> |
|||
<md-dialog aria-label="{{ 'rulenode.add' | translate }}" tb-help="'rulechains'" help-container-id="help-container" style="min-width: 650px;"> |
|||
<form name="theForm" ng-submit="vm.add()"> |
|||
<md-toolbar> |
|||
<div class="md-toolbar-tools"> |
|||
<h2 translate>rulenode.add</h2> |
|||
<span flex></span> |
|||
<div id="help-container"></div> |
|||
<md-button class="md-icon-button" ng-click="vm.cancel()"> |
|||
<ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon> |
|||
</md-button> |
|||
</div> |
|||
</md-toolbar> |
|||
<md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear> |
|||
<span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span> |
|||
<md-dialog-content> |
|||
<div class="md-dialog-content"> |
|||
<tb-rule-node rule-node="vm.ruleNode" rule-chain-id="vm.ruleChainId" is-edit="true" the-form="theForm"></tb-rule-node> |
|||
</div> |
|||
</md-dialog-content> |
|||
<md-dialog-actions layout="row"> |
|||
<span flex></span> |
|||
<md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit" |
|||
class="md-raised md-primary"> |
|||
{{ 'action.add' | translate }} |
|||
</md-button> |
|||
<md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | |
|||
translate }} |
|||
</md-button> |
|||
</md-dialog-actions> |
|||
</form> |
|||
</md-dialog> |
|||
@ -0,0 +1,39 @@ |
|||
<!-- |
|||
|
|||
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. |
|||
|
|||
--> |
|||
<md-content class="md-padding tb-link" layout="column"> |
|||
<fieldset ng-disabled="$root.loading || !isEdit || isReadOnly"> |
|||
<md-input-container class="md-block"> |
|||
<label translate>rulenode.link-label</label> |
|||
<md-select ng-model="selectedLabel" ng-change="selectedLabelChanged()"> |
|||
<md-option ng-repeat="label in labels" ng-value="label"> |
|||
{{label.name}} |
|||
</md-option> |
|||
</md-select> |
|||
<div ng-messages="theForm.linkLabel.$error"> |
|||
<div translate ng-message="required">rulenode.link-label-required</div> |
|||
</div> |
|||
</md-input-container> |
|||
<md-input-container ng-if="selectedLabel.custom" class="md-block"> |
|||
<label translate>rulenode.link-label</label> |
|||
<input required name="customLinkLabel" ng-model="link.label"> |
|||
<div ng-messages="theForm.customLinkLabel.$error"> |
|||
<div translate ng-message="required">rulenode.custom-link-label-required</div> |
|||
</div> |
|||
</md-input-container> |
|||
</fieldset> |
|||
</md-content> |
|||
@ -0,0 +1,71 @@ |
|||
/* |
|||
* 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. |
|||
*/ |
|||
|
|||
/* eslint-disable import/no-unresolved, import/default */ |
|||
|
|||
import linkFieldsetTemplate from './link-fieldset.tpl.html'; |
|||
|
|||
/* eslint-enable import/no-unresolved, import/default */ |
|||
|
|||
/*@ngInject*/ |
|||
export default function LinkDirective($compile, $templateCache, $filter) { |
|||
var linker = function (scope, element) { |
|||
var template = $templateCache.get(linkFieldsetTemplate); |
|||
element.html(template); |
|||
|
|||
scope.selectedLabel = null; |
|||
|
|||
scope.$watch('link', function() { |
|||
scope.selectedLabel = null; |
|||
if (scope.link && scope.labels) { |
|||
if (scope.link.label) { |
|||
var result = $filter('filter')(scope.labels, {name: scope.link.label}); |
|||
if (result && result.length) { |
|||
scope.selectedLabel = result[0]; |
|||
} else { |
|||
result = $filter('filter')(scope.labels, {custom: true}); |
|||
if (result && result.length && result[0].custom) { |
|||
scope.selectedLabel = result[0]; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
|
|||
scope.selectedLabelChanged = function() { |
|||
if (scope.link && scope.selectedLabel) { |
|||
if (!scope.selectedLabel.custom) { |
|||
scope.link.label = scope.selectedLabel.name; |
|||
} else { |
|||
scope.link.label = ""; |
|||
} |
|||
} |
|||
}; |
|||
|
|||
$compile(element.contents())(scope); |
|||
} |
|||
return { |
|||
restrict: "E", |
|||
link: linker, |
|||
scope: { |
|||
link: '=', |
|||
labels: '=', |
|||
isEdit: '=', |
|||
isReadOnly: '=', |
|||
theForm: '=' |
|||
} |
|||
}; |
|||
} |
|||
@ -0,0 +1,262 @@ |
|||
/** |
|||
* 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-rulechain { |
|||
.tb-fullscreen-button-style { |
|||
z-index: 1; |
|||
} |
|||
.tb-rulechain-library { |
|||
width: 250px; |
|||
min-width: 250px; |
|||
overflow-y: auto; |
|||
overflow-x: hidden; |
|||
|
|||
.tb-rulechain-library-panel-group { |
|||
.tb-panel-title { |
|||
-webkit-user-select: none; |
|||
-moz-user-select: none; |
|||
-ms-user-select: none; |
|||
user-select: none; |
|||
min-width: 180px; |
|||
} |
|||
.fc-canvas { |
|||
background: none; |
|||
} |
|||
md-icon.md-expansion-panel-icon { |
|||
margin-right: 0px; |
|||
} |
|||
md-expansion-panel-collapsed, .md-expansion-panel-header-container { |
|||
background: #e6e6e6; |
|||
border-color: #909090; |
|||
position: static; |
|||
} |
|||
md-expansion-panel { |
|||
&.md-open { |
|||
margin-top: 0; |
|||
margin-bottom: 0; |
|||
} |
|||
} |
|||
md-expansion-panel-content { |
|||
padding: 0px; |
|||
} |
|||
} |
|||
} |
|||
.tb-rulechain-graph { |
|||
overflow: auto; |
|||
} |
|||
} |
|||
|
|||
.fc-canvas { |
|||
min-width: 100%; |
|||
min-height: 100%; |
|||
outline: none; |
|||
} |
|||
|
|||
.tb-rule-node { |
|||
display: flex; |
|||
flex-direction: row; |
|||
min-width: 150px; |
|||
max-width: 150px; |
|||
min-height: 28px; |
|||
max-height: 28px; |
|||
padding: 5px 10px; |
|||
border-radius: 5px; |
|||
background-color: #F15B26; |
|||
color: #333; |
|||
border: solid 1px #777; |
|||
font-size: 12px; |
|||
&.tb-input-type { |
|||
background-color: #a3eaa9; |
|||
user-select: none; |
|||
} |
|||
&.tb-filter-type { |
|||
background-color: #f1e861; |
|||
} |
|||
&.tb-enrichment-type { |
|||
background-color: #cdf14e; |
|||
} |
|||
&.tb-transformation-type { |
|||
background-color: #79cef1; |
|||
} |
|||
&.tb-action-type { |
|||
background-color: #f1928f; |
|||
} |
|||
&.tb-rule-chain-type { |
|||
background-color: #d6c4f1; |
|||
} |
|||
md-icon { |
|||
font-size: 20px; |
|||
width: 20px; |
|||
height: 20px; |
|||
min-height: 20px; |
|||
min-width: 20px; |
|||
padding-right: 4px; |
|||
} |
|||
.tb-node-type { |
|||
|
|||
} |
|||
.tb-node-title { |
|||
font-weight: 600; |
|||
} |
|||
.tb-node-type, .tb-node-title { |
|||
overflow: hidden; |
|||
white-space: nowrap; |
|||
text-overflow: ellipsis; |
|||
} |
|||
} |
|||
|
|||
.fc-node { |
|||
z-index: 1; |
|||
outline: none; |
|||
&.fc-hover, &.fc-selected { |
|||
-webkit-filter: brightness(70%); |
|||
filter: brightness(70%); |
|||
} |
|||
&.fc-dragging { |
|||
z-index: 10; |
|||
} |
|||
p { |
|||
padding: 0 15px; |
|||
text-align: center; |
|||
} |
|||
} |
|||
|
|||
.fc-leftConnectors, .fc-rightConnectors { |
|||
position: absolute; |
|||
top: 0; |
|||
height: 100%; |
|||
|
|||
display: flex; |
|||
flex-direction: column; |
|||
|
|||
z-index: 0; |
|||
.fc-magnet { |
|||
align-items: center; |
|||
} |
|||
} |
|||
|
|||
.fc-leftConnectors { |
|||
left: -20px; |
|||
} |
|||
|
|||
.fc-rightConnectors { |
|||
right: -20px; |
|||
} |
|||
|
|||
.fc-magnet { |
|||
display: flex; |
|||
flex-grow: 1; |
|||
height: 60px; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.fc-connector { |
|||
width: 14px; |
|||
height: 14px; |
|||
border: 1px solid #333; |
|||
margin: 10px; |
|||
border-radius: 5px; |
|||
background-color: #ccc; |
|||
} |
|||
|
|||
.fc-connector.fc-hover { |
|||
background-color: #000; |
|||
} |
|||
|
|||
.fc-edge { |
|||
outline: none; |
|||
stroke: gray; |
|||
stroke-width: 4; |
|||
fill: transparent; |
|||
&.fc-selected { |
|||
stroke: red; |
|||
stroke-width: 4; |
|||
fill: transparent; |
|||
} |
|||
&.fc-active { |
|||
animation: dash 3s linear infinite; |
|||
stroke-dasharray: 20; |
|||
} |
|||
&.fc-hover { |
|||
stroke: gray; |
|||
stroke-width: 6; |
|||
fill: transparent; |
|||
} |
|||
&.fc-dragging { |
|||
pointer-events: none; |
|||
} |
|||
} |
|||
|
|||
.edge-endpoint { |
|||
fill: gray; |
|||
} |
|||
|
|||
.fc-nodedelete { |
|||
display: none; |
|||
} |
|||
|
|||
.fc-selected .fc-nodedelete { |
|||
outline: none; |
|||
display: block; |
|||
position: absolute; |
|||
right: -13px; |
|||
top: -16px; |
|||
border: solid 2px white; |
|||
border-radius: 50%; |
|||
font-weight: 600; |
|||
font-size: 18px; |
|||
line-height: 18px; |
|||
height: 20px; |
|||
padding-top: 2px; |
|||
width: 22px; |
|||
background: #494949; |
|||
color: #fff; |
|||
text-align: center; |
|||
vertical-align: bottom; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.fc-edge-label { |
|||
position: absolute; |
|||
user-select: none; |
|||
pointer-events: none; |
|||
opacity: 0.8; |
|||
} |
|||
|
|||
.fc-edge-label-text { |
|||
position: absolute; |
|||
left: 50%; |
|||
-webkit-transform: translateX(-50%); |
|||
transform: translateX(-50%); |
|||
white-space: nowrap; |
|||
text-align: center; |
|||
font-size: 14px; |
|||
font-weight: 600; |
|||
top: 5px; |
|||
span { |
|||
border: solid 2px #003a79; |
|||
border-radius: 10px; |
|||
color: #003a79; |
|||
background-color: #fff; |
|||
padding: 3px 5px; |
|||
} |
|||
} |
|||
|
|||
@keyframes dash { |
|||
from { |
|||
stroke-dashoffset: 500; |
|||
} |
|||
} |
|||
@ -0,0 +1,130 @@ |
|||
<!-- |
|||
|
|||
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. |
|||
|
|||
--> |
|||
|
|||
<md-content flex tb-expand-fullscreen |
|||
expand-tooltip-direction="bottom" layout="column" class="tb-rulechain"> |
|||
<section class="tb-rulechain-container" flex layout="column"> |
|||
<div class="tb-rulechain-layout" flex layout="row"> |
|||
<div class="tb-rulechain-library"> |
|||
<md-expansion-panel-group class="tb-rulechain-library-panel-group" md-component-id="libraryPanelGroup" auto-expand="true" multiple> |
|||
<md-expansion-panel md-component-id="{{typeId}}" id="{{typeId}}" ng-repeat="(typeId, typeModel) in vm.ruleNodeTypesModel"> |
|||
<md-expansion-panel-collapsed> |
|||
<div class="tb-panel-title" translate>{{vm.types.ruleNodeType[typeId].name}}</div> |
|||
<md-expansion-panel-icon></md-expansion-panel-icon> |
|||
</md-expansion-panel-collapsed> |
|||
<md-expansion-panel-expanded> |
|||
<md-expansion-panel-header ng-click="vm.$mdExpansionPanel(typeId).collapse()"> |
|||
<div class="tb-panel-title" translate>{{vm.types.ruleNodeType[typeId].name}}</div> |
|||
<md-expansion-panel-icon></md-expansion-panel-icon> |
|||
</md-expansion-panel-header> |
|||
<md-expansion-panel-content> |
|||
<fc-canvas id="tb-rulechain-{{typeId}}" |
|||
model="vm.ruleNodeTypesModel[typeId].model" selected-objects="vm.ruleNodeTypesModel[typeId].selectedObjects" |
|||
automatic-resize="false" |
|||
node-width="170" |
|||
node-height="50" |
|||
drop-target-id="'tb-rulchain-canvas'"></fc-canvas> |
|||
</md-expansion-panel-content> |
|||
</md-expansion-panel-expanded> |
|||
</md-expansion-panel> |
|||
</md-expansion-panel-group> |
|||
</div> |
|||
<div flex class="tb-rulechain-graph"> |
|||
<fc-canvas id="tb-rulchain-canvas" |
|||
ng-keydown="vm.keyDown($event)" |
|||
ng-keyup="vm.keyUp($event)" |
|||
model="vm.ruleChainModel" |
|||
selected-objects="vm.selectedObjects" |
|||
edge-style="curved" |
|||
node-width="170" |
|||
node-height="50" |
|||
automatic-resize="true" |
|||
control="vm.canvasControl" |
|||
callbacks="vm.editCallbacks"> |
|||
</fc-canvas> |
|||
</div> |
|||
</div> |
|||
<tb-details-sidenav class="tb-rulenode-details-sidenav" |
|||
header-title="{{vm.editingRuleNode.name}}" |
|||
header-subtitle="{{'rulenode.rulenode-details' | translate}}" |
|||
is-read-only="false" |
|||
is-open="vm.isEditingRuleNode" |
|||
is-always-edit="true" |
|||
on-close-details="vm.onEditRuleNodeClosed()" |
|||
on-toggle-details-edit-mode="vm.onRevertRuleNodeEdit(vm.ruleNodeForm)" |
|||
on-apply-details="vm.saveRuleNode(vm.ruleNodeForm)" |
|||
the-form="vm.ruleNodeForm"> |
|||
<details-buttons tb-help="vm.helpLinkIdForRuleNodeType()" help-container-id="help-container"> |
|||
<div id="help-container"></div> |
|||
</details-buttons> |
|||
<form name="vm.ruleNodeForm" ng-if="vm.isEditingRuleNode"> |
|||
<tb-rule-node |
|||
rule-node="vm.editingRuleNode" |
|||
rule-chain-id="vm.ruleChain.id.id" |
|||
is-edit="true" |
|||
is-read-only="false" |
|||
on-delete-rule-node="vm.deleteRuleNode(event, vm.editingRuleNode)" |
|||
the-form="vm.ruleNodeForm"> |
|||
</tb-rule-node> |
|||
</form> |
|||
</tb-details-sidenav> |
|||
<tb-details-sidenav class="tb-rulenode-link-details-sidenav" |
|||
header-title="{{vm.editingRuleNodeLink.label}}" |
|||
header-subtitle="{{'rulenode.link-details' | translate}}" |
|||
is-read-only="false" |
|||
is-open="vm.isEditingRuleNodeLink" |
|||
is-always-edit="true" |
|||
on-close-details="vm.onEditRuleNodeLinkClosed()" |
|||
on-toggle-details-edit-mode="vm.onRevertRuleNodeLinkEdit(vm.ruleNodeLinkForm)" |
|||
on-apply-details="vm.saveRuleNodeLink(vm.ruleNodeLinkForm)" |
|||
the-form="vm.ruleNodeLinkForm"> |
|||
<details-buttons tb-help="vm.helpLinkIdForRuleNodeLink()" help-container-id="link-help-container"> |
|||
<div id="link-help-container"></div> |
|||
</details-buttons> |
|||
<form name="vm.ruleNodeLinkForm" ng-if="vm.isEditingRuleNodeLink"> |
|||
<tb-rule-node-link |
|||
link="vm.editingRuleNodeLink" |
|||
labels="vm.editingRuleNodeLinkLabels" |
|||
is-edit="true" |
|||
is-read-only="false" |
|||
the-form="vm.ruleNodeLinkForm"> |
|||
</tb-rule-node-link> |
|||
</form> |
|||
</tb-details-sidenav> |
|||
</section> |
|||
<section layout="row" layout-wrap class="tb-footer-buttons md-fab" layout-align="start end"> |
|||
<md-button ng-disabled="$root.loading || !vm.isDirty" |
|||
class="tb-btn-footer md-accent md-hue-2 md-fab" |
|||
aria-label="{{ 'action.apply' | translate }}" |
|||
ng-click="vm.saveRuleChain()"> |
|||
<md-tooltip md-direction="top"> |
|||
{{ 'action.apply-changes' | translate }} |
|||
</md-tooltip> |
|||
<ng-md-icon icon="done"></ng-md-icon> |
|||
</md-button> |
|||
<md-button ng-disabled="$root.loading || !vm.isDirty" |
|||
class="tb-btn-footer md-accent md-hue-2 md-fab" |
|||
aria-label="{{ 'action.decline-changes' | translate }}" |
|||
ng-click="vm.revertRuleChain()"> |
|||
<md-tooltip md-direction="top"> |
|||
{{ 'action.decline-changes' | translate }} |
|||
</md-tooltip> |
|||
<ng-md-icon icon="close"></ng-md-icon> |
|||
</md-button> |
|||
</section> |
|||
</md-content> |
|||
@ -0,0 +1,188 @@ |
|||
/* |
|||
* 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. |
|||
*/ |
|||
/* eslint-disable import/no-unresolved, import/default */ |
|||
|
|||
import addRuleChainTemplate from './add-rulechain.tpl.html'; |
|||
import ruleChainCard from './rulechain-card.tpl.html'; |
|||
|
|||
/* eslint-enable import/no-unresolved, import/default */ |
|||
|
|||
/*@ngInject*/ |
|||
export default function RuleChainsController(ruleChainService, userService, importExport, $state, $stateParams, $filter, $translate, types) { |
|||
|
|||
var ruleChainActionsList = [ |
|||
{ |
|||
onAction: function ($event, item) { |
|||
vm.grid.openItem($event, item); |
|||
}, |
|||
name: function() { return $translate.instant('rulechain.details') }, |
|||
details: function() { return $translate.instant('rulechain.rulechain-details') }, |
|||
icon: "edit" |
|||
}, |
|||
{ |
|||
onAction: function ($event, item) { |
|||
exportRuleChain($event, item); |
|||
}, |
|||
name: function() { $translate.instant('action.export') }, |
|||
details: function() { return $translate.instant('rulechain.export') }, |
|||
icon: "file_download" |
|||
}, |
|||
{ |
|||
onAction: function ($event, item) { |
|||
vm.grid.deleteItem($event, item); |
|||
}, |
|||
name: function() { return $translate.instant('action.delete') }, |
|||
details: function() { return $translate.instant('rulechain.delete') }, |
|||
icon: "delete", |
|||
isEnabled: isRuleChainEditable |
|||
} |
|||
]; |
|||
|
|||
var ruleChainAddItemActionsList = [ |
|||
{ |
|||
onAction: function ($event) { |
|||
vm.grid.addItem($event); |
|||
}, |
|||
name: function() { return $translate.instant('action.create') }, |
|||
details: function() { return $translate.instant('rulechain.create-new-rulechain') }, |
|||
icon: "insert_drive_file" |
|||
}, |
|||
{ |
|||
onAction: function ($event) { |
|||
importExport.importRuleChain($event).then( |
|||
function() { |
|||
vm.grid.refreshList(); |
|||
} |
|||
); |
|||
}, |
|||
name: function() { return $translate.instant('action.import') }, |
|||
details: function() { return $translate.instant('rulechain.import') }, |
|||
icon: "file_upload" |
|||
} |
|||
]; |
|||
|
|||
var vm = this; |
|||
|
|||
vm.types = types; |
|||
|
|||
vm.ruleChainGridConfig = { |
|||
|
|||
refreshParamsFunc: null, |
|||
|
|||
deleteItemTitleFunc: deleteRuleChainTitle, |
|||
deleteItemContentFunc: deleteRuleChainText, |
|||
deleteItemsTitleFunc: deleteRuleChainsTitle, |
|||
deleteItemsActionTitleFunc: deleteRuleChainsActionTitle, |
|||
deleteItemsContentFunc: deleteRuleChainsText, |
|||
|
|||
fetchItemsFunc: fetchRuleChains, |
|||
saveItemFunc: saveRuleChain, |
|||
clickItemFunc: openRuleChain, |
|||
deleteItemFunc: deleteRuleChain, |
|||
|
|||
getItemTitleFunc: getRuleChainTitle, |
|||
itemCardTemplateUrl: ruleChainCard, |
|||
parentCtl: vm, |
|||
|
|||
actionsList: ruleChainActionsList, |
|||
addItemActions: ruleChainAddItemActionsList, |
|||
|
|||
onGridInited: gridInited, |
|||
|
|||
addItemTemplateUrl: addRuleChainTemplate, |
|||
|
|||
addItemText: function() { return $translate.instant('rulechain.add-rulechain-text') }, |
|||
noItemsText: function() { return $translate.instant('rulechain.no-rulechains-text') }, |
|||
itemDetailsText: function() { return $translate.instant('rulechain.rulechain-details') }, |
|||
isSelectionEnabled: isRuleChainEditable, |
|||
isDetailsReadOnly: function(ruleChain) { |
|||
return !isRuleChainEditable(ruleChain); |
|||
} |
|||
}; |
|||
|
|||
if (angular.isDefined($stateParams.items) && $stateParams.items !== null) { |
|||
vm.ruleChainGridConfig.items = $stateParams.items; |
|||
} |
|||
|
|||
if (angular.isDefined($stateParams.topIndex) && $stateParams.topIndex > 0) { |
|||
vm.ruleChainGridConfig.topIndex = $stateParams.topIndex; |
|||
} |
|||
|
|||
vm.isRuleChainEditable = isRuleChainEditable; |
|||
|
|||
vm.exportRuleChain = exportRuleChain; |
|||
|
|||
function deleteRuleChainTitle(ruleChain) { |
|||
return $translate.instant('rulechain.delete-rulechain-title', {ruleChainName: ruleChain.name}); |
|||
} |
|||
|
|||
function deleteRuleChainText() { |
|||
return $translate.instant('rulechain.delete-rulechain-text'); |
|||
} |
|||
|
|||
function deleteRuleChainsTitle(selectedCount) { |
|||
return $translate.instant('rulechain.delete-rulechains-title', {count: selectedCount}, 'messageformat'); |
|||
} |
|||
|
|||
function deleteRuleChainsActionTitle(selectedCount) { |
|||
return $translate.instant('rulechain.delete-rulechains-action-title', {count: selectedCount}, 'messageformat'); |
|||
} |
|||
|
|||
function deleteRuleChainsText() { |
|||
return $translate.instant('rulechain.delete-rulechains-text'); |
|||
} |
|||
|
|||
function gridInited(grid) { |
|||
vm.grid = grid; |
|||
} |
|||
|
|||
function fetchRuleChains(pageLink) { |
|||
return ruleChainService.getRuleChains(pageLink); |
|||
} |
|||
|
|||
function saveRuleChain(ruleChain) { |
|||
return ruleChainService.saveRuleChain(ruleChain); |
|||
} |
|||
|
|||
function openRuleChain($event, ruleChain) { |
|||
if ($event) { |
|||
$event.stopPropagation(); |
|||
} |
|||
$state.go('home.ruleChains.ruleChain', {ruleChainId: ruleChain.id.id}); |
|||
} |
|||
|
|||
function deleteRuleChain(ruleChainId) { |
|||
return ruleChainService.deleteRuleChain(ruleChainId); |
|||
} |
|||
|
|||
function getRuleChainTitle(ruleChain) { |
|||
return ruleChain ? ruleChain.name : ''; |
|||
} |
|||
|
|||
function isRuleChainEditable(ruleChain) { |
|||
if (userService.getAuthority() === 'TENANT_ADMIN') { |
|||
return ruleChain && ruleChain.tenantId.id != types.id.nullUid; |
|||
} else { |
|||
return userService.getAuthority() === 'SYS_ADMIN'; |
|||
} |
|||
} |
|||
|
|||
function exportRuleChain($event, ruleChain) { |
|||
$event.stopPropagation(); |
|||
importExport.exportRuleChain(ruleChain.id.id); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
<!-- |
|||
|
|||
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. |
|||
|
|||
--> |
|||
<md-button ng-click="onDeleteRuleNode({event: $event})" |
|||
ng-show="!isEdit && !isReadOnly" |
|||
class="md-raised md-primary">{{ 'rulenode.delete' | translate }}</md-button> |
|||
|
|||
<md-content class="md-padding tb-rulenode" layout="column"> |
|||
<fieldset ng-disabled="$root.loading || !isEdit || isReadOnly"> |
|||
<md-input-container class="md-block"> |
|||
<label translate>rulenode.type</label> |
|||
<input readonly name="type" ng-model="ruleNode.type"> |
|||
</md-input-container> |
|||
<section ng-if="ruleNode.nodeType != types.ruleNodeType.RULE_CHAIN.value"> |
|||
<md-input-container class="md-block"> |
|||
<label translate>rulenode.name</label> |
|||
<input required name="name" ng-model="ruleNode.name"> |
|||
<div ng-messages="theForm.name.$error"> |
|||
<div translate ng-message="required">rulenode.name-required</div> |
|||
</div> |
|||
</md-input-container> |
|||
<md-input-container class="md-block"> |
|||
<label translate>rulenode.description</label> |
|||
<textarea ng-model="ruleNode.additionalInfo.description" rows="2"></textarea> |
|||
</md-input-container> |
|||
</section> |
|||
<section ng-if="ruleNode.nodeType == types.ruleNodeType.RULE_CHAIN.value"> |
|||
<tb-entity-autocomplete the-form="theForm" |
|||
ng-disabled="$root.loading || !isEdit || isReadOnly" |
|||
tb-required="true" |
|||
exclude-entity-ids="[ruleChainId]" |
|||
entity-type="types.entityType.rulechain" |
|||
ng-model="params.targetRuleChainId"> |
|||
</tb-entity-autocomplete> |
|||
<md-input-container class="md-block"> |
|||
<label translate>rulenode.description</label> |
|||
<textarea ng-model="ruleNode.additionalInfo.description" rows="2"></textarea> |
|||
</md-input-container> |
|||
</section> |
|||
</fieldset> |
|||
</md-content> |
|||
@ -0,0 +1,79 @@ |
|||
/* |
|||
* 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. |
|||
*/ |
|||
|
|||
/* eslint-disable import/no-unresolved, import/default */ |
|||
|
|||
import ruleNodeFieldsetTemplate from './rulenode-fieldset.tpl.html'; |
|||
|
|||
/* eslint-enable import/no-unresolved, import/default */ |
|||
|
|||
/*@ngInject*/ |
|||
export default function RuleNodeDirective($compile, $templateCache, ruleChainService, types) { |
|||
var linker = function (scope, element) { |
|||
var template = $templateCache.get(ruleNodeFieldsetTemplate); |
|||
element.html(template); |
|||
|
|||
scope.types = types; |
|||
|
|||
scope.params = { |
|||
targetRuleChainId: null |
|||
}; |
|||
|
|||
scope.$watch('ruleNode', function() { |
|||
if (scope.ruleNode && scope.ruleNode.nodeType == types.ruleNodeType.RULE_CHAIN.value) { |
|||
scope.params.targetRuleChainId = scope.ruleNode.targetRuleChainId; |
|||
watchTargetRuleChain(); |
|||
} else { |
|||
if (scope.targetRuleChainWatch) { |
|||
scope.targetRuleChainWatch(); |
|||
scope.targetRuleChainWatch = null; |
|||
} |
|||
} |
|||
}); |
|||
|
|||
function watchTargetRuleChain() { |
|||
scope.targetRuleChainWatch = scope.$watch('params.targetRuleChainId', |
|||
function(targetRuleChainId) { |
|||
if (scope.ruleNode.targetRuleChainId != targetRuleChainId) { |
|||
scope.ruleNode.targetRuleChainId = targetRuleChainId; |
|||
if (targetRuleChainId) { |
|||
ruleChainService.getRuleChain(targetRuleChainId).then( |
|||
(ruleChain) => { |
|||
scope.ruleNode.name = ruleChain.name; |
|||
} |
|||
); |
|||
} else { |
|||
scope.ruleNode.name = ""; |
|||
} |
|||
} |
|||
} |
|||
); |
|||
} |
|||
$compile(element.contents())(scope); |
|||
} |
|||
return { |
|||
restrict: "E", |
|||
link: linker, |
|||
scope: { |
|||
ruleChainId: '=', |
|||
ruleNode: '=', |
|||
isEdit: '=', |
|||
isReadOnly: '=', |
|||
theForm: '=', |
|||
onDeleteRuleNode: '&' |
|||
} |
|||
}; |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
<!-- |
|||
|
|||
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 |
|||
id="{{node.id}}" |
|||
ng-attr-style="position: absolute; top: {{ node.y }}px; left: {{ node.x }}px;" |
|||
ng-dblclick="callbacks.doubleClick($event, node)"> |
|||
<div class="tb-rule-node {{node.nodeClass}}"> |
|||
<md-icon aria-label="node-type-icon" flex="15" |
|||
class="material-icons">{{node.icon}}</md-icon> |
|||
<div layout="column" flex="85" layout-align="center"> |
|||
<span class="tb-node-type">{{ node.type }}</span> |
|||
<span class="tb-node-title" ng-if="node.name">{{ node.name }}</span> |
|||
</div> |
|||
<div class="{{flowchartConstants.leftConnectorClass}}"> |
|||
<div fc-magnet |
|||
ng-repeat="connector in modelservice.nodes.getConnectorsByType(node, flowchartConstants.leftConnectorType)"> |
|||
<div fc-connector></div> |
|||
</div> |
|||
</div> |
|||
<div class="{{flowchartConstants.rightConnectorClass}}"> |
|||
<div fc-magnet |
|||
ng-repeat="connector in modelservice.nodes.getConnectorsByType(node, flowchartConstants.rightConnectorType)"> |
|||
<div fc-connector></div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div ng-if="modelservice.isEditable() && !node.readonly" class="fc-nodedelete" ng-click="modelservice.nodes.delete(node)"> |
|||
× |
|||
</div> |
|||
</div> |
|||
Loading…
Reference in new issue