Browse Source

Merge pull request #12850 from maxunbearable/adjustments/calculated-fields-highlight-rework

Changed Calculated fields highlights and autocompletes
pull/12857/head
Andrew Shvayka 2 years ago
committed by GitHub
parent
commit
3a23020411
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 14
      ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.scss
  2. 2
      ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.ts
  3. 8
      ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.html
  4. 9
      ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.ts
  5. 2
      ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.html
  6. 107
      ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.scss
  7. 4
      ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.ts
  8. 95
      ui-ngx/src/app/shared/models/calculated-field.models.ts
  9. 1
      ui-ngx/src/assets/locale/locale.constant-en_US.json

14
ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.scss

@ -36,14 +36,20 @@
.tb-js-func {
.ace_tb {
&.ace_calculated-field {
&-key {
&-ctx {
color: #C52F00;
}
&-ts, &-time-window, &-values, &-value, &-func {
&-args {
color: #185F2A;
}
&-key {
color: #c24c1a;
}
&-time-window, &-values, &-func, &-value, &-ts {
color: #7214D0;
}
&-start-ts, &-end-ts, &-limit {
color: #185F2A;
&-start-ts, &-end-ts {
color: #2CAA00;
}
}
}

2
ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.ts

@ -70,7 +70,7 @@ export class CalculatedFieldDialogComponent extends DialogComponent<CalculatedFi
functionArgs$ = this.configFormGroup.get('arguments').valueChanges
.pipe(
startWith(this.data.value?.configuration?.arguments ?? {}),
map(argumentsObj => Object.keys(argumentsObj))
map(argumentsObj => ['ctx', ...Object.keys(argumentsObj)])
);
argumentsEditorCompleter$ = this.configFormGroup.get('arguments').valueChanges

8
ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.html

@ -55,6 +55,14 @@
class="tb-error">
warning
</mat-icon>
} @else if (argumentFormGroup.get('argumentName').touched && argumentFormGroup.get('argumentName').hasError('equalCtx')) {
<mat-icon matSuffix
matTooltipPosition="above"
matTooltipClass="tb-error-tooltip"
[matTooltip]="'calculated-fields.hint.argument-name-ctx' | translate"
class="tb-error">
warning
</mat-icon>
}
</mat-form-field>
</div>

9
ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.ts

@ -64,7 +64,7 @@ export class CalculatedFieldArgumentPanelComponent implements OnInit {
readonly defaultLimit = Math.floor(this.maxDataPointsPerRollingArg / 10);
argumentFormGroup = this.fb.group({
argumentName: ['', [Validators.required, this.uniqNameRequired(), Validators.pattern(charsWithNumRegex), Validators.maxLength(255)]],
argumentName: ['', [Validators.required, this.uniqNameRequired(), this.notEqualCtxValidator(), Validators.pattern(charsWithNumRegex), Validators.maxLength(255)]],
refEntityId: this.fb.group({
entityType: [ArgumentEntityType.Current],
id: ['']
@ -237,6 +237,13 @@ export class CalculatedFieldArgumentPanelComponent implements OnInit {
}
}
private notEqualCtxValidator(): ValidatorFn {
return (control: FormControl) => {
const trimmedValue = control.value.trim().toLowerCase();
return trimmedValue === 'ctx' ? { equalCtx: true } : null;
};
}
private observeUpdatePosition(): void {
merge(
this.refEntityIdFormGroup.get('entityType').valueChanges,

2
ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.html

@ -15,7 +15,7 @@
limitations under the License.
-->
<form #testScriptContainer class="test-dialog-container size-full" [formGroup]="calculatedFieldScriptTestFormGroup">
<form #testScriptContainer class="cf-test-dialog-container size-full" [formGroup]="calculatedFieldScriptTestFormGroup">
<mat-toolbar class="flex justify-between" color="primary">
<h2>{{ 'calculated-fields.test-script-function' | translate }} ({{ 'api-usage.tbel' | translate }})</h2>
<button mat-icon-button

107
ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.scss

@ -13,62 +13,79 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
:host {
.test-dialog-container {
.block-label {
padding: 4px;
color: #00acc1;
background: rgba(220, 220, 220, .35);
border-radius: 5px;
}
.test-block-content {
padding-top: 5px;
padding-left: 5px;
border: 1px solid #c0c0c0;
overflow: scroll;
}
.cf-test-dialog-container {
.gutter {
background-color: #eee;
background-repeat: no-repeat;
background-position: 50%;
}
.block-label-container {
position: absolute;
z-index: 10;
font-size: 12px;
font-weight: bold;
.gutter.gutter-horizontal {
cursor: col-resize;
background-image: url("../../../../../../../assets/split.js/grips/horizontal.png");
}
&.left {
right: 112px;
top: 9px;
}
.gutter.gutter-vertical {
cursor: row-resize;
background-image: url("../../../../../../../assets/split.js/grips/vertical.png");
}
&.right-bottom {
right: 40px;
top: 6px;
}
.block-label {
padding: 4px;
color: #00acc1;
background: rgba(220, 220, 220, .35);
border-radius: 5px;
}
&.right-top {
right: 8px;
top: 2px;
}
}
.test-block-content {
padding-top: 5px;
padding-left: 5px;
border: 1px solid #c0c0c0;
overflow: scroll;
}
}
:host::ng-deep {
.test-dialog-container {
.gutter {
background-color: #eee;
background-repeat: no-repeat;
background-position: 50%;
.block-label-container {
position: absolute;
z-index: 10;
font-size: 12px;
font-weight: bold;
&.left {
right: 112px;
top: 9px;
}
&.right-bottom {
right: 40px;
top: 6px;
}
.gutter.gutter-horizontal {
cursor: col-resize;
background-image: url("../../../../../../../assets/split.js/grips/horizontal.png");
&.right-top {
right: 8px;
top: 2px;
}
}
}
.gutter.gutter-vertical {
cursor: row-resize;
background-image: url("../../../../../../../assets/split.js/grips/vertical.png");
.tb-js-func {
.ace_tb {
&.ace_calculated-field {
&-ctx {
color: #C52F00;
}
&-args {
color: #185F2A;
}
&-key {
color: #c24c1a;
}
&-time-window, &-values, &-func, &-value, &-ts {
color: #7214D0;
}
&-start-ts, &-end-ts {
color: #2CAA00;
}
}
}
}

4
ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.ts

@ -22,6 +22,7 @@ import {
Inject,
OnDestroy,
ViewChild,
ViewEncapsulation,
} from '@angular/core';
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
import { Store } from '@ngrx/store';
@ -49,6 +50,7 @@ import {
selector: 'tb-calculated-field-script-test-dialog',
templateUrl: './calculated-field-script-test-dialog.component.html',
styleUrls: ['./calculated-field-script-test-dialog.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class CalculatedFieldScriptTestDialogComponent extends DialogComponent<CalculatedFieldScriptTestDialogComponent,
string> implements AfterViewInit, OnDestroy {
@ -70,7 +72,7 @@ export class CalculatedFieldScriptTestDialogComponent extends DialogComponent<Ca
readonly ContentType = ContentType;
readonly ScriptLanguage = ScriptLanguage;
readonly functionArgs = Object.keys(this.data.arguments);
readonly functionArgs = ['ctx', ...Object.keys(this.data.arguments)];
private testScriptResize: ResizeObserver;
private splitObjects: SplitObject[] = [];

95
ui-ngx/src/app/shared/models/calculated-field.models.ts

@ -225,7 +225,7 @@ export interface CalculatedFieldLatestTelemetryArgumentValue<ValueType = unknown
}
export interface CalculatedFieldRollingTelemetryArgumentValue<ValueType = unknown> extends CalculatedFieldArgumentValueBase {
timeWindow: { startTs: number; endTs: number; limit: number };
timeWindow: { startTs: number; endTs: number; };
values: CalculatedFieldSingleArgumentValue<ValueType>[];
}
@ -235,10 +235,10 @@ export type CalculatedFieldArgumentEventValue<ValueType = unknown> = CalculatedF
export type CalculatedFieldEventArguments<ValueType = unknown> = Record<string, CalculatedFieldArgumentEventValue<ValueType>>;
export const CalculatedFieldLatestTelemetryArgumentAutocomplete = {
export const CalculatedFieldCtxLatestTelemetryArgumentAutocomplete = {
meta: 'object',
type: '{ ts: number; value: any; }',
description: 'Calculated field latest telemetry value argument.',
description: 'Calculated field context latest telemetry value argument.',
children: {
ts: {
meta: 'number',
@ -253,10 +253,10 @@ export const CalculatedFieldLatestTelemetryArgumentAutocomplete = {
},
};
export const CalculatedFieldAttributeValueArgumentAutocomplete = {
export const CalculatedFieldCtxAttributeValueArgumentAutocomplete = {
meta: 'object',
type: '{ ts: number; value: any; }',
description: 'Calculated field attribute value argument.',
description: 'Calculated field context attribute value argument.',
children: {
ts: {
meta: 'number',
@ -270,6 +270,19 @@ export const CalculatedFieldAttributeValueArgumentAutocomplete = {
}
},
};
export const CalculatedFieldLatestTelemetryArgumentAutocomplete = {
meta: 'any',
type: 'any',
description: 'Calculated field latest telemetry argument value.',
};
export const CalculatedFieldAttributeValueArgumentAutocomplete = {
meta: 'any',
type: 'any',
description: 'Calculated field attribute argument value.',
};
export const CalculatedFieldRollingValueArgumentFunctionsAutocomplete = {
max: {
meta: 'function',
@ -513,35 +526,84 @@ export const getCalculatedFieldArgumentsEditorCompleter = (argumentsObj: Record<
switch (argumentsObj[key].refEntityKey.type) {
case ArgumentType.Attribute:
acc[key] = CalculatedFieldAttributeValueArgumentAutocomplete;
acc.ctx.children.args.children[key] = CalculatedFieldCtxAttributeValueArgumentAutocomplete;
break;
case ArgumentType.LatestTelemetry:
acc[key] = CalculatedFieldLatestTelemetryArgumentAutocomplete;
acc.ctx.children.args.children[key] = CalculatedFieldCtxLatestTelemetryArgumentAutocomplete;
break;
case ArgumentType.Rolling:
acc[key] = CalculatedFieldRollingValueArgumentAutocomplete;
acc.ctx.children.args.children[key] = CalculatedFieldRollingValueArgumentAutocomplete;
break;
}
return acc;
}, {}));
}, {
ctx: {
meta: 'object',
type: '{ args: { [key: string]: object } }',
description: 'Calculated field context.',
children: {
args: {
meta: 'object',
type: '{ [key: string]: object }',
description: 'Calculated field context arguments.',
children: {}
}
}
}
}));
}
export const getCalculatedFieldArgumentsHighlights = (
argumentsObj: Record<string, CalculatedFieldArgument>
): AceHighlightRules => {
const calculatedFieldArgumentsKeys = Object.keys(argumentsObj).map(key => ({
token: 'tb.calculated-field-key',
regex: `\\b${key}\\b`,
next: argumentsObj[key].refEntityKey.type === ArgumentType.Rolling
? 'calculatedFieldRollingArgumentValue'
: 'start'
}));
const calculatedFieldCtxArgumentsHighlightRules = {
calculatedFieldCtxArgs: [
dotOperatorHighlightRule,
...calculatedFieldArgumentsKeys.map(argumentRule => argumentRule.next === 'start' ? {...argumentRule, next: 'calculatedFieldSingleArgumentValue' } : argumentRule),
endGroupHighlightRule
]
};
return {
start: Object.keys(argumentsObj).map(key => ({
token: 'tb.calculated-field-key',
regex: `\\b${key}\\b`,
next: argumentsObj[key].refEntityKey.type === ArgumentType.Rolling
? 'calculatedFieldRollingArgumentValue'
: 'calculatedFieldSingleArgumentValue'
})),
start: [
calculatedFieldArgumentsContextHighlightRules,
...calculatedFieldArgumentsKeys,
],
...calculatedFieldArgumentsContextValueHighlightRules,
...calculatedFieldCtxArgumentsHighlightRules,
...calculatedFieldSingleArgumentValueHighlightRules,
...calculatedFieldRollingArgumentValueHighlightRules,
...calculatedFieldTimeWindowArgumentValueHighlightRules
};
};
const calculatedFieldArgumentsContextHighlightRules: AceHighlightRule = {
token: 'tb.calculated-field-ctx',
regex: /ctx/,
next: 'calculatedFieldCtxValue'
}
const calculatedFieldArgumentsContextValueHighlightRules: AceHighlightRules = {
calculatedFieldCtxValue: [
dotOperatorHighlightRule,
{
token: 'tb.calculated-field-args',
regex: /args/,
next: 'calculatedFieldCtxArgs'
},
endGroupHighlightRule
]
}
const calculatedFieldSingleArgumentValueHighlightRules: AceHighlightRules = {
calculatedFieldSingleArgumentValue: [
dotOperatorHighlightRule,
@ -597,16 +659,11 @@ const calculatedFieldTimeWindowArgumentValueHighlightRules: AceHighlightRules =
regex: /endTs/,
next: 'no_regex'
},
{
token: 'tb.calculated-field-limit',
regex: /limit/,
next: 'no_regex'
},
endGroupHighlightRule
]
}
export const calculatedFieldDefaultScript = 'return {\n' +
' // Convert Fahrenheit to Celsius\n' +
' "temperatureCelsius": (temperature.value - 32) / 1.8\n' +
' "temperatureCelsius": (temperature - 32) / 1.8\n' +
'};'

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

@ -1070,6 +1070,7 @@
"argument-name-pattern": "Argument name is invalid.",
"argument-name-duplicate": "Argument with such name already exists.",
"argument-name-max-length": "Argument name should be less than 256 characters.",
"argument-name-ctx": "Argument name 'ctx' is reserved and cannot be used.",
"argument-type-required": "Argument type is required.",
"max-args": "Maximum number of arguments reached.",
"decimals-range": "Decimals by default should be a number between 0 and 15.",

Loading…
Cancel
Save