Browse Source

UI: Improve scada symbol tags panel.

pull/11391/head
Igor Kulikov 2 years ago
parent
commit
d58600ffd4
  1. 3
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/svg/iot-svg-object-settings.component.html
  2. 23
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/svg/iot-svg-object-settings.component.scss
  3. 2
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/svg/iot-svg-object-settings.component.ts
  4. 4
      ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-components.module.ts
  5. 55
      ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag-function-panel.component.html
  6. 55
      ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag-function-panel.component.scss
  7. 121
      ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag-function-panel.component.ts
  8. 33
      ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag.component.html
  9. 25
      ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag.component.scss
  10. 134
      ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag.component.ts
  11. 32
      ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tags.component.html
  12. 32
      ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tags.component.scss
  13. 116
      ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tags.component.ts
  14. 24
      ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.scss
  15. 36
      ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-tooltip.components.ts
  16. 17
      ui-ngx/src/assets/locale/locale.constant-en_US.json
  17. 1
      ui-ngx/src/styles.scss

3
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/svg/iot-svg-object-settings.component.html

@ -16,7 +16,7 @@
--> -->
<ng-container [formGroup]="iotSvgObjectSettingsFormGroup"> <ng-container [formGroup]="iotSvgObjectSettingsFormGroup">
<div>{{ metadata?.title | customTranslate }}</div> <div class="iot-svg-object-title">{{ metadata?.title | customTranslate }}</div>
<div *ngIf="metadata?.behavior?.length" class="tb-form-panel" formGroupName="behavior"> <div *ngIf="metadata?.behavior?.length" class="tb-form-panel" formGroupName="behavior">
<div class="tb-form-panel-title" translate>scada.behavior.behavior</div> <div class="tb-form-panel-title" translate>scada.behavior.behavior</div>
<div *ngFor="let behaviour of metadata.behavior" class="tb-form-row"> <div *ngFor="let behaviour of metadata.behavior" class="tb-form-row">
@ -52,6 +52,7 @@
</div> </div>
</div> </div>
<div *ngIf="propertyRows?.length" class="tb-form-panel" formGroupName="properties"> <div *ngIf="propertyRows?.length" class="tb-form-panel" formGroupName="properties">
<div class="tb-form-panel-title" translate>widget-config.appearance</div>
<div *ngFor="let propertyRow of propertyRows" class="tb-form-row space-between" [class]="propertyRow.rowClass"> <div *ngFor="let propertyRow of propertyRows" class="tb-form-row space-between" [class]="propertyRow.rowClass">
<mat-slide-toggle *ngIf="propertyRow.switch" class="mat-slide fixed-title-width" formControlName="{{ propertyRow.switch.id }}"> <mat-slide-toggle *ngIf="propertyRow.switch" class="mat-slide fixed-title-width" formControlName="{{ propertyRow.switch.id }}">
{{ propertyRow.label | customTranslate }} {{ propertyRow.label | customTranslate }}

23
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/svg/iot-svg-object-settings.component.scss

@ -0,0 +1,23 @@
/**
* Copyright © 2016-2024 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.
*/
:host {
.iot-svg-object-title {
font-size: 18px;
font-style: normal;
font-weight: 500;
line-height: 24px;
}
}

2
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/svg/iot-svg-object-settings.component.ts

