RuleChain page
This commit is contained in:
parent
e85c47aebf
commit
cf1684572b
23
msa/js-executor/package-lock.json
generated
23
msa/js-executor/package-lock.json
generated
@ -1407,14 +1407,12 @@
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
@ -1429,20 +1427,17 @@
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
@ -1559,8 +1554,7 @@
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
@ -1572,7 +1566,6 @@
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
@ -1587,7 +1580,6 @@
|
||||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
@ -1699,8 +1691,7 @@
|
||||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
@ -1712,7 +1703,6 @@
|
||||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
@ -1834,7 +1824,6 @@
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
|
||||
@ -33,7 +33,10 @@
|
||||
"styles": [
|
||||
"src/styles.scss",
|
||||
"node_modules/jquery.terminal/css/jquery.terminal.min.css",
|
||||
"node_modules/tooltipster/dist/css/tooltipster.bundle.min.css",
|
||||
"node_modules/tooltipster/dist/css/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-shadow.min.css",
|
||||
"src/app/shared/components/json-form/react/json-form.scss",
|
||||
"src/app/modules/home/pages/rulechain/rulechain-page.tooltipster.scss",
|
||||
"node_modules/rc-select/assets/index.css"
|
||||
],
|
||||
"stylePreprocessorOptions": {
|
||||
@ -54,6 +57,7 @@
|
||||
"node_modules/flot/src/plugins/jquery.flot.stack.js",
|
||||
"node_modules/flot.curvedlines/curvedLines.js",
|
||||
"node_modules/tinycolor2/dist/tinycolor-min.js",
|
||||
"node_modules/tooltipster/dist/js/tooltipster.bundle.min.js",
|
||||
"node_modules/split.js/dist/split.js",
|
||||
"node_modules/js-beautify/js/lib/beautify.js",
|
||||
"node_modules/js-beautify/js/lib/beautify-css.js",
|
||||
|
||||
3480
ui-ngx/package-lock.json
generated
3480
ui-ngx/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -12,52 +12,52 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "~8.2.11",
|
||||
"@angular/animations": "~8.2.14",
|
||||
"@angular/cdk": "~8.2.3",
|
||||
"@angular/common": "~8.2.11",
|
||||
"@angular/compiler": "~8.2.11",
|
||||
"@angular/core": "~8.2.11",
|
||||
"@angular/flex-layout": "^8.0.0-beta.26",
|
||||
"@angular/forms": "~8.2.11",
|
||||
"@angular/common": "~8.2.14",
|
||||
"@angular/compiler": "~8.2.14",
|
||||
"@angular/core": "~8.2.14",
|
||||
"@angular/flex-layout": "^8.0.0-beta.27",
|
||||
"@angular/forms": "~8.2.14",
|
||||
"@angular/material": "^8.2.3",
|
||||
"@angular/platform-browser": "~8.2.11",
|
||||
"@angular/platform-browser-dynamic": "~8.2.11",
|
||||
"@angular/router": "~8.2.11",
|
||||
"@auth0/angular-jwt": "^3.0.0",
|
||||
"@date-io/date-fns": "^1.3.11",
|
||||
"@angular/platform-browser": "~8.2.14",
|
||||
"@angular/platform-browser-dynamic": "~8.2.14",
|
||||
"@angular/router": "~8.2.14",
|
||||
"@auth0/angular-jwt": "^3.0.1",
|
||||
"@date-io/date-fns": "^1.3.13",
|
||||
"@flowjs/flow.js": "^2.13.2",
|
||||
"@flowjs/ngx-flow": "^0.4.3",
|
||||
"@mat-datetimepicker/core": "^2.0.1",
|
||||
"@material-ui/core": "^4.5.1",
|
||||
"@material-ui/core": "^4.7.2",
|
||||
"@material-ui/icons": "^4.5.1",
|
||||
"@material-ui/pickers": "^3.2.7",
|
||||
"@ngrx/effects": "^8.2.0",
|
||||
"@ngrx/store": "^8.2.0",
|
||||
"@ngrx/store-devtools": "^8.2.0",
|
||||
"@ngx-share/core": "^7.1.2",
|
||||
"@material-ui/pickers": "^3.2.8",
|
||||
"@ngrx/effects": "^8.5.2",
|
||||
"@ngrx/store": "^8.5.2",
|
||||
"@ngrx/store-devtools": "^8.5.2",
|
||||
"@ngx-share/core": "^7.1.4",
|
||||
"@ngx-translate/core": "^11.0.1",
|
||||
"@ngx-translate/http-loader": "^4.0.0",
|
||||
"ace-builds": "^1.4.5",
|
||||
"angular-gridster2": "^8.1.0",
|
||||
"ace-builds": "^1.4.7",
|
||||
"angular-gridster2": "^8.2.0",
|
||||
"angular2-hotkeys": "^2.1.5",
|
||||
"base64-js": "^1.3.1",
|
||||
"compass-sass-mixins": "^0.12.7",
|
||||
"core-js": "^3.1.4",
|
||||
"date-fns": "2.1.0",
|
||||
"deep-equal": "^1.0.1",
|
||||
"core-js": "^3.5.0",
|
||||
"date-fns": "2.8.1",
|
||||
"deep-equal": "^1.1.1",
|
||||
"flot": "git://github.com/thingsboard/flot.git#0.9-work",
|
||||
"flot.curvedlines": "git://github.com/MichaelZinsmaier/CurvedLines.git#master",
|
||||
"font-awesome": "^4.7.0",
|
||||
"hammerjs": "^2.0.8",
|
||||
"javascript-detect-element-resize": "^0.5.3",
|
||||
"jquery": "^3.4.1",
|
||||
"jquery.terminal": "^2.8.0",
|
||||
"jquery.terminal": "^2.9.0",
|
||||
"js-beautify": "^1.10.2",
|
||||
"json-schema-defaults": "^0.4.0",
|
||||
"material-design-icons": "^3.0.1",
|
||||
"messageformat": "^2.3.0",
|
||||
"moment": "^2.24.0",
|
||||
"ngx-clipboard": "^12.2.0",
|
||||
"ngx-clipboard": "^12.3.0",
|
||||
"ngx-color-picker": "^8.2.0",
|
||||
"ngx-flowchart": "git://github.com/thingsboard/ngx-flowchart.git#master",
|
||||
"ngx-hm-carousel": "^1.7.2",
|
||||
@ -65,50 +65,55 @@
|
||||
"objectpath": "^1.2.2",
|
||||
"prop-types": "^15.7.2",
|
||||
"rc-select": "^9.2.1",
|
||||
"react": "^16.10.2",
|
||||
"react": "^16.12.0",
|
||||
"react-ace": "^8.0.0",
|
||||
"react-dom": "^16.10.2",
|
||||
"react-dropzone": "^10.1.10",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-dropzone": "^10.2.1",
|
||||
"reactcss": "^1.2.3",
|
||||
"rxjs": "~6.5.2",
|
||||
"rxjs": "~6.5.3",
|
||||
"schema-inspector": "^1.6.8",
|
||||
"screenfull": "^4.2.1",
|
||||
"screenfull": "^5.0.0",
|
||||
"split.js": "^1.5.11",
|
||||
"tinycolor2": "^1.4.1",
|
||||
"tooltipster": "^4.2.7",
|
||||
"tslib": "^1.10.0",
|
||||
"tv4": "^1.3.0",
|
||||
"typeface-roboto": "^0.0.75",
|
||||
"zone.js": "~0.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-builders/custom-webpack": "^8.2.0",
|
||||
"@angular-devkit/build-angular": "^0.802.0",
|
||||
"@angular/cli": "~8.2.2",
|
||||
"@angular/compiler-cli": "~8.2.11",
|
||||
"@angular/language-service": "~8.2.11",
|
||||
"@angular-builders/custom-webpack": "^8.4.1",
|
||||
"@angular-devkit/build-angular": "^0.803.20",
|
||||
"@angular/cli": "~8.3.20",
|
||||
"@angular/compiler-cli": "~8.2.14",
|
||||
"@angular/language-service": "~8.2.14",
|
||||
"@types/flot": "0.0.31",
|
||||
"@types/jasmine": "~3.4.0",
|
||||
"@types/jasminewd2": "~2.0.6",
|
||||
"@types/jasmine": "~3.5.0",
|
||||
"@types/jasminewd2": "~2.0.8",
|
||||
"@types/jquery": "^3.3.31",
|
||||
"@types/js-beautify": "^1.8.1",
|
||||
"@types/node": "~10.14.15",
|
||||
"@types/react": "^16.9.9",
|
||||
"@types/react-dom": "^16.9.2",
|
||||
"@types/node": "~12.12.17",
|
||||
"@types/react": "^16.9.16",
|
||||
"@types/react-dom": "^16.9.4",
|
||||
"@types/tinycolor2": "^1.4.2",
|
||||
"codelyzer": "~5.1.0",
|
||||
"compression-webpack-plugin": "^3.0.0",
|
||||
"directory-tree": "^2.2.3",
|
||||
"jasmine-core": "~3.4.0",
|
||||
"@types/tooltipster": "0.0.29",
|
||||
"codelyzer": "~5.2.0",
|
||||
"compression-webpack-plugin": "^3.0.1",
|
||||
"directory-tree": "^2.2.4",
|
||||
"jasmine-core": "~3.5.0",
|
||||
"jasmine-spec-reporter": "~4.2.1",
|
||||
"karma": "~4.2.0",
|
||||
"karma-chrome-launcher": "~3.0.0",
|
||||
"karma-coverage-istanbul-reporter": "~2.1.0",
|
||||
"karma": "~4.4.1",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage-istanbul-reporter": "~2.1.1",
|
||||
"karma-jasmine": "~2.0.1",
|
||||
"karma-jasmine-html-reporter": "^1.4.2",
|
||||
"ngrx-store-freeze": "^0.2.4",
|
||||
"protractor": "~5.4.2",
|
||||
"ts-node": "~8.3.0",
|
||||
"tslint": "~5.18.0",
|
||||
"ts-node": "~8.5.4",
|
||||
"tslint": "~5.20.1",
|
||||
"typescript": "~3.5.3"
|
||||
},
|
||||
"resolutions": {
|
||||
"serialize-javascript": "^2.1.1"
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ import { alarmFields } from '@shared/models/alarm.models';
|
||||
import { materialColors } from '@app/shared/models/material.models';
|
||||
import { WidgetInfo } from '@home/models/widget-component.models';
|
||||
import jsonSchemaDefaults from 'json-schema-defaults';
|
||||
import * as materialIconsCodepoints from '!raw-loader!material-design-icons/iconfont/codepoints';
|
||||
import materialIconsCodepoints from '!raw-loader!material-design-icons/iconfont/codepoints';
|
||||
import { Observable, of, ReplaySubject } from 'rxjs';
|
||||
|
||||
const varsRegex = /\$\{([^}]*)\}/g;
|
||||
|
||||
@ -30,9 +30,9 @@ import { entityTypeTranslations } from '@shared/models/entity-type.models';
|
||||
import { UtilsService } from '@core/services/utils.service';
|
||||
import { deepClone, isUndefined } from '@core/utils';
|
||||
|
||||
import * as customSampleJs from '!raw-loader!./custom-sample-js.raw';
|
||||
import * as customSampleCss from '!raw-loader!./custom-sample-css.raw';
|
||||
import * as customSampleHtml from '!raw-loader!./custom-sample-html.raw';
|
||||
import customSampleJs from '!raw-loader!./custom-sample-js.raw';
|
||||
import customSampleCss from '!raw-loader!./custom-sample-css.raw';
|
||||
import customSampleHtml from '!raw-loader!./custom-sample-html.raw';
|
||||
|
||||
export interface WidgetActionCallbacks {
|
||||
fetchDashboardStates: (query: string) => Array<string>;
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
///
|
||||
|
||||
import { PageComponent } from '@shared/components/page.component';
|
||||
import { Input, OnDestroy, OnInit } from '@angular/core';
|
||||
import { Inject, Input, OnDestroy, OnInit } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AppState } from '@core/core.state';
|
||||
import { WidgetContext, IDynamicWidgetComponent } from '@home/models/widget-component.models';
|
||||
@ -38,8 +38,8 @@ export class DynamicWidgetComponent extends PageComponent implements IDynamicWid
|
||||
|
||||
[key: string]: any;
|
||||
|
||||
constructor(public raf: RafService,
|
||||
protected store: Store<AppState>) {
|
||||
constructor(@Inject(RafService) public raf: RafService,
|
||||
@Inject(Store) protected store: Store<AppState>) {
|
||||
super(store);
|
||||
}
|
||||
|
||||
|
||||
@ -35,24 +35,48 @@
|
||||
<mat-sidenav-content>
|
||||
<div fxLayout="column" role="main" style="height: 100%;">
|
||||
<mat-toolbar fxLayout="row" color="primary" class="mat-elevation-z1 tb-primary-toolbar">
|
||||
<button [fxShow]="!forceFullscreen" mat-button mat-icon-button id="main" fxHide.gt-sm (click)="sidenav.toggle()">
|
||||
<button [fxShow]="!forceFullscreen" mat-button mat-icon-button id="main"
|
||||
[ngClass]="{'tb-invisible': displaySearchMode()}"
|
||||
fxHide.gt-sm (click)="sidenav.toggle()">
|
||||
<mat-icon class="material-icons">menu</mat-icon>
|
||||
</button>
|
||||
<button [fxShow]="forceFullscreen" mat-button mat-icon-button (click)="goBack()">
|
||||
<button [fxShow]="forceFullscreen" mat-button mat-icon-button
|
||||
[ngClass]="{'tb-invisible': displaySearchMode()}"
|
||||
(click)="goBack()">
|
||||
<mat-icon class="material-icons">arrow_back</mat-icon>
|
||||
</button>
|
||||
<div fxFlex tb-breadcrumb [activeComponent]="activeComponent" class="mat-toolbar-tools">
|
||||
<button mat-button mat-icon-button
|
||||
[ngClass]="{'tb-invisible': !displaySearchMode()}"
|
||||
(click)="closeSearch()">
|
||||
<mat-icon class="material-icons">arrow_back</mat-icon>
|
||||
</button>
|
||||
<div [fxShow]="!displaySearchMode()"
|
||||
fxFlex tb-breadcrumb [activeComponent]="activeComponent" class="mat-toolbar-tools">
|
||||
</div>
|
||||
<button *ngIf="fullscreenEnabled" mat-button mat-icon-button fxHide.xs fxHide.sm (click)="toggleFullscreen()">
|
||||
<div [fxShow]="displaySearchMode()" fxFlex fxLayout="row" class="tb-dark">
|
||||
<mat-form-field fxFlex floatLabel="always">
|
||||
<mat-label></mat-label>
|
||||
<input #searchInput matInput
|
||||
[(ngModel)]="searchText"
|
||||
placeholder="{{ 'common.enter-search' | translate }}"/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<button [fxShow]="searchEnabled"
|
||||
mat-button mat-icon-button
|
||||
(click)="openSearch()">
|
||||
<mat-icon class="material-icons">search</mat-icon>
|
||||
</button>
|
||||
<button *ngIf="fullscreenEnabled" [fxShow]="!displaySearchMode()"
|
||||
mat-button mat-icon-button fxHide.xs fxHide.sm (click)="toggleFullscreen()">
|
||||
<mat-icon class="material-icons">{{ isFullscreen() ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon>
|
||||
</button>
|
||||
<tb-user-menu [displayUserInfo]="true"></tb-user-menu>
|
||||
<tb-user-menu [displayUserInfo]="!displaySearchMode()"></tb-user-menu>
|
||||
</mat-toolbar>
|
||||
<mat-progress-bar color="warn" style="z-index: 10; margin-bottom: -4px; width: 100%;" mode="indeterminate"
|
||||
*ngIf="isLoading$ | async">
|
||||
</mat-progress-bar>
|
||||
<div fxFlex fxLayout="column" tb-toast class="tb-main-content">
|
||||
<router-outlet (activate)="activeComponent = $event;"></router-outlet>
|
||||
<router-outlet (activate)="activeComponentChanged($event)"></router-outlet>
|
||||
</div>
|
||||
</div>
|
||||
</mat-sidenav-content>
|
||||
|
||||
@ -17,6 +17,11 @@
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.tb-invisible {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
mat-sidenav-container {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
@ -14,10 +14,10 @@
|
||||
/// limitations under the License.
|
||||
///
|
||||
|
||||
import { Component, Inject, OnInit, ViewChild } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { AfterViewInit, Component, ElementRef, Inject, OnInit, ViewChild } from '@angular/core';
|
||||
import { fromEvent, Observable } from 'rxjs';
|
||||
import { select, Store } from '@ngrx/store';
|
||||
import { map, mergeMap, take } from 'rxjs/operators';
|
||||
import { debounceTime, distinctUntilChanged, map, mergeMap, take, tap } from 'rxjs/operators';
|
||||
|
||||
import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout';
|
||||
import { User } from '@shared/models/user.model';
|
||||
@ -34,19 +34,21 @@ import * as screenfull from 'screenfull';
|
||||
import { MatSidenav } from '@angular/material';
|
||||
import { AuthState } from '@core/auth/auth.models';
|
||||
import { WINDOW } from '@core/services/window.service';
|
||||
import { ISearchableComponent, instanceOfSearchableComponent } from '@home/models/searchable-component.models';
|
||||
|
||||
@Component({
|
||||
selector: 'tb-home',
|
||||
templateUrl: './home.component.html',
|
||||
styleUrls: ['./home.component.scss']
|
||||
})
|
||||
export class HomeComponent extends PageComponent implements OnInit {
|
||||
export class HomeComponent extends PageComponent implements AfterViewInit, OnInit {
|
||||
|
||||
authState: AuthState = getCurrentAuthState(this.store);
|
||||
|
||||
forceFullscreen = this.authState.forceFullscreen;
|
||||
|
||||
activeComponent: any;
|
||||
searchableComponent: ISearchableComponent;
|
||||
|
||||
sidenavMode = 'side';
|
||||
sidenavOpened = true;
|
||||
@ -56,6 +58,8 @@ export class HomeComponent extends PageComponent implements OnInit {
|
||||
@ViewChild('sidenav', {static: false})
|
||||
sidenav: MatSidenav;
|
||||
|
||||
@ViewChild('searchInput', {static: false}) searchInputField: ElementRef;
|
||||
|
||||
// @ts-ignore
|
||||
fullscreenEnabled = screenfull.enabled;
|
||||
|
||||
@ -63,6 +67,10 @@ export class HomeComponent extends PageComponent implements OnInit {
|
||||
userDetails$: Observable<User>;
|
||||
userDetailsString: Observable<string>;
|
||||
|
||||
searchEnabled = false;
|
||||
showSearch = false;
|
||||
searchText = '';
|
||||
|
||||
constructor(protected store: Store<AppState>,
|
||||
@Inject(WINDOW) private window: Window,
|
||||
private authService: AuthService,
|
||||
@ -98,6 +106,18 @@ export class HomeComponent extends PageComponent implements OnInit {
|
||||
);
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
fromEvent(this.searchInputField.nativeElement, 'keyup')
|
||||
.pipe(
|
||||
debounceTime(150),
|
||||
distinctUntilChanged(),
|
||||
tap(() => {
|
||||
this.searchTextUpdated();
|
||||
})
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
sidenavClicked() {
|
||||
if (this.sidenavMode === 'over') {
|
||||
this.sidenav.toggle();
|
||||
@ -120,4 +140,47 @@ export class HomeComponent extends PageComponent implements OnInit {
|
||||
goBack() {
|
||||
this.window.history.back();
|
||||
}
|
||||
|
||||
activeComponentChanged(activeComponent: any) {
|
||||
this.showSearch = false;
|
||||
this.searchText = '';
|
||||
this.activeComponent = activeComponent;
|
||||
if (this.activeComponent && instanceOfSearchableComponent(this.activeComponent)) {
|
||||
this.searchEnabled = true;
|
||||
this.searchableComponent = this.activeComponent;
|
||||
} else {
|
||||
this.searchEnabled = false;
|
||||
this.searchableComponent = null;
|
||||
}
|
||||
}
|
||||
|
||||
displaySearchMode(): boolean {
|
||||
return this.searchEnabled && this.showSearch;
|
||||
}
|
||||
|
||||
openSearch() {
|
||||
if (this.searchEnabled) {
|
||||
this.showSearch = true;
|
||||
setTimeout(() => {
|
||||
this.searchInputField.nativeElement.focus();
|
||||
this.searchInputField.nativeElement.setSelectionRange(0, 0);
|
||||
}, 10);
|
||||
}
|
||||
}
|
||||
|
||||
closeSearch() {
|
||||
if (this.searchEnabled) {
|
||||
this.showSearch = false;
|
||||
if (this.searchText.length) {
|
||||
this.searchText = '';
|
||||
this.searchTextUpdated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private searchTextUpdated() {
|
||||
if (this.searchableComponent) {
|
||||
this.searchableComponent.onSearchTextUpdated(this.searchText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
///
|
||||
/// Copyright © 2016-2019 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 interface ISearchableComponent {
|
||||
onSearchTextUpdated(searchText: string);
|
||||
}
|
||||
|
||||
export function instanceOfSearchableComponent(object: any): object is ISearchableComponent {
|
||||
return 'onSearchTextUpdated' in object;
|
||||
}
|
||||
@ -30,7 +30,7 @@
|
||||
</button>
|
||||
</section>
|
||||
<mat-drawer-container style="width: 100%;">
|
||||
<mat-drawer class="tb-rulechain-library"
|
||||
<mat-drawer class="tb-rulechain-library mat-elevation-z4"
|
||||
disableClose="true"
|
||||
mode="side"
|
||||
[opened]="isLibraryOpen"
|
||||
@ -45,13 +45,13 @@
|
||||
</button>
|
||||
<mat-form-field fxFlex floatLabel="always">
|
||||
<mat-label></mat-label>
|
||||
<input matInput
|
||||
[(ngModel)]="ruleNodeSearch"
|
||||
<input #ruleNodeSearchInput matInput
|
||||
[(ngModel)]="ruleNodeTypeSearch"
|
||||
placeholder="{{'rulenode.search' | translate}}"/>
|
||||
</mat-form-field>
|
||||
<button mat-button mat-icon-button class="tb-small"
|
||||
[fxShow]="ruleNodeSearch !== ''"
|
||||
(click)="ruleNodeSearch = ''"
|
||||
[fxShow]="ruleNodeTypeSearch !== ''"
|
||||
(click)="ruleNodeTypeSearch = ''; updateRuleChainLibrary()"
|
||||
matTooltip="{{'action.clear-search' | translate}}"
|
||||
matTooltipPosition="above">
|
||||
<mat-icon>close</mat-icon>
|
||||
@ -64,17 +64,43 @@
|
||||
</button>
|
||||
</div>
|
||||
</mat-toolbar>
|
||||
<div class="tb-rulechain-library-panel-group">
|
||||
<mat-expansion-panel #ruleNodeTypeExpansionPanels
|
||||
class="mat-elevation-z2"
|
||||
[expanded]="true" *ngFor="let ruleNodeType of ruleNodeTypesLibraryArray">
|
||||
<mat-expansion-panel-header expandedHeight="48px"
|
||||
(mouseenter)="typeHeaderMouseEnter($event, ruleNodeType)"
|
||||
(mouseleave)="destroyTooltips()">
|
||||
<mat-panel-title>
|
||||
<mat-icon style="margin-right: 8px;">{{ ruleNodeTypeDescriptorsMap.get(ruleNodeType).icon }}</mat-icon>
|
||||
<div class="tb-panel-title" translate>{{ ruleNodeTypeDescriptorsMap.get(ruleNodeType).name }}</div>
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
<fc-canvas id="tb-rulchain-{{ruleNodeType}}"
|
||||
[model]="ruleNodeTypesModel[ruleNodeType].model"
|
||||
[selectedObjects]="ruleNodeTypesModel[ruleNodeType].selectedObjects"
|
||||
[automaticResize]="false"
|
||||
[userCallbacks]="nodeLibCallbacks"
|
||||
[nodeWidth]="170"
|
||||
[nodeHeight]="50"
|
||||
[dropTargetId]="'tb-rulchain-canvas'">
|
||||
</fc-canvas>
|
||||
</mat-expansion-panel>
|
||||
</div>
|
||||
</mat-drawer>
|
||||
<mat-drawer-content>
|
||||
<div class="tb-absolute-fill tb-rulechain-graph">
|
||||
<fc-canvas #fcCanvas
|
||||
<fc-canvas #ruleChainCanvas
|
||||
id="tb-rulchain-canvas"
|
||||
[model]="ruleChainModel"
|
||||
(modelChanged)="onModelChanged()"
|
||||
[selectedObjects]="selectedObjects"
|
||||
[edgeStyle]="flowchartConstants.curvedStyle"
|
||||
[automaticResize]="true"
|
||||
[dragAnimation]="flowchartConstants.dragAnimationRepaint">
|
||||
[nodeWidth]="170"
|
||||
[nodeHeight]="50"
|
||||
[dragAnimation]="flowchartConstants.dragAnimationRepaint"
|
||||
[userCallbacks]="editCallbacks">
|
||||
</fc-canvas>
|
||||
</div>
|
||||
</mat-drawer-content>
|
||||
|
||||
@ -73,6 +73,32 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.tb-rulechain-library-panel-group {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
.mat-expansion-panel {
|
||||
border-radius: 0px;
|
||||
&:last-child {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.mat-expansion-panel-header {
|
||||
background: #e6e6e6;
|
||||
}
|
||||
&.mat-expanded {
|
||||
.mat-expansion-panel-header {
|
||||
border-bottom: 1px solid;
|
||||
border-color: #909090;
|
||||
}
|
||||
}
|
||||
}
|
||||
.tb-panel-title {
|
||||
min-width: 140px;
|
||||
user-select: none;
|
||||
}
|
||||
.fc-canvas {
|
||||
background: #f9f9f9;
|
||||
}
|
||||
}
|
||||
}
|
||||
.tb-rulechain-graph {
|
||||
z-index: 0;
|
||||
@ -99,6 +125,11 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.tb-rulechain-library-panel-group {
|
||||
.mat-expansion-panel-body {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.fc-canvas {
|
||||
|
||||
@ -14,14 +14,14 @@
|
||||
/// limitations under the License.
|
||||
///
|
||||
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { AfterViewInit, Component, ElementRef, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core';
|
||||
import { PageComponent } from '@shared/components/page.component';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AppState } from '@core/core.state';
|
||||
import { FormBuilder } from '@angular/forms';
|
||||
import { HasDirtyFlag } from '@core/guards/confirm-on-exit.guard';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { MatDialog } from '@angular/material';
|
||||
import { MatDialog, MatExpansionPanel } from '@angular/material';
|
||||
import { DialogService } from '@core/services/dialog.service';
|
||||
import { AuthService } from '@core/auth/auth.service';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
@ -31,26 +31,46 @@ import {
|
||||
RuleChain,
|
||||
ruleChainNodeComponent
|
||||
} from '@shared/models/rule-chain.models';
|
||||
import { FlowchartConstants } from 'ngx-flowchart/dist/ngx-flowchart';
|
||||
import { RuleNodeComponentDescriptor, RuleNodeType, ruleNodeTypeDescriptors } from '@shared/models/rule-node.models';
|
||||
import { FlowchartConstants, UserCallbacks, NgxFlowchartComponent } from 'ngx-flowchart/dist/ngx-flowchart';
|
||||
import {
|
||||
RuleNodeComponentDescriptor,
|
||||
RuleNodeType,
|
||||
ruleNodeTypeDescriptors,
|
||||
ruleNodeTypesLibrary
|
||||
} from '@shared/models/rule-node.models';
|
||||
import { FcRuleEdge, FcRuleNode, FcRuleNodeModel, FcRuleNodeType, FcRuleNodeTypeModel } from './rulechain-page.models';
|
||||
import { RuleChainService } from '@core/http/rule-chain.service';
|
||||
import { fromEvent, of } from 'rxjs';
|
||||
import { debounceTime, distinctUntilChanged, tap } from 'rxjs/operators';
|
||||
import Timeout = NodeJS.Timeout;
|
||||
import { ISearchableComponent } from '../../models/searchable-component.models';
|
||||
|
||||
@Component({
|
||||
selector: 'tb-rulechain-page',
|
||||
templateUrl: './rulechain-page.component.html',
|
||||
styleUrls: ['./rulechain-page.component.scss']
|
||||
})
|
||||
export class RuleChainPageComponent extends PageComponent implements OnInit, HasDirtyFlag {
|
||||
export class RuleChainPageComponent extends PageComponent
|
||||
implements AfterViewInit, OnInit, HasDirtyFlag, ISearchableComponent {
|
||||
|
||||
get isDirty(): boolean {
|
||||
return this.isDirtyValue || this.isImport;
|
||||
}
|
||||
|
||||
@ViewChild('ruleNodeSearchInput', {static: false}) ruleNodeSearchInputField: ElementRef;
|
||||
|
||||
@ViewChild('ruleChainCanvas', {static: true}) ruleChainCanvas: NgxFlowchartComponent;
|
||||
|
||||
@ViewChildren('ruleNodeTypeExpansionPanels',
|
||||
{read: MatExpansionPanel}) expansionPanels: QueryList<MatExpansionPanel>;
|
||||
|
||||
ruleNodeTypeDescriptorsMap = ruleNodeTypeDescriptors;
|
||||
ruleNodeTypesLibraryArray = ruleNodeTypesLibrary;
|
||||
|
||||
isImport: boolean;
|
||||
isDirtyValue: boolean;
|
||||
|
||||
errorTooltips = {};
|
||||
errorTooltips: {[nodeId: string]: JQueryTooltipster.ITooltipsterInstance} = {};
|
||||
isFullscreen = false;
|
||||
|
||||
editingRuleNode = null;
|
||||
@ -62,6 +82,7 @@ export class RuleChainPageComponent extends PageComponent implements OnInit, Has
|
||||
isLibraryOpen = true;
|
||||
|
||||
ruleNodeSearch = '';
|
||||
ruleNodeTypeSearch = '';
|
||||
|
||||
ruleChain: RuleChain;
|
||||
ruleChainMetaData: ResolvedRuleChainMetaData;
|
||||
@ -71,16 +92,58 @@ export class RuleChainPageComponent extends PageComponent implements OnInit, Has
|
||||
edges: []
|
||||
};
|
||||
selectedObjects = [];
|
||||
|
||||
editCallbacks: UserCallbacks = {
|
||||
edgeDoubleClick: (event, edge) => {
|
||||
console.log('TODO');
|
||||
},
|
||||
edgeEdit: (event, edge) => {
|
||||
console.log('TODO');
|
||||
},
|
||||
nodeCallbacks: {
|
||||
doubleClick: (event, node) => {
|
||||
console.log('TODO');
|
||||
},
|
||||
nodeEdit: (event, node) => {
|
||||
console.log('TODO');
|
||||
},
|
||||
mouseEnter: this.displayNodeDescriptionTooltip.bind(this),
|
||||
mouseLeave: this.destroyTooltips.bind(this),
|
||||
mouseDown: this.destroyTooltips.bind(this)
|
||||
},
|
||||
isValidEdge: (source, destination) => {
|
||||
return source.type === FlowchartConstants.rightConnectorType && destination.type === FlowchartConstants.leftConnectorType;
|
||||
},
|
||||
createEdge: (event, edge) => {
|
||||
console.log('TODO');
|
||||
return of(edge);
|
||||
},
|
||||
dropNode: (event, node) => {
|
||||
console.log('TODO dropNode');
|
||||
console.log(node);
|
||||
}
|
||||
};
|
||||
|
||||
nextNodeID: number;
|
||||
nextConnectorID: number;
|
||||
inputConnectorId: number;
|
||||
|
||||
ruleNodeTypesModel: {[type: string]: {model: FcRuleNodeTypeModel, selectedObjects: any[]}} = {};
|
||||
|
||||
nodeLibCallbacks: UserCallbacks = {
|
||||
nodeCallbacks: {
|
||||
mouseEnter: this.displayLibNodeDescriptionTooltip.bind(this),
|
||||
mouseLeave: this.destroyTooltips.bind(this),
|
||||
mouseDown: this.destroyTooltips.bind(this)
|
||||
}
|
||||
};
|
||||
|
||||
ruleNodeComponents: Array<RuleNodeComponentDescriptor>;
|
||||
|
||||
flowchartConstants = FlowchartConstants;
|
||||
|
||||
private tooltipTimeout: Timeout;
|
||||
|
||||
constructor(protected store: Store<AppState>,
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
@ -97,6 +160,23 @@ export class RuleChainPageComponent extends PageComponent implements OnInit, Has
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
fromEvent(this.ruleNodeSearchInputField.nativeElement, 'keyup')
|
||||
.pipe(
|
||||
debounceTime(150),
|
||||
distinctUntilChanged(),
|
||||
tap(() => {
|
||||
this.updateRuleChainLibrary();
|
||||
})
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
onSearchTextUpdated(searchText: string) {
|
||||
this.ruleNodeSearch = searchText;
|
||||
this.updateRuleNodesHighlight();
|
||||
}
|
||||
|
||||
private init() {
|
||||
this.ruleChain = this.route.snapshot.data.ruleChain;
|
||||
if (this.route.snapshot.data.import && !this.ruleChain) {
|
||||
@ -106,8 +186,8 @@ export class RuleChainPageComponent extends PageComponent implements OnInit, Has
|
||||
this.isImport = this.route.snapshot.data.import;
|
||||
this.ruleChainMetaData = this.route.snapshot.data.ruleChainMetaData;
|
||||
this.ruleNodeComponents = this.route.snapshot.data.ruleNodeComponents;
|
||||
for (const type of Object.keys(RuleNodeType)) {
|
||||
const desc = ruleNodeTypeDescriptors.get(RuleNodeType[type]);
|
||||
for (const type of ruleNodeTypesLibrary) {
|
||||
const desc = ruleNodeTypeDescriptors.get(type);
|
||||
if (!desc.special) {
|
||||
this.ruleNodeTypesModel[type] = {
|
||||
model: {
|
||||
@ -118,10 +198,17 @@ export class RuleChainPageComponent extends PageComponent implements OnInit, Has
|
||||
};
|
||||
}
|
||||
}
|
||||
this.loadRuleChainLibrary(this.ruleNodeComponents);
|
||||
this.updateRuleChainLibrary();
|
||||
this.createRuleChainModel();
|
||||
}
|
||||
|
||||
private updateRuleChainLibrary() {
|
||||
const search = this.ruleNodeTypeSearch.toUpperCase();
|
||||
const res = this.ruleNodeComponents.filter(
|
||||
(ruleNodeComponent) => ruleNodeComponent.name.toUpperCase().includes(search));
|
||||
this.loadRuleChainLibrary(res);
|
||||
}
|
||||
|
||||
private loadRuleChainLibrary(ruleNodeComponents: Array<RuleNodeComponentDescriptor>) {
|
||||
for (const componentType of Object.keys(this.ruleNodeTypesModel)) {
|
||||
this.ruleNodeTypesModel[componentType].model.nodes.length = 0;
|
||||
@ -167,6 +254,21 @@ export class RuleChainPageComponent extends PageComponent implements OnInit, Has
|
||||
}
|
||||
model.nodes.push(node);
|
||||
});
|
||||
if (this.expansionPanels) {
|
||||
for (let i = 0; i < ruleNodeTypesLibrary.length; i++) {
|
||||
const panel = this.expansionPanels.find((item, index) => {
|
||||
return index === i;
|
||||
});
|
||||
if (panel) {
|
||||
const type = ruleNodeTypesLibrary[i];
|
||||
if (!this.ruleNodeTypesModel[type].model.nodes.length) {
|
||||
panel.close();
|
||||
} else {
|
||||
panel.open();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private createRuleChainModel() {
|
||||
@ -350,5 +452,115 @@ export class RuleChainPageComponent extends PageComponent implements OnInit, Has
|
||||
this.isDirtyValue = true;
|
||||
}
|
||||
|
||||
typeHeaderMouseEnter(event: MouseEvent, ruleNodeType: RuleNodeType) {
|
||||
const type = ruleNodeTypeDescriptors.get(ruleNodeType);
|
||||
this.displayTooltip(event,
|
||||
'<div class="tb-rule-node-tooltip tb-lib-tooltip">' +
|
||||
'<div id="tb-node-content" layout="column">' +
|
||||
'<div class="tb-node-title">' + this.translate.instant(type.name) + '</div>' +
|
||||
'<div class="tb-node-details">' + this.translate.instant(type.details) + '</div>' +
|
||||
'</div>' +
|
||||
'</div>'
|
||||
);
|
||||
}
|
||||
|
||||
displayLibNodeDescriptionTooltip(event: MouseEvent, node: FcRuleNodeType) {
|
||||
this.displayTooltip(event,
|
||||
'<div class="tb-rule-node-tooltip tb-lib-tooltip">' +
|
||||
'<div id="tb-node-content" layout="column">' +
|
||||
'<div class="tb-node-title">' + node.component.name + '</div>' +
|
||||
'<div class="tb-node-description">' + node.component.configurationDescriptor.nodeDefinition.description + '</div>' +
|
||||
'<div class="tb-node-details">' + node.component.configurationDescriptor.nodeDefinition.details + '</div>' +
|
||||
'</div>' +
|
||||
'</div>'
|
||||
);
|
||||
}
|
||||
|
||||
displayNodeDescriptionTooltip(event: MouseEvent, node: FcRuleNode) {
|
||||
if (!this.errorTooltips[node.id]) {
|
||||
let name: string;
|
||||
let desc: string;
|
||||
let details: string;
|
||||
if (node.component.type === RuleNodeType.INPUT) {
|
||||
name = this.translate.instant(ruleNodeTypeDescriptors.get(RuleNodeType.INPUT).name);
|
||||
desc = this.translate.instant(ruleNodeTypeDescriptors.get(RuleNodeType.INPUT).details);
|
||||
} else {
|
||||
name = node.name;
|
||||
desc = this.translate.instant(ruleNodeTypeDescriptors.get(node.component.type).name) + ' - ' + node.component.name;
|
||||
if (node.additionalInfo) {
|
||||
details = node.additionalInfo.description;
|
||||
}
|
||||
}
|
||||
let tooltipContent = '<div class="tb-rule-node-tooltip">' +
|
||||
'<div id="tb-node-content" layout="column">' +
|
||||
'<div class="tb-node-title">' + name + '</div>' +
|
||||
'<div class="tb-node-description">' + desc + '</div>';
|
||||
if (details) {
|
||||
tooltipContent += '<div class="tb-node-details">' + details + '</div>';
|
||||
}
|
||||
tooltipContent += '</div>' +
|
||||
'</div>';
|
||||
this.displayTooltip(event, tooltipContent);
|
||||
}
|
||||
}
|
||||
|
||||
destroyTooltips() {
|
||||
if (this.tooltipTimeout) {
|
||||
clearTimeout(this.tooltipTimeout);
|
||||
this.tooltipTimeout = null;
|
||||
}
|
||||
const instances = $.tooltipster.instances();
|
||||
instances.forEach((instance) => {
|
||||
if (!instance.isErrorTooltip) {
|
||||
instance.destroy();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updateRuleNodesHighlight() {
|
||||
for (const ruleNode of this.ruleChainModel.nodes) {
|
||||
ruleNode.highlighted = false;
|
||||
}
|
||||
if (this.ruleNodeSearch) {
|
||||
const search = this.ruleNodeSearch.toUpperCase();
|
||||
const res = this.ruleChainModel.nodes.filter(node => node.name.toUpperCase().includes(search));
|
||||
if (res) {
|
||||
for (const ruleNode of res) {
|
||||
ruleNode.highlighted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.ruleChainCanvas.modelService.detectChanges();
|
||||
}
|
||||
|
||||
private displayTooltip(event: MouseEvent, content: string) {
|
||||
this.destroyTooltips();
|
||||
this.tooltipTimeout = setTimeout(() => {
|
||||
const element = $(event.target);
|
||||
element.tooltipster(
|
||||
{
|
||||
theme: 'tooltipster-shadow',
|
||||
delay: 100,
|
||||
trigger: 'custom',
|
||||
triggerOpen: {
|
||||
click: false,
|
||||
tap: false
|
||||
},
|
||||
triggerClose: {
|
||||
click: true,
|
||||
tap: true,
|
||||
scroll: true
|
||||
},
|
||||
side: 'right',
|
||||
trackOrigin: true
|
||||
}
|
||||
);
|
||||
const contentElement = $(content);
|
||||
const tooltip = element.tooltipster('instance');
|
||||
tooltip.content(contentElement);
|
||||
tooltip.open();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -37,6 +37,7 @@ export interface FcRuleNode extends FcRuleNodeType {
|
||||
debugMode?: boolean;
|
||||
targetRuleChainId?: string;
|
||||
error?: string;
|
||||
highlighted?: boolean;
|
||||
}
|
||||
|
||||
export interface FcRuleEdge extends FcEdge {
|
||||
|
||||
@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright © 2016-2019 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.
|
||||
*/
|
||||
.tooltipster-base {
|
||||
.tb-rule-node-tooltip,
|
||||
.tb-rule-node-help {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.tb-rule-node-tooltip {
|
||||
max-width: 300px;
|
||||
font-size: 14px;
|
||||
|
||||
&.tb-lib-tooltip {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
.tb-rule-node-help {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.tb-rule-node-error-tooltip {
|
||||
font-size: 16px;
|
||||
color: #ea0d0d;
|
||||
}
|
||||
|
||||
.tb-rule-node-tooltip,
|
||||
.tb-rule-node-error-tooltip,
|
||||
.tb-rule-node-help {
|
||||
#tb-node-content {
|
||||
.tb-node-title {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.tb-node-description {
|
||||
font-style: italic;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.tb-node-details {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
code {
|
||||
padding: 0 3px 2px 3px;
|
||||
margin: 1px;
|
||||
font-size: 12px;
|
||||
color: #ad1625;
|
||||
white-space: nowrap;
|
||||
background-color: #f7f7f9;
|
||||
border: 1px solid #e1e1e8;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -22,8 +22,8 @@
|
||||
(mouseleave)="userNodeCallbacks.mouseLeave($event, node)">
|
||||
<div class="{{flowchartConstants.nodeOverlayClass}}"></div>
|
||||
<div class="tb-rule-node {{node.nodeClass}}" [ngClass]="{'tb-rule-node-highlighted' : node.highlighted, 'tb-rule-node-invalid': node.error }">
|
||||
<mat-icon *ngIf="!node.iconUrl" fxFlex="15">{{node.icon}}</mat-icon>
|
||||
<img *ngIf="node.iconUrl" fxFlex="15" src="{{node.iconUrl}}"/>
|
||||
<mat-icon *ngIf="!iconUrl" fxFlex="15">{{node.icon}}</mat-icon>
|
||||
<img *ngIf="iconUrl" fxFlex="15" [src]="iconUrl"/>
|
||||
<div fxLayout="column" fxFlex="85" fxLayoutAlign="center">
|
||||
<span class="tb-node-type">{{ node.component.name }}</span>
|
||||
<span class="tb-node-title" *ngIf="node.name">{{ node.name }}</span>
|
||||
|
||||
@ -14,7 +14,8 @@
|
||||
/// limitations under the License.
|
||||
///
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FcNodeComponent } from 'ngx-flowchart/dist/ngx-flowchart';
|
||||
|
||||
@Component({
|
||||
@ -22,10 +23,19 @@ import { FcNodeComponent } from 'ngx-flowchart/dist/ngx-flowchart';
|
||||
templateUrl: './rulenode.component.html',
|
||||
styleUrls: ['./rulenode.component.scss']
|
||||
})
|
||||
export class RuleNodeComponent extends FcNodeComponent {
|
||||
export class RuleNodeComponent extends FcNodeComponent implements OnInit {
|
||||
|
||||
constructor() {
|
||||
iconUrl: SafeResourceUrl;
|
||||
|
||||
constructor(private sanitizer: DomSanitizer) {
|
||||
super();
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
super.ngOnInit();
|
||||
if (this.node.iconUrl) {
|
||||
this.iconUrl = this.sanitizer.bypassSecurityTrustResourceUrl(this.node.iconUrl);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -70,6 +70,15 @@ export enum RuleNodeType {
|
||||
INPUT = 'INPUT'
|
||||
}
|
||||
|
||||
export const ruleNodeTypesLibrary = [
|
||||
RuleNodeType.FILTER,
|
||||
RuleNodeType.ENRICHMENT,
|
||||
RuleNodeType.TRANSFORMATION,
|
||||
RuleNodeType.ACTION,
|
||||
RuleNodeType.EXTERNAL,
|
||||
RuleNodeType.RULE_CHAIN,
|
||||
];
|
||||
|
||||
export interface RuleNodeTypeDescriptor {
|
||||
value: RuleNodeType;
|
||||
name: string;
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/app",
|
||||
"types": ["node", "jquery", "flot", "tinycolor2", "js-beautify", "react", "react-dom"]
|
||||
"types": ["node", "jquery", "flot", "tooltipster", "tinycolor2", "js-beautify", "react", "react-dom"]
|
||||
},
|
||||
"exclude": [
|
||||
"test.ts",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user