From 5b8c8d1aedeb367a65c227db42e6d71d96ca2aa2 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Fri, 4 Apr 2025 16:11:46 +0300 Subject: [PATCH 1/4] UI: Show error for bad xml scada symbols --- .../scada-symbol/scada-symbol.component.ts | 51 ++++++++++--------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.component.ts b/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.component.ts index 955ab16f97..caaf0edc01 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.component.ts +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.component.ts @@ -79,6 +79,7 @@ import { SaveWidgetTypeAsDialogResult } from '@home/pages/widget/save-widget-type-as-dialog.component'; import { WidgetService } from '@core/http/widget.service'; +import { ActionNotificationShow } from '@core/notification/notification.actions'; @Component({ selector: 'tb-scada-symbol', @@ -214,31 +215,35 @@ export class ScadaSymbolComponent extends PageComponent } const metadata: ScadaSymbolMetadata = this.scadaSymbolFormGroup.get('metadata').value; const scadaSymbolContent = this.prepareScadaSymbolContent(metadata); - const file = createFileFromContent(scadaSymbolContent, this.symbolData.imageResource.fileName, - this.symbolData.imageResource.descriptor.mediaType); - const type = imageResourceType(this.symbolData.imageResource); - let imageInfoObservable = - this.imageService.updateImage(type, this.symbolData.imageResource.resourceKey, file); - if (metadata.title !== this.symbolData.imageResource.title) { - imageInfoObservable = imageInfoObservable.pipe( - switchMap(imageInfo => { - imageInfo.title = metadata.title; - return this.imageService.updateImageInfo(imageInfo); - }) - ); - } - imageInfoObservable.pipe( - switchMap(imageInfo => this.imageService.getImageString( + if (scadaSymbolContent.includes('parsererror')) { + this.store.dispatch(new ActionNotificationShow({ message: scadaSymbolContent, type: 'error' })); + } else { + const file = createFileFromContent(scadaSymbolContent, this.symbolData.imageResource.fileName, + this.symbolData.imageResource.descriptor.mediaType); + const type = imageResourceType(this.symbolData.imageResource); + let imageInfoObservable = + this.imageService.updateImage(type, this.symbolData.imageResource.resourceKey, file); + if (metadata.title !== this.symbolData.imageResource.title) { + imageInfoObservable = imageInfoObservable.pipe( + switchMap(imageInfo => { + imageInfo.title = metadata.title; + return this.imageService.updateImageInfo(imageInfo); + }) + ); + } + imageInfoObservable.pipe( + switchMap(imageInfo => this.imageService.getImageString( `${IMAGES_URL_PREFIX}/${type}/${encodeURIComponent(imageInfo.resourceKey)}`).pipe( - map(content => ({ - imageResource: imageInfo, - scadaSymbolContent: content - })) + map(content => ({ + imageResource: imageInfo, + scadaSymbolContent: content + })) )) - ).subscribe(data => { - this.init(data); - this.updateBreadcrumbs.emit(); - }); + ).subscribe(data => { + this.init(data); + this.updateBreadcrumbs.emit(); + }); + } } } From b854dcf0c7242560bbb87d50f3ef6ea6e12e5df1 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Thu, 10 Apr 2025 14:59:11 +0300 Subject: [PATCH 2/4] UI: Refactoring error msg --- .../components/widget/lib/scada/scada-symbol.models.ts | 2 +- .../home/pages/scada-symbol/scada-symbol.component.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol.models.ts index e52c6f9f54..abe570fa3c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol.models.ts @@ -271,7 +271,7 @@ export const updateScadaSymbolMetadataInContent = (svgContent: string, metadata: const svgDoc = new DOMParser().parseFromString(svgContent, 'image/svg+xml'); const parsererror = svgDoc.getElementsByTagName('parsererror'); if (parsererror?.length) { - return parsererror[0].outerHTML; + throw Error(parsererror[0].textContent) } updateScadaSymbolMetadataInDom(svgDoc, metadata); return svgDoc.documentElement.outerHTML; diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.component.ts b/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.component.ts index caaf0edc01..c618380565 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.component.ts +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.component.ts @@ -214,10 +214,8 @@ export class ScadaSymbolComponent extends PageComponent this.editObjectCallbacks.tagsUpdated(tags); } const metadata: ScadaSymbolMetadata = this.scadaSymbolFormGroup.get('metadata').value; - const scadaSymbolContent = this.prepareScadaSymbolContent(metadata); - if (scadaSymbolContent.includes('parsererror')) { - this.store.dispatch(new ActionNotificationShow({ message: scadaSymbolContent, type: 'error' })); - } else { + try { + const scadaSymbolContent = this.prepareScadaSymbolContent(metadata); const file = createFileFromContent(scadaSymbolContent, this.symbolData.imageResource.fileName, this.symbolData.imageResource.descriptor.mediaType); const type = imageResourceType(this.symbolData.imageResource); @@ -243,6 +241,8 @@ export class ScadaSymbolComponent extends PageComponent this.init(data); this.updateBreadcrumbs.emit(); }); + } catch (e) { + this.store.dispatch(new ActionNotificationShow({ message: e.message, type: 'error' })); } } } From 413cc12126796aea78fb6d98d6a7a2ff1113a6db Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Fri, 11 Apr 2025 09:34:44 +0300 Subject: [PATCH 3/4] UI: Handle error on apply preview upload and download --- .../scada-symbol/scada-symbol.component.ts | 96 ++++++++++--------- .../image/upload-image-dialog.component.html | 2 +- .../image/upload-image-dialog.component.ts | 63 +++++++----- 3 files changed, 90 insertions(+), 71 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.component.ts b/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.component.ts index c618380565..a2b47ee811 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.component.ts +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.component.ts @@ -253,43 +253,47 @@ export class ScadaSymbolComponent extends PageComponent enterPreviewMode() { this.previewMetadata = this.scadaSymbolFormGroup.get('metadata').value; - this.symbolData.scadaSymbolContent = this.prepareScadaSymbolContent(this.previewMetadata); - this.previewScadaSymbolObjectSettings = { - behavior: {}, - properties: {} - }; - this.scadaPreviewFormGroup.patchValue({ - scadaSymbolObjectSettings: this.previewScadaSymbolObjectSettings - }, {emitEvent: false}); - this.scadaPreviewFormGroup.markAsPristine(); - const settings: ScadaSymbolWidgetSettings = {...scadaSymbolWidgetDefaultSettings, - ...{ + try { + this.symbolData.scadaSymbolContent = this.prepareScadaSymbolContent(this.previewMetadata); + this.previewScadaSymbolObjectSettings = { + behavior: {}, + properties: {} + }; + this.scadaPreviewFormGroup.patchValue({ + scadaSymbolObjectSettings: this.previewScadaSymbolObjectSettings + }, {emitEvent: false}); + this.scadaPreviewFormGroup.markAsPristine(); + const settings: ScadaSymbolWidgetSettings = {...scadaSymbolWidgetDefaultSettings, + ...{ simulated: true, scadaSymbolUrl: null, scadaSymbolContent: this.symbolData.scadaSymbolContent, scadaSymbolObjectSettings: this.previewScadaSymbolObjectSettings, padding: '0', background: colorBackground('rgba(0,0,0,0)') - } - }; - this.previewWidget = { - typeFullFqn: 'system.scada_symbol', - type: widgetType.rpc, - sizeX: this.previewMetadata.widgetSizeX || 3, - sizeY: this.previewMetadata.widgetSizeY || 3, - row: 0, - col: 0, - config: { - settings, - showTitle: false, - dropShadow: false, - padding: '0', - margin: '0', - backgroundColor: 'rgba(0,0,0,0)' - } - }; - this.previewWidgets = [this.previewWidget]; - this.previewMode = true; + } + }; + this.previewWidget = { + typeFullFqn: 'system.scada_symbol', + type: widgetType.rpc, + sizeX: this.previewMetadata.widgetSizeX || 3, + sizeY: this.previewMetadata.widgetSizeY || 3, + row: 0, + col: 0, + config: { + settings, + showTitle: false, + dropShadow: false, + padding: '0', + margin: '0', + backgroundColor: 'rgba(0,0,0,0)' + } + }; + this.previewWidgets = [this.previewWidget]; + this.previewMode = true; + } catch (e) { + this.store.dispatch(new ActionNotificationShow({ message: e.message, type: 'error' })); + } } exitPreviewMode() { @@ -379,19 +383,23 @@ export class ScadaSymbolComponent extends PageComponent metadata = parseScadaSymbolMetadataFromContent(this.origSymbolData.scadaSymbolContent); } const linkElement = document.createElement('a'); - const scadaSymbolContent = this.prepareScadaSymbolContent(metadata); - const blob = new Blob([scadaSymbolContent], { type: this.symbolData.imageResource.descriptor.mediaType }); - const url = URL.createObjectURL(blob); - linkElement.setAttribute('href', url); - linkElement.setAttribute('download', this.symbolData.imageResource.fileName); - const clickEvent = new MouseEvent('click', - { - view: window, - bubbles: true, - cancelable: false - } - ); - linkElement.dispatchEvent(clickEvent); + try { + const scadaSymbolContent = this.prepareScadaSymbolContent(metadata); + const blob = new Blob([scadaSymbolContent], { type: this.symbolData.imageResource.descriptor.mediaType }); + const url = URL.createObjectURL(blob); + linkElement.setAttribute('href', url); + linkElement.setAttribute('download', this.symbolData.imageResource.fileName); + const clickEvent = new MouseEvent('click', + { + view: window, + bubbles: true, + cancelable: false + } + ); + linkElement.dispatchEvent(clickEvent); + } catch (e) { + this.store.dispatch(new ActionNotificationShow({ message: e.message, type: 'error' })); + } } createWidget() { diff --git a/ui-ngx/src/app/shared/components/image/upload-image-dialog.component.html b/ui-ngx/src/app/shared/components/image/upload-image-dialog.component.html index bbaf7d88ae..11dffb1b25 100644 --- a/ui-ngx/src/app/shared/components/image/upload-image-dialog.component.html +++ b/ui-ngx/src/app/shared/components/image/upload-image-dialog.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+

{{ ( uploadImage ? (isScada ? 'scada.upload-symbol' : 'image.upload-image') : (isScada ? 'scada.update-symbol' : 'image.update-image') ) | translate }}

diff --git a/ui-ngx/src/app/shared/components/image/upload-image-dialog.component.ts b/ui-ngx/src/app/shared/components/image/upload-image-dialog.component.ts index 86bf9c4cd8..779cc021d4 100644 --- a/ui-ngx/src/app/shared/components/image/upload-image-dialog.component.ts +++ b/ui-ngx/src/app/shared/components/image/upload-image-dialog.component.ts @@ -41,6 +41,7 @@ import { updateScadaSymbolMetadataInContent } from '@home/components/widget/lib/scada/scada-symbol.models'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { ActionNotificationShow } from '@core/notification/notification.actions'; export interface UploadImageDialogData { imageSubType: ResourceSubType; @@ -135,38 +136,48 @@ export class UploadImageDialogComponent extends upload(): void { this.submitted = true; let file: File = this.uploadImageFormGroup.get('file').value; - if (this.uploadImage) { - const title: string = this.uploadImageFormGroup.get('title').value; - if (this.isScada) { - if (!this.scadaSymbolMetadata) { - this.scadaSymbolMetadata = emptyMetadata(); - } - if (this.scadaSymbolMetadata.title !== title) { - this.scadaSymbolMetadata.title = title; + try { + if (this.uploadImage) { + const title: string = this.uploadImageFormGroup.get('title').value; + if (this.isScada) { + if (!this.scadaSymbolMetadata) { + this.scadaSymbolMetadata = emptyMetadata(); + } + if (this.scadaSymbolMetadata.title !== title) { + this.scadaSymbolMetadata.title = title; + } + const newContent = updateScadaSymbolMetadataInContent(this.scadaSymbolContent, this.scadaSymbolMetadata); + file = updateFileContent(file, newContent); } - const newContent = updateScadaSymbolMetadataInContent(this.scadaSymbolContent, this.scadaSymbolMetadata); - file = updateFileContent(file, newContent); - } - forkJoin([ - this.imageService.uploadImage(file, title, this.data.imageSubType), - blobToBase64(file) - ]).subscribe(([imageInfo, base64]) => { - this.dialogRef.close({image: Object.assign(imageInfo, {base64})}); - }); - } else { - if (this.isScada) { - blobToText(file).subscribe(scadaSymbolContent => { - this.dialogRef.close({scadaSymbolContent}); - }); - } else { - const image = this.data.image; forkJoin([ - this.imageService.updateImage(imageResourceType(image), image.resourceKey, file), + this.imageService.uploadImage(file, title, this.data.imageSubType), blobToBase64(file) ]).subscribe(([imageInfo, base64]) => { - this.dialogRef.close({image:Object.assign(imageInfo, {base64})}); + this.dialogRef.close({image: Object.assign(imageInfo, {base64})}); }); + } else { + if (this.isScada) { + blobToText(file).subscribe(scadaSymbolContent => { + this.dialogRef.close({scadaSymbolContent}); + }); + } else { + const image = this.data.image; + forkJoin([ + this.imageService.updateImage(imageResourceType(image), image.resourceKey, file), + blobToBase64(file) + ]).subscribe(([imageInfo, base64]) => { + this.dialogRef.close({image:Object.assign(imageInfo, {base64})}); + }); + } } + } catch (e) { + this.store.dispatch(new ActionNotificationShow({ + message: e.message, + type: 'error', + verticalPosition: 'bottom', + horizontalPosition: 'right', + target: 'uploadRoot' + })); } } } From 84778afc0d8ffe4f4ec9524759600516d97ba1f6 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Fri, 11 Apr 2025 10:12:46 +0300 Subject: [PATCH 4/4] UI: Change error position for upload dialog --- .../components/image/upload-image-dialog.component.html | 6 +++--- .../components/image/upload-image-dialog.component.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/shared/components/image/upload-image-dialog.component.html b/ui-ngx/src/app/shared/components/image/upload-image-dialog.component.html index 11dffb1b25..47950e53b7 100644 --- a/ui-ngx/src/app/shared/components/image/upload-image-dialog.component.html +++ b/ui-ngx/src/app/shared/components/image/upload-image-dialog.component.html @@ -15,7 +15,7 @@ limitations under the License. --> - +

{{ ( uploadImage ? (isScada ? 'scada.upload-symbol' : 'image.upload-image') : (isScada ? 'scada.update-symbol' : 'image.update-image') ) | translate }}

@@ -28,8 +28,8 @@
-
-
+
+