@ -51,7 +51,7 @@ import { ImageService } from '@core/http/image.service';
@Component({ @Component({
selector: 'tb-iot-svg-object-settings', selector: 'tb-iot-svg-object-settings',
templateUrl: './iot-svg-object-settings.component.html', templateUrl: './iot-svg-object-settings.component.html',
styleUrls: ['./../../widget-settings.scss'], styleUrls: ['./iot-svg-object-settings.component.scss', './../../widget-settings.scss'],
providers: [ providers: [
{ {
provide: NG_VALUE_ACCESSOR, provide: NG_VALUE_ACCESSOR,

4
ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-components.module.ts

@ -45,6 +45,9 @@ import {
ScadaSymbolPropertyPanelComponent ScadaSymbolPropertyPanelComponent
} from '@home/pages/scada-symbol/metadata-components/scada-symbol-property-panel.component'; } from '@home/pages/scada-symbol/metadata-components/scada-symbol-property-panel.component';
import { WidgetSettingsCommonModule } from '@home/components/widget/lib/settings/common/widget-settings-common.module'; import { WidgetSettingsCommonModule } from '@home/components/widget/lib/settings/common/widget-settings-common.module';
import {
ScadaSymbolMetadataTagFunctionPanelComponent
} from '@home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag-function-panel.component';
@NgModule({ @NgModule({
declarations: declarations:
@ -52,6 +55,7 @@ import { WidgetSettingsCommonModule } from '@home/components/widget/lib/settings
ScadaSymbolMetadataComponent, ScadaSymbolMetadataComponent,
ScadaSymbolMetadataTagComponent, ScadaSymbolMetadataTagComponent,
ScadaSymbolMetadataTagsComponent, ScadaSymbolMetadataTagsComponent,
ScadaSymbolMetadataTagFunctionPanelComponent,
ScadaSymbolBehaviorsComponent, ScadaSymbolBehaviorsComponent,
ScadaSymbolBehaviorRowComponent, ScadaSymbolBehaviorRowComponent,
ScadaSymbolBehaviorPanelComponent, ScadaSymbolBehaviorPanelComponent,

55
ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag-function-panel.component.html

@ -0,0 +1,55 @@
<!--
Copyright © 2016-2024 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 class="tb-scada-symbol-metadata-tag-function-panel" [formGroup]="tagFunctionFormGroup">
<div class="tb-scada-symbol-metadata-tag-function-title-container">
<mat-chip-set>
<mat-chip>
<span>
{{ tag }}
</span>
</mat-chip>
</mat-chip-set>
<div class="tb-scada-symbol-metadata-tag-function-title">{{ panelTitle | translate }}</div>
</div>
<div class="tb-scada-symbol-metadata-tag-function-panel-content">
<tb-js-func #tagFunctionComponent
minHeight="300px"
formControlName="tagFunction"
[objectHighlightRules]="objectHighlightRules"
[propertyHighlightRules]="propertyHighlightRules"
[editorCompleter]="completer"
[functionArgs]="tagFunctionArgs"
[helpId]="tagFunctionHelpId">
</tb-js-func>
</div>
<div class="tb-scada-symbol-metadata-tag-function-panel-buttons">
<button mat-button
color="primary"
type="button"
(click)="cancel()">
{{ 'action.cancel' | translate }}
</button>
<button mat-raised-button
color="primary"
type="button"
(click)="applyTagFunction()"
[disabled]="tagFunctionFormGroup.invalid || !tagFunctionFormGroup.dirty">
{{ 'action.apply' | translate }}
</button>
</div>
</div>

55
ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag-function-panel.component.scss

@ -0,0 +1,55 @@
/**
* Copyright © 2016-2024 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 '../../../../../../scss/constants';
.tb-scada-symbol-metadata-tag-function-panel {
width: 800px;
display: flex;
flex-direction: column;
gap: 16px;
@media #{$mat-lt-md} {
width: 90vw;
}
.tb-scada-symbol-metadata-tag-function-panel-content {
display: flex;
flex-direction: column;
gap: 16px;
overflow: auto;
margin: -10px;
padding: 10px;
}
.tb-scada-symbol-metadata-tag-function-title-container {
display: flex;
flex-direction: row;
gap: 16px;
align-items: center;
}
.tb-scada-symbol-metadata-tag-function-title {
font-size: 16px;
font-weight: 500;
line-height: 24px;
letter-spacing: 0.25px;
color: rgba(0, 0, 0, 0.87);
}
.tb-scada-symbol-metadata-tag-function-panel-buttons {
height: 40px;
display: flex;
flex-direction: row;
gap: 16px;
justify-content: flex-end;
align-items: flex-end;
}
}

121
ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag-function-panel.component.ts

@ -0,0 +1,121 @@
///
/// Copyright © 2016-2024 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 {
AfterViewInit,
Component,
EventEmitter,
Input,
OnInit,
Output,
ViewChild,
ViewEncapsulation
} from '@angular/core';
import { TbPopoverComponent } from '@shared/components/popover.component';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { WidgetService } from '@core/http/widget.service';
import { TranslateService } from '@ngx-translate/core';
import { TbEditorCompleter } from '@shared/models/ace/completion.models';
import { TbHighlightRule } from '@shared/models/ace/ace.models';
import {
scadaSymbolClickActionHighlightRules,
scadaSymbolClickActionPropertiesHighlightRules,
scadaSymbolElementStateRenderHighlightRules,
scadaSymbolElementStateRenderPropertiesHighlightRules
} from '@home/pages/scada-symbol/scada-symbol.models';
import { JsFuncComponent } from '@shared/components/js-func.component';
@Component({
selector: 'tb-scada-symbol-metadata-tag-function-panel',
templateUrl: './scada-symbol-metadata-tag-function-panel.component.html',
styleUrls: ['./scada-symbol-metadata-tag-function-panel.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class ScadaSymbolMetadataTagFunctionPanelComponent implements OnInit, AfterViewInit {
@ViewChild('tagFunctionComponent')
tagFunctionComponent: JsFuncComponent;
@Input()
tagFunction: string;
@Input()
tagFunctionType: 'renderFunction' | 'clickAction';
@Input()
tag: string;
@Input()
completer: TbEditorCompleter;
@Input()
popover: TbPopoverComponent<ScadaSymbolMetadataTagFunctionPanelComponent>;
@Output()
tagFunctionApplied = new EventEmitter<string>();
functionScopeVariables = this.widgetService.getWidgetScopeVariables();
tagFunctionFormGroup: UntypedFormGroup;
panelTitle: string;
tagFunctionArgs: string[];
tagFunctionHelpId: string;
objectHighlightRules: TbHighlightRule[];
propertyHighlightRules: TbHighlightRule[];
constructor(private fb: UntypedFormBuilder,
private widgetService: WidgetService) {
}
ngOnInit(): void {
this.tagFunctionFormGroup = this.fb.group(
{
tagFunction: [this.tagFunction, []]
}
);
if (this.tagFunctionType === 'renderFunction') {
this.panelTitle = 'scada.state-render-function';
this.tagFunctionArgs = ['ctx', 'element'];
this.objectHighlightRules = scadaSymbolElementStateRenderHighlightRules;
this.propertyHighlightRules = scadaSymbolElementStateRenderPropertiesHighlightRules;
this.tagFunctionHelpId = 'widget/lib/timeseries/cell_style_fn'; // TODO:
} else if (this.tagFunctionType === 'clickAction') {
this.panelTitle = 'scada.tag.on-click-action';
this.tagFunctionArgs = ['ctx', 'element', 'event'];
this.objectHighlightRules = scadaSymbolClickActionHighlightRules;
this.propertyHighlightRules = scadaSymbolClickActionPropertiesHighlightRules;
this.tagFunctionHelpId = 'widget/lib/timeseries/cell_style_fn'; // TODO:
}
}
ngAfterViewInit() {
this.tagFunctionComponent.focus();
}
cancel() {
this.popover?.hide();
}
applyTagFunction() {
const tagFunction: string = this.tagFunctionFormGroup.get('tagFunction').value;
this.tagFunctionApplied.emit(tagFunction);
}
}

33
ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag.component.html

@ -15,8 +15,35 @@
limitations under the License. limitations under the License.
--> -->
<div [formGroup]="tagFormGroup" class="tb-form-panel stroked"> <div [formGroup]="tagFormGroup" class="tb-form-table-row tb-scada-symbol-metadata-tag-row">
<mat-expansion-panel #expansionPanel class="tb-settings"> <div class="tb-tag-field">
<mat-chip-set>
<mat-chip>
<span class="tb-scada-symbol-metadata-tag-label">
{{ tagFormGroup.get('tag').value }}
</span>
</mat-chip>
</mat-chip-set>
</div>
<div class="tb-state-render-function-field">
<button #editStateRenderFunctionButton
mat-button
color="primary"
(click)="editTagStateRenderFunction()">
<mat-icon>{{ tagFormGroup.get('stateRenderFunction').value ? 'edit' : 'add' }}</mat-icon>
<span>{{ (tagFormGroup.get('stateRenderFunction').value ? 'action.edit' : 'action.add') | translate }}</span>
</button>
</div>
<div class="tb-on-click-action-field">
<button #editClickActionButton
mat-button
color="primary"
(click)="editClickAction()">
<mat-icon>{{ tagFormGroup.get('clickAction').value ? 'edit' : 'add' }}</mat-icon>
<span>{{ (tagFormGroup.get('clickAction').value ? 'action.edit' : 'action.add') | translate }}</span>
</button>
</div>
<!--mat-expansion-panel #expansionPanel class="tb-settings">
<mat-expansion-panel-header fxLayout="row wrap"> <mat-expansion-panel-header fxLayout="row wrap">
<div class="tb-scada-symbol-metadata-tag-header"> <div class="tb-scada-symbol-metadata-tag-header">
<div class="tb-form-row tb-flex"> <div class="tb-form-row tb-flex">
@ -78,5 +105,5 @@
</mat-expansion-panel> </mat-expansion-panel>
</div> </div>
</ng-template> </ng-template>
</mat-expansion-panel> </mat-expansion-panel-->
</div> </div>

25
ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag.component.scss

@ -13,10 +13,23 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
.tb-scada-symbol-metadata-tag-header { .tb-scada-symbol-metadata-tag-row {
flex: 1; .tb-tag-field {
display: flex; flex: 1 1 70%;
flex-direction: row; }
gap: 8px; .tb-state-render-function-field {
padding-right: 8px; flex: 1 1 15%;
}
.tb-on-click-action-field {
flex: 1 1 15%;
}
.tb-state-render-function-field, .tb-on-click-action-field {
display: flex;
justify-content: flex-end;
.mdc-button {
.mat-mdc-button-touch-target {
height: 36px;
}
}
}
} }

134
ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag.component.ts

@ -21,12 +21,13 @@ import {
Input, Input,
OnChanges, OnChanges,
OnInit, OnInit,
Output, Output, Renderer2,
SimpleChanges, SimpleChanges,
ViewChild, ViewChild, ViewContainerRef,
ViewEncapsulation ViewEncapsulation
} from '@angular/core'; } from '@angular/core';
import { import {
AbstractControl,
ControlValueAccessor, ControlValueAccessor,
NG_VALIDATORS, NG_VALIDATORS,
NG_VALUE_ACCESSOR, NG_VALUE_ACCESSOR,
@ -47,6 +48,15 @@ import {
scadaSymbolElementStateRenderHighlightRules, scadaSymbolElementStateRenderHighlightRules,
scadaSymbolElementStateRenderPropertiesHighlightRules scadaSymbolElementStateRenderPropertiesHighlightRules
} from '@home/pages/scada-symbol/scada-symbol.models'; } from '@home/pages/scada-symbol/scada-symbol.models';
import { MatButton } from '@angular/material/button';
import { TbPopoverService } from '@shared/components/popover.service';
import { deepClone } from '@core/utils';
import {
ScadaSymbolBehaviorPanelComponent
} from '@home/pages/scada-symbol/metadata-components/scada-symbol-behavior-panel.component';
import {
ScadaSymbolMetadataTagFunctionPanelComponent
} from '@home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag-function-panel.component';
@Component({ @Component({
selector: 'tb-scada-symbol-metadata-tag', selector: 'tb-scada-symbol-metadata-tag',
@ -66,83 +76,41 @@ import {
], ],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class ScadaSymbolMetadataTagComponent implements ControlValueAccessor, OnInit, OnChanges, Validator { export class ScadaSymbolMetadataTagComponent implements ControlValueAccessor, OnInit, Validator {
@ViewChild('tagSelect')
tagSelect: MatSelect;
@ViewChild('expansionPanel')
expansionPanel: MatExpansionPanel;
@ViewChild('renderFunctionExpansionPanel') @ViewChild('editStateRenderFunctionButton')
renderFunctionExpansionPanel: MatExpansionPanel; editStateRenderFunctionButton: MatButton;
@ViewChild('clickActionExpansionPanel') @ViewChild('editClickActionButton')
clickActionExpansionPanel: MatExpansionPanel; editClickActionButton: MatButton;
@ViewChild('stateRenderFunction')
stateRenderFunction: JsFuncComponent;
@ViewChild('clickAction')
clickAction: JsFuncComponent;
@Input() @Input()
disabled: boolean; disabled: boolean;
@Input()
tags: string[];
@Input() @Input()
elementStateRenderFunctionCompleter: TbEditorCompleter; elementStateRenderFunctionCompleter: TbEditorCompleter;
@Input() @Input()
clickActionFunctionCompleter: TbEditorCompleter; clickActionFunctionCompleter: TbEditorCompleter;
@Output()
tagRemoved = new EventEmitter();
availableTags: string[];
tagFormGroup: UntypedFormGroup; tagFormGroup: UntypedFormGroup;
modelValue: IotSvgTag; modelValue: IotSvgTag;
scadaSymbolElementStateRenderHighlightRules = scadaSymbolElementStateRenderHighlightRules;
scadaSymbolElementStateRenderPropertiesHighlightRules = scadaSymbolElementStateRenderPropertiesHighlightRules;
scadaSymbolClickActionHighlightRules = scadaSymbolClickActionHighlightRules;
scadaSymbolClickActionPropertiesHighlightRules = scadaSymbolClickActionPropertiesHighlightRules;
private propagateChange = (_val: any) => {}; private propagateChange = (_val: any) => {};
constructor(private fb: UntypedFormBuilder) { constructor(private fb: UntypedFormBuilder,
private popoverService: TbPopoverService,
private renderer: Renderer2,
private viewContainerRef: ViewContainerRef) {
} }
ngOnInit() { ngOnInit() {
this.availableTags = (this.tags || []).concat();
this.tagFormGroup = this.fb.group({ this.tagFormGroup = this.fb.group({
tag: [null, [Validators.required]], tag: [null, []],
stateRenderFunction: [null, []], stateRenderFunction: [null, []],
clickAction: [null, []] clickAction: [null, []]
}); });
this.tagFormGroup.valueChanges.subscribe(
() => this.updateModel()
);
}
ngOnChanges(changes: SimpleChanges): void {
for (const propName of Object.keys(changes)) {
const change = changes[propName];
if (!change.firstChange && change.currentValue !== change.previousValue) {
if (['tags'].includes(propName)) {
this.availableTags = (this.tags || []).concat();
if (this.modelValue?.tag && !this.availableTags.includes(this.modelValue?.tag)) {
this.availableTags.push(this.modelValue?.tag);
this.availableTags.sort();
}
}
}
}
} }
registerOnChange(fn: any): void { registerOnChange(fn: any): void {
@ -163,9 +131,6 @@ export class ScadaSymbolMetadataTagComponent implements ControlValueAccessor, On
writeValue(value: IotSvgTag): void { writeValue(value: IotSvgTag): void {
this.modelValue = value; this.modelValue = value;
if (value?.tag && !(this.tags || []).includes(value?.tag)) {
this.availableTags = (this.tags || []).concat(value.tag).sort();
}
const clickAction = value?.actions && value?.actions.click ? value.actions.click.actionFunction : null; const clickAction = value?.actions && value?.actions.click ? value.actions.click.actionFunction : null;
this.tagFormGroup.patchValue( this.tagFormGroup.patchValue(
{ {
@ -186,27 +151,61 @@ export class ScadaSymbolMetadataTagComponent implements ControlValueAccessor, On
} }
editTagStateRenderFunction(): void { editTagStateRenderFunction(): void {
this.openPanelWithCallback(this.expansionPanel, () => { this.openTagFunction('renderFunction', this.editStateRenderFunctionButton);
/*this.openPanelWithCallback(this.expansionPanel, () => {
this.openPanelWithCallback(this.renderFunctionExpansionPanel, () => { this.openPanelWithCallback(this.renderFunctionExpansionPanel, () => {
this.stateRenderFunction.focus(); this.stateRenderFunction.focus();
}); });
}); });*/
} }
editClickAction(): void { editClickAction(): void {
this.openPanelWithCallback(this.expansionPanel, () => { this.openTagFunction('clickAction', this.editClickActionButton);
/*this.openPanelWithCallback(this.expansionPanel, () => {
this.openPanelWithCallback(this.clickActionExpansionPanel, () => { this.openPanelWithCallback(this.clickActionExpansionPanel, () => {
this.clickAction.focus(); this.clickAction.focus();
}); });
}); });*/
} }
focus() { private openTagFunction(tagFunctionType: 'renderFunction' | 'clickAction',
this.tagSelect._elementRef.nativeElement.scrollIntoView(); button: MatButton) {
this.tagSelect.focus(); const trigger = button._elementRef.nativeElement;
trigger.scrollIntoView();
if (this.popoverService.hasPopover(trigger)) {
this.popoverService.hidePopover(trigger);
} else {
let tagFunctionControl: AbstractControl;
let completer: TbEditorCompleter;
if (tagFunctionType === 'renderFunction') {
tagFunctionControl = this.tagFormGroup.get('stateRenderFunction');
completer = this.elementStateRenderFunctionCompleter;
} else if (tagFunctionType === 'clickAction') {
tagFunctionControl = this.tagFormGroup.get('clickAction');
completer = this.clickActionFunctionCompleter;
}
const ctx: any = {
tagFunction: tagFunctionControl.value,
tagFunctionType,
tag: this.tagFormGroup.get('tag').value,
completer
};
const scadaSymbolTagFunctionPanelPopover = this.popoverService.displayPopover(trigger, this.renderer,
this.viewContainerRef, ScadaSymbolMetadataTagFunctionPanelComponent,
['leftOnly', 'leftTopOnly', 'leftBottomOnly'], true, null,
ctx,
{},
{}, {}, true);
scadaSymbolTagFunctionPanelPopover.tbComponentRef.instance.popover = scadaSymbolTagFunctionPanelPopover;
scadaSymbolTagFunctionPanelPopover.tbComponentRef.instance.tagFunctionApplied.subscribe((tagFunction) => {
scadaSymbolTagFunctionPanelPopover.hide();
tagFunctionControl.patchValue(tagFunction, {emitEvent: false});
this.updateModel();
});
}
} }
private openPanelWithCallback(panel: MatExpansionPanel, callback: () => void) { /* private openPanelWithCallback(panel: MatExpansionPanel, callback: () => void) {
if (!panel.expanded) { if (!panel.expanded) {
const s = panel.afterExpand.subscribe(() => { const s = panel.afterExpand.subscribe(() => {
s.unsubscribe(); s.unsubscribe();
@ -218,13 +217,10 @@ export class ScadaSymbolMetadataTagComponent implements ControlValueAccessor, On
} else { } else {
callback(); callback();
} }
} }*/
private updateModel() { private updateModel() {
const value = this.tagFormGroup.value; const value = this.tagFormGroup.value;
if (value.tag && !this.modelValue?.tag) {
this.expansionPanel.open();
}
this.modelValue = { this.modelValue = {
tag: value.tag, tag: value.tag,
stateRenderFunction: value.stateRenderFunction stateRenderFunction: value.stateRenderFunction

32
ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tags.component.html

@ -16,23 +16,25 @@
--> -->
<div class="tb-form-panel tb-scada-symbol-metadata-tags"> <div class="tb-form-panel tb-scada-symbol-metadata-tags">
<div *ngIf="tagsFormArray().controls.length; else noTags" class="tb-scada-symbol-metadata-tags-list"> <div class="tb-form-table">
<div *ngFor="let tagControl of tagsFormArray().controls; trackBy: trackByTag; let $index = index; let $last = last"> <div class="tb-form-table-header">
<tb-scada-symbol-metadata-tag fxFlex <div class="tb-form-table-header-cell tb-tag-header" translate>scada.tag.tag</div>
[elementStateRenderFunctionCompleter]="elementStateRenderFunctionCompleter" <div class="tb-form-table-header-cell tb-state-render-function-header" translate>scada.state-render-function</div>
[clickActionFunctionCompleter]="clickActionFunctionCompleter" <div class="tb-form-table-header-cell tb-on-click-action-header" translate>scada.tag.on-click-action</div>
[formControl]="tagControl" </div>
[tags]="availableTags" <div *ngIf="tagsFormArray().controls.length; else noTags" class="tb-form-table-body">
(tagRemoved)="removeTag($index)"> <div *ngFor="let tagControl of tagsFormArray().controls; trackBy: trackByTag; let $index = index; let $last = last">
</tb-scada-symbol-metadata-tag> <tb-scada-symbol-metadata-tag fxFlex
[elementStateRenderFunctionCompleter]="elementStateRenderFunctionCompleter"
[clickActionFunctionCompleter]="clickActionFunctionCompleter"
[formControl]="tagControl">
</tb-scada-symbol-metadata-tag>
<mat-divider *ngIf="!$last"></mat-divider>
</div>
</div> </div>
</div>
<div>
<button *ngIf="availableTags?.length" type="button" mat-stroked-button color="primary" (click)="addTag()">
{{ 'scada.add-tag' | translate }}
</button>
</div> </div>
</div> </div>
<ng-template #noTags> <ng-template #noTags>
<span fxLayoutAlign="start center" class="tb-prompt tb-no-tags">{{ 'scada.no-tags' | translate }}</span> <span fxLayoutAlign="start center"
class="tb-prompt">{{ 'scada.tag.no-tags' | translate }}</span>
</ng-template> </ng-template>

32
ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tags.component.scss

@ -16,13 +16,31 @@
.tb-scada-symbol-metadata-tags { .tb-scada-symbol-metadata-tags {
flex: 1; flex: 1;
margin: 12px; margin: 12px;
.tb-scada-symbol-metadata-tags-list { .tb-form-table-header-cell {
overflow: auto; &.tb-tag-header {
display: flex; flex: 1 1 70%;
flex-direction: column; }
gap: 8px; &.tb-state-render-function-header {
flex: 1 1 15%;
}
&.tb-on-click-action-header {
flex: 1 1 15%;
}
&.tb-state-render-function-header, &.tb-on-click-action-header {
display: flex;
justify-content: flex-end;
}
}
.tb-form-table {
overflow: hidden;
} }
.tb-no-tags { .tb-form-table-body {
height: 60px; overflow: auto;
tb-scada-symbol-metadata-tag {
overflow: hidden;
}
.mat-divider {
margin-top: 8px;
}
} }
} }

116
ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tags.component.ts

@ -16,10 +16,12 @@
import { import {
Component, Component,
forwardRef, HostBinding, forwardRef,
HostBinding,
Input, Input,
OnChanges, OnChanges,
OnInit, QueryList, OnInit,
QueryList,
SimpleChanges, SimpleChanges,
ViewChildren, ViewChildren,
ViewEncapsulation ViewEncapsulation
@ -33,7 +35,6 @@ import {
UntypedFormBuilder, UntypedFormBuilder,
UntypedFormControl, UntypedFormControl,
UntypedFormGroup, UntypedFormGroup,
ValidationErrors,
Validator Validator
} from '@angular/forms'; } from '@angular/forms';
import { IotSvgTag } from '@home/components/widget/lib/svg/iot-svg.models'; import { IotSvgTag } from '@home/components/widget/lib/svg/iot-svg.models';
@ -42,15 +43,8 @@ import {
} from '@home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag.component'; } from '@home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag.component';
import { TbEditorCompleter } from '@shared/models/ace/completion.models'; import { TbEditorCompleter } from '@shared/models/ace/completion.models';
const tagValidator = (control: AbstractControl): ValidationErrors | null => { const tagIsEmpty = (tag: IotSvgTag): boolean =>
const tag: IotSvgTag = control.value; !tag.stateRenderFunction && !tag.actions?.click?.actionFunction;
if (!tag.tag) {
return {
tag: true
};
}
return null;
};
@Component({ @Component({
selector: 'tb-scada-symbol-metadata-tags', selector: 'tb-scada-symbol-metadata-tags',
@ -90,10 +84,10 @@ export class ScadaSymbolMetadataTagsComponent implements ControlValueAccessor, O
@Input() @Input()
clickActionFunctionCompleter: TbEditorCompleter; clickActionFunctionCompleter: TbEditorCompleter;
availableTags: string[];
tagsFormGroup: UntypedFormGroup; tagsFormGroup: UntypedFormGroup;
private modelValue: IotSvgTag[];
private propagateChange = (_val: any) => {}; private propagateChange = (_val: any) => {};
constructor(private fb: UntypedFormBuilder) { constructor(private fb: UntypedFormBuilder) {
@ -103,15 +97,17 @@ export class ScadaSymbolMetadataTagsComponent implements ControlValueAccessor, O
this.tagsFormGroup = this.fb.group({ this.tagsFormGroup = this.fb.group({
tags: this.fb.array([]) tags: this.fb.array([])
}); });
this.updateAvailableTags(); const tagsResult = this.setupTags();
this.tagsFormGroup.setControl('tags', this.prepareTagsFormArray(tagsResult.tags), {emitEvent: false});
this.tagsFormGroup.valueChanges.subscribe( this.tagsFormGroup.valueChanges.subscribe(
() => { () => {
let tags: IotSvgTag[] = this.tagsFormGroup.get('tags').value; let value: IotSvgTag[] = this.tagsFormGroup.get('tags').value;
if (tags) { if (value) {
tags = tags.filter(t => !!t.tag); value = value.filter(t => !tagIsEmpty(t));
} }
this.updateAvailableTags(); this.modelValue = value;
this.propagateChange(tags); this.propagateChange(this.modelValue);
} }
); );
} }
@ -121,7 +117,15 @@ export class ScadaSymbolMetadataTagsComponent implements ControlValueAccessor, O
const change = changes[propName]; const change = changes[propName];
if (!change.firstChange && change.currentValue !== change.previousValue) { if (!change.firstChange && change.currentValue !== change.previousValue) {
if (['tags'].includes(propName)) { if (['tags'].includes(propName)) {
this.updateAvailableTags(); const tagsResult = this.setupTags(this.modelValue);
const tagsControls = this.prepareTagsFormArray(tagsResult.tags);
if (tagsResult.emitEvent) {
setTimeout(() => {
this.tagsFormGroup.setControl('tags', tagsControls, {emitEvent: true});
});
} else {
this.tagsFormGroup.setControl('tags', tagsControls, {emitEvent: false});
}
} }
} }
} }
@ -144,8 +148,9 @@ export class ScadaSymbolMetadataTagsComponent implements ControlValueAccessor, O
} }
writeValue(value: IotSvgTag[] | undefined): void { writeValue(value: IotSvgTag[] | undefined): void {
const tags= value || []; this.modelValue = value || [];
this.tagsFormGroup.setControl('tags', this.prepareTagsFormArray(tags), {emitEvent: false}); const tagsResult= this.setupTags(this.modelValue);
this.tagsFormGroup.setControl('tags', this.prepareTagsFormArray(tagsResult.tags), {emitEvent: false});
} }
public validate(_c: UntypedFormControl) { public validate(_c: UntypedFormControl) {
@ -165,20 +170,7 @@ export class ScadaSymbolMetadataTagsComponent implements ControlValueAccessor, O
return tagControl; return tagControl;
} }
removeTag(index: number, emitEvent = true) {
(this.tagsFormGroup.get('tags') as UntypedFormArray).removeAt(index, {emitEvent});
}
addTag() {
this.addNewTag(null);
setTimeout(() => {
const tagComponent = this.metadataTags.get(this.metadataTags.length-1);
tagComponent.focus();
});
}
editTagStateRenderFunction(tag: string): void { editTagStateRenderFunction(tag: string): void {
this.addTagIfNotPresent(tag);
setTimeout(() => { setTimeout(() => {
const tags: IotSvgTag[] = this.tagsFormGroup.get('tags').value; const tags: IotSvgTag[] = this.tagsFormGroup.get('tags').value;
const index = tags.findIndex(t => t.tag === tag); const index = tags.findIndex(t => t.tag === tag);
@ -188,7 +180,6 @@ export class ScadaSymbolMetadataTagsComponent implements ControlValueAccessor, O
} }
editTagClickAction(tag: string): void { editTagClickAction(tag: string): void {
this.addTagIfNotPresent(tag);
setTimeout(() => { setTimeout(() => {
const tags: IotSvgTag[] = this.tagsFormGroup.get('tags').value; const tags: IotSvgTag[] = this.tagsFormGroup.get('tags').value;
const index = tags.findIndex(t => t.tag === tag); const index = tags.findIndex(t => t.tag === tag);
@ -197,44 +188,39 @@ export class ScadaSymbolMetadataTagsComponent implements ControlValueAccessor, O
}); });
} }
private addTagIfNotPresent(tag: string) { private setupTags(existing?: IotSvgTag[]): {tags: IotSvgTag[]; emitEvent: boolean} {
const tags: IotSvgTag[] = this.tagsFormGroup.get('tags').value; existing = (existing || []).filter(t => !tagIsEmpty(t));
if (!tags || !tags.find(t => t.tag === tag)) { const result = (this.tags || []).sort().map(tag => ({
this.addNewTag(tag); tag,
stateRenderFunction: null,
actions: {
click: {
actionFunction: null
}
}
}));
for (const tag of existing) {
const found = result.find(t => t.tag === tag.tag);
if (found) {
found.stateRenderFunction = tag.stateRenderFunction;
found.actions.click.actionFunction = tag.actions?.click?.actionFunction;
}
} }
} const tagRemoved = !!existing.find(existingTag =>
!result.find(t => t.tag === existingTag.tag));
private addNewTag(tagLabel: string) { return {
const tag: IotSvgTag = { tags: result,
tag: tagLabel emitEvent: tagRemoved
}; };
const tagsArray = this.tagsFormGroup.get('tags') as UntypedFormArray;
const tagControl = this.fb.control(tag, [tagValidator]);
tagsArray.push(tagControl);
} }
private prepareTagsFormArray(tags: IotSvgTag[] | undefined): UntypedFormArray { private prepareTagsFormArray(tags: IotSvgTag[] | undefined): UntypedFormArray {
const tagsControls: Array<AbstractControl> = []; const tagsControls: Array<AbstractControl> = [];
if (tags) { if (tags) {
tags.forEach((tag) => { tags.forEach((tag) => {
tagsControls.push(this.fb.control(tag, [tagValidator])); tagsControls.push(this.fb.control(tag, []));
}); });
} }
return this.fb.array(tagsControls); return this.fb.array(tagsControls);
} }
private updateAvailableTags() {
if (this.tags) {
for (const c of this.tagsFormArray().controls) {
const svgTag: IotSvgTag = c.value;
if (svgTag.tag && !this.tags.includes(svgTag.tag)) {
const index = this.tagsFormArray().controls.indexOf(c);
this.removeTag(index, false);
}
}
}
const svgTags: IotSvgTag[] = this.tagsFormGroup.get('tags').value;
const usedTags = (svgTags || []).filter(t => !!t.tag).map(t => t.tag);
this.availableTags = (this.tags || []).filter(t => !usedTags.includes(t));
}
} }

24
ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.scss

@ -79,35 +79,33 @@
.ace_tb { .ace_tb {
&.ace_scada-symbol { &.ace_scada-symbol {
&-ctx { &-ctx {
color: orangered; color: #C52F00;
font-weight: bold;
&-properties, &-property { &-properties, &-property {
color: #0c959c; color: #185F2A;
} }
&-values, &-value { &-values, &-value {
color: #669900; color: #2CAA00;
} }
&-tags, &-tag { &-tags, &-tag {
color: #cc8500; color: #DF8600;
} }
&-api, &-api-method { &-api, &-api-method {
color: #ff00fe; color: #7214D0;
} }
&-properties, &-values, &-tags, &-api { &-properties, &-values, &-tags, &-api {
font-style: italic; // font-style: italic;
// font-weight: bold; // font-weight: bold;
} }
&-property, &-value, &-tag, &-api-method { &-property, &-value, &-tag, &-api-method {
font-weight: bold; font-weight: 700;
// font-weight: bold;
} }
} }
&-svg, &-element, &-event { &-svg, &-element, &-event {
color: orangered; color: #C52F00;
font-weight: bold; // font-weight: bold;
&-properties { &-properties {
color: #0c959c; color: #7214D0;
font-weight: bold; font-weight: 700;
} }
} }
} }

36
ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-tooltip.components.ts

@ -37,6 +37,7 @@ import { ENTER } from '@angular/cdk/keycodes';
import Timeout = NodeJS.Timeout; import Timeout = NodeJS.Timeout;
import { MatButton } from '@angular/material/button'; import { MatButton } from '@angular/material/button';
import ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance; import ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance;
import { TranslateService } from '@ngx-translate/core';
@Directive() @Directive()
abstract class ScadaSymbolPanelComponent implements AfterViewInit { abstract class ScadaSymbolPanelComponent implements AfterViewInit {
@ -60,7 +61,7 @@ abstract class ScadaSymbolPanelComponent implements AfterViewInit {
<span>{{ symbolElement?.element?.type }}:</span> <span>{{ symbolElement?.element?.type }}:</span>
<button mat-stroked-button color="primary" (click)="onAddTag()"> <button mat-stroked-button color="primary" (click)="onAddTag()">
<mat-icon>add</mat-icon> <mat-icon>add</mat-icon>
<span>Add tag</span> <span translate>scada.tag.add-tag</span>
</button> </button>
</div>`, </div>`,
styleUrls: ['./scada-symbol-tooltip.component.scss'], styleUrls: ['./scada-symbol-tooltip.component.scss'],
@ -83,20 +84,20 @@ class ScadaSymbolAddTagPanelComponent extends ScadaSymbolPanelComponent {
@Component({ @Component({
template: `<div class="tb-scada-symbol-tooltip-panel"> template: `<div class="tb-scada-symbol-tooltip-panel">
<span>{{ isAdd ? 'Enter tag:' : 'Update tag:' }}</span> <span>{{ (isAdd ? 'scada.tag.enter-tag' : 'scada.tag.update-tag' ) | translate }}:</span>
<mat-form-field class="tb-inline-field" appearance="outline" subscriptSizing="dynamic"> <mat-form-field class="tb-inline-field" appearance="outline" subscriptSizing="dynamic">
<input #tagField matInput [(ngModel)]="tag" (keydown)="tagEnter($event)" (blur)="onBlur()" <input #tagField matInput [(ngModel)]="tag" (keydown)="tagEnter($event)" (blur)="onBlur()"
placeholder="{{ 'widget-config.set' | translate }}"> placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field> </mat-form-field>
<button type="button" mat-icon-button class="tb-mat-20" <button type="button" mat-icon-button class="tb-mat-20"
matTooltip="Apply" matTooltip="{{ 'action.apply' | translate }}"
matTooltipPosition="above" matTooltipPosition="above"
[disabled]="!tag" [disabled]="!tag"
(click)="onApply()"> (click)="onApply()">
<mat-icon>done</mat-icon> <mat-icon>done</mat-icon>
</button> </button>
<button type="button" mat-icon-button class="tb-mat-20" <button type="button" mat-icon-button class="tb-mat-20"
matTooltip="Cancel" matTooltip="{{ 'action.cancel' | translate }}"
matTooltipPosition="above" matTooltipPosition="above"
(click)="onCancel()"> (click)="onCancel()">
<mat-icon>close</mat-icon> <mat-icon>close</mat-icon>
@ -184,20 +185,20 @@ class ScadaSymbolTagInputPanelComponent extends ScadaSymbolPanelComponent implem
<span>{{ symbolElement?.element?.type }}:</span> <span>{{ symbolElement?.element?.type }}:</span>
<span><b>{{ symbolElement?.tag }}</b></span> <span><b>{{ symbolElement?.tag }}</b></span>
<button type="button" mat-icon-button class="tb-mat-20" <button type="button" mat-icon-button class="tb-mat-20"
matTooltip="Update tag" matTooltip="{{ 'scada.tag.update-tag' | translate }}"
matTooltipPosition="above" matTooltipPosition="above"
(click)="onUpdateTag()"> (click)="onUpdateTag()">
<mat-icon>edit</mat-icon> <mat-icon>edit</mat-icon>
</button> </button>
<button #tagSettingsButton type="button" <button #tagSettingsButton type="button"
mat-icon-button class="tb-mat-20" mat-icon-button class="tb-mat-20"
matTooltip="Settings" matTooltip="{{ 'scada.tag.tag-settings' | translate }}"
matTooltipPosition="above"> matTooltipPosition="above">
<mat-icon>settings</mat-icon> <mat-icon>settings</mat-icon>
</button> </button>
<button #removeTagButton type="button" <button #removeTagButton type="button"
mat-icon-button class="tb-mat-20" mat-icon-button class="tb-mat-20"
matTooltip="Remove tag" matTooltip="{{ 'scada.tag.remove-tag' | translate }}"
matTooltipPosition="above"> matTooltipPosition="above">
<mat-icon>delete</mat-icon> <mat-icon>delete</mat-icon>
</button> </button>
@ -288,12 +289,12 @@ class ScadaSymbolTagPanelComponent extends ScadaSymbolPanelComponent implements
<div class="tb-scada-symbol-tooltip-panel"> <div class="tb-scada-symbol-tooltip-panel">
<button mat-stroked-button color="primary" (click)="onCancel()"> <button mat-stroked-button color="primary" (click)="onCancel()">
<mat-icon>close</mat-icon> <mat-icon>close</mat-icon>
<span>No</span> <span translate>action.no</span>
</button> </button>
<button #yesButton <button #yesButton
mat-stroked-button color="primary" (click)="onRemoveTag()"> mat-stroked-button color="primary" (click)="onRemoveTag()">
<mat-icon>done</mat-icon> <mat-icon>done</mat-icon>
<span>Yes</span> <span translate>action.yes</span>
</button> </button>
</div> </div>
</div>`, </div>`,
@ -313,13 +314,14 @@ class ScadaSymbolRemoveTagConfirmComponent extends ScadaSymbolPanelComponent imp
@Output() @Output()
removeTag = new EventEmitter(); removeTag = new EventEmitter();
constructor(public element: ElementRef<HTMLElement>) { constructor(public element: ElementRef<HTMLElement>,
private translate: TranslateService) {
super(element); super(element);
} }
ngOnInit() { ngOnInit() {
this.deleteText = `Are you sure you want to delete tag<br/><b>${this.symbolElement?.tag}</b> this.deleteText = this.translate.instant('scada.tag.delete-tag-text',
from <b>${this.symbolElement?.element?.type}</b> element?`; {tag: this.symbolElement?.tag, elementType: this.symbolElement?.element?.type});
} }
public onCancel() { public onCancel() {
@ -339,29 +341,29 @@ class ScadaSymbolRemoveTagConfirmComponent extends ScadaSymbolPanelComponent imp
color="primary" color="primary"
(click)="editStateRenderFunction()"> (click)="editStateRenderFunction()">
<mat-icon>edit</mat-icon> <mat-icon>edit</mat-icon>
<span>Edit</span> <span translate>action.edit</span>
</button> </button>
<button *ngIf="!hasStateRenderFunction" <button *ngIf="!hasStateRenderFunction"
mat-stroked-button mat-stroked-button
color="primary" color="primary"
(click)="editStateRenderFunction()"> (click)="editStateRenderFunction()">
<mat-icon>add</mat-icon> <mat-icon>add</mat-icon>
<span>Add</span> <span translate>action.add</span>
</button> </button>
<div translate>scada.on-click-action</div> <div translate>scada.tag.on-click-action</div>
<button *ngIf="hasClickAction" <button *ngIf="hasClickAction"
mat-stroked-button mat-stroked-button
color="primary" color="primary"
(click)="editClickAction()"> (click)="editClickAction()">
<mat-icon>edit</mat-icon> <mat-icon>edit</mat-icon>
<span>Edit</span> <span translate>action.edit</span>
</button> </button>
<button *ngIf="!hasClickAction" <button *ngIf="!hasClickAction"
mat-stroked-button mat-stroked-button
color="primary" color="primary"
(click)="editClickAction()"> (click)="editClickAction()">
<mat-icon>add</mat-icon> <mat-icon>add</mat-icon>
<span>Add</span> <span translate>action.add</span>
</button> </button>
</div>`, </div>`,
styleUrls: ['./scada-symbol-tooltip.component.scss'], styleUrls: ['./scada-symbol-tooltip.component.scss'],

17
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -3414,13 +3414,18 @@
"title": "Title", "title": "Title",
"state-render-function": "State render function", "state-render-function": "State render function",
"preview": "Preview", "preview": "Preview",
"tag": "Tag",
"on-click-action": "On click action",
"remove-tag": "Remove tag",
"add-tag": "Add tag",
"no-tags": "No tags configured",
"select-tag": "Select tag",
"preview-widget-action-text": "Widget action '{{type}}' successfully invoked!", "preview-widget-action-text": "Widget action '{{type}}' successfully invoked!",
"tag": {
"tag": "Tag",
"on-click-action": "On click action",
"no-tags": "No tags configured",
"delete-tag-text": "Are you sure you want to delete tag<br/><b>{{tag}}</b> from <b>{{elementType}}</b> element?",
"update-tag": "Update tag",
"enter-tag": "Enter tag",
"tag-settings": "Tag settings",
"remove-tag": "Remove tag",
"add-tag": "Add tag"
},
"behavior": { "behavior": {
"behavior": "Behavior", "behavior": "Behavior",
"id": "Id", "id": "Id",

1
ui-ngx/src/styles.scss

@ -392,6 +392,7 @@ mat-icon {
} }
.tb-ace-doc-tooltip { .tb-ace-doc-tooltip {
white-space: pre-wrap;
code { code {
color: #444; color: #444;
&.title { &.title {

Loading…
Cancel
Save