UI: Release ace editor resources on destroy. Improve node script test dialog.

This commit is contained in:
Igor Kulikov 2022-10-19 19:10:33 +03:00
parent 05f47f3796
commit 8abe2f19e1
17 changed files with 111 additions and 21 deletions

View File

@ -14,7 +14,7 @@
/// limitations under the License.
///
import { Component, ElementRef, Inject, OnInit, Renderer2, ViewChild } from '@angular/core';
import { Component, ElementRef, Inject, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
@ -33,7 +33,7 @@ export interface AuditLogDetailsDialogData {
templateUrl: './audit-log-details-dialog.component.html',
styleUrls: ['./audit-log-details-dialog.component.scss']
})
export class AuditLogDetailsDialogComponent extends DialogComponent<AuditLogDetailsDialogComponent> implements OnInit {
export class AuditLogDetailsDialogComponent extends DialogComponent<AuditLogDetailsDialogComponent> implements OnInit, OnDestroy {
@ViewChild('actionDataEditor', {static: true})
actionDataEditorElmRef: ElementRef;
@ -45,6 +45,7 @@ export class AuditLogDetailsDialogComponent extends DialogComponent<AuditLogDeta
displayFailureDetails: boolean;
actionData: string;
actionFailureDetails: string;
aceEditors: Ace.Editor[] = [];
constructor(protected store: Store<AppState>,
protected router: Router,
@ -66,6 +67,11 @@ export class AuditLogDetailsDialogComponent extends DialogComponent<AuditLogDeta
}
}
ngOnDestroy(): void {
this.aceEditors.forEach(editor => editor.destroy());
super.ngOnDestroy();
}
createEditor(editorElementRef: ElementRef, content: string): void {
const editorElement = editorElementRef.nativeElement;
let editorOptions: Partial<Ace.EditorOptions> = {
@ -86,6 +92,7 @@ export class AuditLogDetailsDialogComponent extends DialogComponent<AuditLogDeta
getAce().subscribe(
(ace) => {
const editor = ace.edit(editorElement, editorOptions);
this.aceEditors.push(editor);
editor.session.setUseWrapMode(false);
editor.setValue(content, -1);
this.updateEditorSize(editorElement, content, editor);

View File

@ -14,7 +14,7 @@
/// limitations under the License.
///
import { Component, ElementRef, Inject, OnInit, Renderer2, ViewChild } from '@angular/core';
import { Component, ElementRef, Inject, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
@ -40,7 +40,7 @@ export interface EventContentDialogData {
templateUrl: './event-content-dialog.component.html',
styleUrls: ['./event-content-dialog.component.scss']
})
export class EventContentDialogComponent extends DialogComponent<EventContentDialogData> implements OnInit {
export class EventContentDialogComponent extends DialogComponent<EventContentDialogData> implements OnInit, OnDestroy {
@ViewChild('eventContentEditor', {static: true})
eventContentEditorElmRef: ElementRef;
@ -48,6 +48,7 @@ export class EventContentDialogComponent extends DialogComponent<EventContentDia
content: string;
title: string;
contentType: ContentType;
aceEditor: Ace.Editor;
constructor(protected store: Store<AppState>,
protected router: Router,
@ -65,6 +66,13 @@ export class EventContentDialogComponent extends DialogComponent<EventContentDia
this.createEditor(this.eventContentEditorElmRef, this.content);
}
ngOnDestroy(): void {
if (this.aceEditor) {
this.aceEditor.destroy();
}
super.ngOnDestroy();
}
isJson(str) {
try {
return isLiteralObject(JSON.parse(str));
@ -116,10 +124,10 @@ export class EventContentDialogComponent extends DialogComponent<EventContentDia
editorOptions = {...editorOptions, ...advancedOptions};
getAce().subscribe(
(ace) => {
const editor = ace.edit(editorElement, editorOptions);
editor.session.setUseWrapMode(false);
editor.setValue(processedContent, -1);
this.updateEditorSize(editorElement, processedContent, editor);
this.aceEditor = ace.edit(editorElement, editorOptions);
this.aceEditor.session.setUseWrapMode(false);
this.aceEditor.setValue(processedContent, -1);
this.updateEditorSize(editorElement, processedContent, this.aceEditor);
}
);
}

View File

@ -14,7 +14,7 @@
/// limitations under the License.
///
import { AfterViewInit, Component, ElementRef, Inject, Renderer2, ViewChild } from '@angular/core';
import { AfterViewInit, Component, ElementRef, Inject, OnDestroy, Renderer2, ViewChild } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
@ -54,7 +54,7 @@ export interface ImportDialogCsvData {
styleUrls: ['./import-dialog-csv.component.scss']
})
export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvComponent, boolean>
implements AfterViewInit {
implements AfterViewInit, OnDestroy {
@ViewChild('importStepper', {static: true}) importStepper: MatVerticalStepper;
@ -91,6 +91,8 @@ export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvCom
isImportData = false;
statistical: BulkImportResult;
aceEditor: Ace.Editor;
private allowAssignColumn: ImportEntityColumnType[];
private initEditorComponent = false;
private parseData: CsvToJsonResult;
@ -131,6 +133,13 @@ export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvCom
this.allowAssignColumn = columns.map(column => column.value);
}
ngOnDestroy(): void {
if (this.aceEditor) {
this.aceEditor.destroy();
}
super.ngOnDestroy();
}
cancel(): void {
this.dialogRef.close(false);
}
@ -271,10 +280,10 @@ export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvCom
const content = contents.map(error => error.replace('\n', '')).join('\n');
getAce().subscribe(
(ace) => {
const editor = ace.edit(editorElement, editorOptions);
editor.session.setUseWrapMode(false);
editor.setValue(content, -1);
this.updateEditorSize(editorElement, content, editor);
this.aceEditor = ace.edit(editorElement, editorOptions);
this.aceEditor.session.setUseWrapMode(false);
this.aceEditor.setValue(content, -1);
this.updateEditorSize(editorElement, content, this.aceEditor);
}
);
}

View File

@ -93,6 +93,7 @@ export class CustomActionPrettyResourcesTabsComponent extends PageComponent impl
}
ngOnDestroy(): void {
this.aceEditors.forEach(editor => editor.destroy());
this.aceResize$.disconnect();
}

View File

@ -210,6 +210,7 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe
ngOnDestroy(): void {
this.window.removeEventListener('message', this.onWindowMessageListener);
this.aceEditors.forEach(editor => editor.destroy());
this.aceResize$.disconnect();
this.rxSubscriptions.forEach((subscription) => {
subscription.unsubscribe();
@ -599,6 +600,7 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe
config.title = this.widget.widgetName;
this.widget.defaultConfig = JSON.stringify(config);
this.iframe.attr('data-widget', JSON.stringify(this.widget));
// @ts-ignore
this.iframe[0].contentWindow.location.reload(true);
}

View File

@ -145,6 +145,9 @@ export class CssComponent implements OnInit, OnDestroy, ControlValueAccessor, Va
if (this.editorResize$) {
this.editorResize$.disconnect();
}
if (this.cssEditor) {
this.cssEditor.destroy();
}
}
private onAceEditorResize() {

View File

@ -18,7 +18,7 @@
<form class="tb-node-script-test-dialog"
[formGroup]="nodeScriptTestFormGroup" (ngSubmit)="save()">
<mat-toolbar fxLayout="row" color="primary">
<h2>{{ 'rulenode.test-script-function' | translate }}</h2>
<h2>{{ 'rulenode.test-script-function' | translate }} ({{ (scriptLang === scriptLanguage.JS ? 'rulenode.script-lang-java-script' : 'rulenode.script-lang-mvel') | translate }})</h2>
<span fxFlex></span>
<button mat-button mat-icon-button
(click)="cancel()"

View File

@ -98,6 +98,10 @@ export class NodeScriptTestDialogComponent extends DialogComponent<NodeScriptTes
contentTypes = ContentType;
scriptLanguage = ScriptLanguage;
scriptLang = this.data.scriptLang ? this.data.scriptLang : ScriptLanguage.JS;
constructor(protected store: Store<AppState>,
protected router: Router,
@Inject(MAT_DIALOG_DATA) public data: NodeScriptTestDialogData,
@ -192,8 +196,7 @@ export class NodeScriptTestDialogComponent extends DialogComponent<NodeScriptTes
metadata: this.nodeScriptTestFormGroup.get('metadata').value,
script: this.nodeScriptTestFormGroup.get('script').value
};
const scriptLang = this.data.scriptLang ? this.data.scriptLang : ScriptLanguage.JS;
return this.ruleChainService.testScript(inputParams, scriptLang).pipe(
return this.ruleChainService.testScript(inputParams, this.scriptLang).pipe(
mergeMap((result) => {
if (result.error) {
this.store.dispatch(new ActionNotificationShow(

View File

@ -147,6 +147,9 @@ export class HtmlComponent implements OnInit, OnDestroy, ControlValueAccessor, V
if (this.editorResize$) {
this.editorResize$.disconnect();
}
if (this.htmlEditor) {
this.htmlEditor.destroy();
}
}
private onAceEditorResize() {

View File

@ -228,6 +228,9 @@ export class JsFuncComponent implements OnInit, OnDestroy, ControlValueAccessor,
if (this.editorResize$) {
this.editorResize$.disconnect();
}
if (this.jsEditor) {
this.jsEditor.destroy();
}
}
private onAceEditorResize() {

View File

@ -181,6 +181,9 @@ export class JsonContentComponent implements OnInit, ControlValueAccessor, Valid
if (this.editorResize$) {
this.editorResize$.disconnect();
}
if (this.jsonEditor) {
this.jsonEditor.destroy();
}
}
private onAceEditorResize() {

View File

@ -147,6 +147,9 @@ export class JsonObjectEditComponent implements OnInit, ControlValueAccessor, Va
if (this.editorResize$) {
this.editorResize$.disconnect();
}
if (this.jsonEditor) {
this.jsonEditor.destroy();
}
}
private onAceEditorResize() {

View File

@ -14,7 +14,7 @@
/// limitations under the License.
///
import { Component, ElementRef, forwardRef, Input, OnInit, Renderer2, ViewChild } from '@angular/core';
import { Component, ElementRef, forwardRef, Input, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { Ace } from 'ace-builds';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
@ -36,7 +36,7 @@ import { getAce } from '@shared/models/ace/ace.models';
}
]
})
export class JsonObjectViewComponent implements OnInit {
export class JsonObjectViewComponent implements OnInit, OnDestroy {
@ViewChild('jsonViewer', {static: true})
jsonViewerElmRef: ElementRef;
@ -112,6 +112,12 @@ export class JsonObjectViewComponent implements OnInit {
);
}
ngOnDestroy(): void {
if (this.jsonViewer) {
this.jsonViewer.destroy();
}
}
updateEditorSize(editorElement: any, content: string, editor: Ace.Editor) {
let newHeight = 200;
let newWidth = 600;

View File

@ -14,7 +14,7 @@
/// limitations under the License.
///
import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core';
import { Component, ElementRef, forwardRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { Ace } from 'ace-builds';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
@ -32,7 +32,7 @@ import { getAce } from '@shared/models/ace/ace.models';
}
]
})
export class MarkdownEditorComponent implements OnInit, ControlValueAccessor {
export class MarkdownEditorComponent implements OnInit, ControlValueAccessor, OnDestroy {
@Input() label: string;
@ -104,6 +104,12 @@ export class MarkdownEditorComponent implements OnInit, ControlValueAccessor {
}
}
ngOnDestroy(): void {
if (this.markdownEditor) {
this.markdownEditor.destroy();
}
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}

View File

@ -129,6 +129,9 @@ export class ProtobufContentComponent implements OnInit, ControlValueAccessor, O
if (this.editorResize$) {
this.editorResize$.disconnect();
}
if (this.protobufEditor) {
this.protobufEditor.destroy();
}
}
registerOnChange(fn: any): void {

View File

@ -2974,6 +2974,8 @@
"ui-resources-load-error": "Failed to load configuration ui resources.",
"invalid-target-rulechain": "Unable to resolve target rule chain!",
"test-script-function": "Test script function",
"script-lang-java-script": "Java Script",
"script-lang-mvel": "MVEL",
"message": "Message",
"message-type": "Message type",
"select-message-type": "Select message type",

View File

@ -1465,4 +1465,32 @@ mat-label {
pointer-events: none;
}
}
.mat-button-toggle-group.tb-button-toggle-group {
&.mat-button-toggle-group-appearance-standard {
border: none;
.mat-button-toggle+.mat-button-toggle {
border-left: none;
}
}
.mat-button-toggle {
background: rgba(0, 0, 0, 0.06);
height: 32px;
align-items: center;
display: flex;
}
.mat-button-toggle-checked .mat-button-toggle-button {
background-color: #fff;
border-radius: 4px;
margin-left: 2px;
margin-right: 2px;
}
.mat-button-toggle-appearance-standard .mat-button-toggle-label-content {
line-height: 28px;
font-size: 14px;
}
.mat-button-toggle-checked.mat-button-toggle-appearance-standard:not(.mat-button-toggle-disabled):hover .mat-button-toggle-focus-overlay {
opacity: .01;
}
}
}