[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
This commit is contained in:
Mykyta Maliarchuk 2025-04-02 14:07:20 +02:00 committed by GitHub
parent c85245b241
commit 8e0ea373f0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 119 additions and 10 deletions

View File

@ -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)`<any>` | 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

View File

@ -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)`<any>` | 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

View File

@ -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)`>`<br/>
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)`>`<br/>
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`<Blob>`
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`<any>`
Get related content items for passed in Process Instance ID, only metadata for related content is returned:

View File

@ -33,6 +33,7 @@ export class ContentLinkModel {
contentRawUrl: string;
contentBlob: Blob;
thumbnailStatus: string;
sourceId: string;
constructor(obj?: any) {
this.contentAvailable = obj?.contentAvailable;

View File

@ -1,6 +1,6 @@
<div class="adf-viewer__unknown-format-view">
<div>
<mat-icon class="icon">error</mat-icon>
<div class="adf-viewer__unknown-label">{{ 'ADF_VIEWER.UNKNOWN_FORMAT' | translate }}</div>
<div class="adf-viewer__unknown-label">{{ customError || 'ADF_VIEWER.UNKNOWN_FORMAT' | translate }}</div>
</div>
</div>

View File

@ -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<UnknownFormatComponent>;
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);
});
});

View File

@ -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;
}

View File

@ -85,7 +85,7 @@
</ng-container>
<ng-container *ngSwitchDefault>
<adf-viewer-unknown-format />
<adf-viewer-unknown-format [customError]="customError"/>
</ng-container>
</div>
</div>

View File

@ -117,6 +117,10 @@ export class ViewerRenderComponent implements OnChanges, OnInit {
@Input()
viewerTemplateExtensions: TemplateRef<any>;
/** Custom error message to be displayed in the viewer. */
@Input()
customError: string = undefined;
/** Emitted when the filename extension changes. */
@Output()
extensionChange = new EventEmitter<string>();

View File

@ -174,7 +174,8 @@
(isSaving)="allowNavigate = !$event"
[tracks]="tracks"
[viewerTemplateExtensions]="viewerExtensions ?? viewerTemplateExtensions"
[nodeId]="nodeId" />
[nodeId]="nodeId"
[customError]="customError" />
</div>
</div>

View File

@ -244,6 +244,10 @@ export class ViewerComponent<T> 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.
*/

View File

@ -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');

View File

@ -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<Blob> {
return from(this.contentApi.getRawContent(contentId, 'preview')).pipe(catchError((err) => this.handleError(err)));
}
/**
* Gets related content items for a task instance.
*

View File

@ -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);
}