From 8e0ea373f0af8964aa156edb45f100e27a351b28 Mon Sep 17 00:00:00 2001 From: Mykyta Maliarchuk <84377976+nikita-web-ua@users.noreply.github.com> Date: Wed, 2 Apr 2025 14:07:20 +0200 Subject: [PATCH] [ACS-9406] Add getContentRenditionTypePreview to process-content service (#10743) * [ACS-9406] Add getContentRenditionTypePreview to process-content service * [ACS-9406] remove extra space * [ACS-9406] fix unit tests * [ACS-9406] fix unit tests * [ACS-9406] cr fixes --- .../components/viewer-render.component.md | 1 + docs/core/components/viewer.component.md | 1 + docs/core/services/process-content.service.md | 24 ++++++++++ .../widgets/core/content-link.model.ts | 1 + .../unknown-format.component.html | 2 +- .../unknown-format.component.spec.ts | 46 +++++++++++++++++++ .../unknown-format.component.ts | 8 +++- .../viewer-render.component.html | 2 +- .../viewer-render/viewer-render.component.ts | 4 ++ .../viewer/components/viewer.component.html | 3 +- .../lib/viewer/components/viewer.component.ts | 4 ++ .../services/process-content.service.spec.ts | 21 +++++++-- .../form/services/process-content.service.ts | 10 ++++ .../form/widgets/document/content.widget.ts | 2 +- 14 files changed, 119 insertions(+), 10 deletions(-) create mode 100644 lib/core/src/lib/viewer/components/unknown-format/unknown-format.component.spec.ts diff --git a/docs/core/components/viewer-render.component.md b/docs/core/components/viewer-render.component.md index 2d0d7af616..743deb404a 100644 --- a/docs/core/components/viewer-render.component.md +++ b/docs/core/components/viewer-render.component.md @@ -64,6 +64,7 @@ Using with file [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob): | urlFile | `string` | "" | If you want to load an external file that does not come from ACS you can use this URL to specify where to load the file from. | | viewerTemplateExtensions | [`TemplateRef`](https://angular.io/api/core/TemplateRef)`` | null | Template containing ViewerExtensionDirective instances providing different viewer extensions based on supported file extension. | | nodeId | `string` | null | Identifier of a node opened by a viewer. | +| customError | `string` | undefined | Custom error message to be displayed in the viewer. | ### Events diff --git a/docs/core/components/viewer.component.md b/docs/core/components/viewer.component.md index 4a4efb98df..c485c666d1 100644 --- a/docs/core/components/viewer.component.md +++ b/docs/core/components/viewer.component.md @@ -90,6 +90,7 @@ See the [Custom layout](#custom-layout) section for full details of all availabl | viewerExtensions | [`TemplateRef`](https://angular.io/api/core/TemplateRef)`` | null | Template containing ViewerExtensionDirective instances providing different viewer extensions based on supported file extension. | | nodeId | `string` | null | Identifier of a node opened by a viewer. | | nodeMimeType | `string` | undefined | Original node mime type, should be provided when renditiona mime type is different. | +| customError | `string` | undefined | Custom error message to be displayed in the viewer. | ### Events diff --git a/docs/core/services/process-content.service.md b/docs/core/services/process-content.service.md index 81e0dacb45..895f0b2064 100644 --- a/docs/core/services/process-content.service.md +++ b/docs/core/services/process-content.service.md @@ -40,6 +40,10 @@ Manipulates content related to a Process Instance or Task Instance in APS. Gets the thumbnail for a related content file. - _contentId:_ `number` - ID of the related content - **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob)`>` - Binary data of the thumbnail image +- **getContentRenditionTypePreview**(contentId: `number`): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob)`>`
+ Gets the preview rendition for a related content file. + - _contentId:_ `number` - ID of the related content + - **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob)`>` - Binary data of the related content - **getFileContent**(contentId: `number`): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`RelatedContentRepresentation`](https://github.com/Alfresco/alfresco-js-api/blob/master/src/alfresco-activiti-rest-api/docs/RelatedContentRepresentation.md)`>`
Gets the metadata for a related content item. - _contentId:_ `number` - ID of the content item @@ -325,6 +329,26 @@ The response looks like in this sample: See `getProcessRelatedContent` and `getTaskRelatedContent` for how to get to the `contentId`. +#### getContentRenditionTypePreview(contentId: number): Observable`` + +Get the preview type rendition for a related content file. A content file might be for example an +MS Word document. This method would give you the PDF preview for this document, +if it has been generated: + +```ts +const contentId = 1; +this.contentService.getContentRenditionTypePreview(contentId).subscribe( + res => { + console.log('Response Preview BLOB: ', res); + }, error => { + console.log('Error: ', error); + }); +``` + +The preview BLOB response looks something like this: + +`Blob(44101) {size: 44101, type: "application/pdf"}` + #### getProcessRelatedContent(processId: string): Observable`` Get related content items for passed in Process Instance ID, only metadata for related content is returned: diff --git a/lib/core/src/lib/form/components/widgets/core/content-link.model.ts b/lib/core/src/lib/form/components/widgets/core/content-link.model.ts index e8ad37f0d4..ce8987b920 100644 --- a/lib/core/src/lib/form/components/widgets/core/content-link.model.ts +++ b/lib/core/src/lib/form/components/widgets/core/content-link.model.ts @@ -33,6 +33,7 @@ export class ContentLinkModel { contentRawUrl: string; contentBlob: Blob; thumbnailStatus: string; + sourceId: string; constructor(obj?: any) { this.contentAvailable = obj?.contentAvailable; diff --git a/lib/core/src/lib/viewer/components/unknown-format/unknown-format.component.html b/lib/core/src/lib/viewer/components/unknown-format/unknown-format.component.html index 457f290e8a..ff8ad3a9b8 100644 --- a/lib/core/src/lib/viewer/components/unknown-format/unknown-format.component.html +++ b/lib/core/src/lib/viewer/components/unknown-format/unknown-format.component.html @@ -1,6 +1,6 @@
error -
{{ 'ADF_VIEWER.UNKNOWN_FORMAT' | translate }}
+
{{ customError || 'ADF_VIEWER.UNKNOWN_FORMAT' | translate }}
diff --git a/lib/core/src/lib/viewer/components/unknown-format/unknown-format.component.spec.ts b/lib/core/src/lib/viewer/components/unknown-format/unknown-format.component.spec.ts new file mode 100644 index 0000000000..6fcccd8a85 --- /dev/null +++ b/lib/core/src/lib/viewer/components/unknown-format/unknown-format.component.spec.ts @@ -0,0 +1,46 @@ +/*! + * @license + * Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * 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 { UnknownFormatComponent } from './unknown-format.component'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { CoreTestingModule } from '@alfresco/adf-core'; + +describe('Unknown Format Component', () => { + let fixture: ComponentFixture; + + const getErrorMessageElement = (): string => fixture.debugElement.nativeElement.querySelector('.adf-viewer__unknown-label').innerText; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [CoreTestingModule] + }); + fixture = TestBed.createComponent(UnknownFormatComponent); + fixture.detectChanges(); + }); + + it('should render default error message', () => { + expect(getErrorMessageElement()).toBe('ADF_VIEWER.UNKNOWN_FORMAT'); + }); + + it('should render custom error message if such provided', () => { + const errorMessage = 'Custom error message'; + fixture.componentInstance.customError = errorMessage; + + fixture.detectChanges(); + expect(getErrorMessageElement()).toBe(errorMessage); + }); +}); diff --git a/lib/core/src/lib/viewer/components/unknown-format/unknown-format.component.ts b/lib/core/src/lib/viewer/components/unknown-format/unknown-format.component.ts index dc6465be2a..565d364a6a 100644 --- a/lib/core/src/lib/viewer/components/unknown-format/unknown-format.component.ts +++ b/lib/core/src/lib/viewer/components/unknown-format/unknown-format.component.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { Component, ViewEncapsulation } from '@angular/core'; +import { Component, Input, ViewEncapsulation } from '@angular/core'; import { MatIconModule } from '@angular/material/icon'; import { TranslateModule } from '@ngx-translate/core'; @@ -27,4 +27,8 @@ import { TranslateModule } from '@ngx-translate/core'; imports: [MatIconModule, TranslateModule], encapsulation: ViewEncapsulation.None }) -export class UnknownFormatComponent {} +export class UnknownFormatComponent { + /** Custom error message to be displayed . */ + @Input() + customError: string; +} diff --git a/lib/core/src/lib/viewer/components/viewer-render/viewer-render.component.html b/lib/core/src/lib/viewer/components/viewer-render/viewer-render.component.html index c255968a8f..38d9d8affd 100644 --- a/lib/core/src/lib/viewer/components/viewer-render/viewer-render.component.html +++ b/lib/core/src/lib/viewer/components/viewer-render/viewer-render.component.html @@ -85,7 +85,7 @@ - + diff --git a/lib/core/src/lib/viewer/components/viewer-render/viewer-render.component.ts b/lib/core/src/lib/viewer/components/viewer-render/viewer-render.component.ts index c7439cdd55..316e7648b3 100644 --- a/lib/core/src/lib/viewer/components/viewer-render/viewer-render.component.ts +++ b/lib/core/src/lib/viewer/components/viewer-render/viewer-render.component.ts @@ -117,6 +117,10 @@ export class ViewerRenderComponent implements OnChanges, OnInit { @Input() viewerTemplateExtensions: TemplateRef; + /** Custom error message to be displayed in the viewer. */ + @Input() + customError: string = undefined; + /** Emitted when the filename extension changes. */ @Output() extensionChange = new EventEmitter(); diff --git a/lib/core/src/lib/viewer/components/viewer.component.html b/lib/core/src/lib/viewer/components/viewer.component.html index 8af0af85e0..63517a6736 100644 --- a/lib/core/src/lib/viewer/components/viewer.component.html +++ b/lib/core/src/lib/viewer/components/viewer.component.html @@ -174,7 +174,8 @@ (isSaving)="allowNavigate = !$event" [tracks]="tracks" [viewerTemplateExtensions]="viewerExtensions ?? viewerTemplateExtensions" - [nodeId]="nodeId" /> + [nodeId]="nodeId" + [customError]="customError" /> diff --git a/lib/core/src/lib/viewer/components/viewer.component.ts b/lib/core/src/lib/viewer/components/viewer.component.ts index f4eebfe808..dce8eeb721 100644 --- a/lib/core/src/lib/viewer/components/viewer.component.ts +++ b/lib/core/src/lib/viewer/components/viewer.component.ts @@ -244,6 +244,10 @@ export class ViewerComponent implements OnDestroy, OnInit, OnChanges { @Input() nodeMimeType: string = undefined; + /** Custom error message to be displayed in the viewer. */ + @Input() + customError: string = undefined; + /** * Enable dialog box to allow user to download the previewed file, in case the preview is not responding for a set period of time. */ diff --git a/lib/process-services/src/lib/form/services/process-content.service.spec.ts b/lib/process-services/src/lib/form/services/process-content.service.spec.ts index c4c21cea48..dcfad50ea8 100644 --- a/lib/process-services/src/lib/form/services/process-content.service.spec.ts +++ b/lib/process-services/src/lib/form/services/process-content.service.spec.ts @@ -16,7 +16,6 @@ */ import { TestBed } from '@angular/core/testing'; -import { of } from 'rxjs'; import { ProcessContentService } from './process-content.service'; import { CoreTestingModule } from '@alfresco/adf-core'; import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-content-services'; @@ -176,10 +175,24 @@ describe('ProcessContentService', () => { }); it('should return a Blob as thumbnail', (done) => { - const contentId: number = 999; - const blob = createFakeBlob(); - spyOn(service, 'getContentThumbnail').and.returnValue(of(blob)); + const contentId = 999; + spyOn(service.contentApi, 'getRawContent').and.returnValue(Promise.resolve(createFakeBlob())); + service.getContentThumbnail(contentId).subscribe((result) => { + expect(service.contentApi.getRawContent).toHaveBeenCalledWith(contentId, 'thumbnail'); + expect(result).toEqual(jasmine.any(Blob)); + expect(result.size).toEqual(48); + expect(result.type).toEqual('image/png'); + done(); + }); + }); + + it('should return a Blob as preview', (done) => { + const contentId = 999; + spyOn(service.contentApi, 'getRawContent').and.returnValue(Promise.resolve(createFakeBlob())); + + service.getContentRenditionTypePreview(contentId).subscribe((result) => { + expect(service.contentApi.getRawContent).toHaveBeenCalledWith(contentId, 'preview'); expect(result).toEqual(jasmine.any(Blob)); expect(result.size).toEqual(48); expect(result.type).toEqual('image/png'); diff --git a/lib/process-services/src/lib/form/services/process-content.service.ts b/lib/process-services/src/lib/form/services/process-content.service.ts index cf70d65262..36b3233db4 100644 --- a/lib/process-services/src/lib/form/services/process-content.service.ts +++ b/lib/process-services/src/lib/form/services/process-content.service.ts @@ -120,6 +120,16 @@ export class ProcessContentService { return from(this.contentApi.getRawContent(contentId, 'thumbnail')).pipe(catchError((err) => this.handleError(err))); } + /** + * Gets the preview rendition for a related content file. + * + * @param contentId ID of the related content + * @returns Binary data of the related content + */ + getContentRenditionTypePreview(contentId: number): Observable { + return from(this.contentApi.getRawContent(contentId, 'preview')).pipe(catchError((err) => this.handleError(err))); + } + /** * Gets related content items for a task instance. * diff --git a/lib/process-services/src/lib/form/widgets/document/content.widget.ts b/lib/process-services/src/lib/form/widgets/document/content.widget.ts index af648a4ea2..44005282e8 100644 --- a/lib/process-services/src/lib/form/widgets/document/content.widget.ts +++ b/lib/process-services/src/lib/form/widgets/document/content.widget.ts @@ -112,7 +112,7 @@ export class ContentWidgetComponent implements OnChanges { } openViewer(content: ContentLinkModel): void { - let fetch = this.processContentService.getContentPreview(content.id); + let fetch = this.processContentService.getContentRenditionTypePreview(content.id); if (content.isTypeImage() || content.isTypePdf()) { fetch = this.processContentService.getFileRawContent(content.id); }