From 03ba0c32dc8ee9a72d88c64377aec4aa63959d6c Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 28 Nov 2024 20:05:26 +0200 Subject: [PATCH] Implement JS Module resources support. --- ui-ngx/src/app/core/services/utils.service.ts | 39 +--- .../widget/lib/action/action-widget.models.ts | 13 +- .../common/action/custom-action.models.ts | 3 +- .../js-library-table-config.resolver.ts | 1 + .../home/pages/widget/widget-editor.models.ts | 4 +- .../components/help-markdown.component.ts | 15 +- .../components/help-popup.component.html | 13 +- .../components/help-popup.component.scss | 15 +- .../shared/components/help-popup.component.ts | 56 ++++-- .../js-func-module-row.component.html | 15 ++ .../js-func-module-row.component.scss | 4 +- .../js-func-module-row.component.ts | 36 +++- .../components/js-func-modules.component.scss | 8 +- .../shared/components/js-func.component.ts | 71 ++++--- .../json-form/json-form.component.ts | 2 +- .../app/shared/components/popover.service.ts | 5 + .../resource-autocomplete.component.ts | 10 +- .../shared/models/ace/completion.models.ts | 2 +- ui-ngx/src/app/shared/models/error.models.ts | 47 +++++ .../app/shared/models/js-function.models.ts | 175 +++++++++++++++++- .../assets/locale/locale.constant-en_US.json | 4 +- 21 files changed, 418 insertions(+), 120 deletions(-) diff --git a/ui-ngx/src/app/core/services/utils.service.ts b/ui-ngx/src/app/core/services/utils.service.ts index f2f2ba39e8..d9e8788cba 100644 --- a/ui-ngx/src/app/core/services/utils.service.ts +++ b/ui-ngx/src/app/core/services/utils.service.ts @@ -19,7 +19,7 @@ import { Inject, Injectable, NgZone, Renderer2 } from '@angular/core'; import { WINDOW } from '@core/services/window.service'; -import { ExceptionData } from '@app/shared/models/error.models'; +import { ExceptionData, parseException } from '@app/shared/models/error.models'; import { base64toObj, base64toString, @@ -214,42 +214,7 @@ export class UtilsService { } public parseException(exception: any, lineOffset?: number): ExceptionData { - const data: ExceptionData = {}; - if (exception) { - if (typeof exception === 'string') { - data.message = exception; - } else if (exception instanceof String) { - data.message = exception.toString(); - } else { - if (exception.name) { - data.name = exception.name; - } else { - data.name = 'UnknownError'; - } - if (exception.message) { - data.message = exception.message; - } - if (exception.lineNumber) { - data.lineNumber = exception.lineNumber; - if (exception.columnNumber) { - data.columnNumber = exception.columnNumber; - } - } else if (exception.stack) { - const lineInfoRegexp = /(.*):(\d*)(:)?(\d*)?/g; - const lineInfoGroups = lineInfoRegexp.exec(exception.stack); - if (lineInfoGroups != null && lineInfoGroups.length >= 3) { - if (isUndefined(lineOffset)) { - lineOffset = -2; - } - data.lineNumber = Number(lineInfoGroups[2]) + lineOffset; - if (lineInfoGroups.length >= 5) { - data.columnNumber = Number(lineInfoGroups[4]); - } - } - } - } - } - return data; + return parseException(exception, lineOffset); } public customTranslation(translationValue: string, defaultValue: string): string { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/action/action-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/action/action-widget.models.ts index f4d9cf8d58..38d704d51b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/action/action-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/action/action-widget.models.ts @@ -24,7 +24,6 @@ import { import { WidgetContext } from '@home/models/widget-component.models'; import { BehaviorSubject, forkJoin, Observable, Observer, of, Subscription, throwError } from 'rxjs'; import { catchError, delay, map, share, take } from 'rxjs/operators'; -import { UtilsService } from '@core/services/utils.service'; import { AfterViewInit, ChangeDetectorRef, Directive, Input, OnDestroy, OnInit, TemplateRef } from '@angular/core'; import { DataToValueSettings, @@ -45,6 +44,7 @@ import { ValueType } from '@shared/models/constants'; import { EntityType, entityTypeTranslations } from '@shared/models/entity-type.models'; import { EntityId } from '@shared/models/id/entity-id'; import { isDefinedAndNotNull } from '@core/utils'; +import { parseError } from '@shared/models/error.models'; @Directive() // eslint-disable-next-line @angular-eslint/directive-class-suffix @@ -110,7 +110,7 @@ export abstract class BasicActionWidgetComponent implements OnInit, OnDestroy, A } }, error: (err: any) => { - const message = parseError(this.ctx, err); + const message = parseError(err); this.onError(message); if (valueObserver?.error) { valueObserver.error(err); @@ -152,7 +152,7 @@ export abstract class BasicActionWidgetComponent implements OnInit, OnDestroy, A if (setValueObserver?.error) { setValueObserver.error(err); } - const message = parseError(this.ctx, err); + const message = parseError(err); this.onError(message); } }); @@ -214,7 +214,7 @@ export abstract class ValueAction { protected settings: ValueActionSettings) {} protected handleError(err: any): Error { - const reason = parseError(this.ctx, err); + const reason = parseError(err); let errorMessage = this.ctx.translate.instant('widgets.value-action.error.failed-to-perform-action', {actionLabel: this.settings.actionLabel}); if (reason) { @@ -709,15 +709,12 @@ export class TimeSeriesValueSetter extends TelemetryValueSetter { } -const parseError = (ctx: WidgetContext, err: any): string => - ctx.$injector.get(UtilsService).parseException(err).message || 'Unknown Error'; - const handleRpcError = (ctx: WidgetContext, err: any): Error => { let reason: string; if (ctx.defaultSubscription.rpcErrorText) { reason = ctx.defaultSubscription.rpcErrorText; } else { - reason = parseError(ctx, err); + reason = parseError(err); } return new Error(reason); }; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action.models.ts index 593b11080c..bbb1018982 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action.models.ts @@ -63,8 +63,7 @@ const customActionCompletions: TbEditorCompletions = { type: 'string', description: 'Label of the entity for which the action was triggered.' } - }, - ...serviceCompletions + } }; const customPrettyActionCompletions: TbEditorCompletions = { diff --git a/ui-ngx/src/app/modules/home/pages/admin/resource/js-library-table-config.resolver.ts b/ui-ngx/src/app/modules/home/pages/admin/resource/js-library-table-config.resolver.ts index 5f48532eff..b0fadd53d9 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/resource/js-library-table-config.resolver.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/resource/js-library-table-config.resolver.ts @@ -104,6 +104,7 @@ export class JsLibraryTableConfigResolver { } }; this.config.saveEntity = resource => { + resource.resourceType = ResourceType.JS_MODULE; let saveObservable = this.resourceService.saveResource(resource); if (resource.resourceSubType === ResourceSubType.MODULE) { saveObservable = saveObservable.pipe( diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.models.ts b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.models.ts index cb4a3805f3..5d4afd93fc 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.models.ts +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.models.ts @@ -85,9 +85,7 @@ const widgetEditorCompletions: TbEditorCompletions = { }, ...widgetContextCompletions } - }}, - ...widgetContextCompletions, - ...serviceCompletions + }} }; export const widgetEditorCompleter = new TbEditorCompleter(widgetEditorCompletions); diff --git a/ui-ngx/src/app/shared/components/help-markdown.component.ts b/ui-ngx/src/app/shared/components/help-markdown.component.ts index 79c2476953..c3dab70408 100644 --- a/ui-ngx/src/app/shared/components/help-markdown.component.ts +++ b/ui-ngx/src/app/shared/components/help-markdown.component.ts @@ -21,10 +21,11 @@ import { OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core'; -import { BehaviorSubject } from 'rxjs'; +import { BehaviorSubject, Observable } from 'rxjs'; import { share } from 'rxjs/operators'; import { HelpService } from '@core/services/help.service'; import { coerceBoolean } from '@shared/decorators/coercion'; +import { base64toString } from '@core/utils'; @Component({ selector: 'tb-help-markdown', @@ -37,6 +38,10 @@ export class HelpMarkdownComponent implements OnDestroy, OnInit, OnChanges { @Input() helpContent: string; + @Input() helpContentBase64: string; + + @Input() asyncHelpContent: Observable; + @Input() @coerceBoolean() visible: boolean; @@ -73,7 +78,7 @@ export class HelpMarkdownComponent implements OnDestroy, OnInit, OnChanges { this.loadHelp(); } } - if (propName === 'helpId' || propName === 'helpContent') { + if (['helpId', 'helpContent', 'helpContentBase64', 'asyncHelpContent'].includes(propName)) { this.markdownText.next(null); this.loadHelpWhenVisible(); } @@ -96,6 +101,12 @@ export class HelpMarkdownComponent implements OnDestroy, OnInit, OnChanges { }); } else if (this.helpContent) { this.markdownText.next(this.helpContent); + } else if (this.helpContentBase64) { + this.markdownText.next(base64toString(this.helpContentBase64)); + } else if (this.asyncHelpContent) { + this.asyncHelpContent.subscribe((content) => { + this.markdownText.next(content); + }); } } diff --git a/ui-ngx/src/app/shared/components/help-popup.component.html b/ui-ngx/src/app/shared/components/help-popup.component.html index 8f2d15e69b..177da2e74b 100644 --- a/ui-ngx/src/app/shared/components/help-popup.component.html +++ b/ui-ngx/src/app/shared/components/help-popup.component.html @@ -17,16 +17,20 @@ -->
@@ -34,6 +38,7 @@