[ACS-9250] Adjust viewer to display properly under parent without overlay mode (#10950)

This commit is contained in:
MichalKinas 2025-06-20 17:46:29 +02:00 committed by GitHub
parent 27502d5d67
commit c16417cbff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 127 additions and 14 deletions

View File

@ -116,7 +116,8 @@ export class CustomResourcesService {
'-TYPE:"fm:topic"', '-TYPE:"fm:topic"',
'-TYPE:"fm:post"', '-TYPE:"fm:post"',
'-TYPE:"ia:calendarEvent"', '-TYPE:"ia:calendarEvent"',
'-TYPE:"lnk:link"' '-TYPE:"lnk:link"',
'-ASPECT:"app:linked"'
]; ];
return new Observable((observer) => { return new Observable((observer) => {

View File

@ -51,7 +51,7 @@ export abstract class InfiniteScrollDatasource<T> extends DataSource<T> {
if (this.batchesFetched * this.batchSize <= range.end) { if (this.batchesFetched * this.batchSize <= range.end) {
forkJoin([ forkJoin([
this.dataStream.asObservable().pipe(take(1)), this.dataStream.asObservable().pipe(take(1)),
this.getNextBatch({ skipCount: this.batchSize * this.batchesFetched, maxItems: this.batchSize }).pipe( this.getNextBatch({ skipCount: this._itemsCount, maxItems: this.batchSize }).pipe(
take(1), take(1),
tap((nextBatch) => (this._itemsCount += nextBatch.length)) tap((nextBatch) => (this._itemsCount += nextBatch.length))
) )

View File

@ -23,7 +23,8 @@
[nodeMimeType]="nodeMimeType" [nodeMimeType]="nodeMimeType"
[urlFile]="urlFileContent" [urlFile]="urlFileContent"
[tracks]="tracks" [tracks]="tracks"
[readOnly]="readOnly" [readOnly]="readOnly || !canEditNode"
[showToolbarDividers]="showToolbarDividers"
[allowedEditActions]="allowedEditActions" [allowedEditActions]="allowedEditActions"
[viewerExtensions]="viewerExtensions" [viewerExtensions]="viewerExtensions"
[nodeId]="nodeId" [nodeId]="nodeId"
@ -53,7 +54,7 @@
<ng-content select="adf-viewer-sidebar" /> <ng-content select="adf-viewer-sidebar" />
</adf-viewer-sidebar> </adf-viewer-sidebar>
<adf-viewer-toolbar-custom-actions> <adf-viewer-toolbar-custom-actions *ngIf="allowDownload || allowPrint">
<button id="adf-alfresco-viewer-download" <button id="adf-alfresco-viewer-download"
*ngIf="allowDownload" *ngIf="allowDownload"
mat-icon-button mat-icon-button

View File

@ -874,10 +874,11 @@ describe('AlfrescoViewerComponent', () => {
}); });
describe('Events', () => { describe('Events', () => {
it('should update version when emitted by image-viewer and user has update permissions', () => { it('should update version when emitted by image-viewer when user has update permissions and read only is set to false', () => {
spyOn(uploadService, 'uploadFilesInTheQueue').and.callFake(() => {}); spyOn(uploadService, 'uploadFilesInTheQueue').and.callFake(() => {});
spyOn(uploadService, 'addToQueue'); spyOn(uploadService, 'addToQueue');
component.readOnly = false; component.readOnly = false;
component.canEditNode = true;
component.nodeEntry = new NodeEntry({ component.nodeEntry = new NodeEntry({
entry: new Node({ name: 'fakeImage.png', id: '12', content: new ContentInfo({ mimeType: 'img/png' }) }) entry: new Node({ name: 'fakeImage.png', id: '12', content: new ContentInfo({ mimeType: 'img/png' }) })
}); });
@ -899,13 +900,31 @@ describe('AlfrescoViewerComponent', () => {
component.onSubmitFile(fakeBlob); component.onSubmitFile(fakeBlob);
fixture.detectChanges(); fixture.detectChanges();
expect(component.canEditNode).toBe(true);
expect(uploadService.addToQueue).toHaveBeenCalledWith(...[newFile]); expect(uploadService.addToQueue).toHaveBeenCalledWith(...[newFile]);
expect(uploadService.uploadFilesInTheQueue).toHaveBeenCalled(); expect(uploadService.uploadFilesInTheQueue).toHaveBeenCalled();
}); });
it('should not update version when emitted by image-viewer and user doesn`t have update permissions', () => { it('should not update version when emitted by image-viewer when user doesn`t have update permissions', () => {
spyOn(uploadService, 'uploadFilesInTheQueue').and.callFake(() => {});
component.readOnly = false;
component.canEditNode = false;
component.nodeEntry = new NodeEntry({
entry: new Node({ name: 'fakeImage.png', id: '12', content: new ContentInfo({ mimeType: 'img/png' }) })
});
const data = atob('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==');
const fakeBlob = new Blob([data], { type: 'image/png' });
component.onSubmitFile(fakeBlob);
fixture.detectChanges();
expect(uploadService.uploadFilesInTheQueue).not.toHaveBeenCalled();
});
it('should not update version when emitted by image-viewer when user has update permissions and viewer is in read only mode', () => {
spyOn(uploadService, 'uploadFilesInTheQueue').and.callFake(() => {}); spyOn(uploadService, 'uploadFilesInTheQueue').and.callFake(() => {});
component.readOnly = true; component.readOnly = true;
component.canEditNode = true;
component.nodeEntry = new NodeEntry({ component.nodeEntry = new NodeEntry({
entry: new Node({ name: 'fakeImage.png', id: '12', content: new ContentInfo({ mimeType: 'img/png' }) }) entry: new Node({ name: 'fakeImage.png', id: '12', content: new ContentInfo({ mimeType: 'img/png' }) })
}); });

View File

@ -189,6 +189,14 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit {
@Input() @Input()
sidebarLeftTemplate: TemplateRef<any> = null; sidebarLeftTemplate: TemplateRef<any> = null;
/** Should viewer work in read only mode */
@Input()
readOnly = false;
/** Toggles dividers visibility */
@Input()
showToolbarDividers = true;
/** Emitted when the shared link used is not valid. */ /** Emitted when the shared link used is not valid. */
@Output() @Output()
invalidSharedLink = new EventEmitter<void>(); invalidSharedLink = new EventEmitter<void>();
@ -214,7 +222,7 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit {
nodeMimeType: string; nodeMimeType: string;
nodeEntry: NodeEntry; nodeEntry: NodeEntry;
tracks: Track[] = []; tracks: Track[] = [];
readOnly: boolean = true; canEditNode: boolean = false;
allowedEditActions: { [key: string]: boolean } = { allowedEditActions: { [key: string]: boolean } = {
rotate: true, rotate: true,
crop: true crop: true
@ -316,7 +324,7 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit {
} }
private async setUpNodeFile(nodeData: Node, versionData?: Version): Promise<void> { private async setUpNodeFile(nodeData: Node, versionData?: Version): Promise<void> {
this.readOnly = !this.contentService.hasAllowableOperations(nodeData, 'update'); this.canEditNode = this.contentService.hasAllowableOperations(nodeData, 'update');
let mimeType: string; let mimeType: string;
let nodeMimeType: string; let nodeMimeType: string;
let urlFileContent: string; let urlFileContent: string;
@ -420,7 +428,7 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit {
} }
onSubmitFile(newImageBlob: Blob) { onSubmitFile(newImageBlob: Blob) {
if (this?.nodeEntry?.entry?.id && !this.readOnly) { if (this?.nodeEntry?.entry?.id && !this.readOnly && this.canEditNode) {
const newImageFile: File = new File([newImageBlob], this?.nodeEntry?.entry?.name, { type: this?.nodeEntry?.entry?.content?.mimeType }); const newImageFile: File = new File([newImageBlob], this?.nodeEntry?.entry?.name, { type: this?.nodeEntry?.entry?.content?.mimeType });
const newFile = new FileModel( const newFile = new FileModel(
newImageFile, newImageFile,

View File

@ -20,12 +20,14 @@ import { DataRow } from './data-row.model';
// Simple implementation of the DataRow interface. // Simple implementation of the DataRow interface.
export class ObjectDataRow implements DataRow { export class ObjectDataRow implements DataRow {
constructor(private obj: any, public isSelected: boolean = false, public isSelectable: boolean = true) { constructor(private obj: any, public isSelected: boolean = false, public isSelectable: boolean = true) {
if (!obj) { if (!obj) {
throw new Error('Object source not found'); throw new Error('Object source not found');
} }
}
getSourceObject(): any {
return this.obj;
} }
getValue(key: string): any { getValue(key: string): any {

View File

@ -64,3 +64,13 @@
} }
} }
} }
.adf-viewer-inline {
.adf-image-viewer {
height: 100%;
.adf-image-container {
height: 100%;
}
}
}

View File

@ -7,3 +7,7 @@
justify-content: center; justify-content: center;
color: var(--adf-theme-foreground-text-color); color: var(--adf-theme-foreground-text-color);
} }
.adf-viewer-inline .adf-viewer__unknown-format-view {
height: 100%;
}

View File

@ -86,3 +86,19 @@
display: contents; display: contents;
} }
} }
.adf-viewer-inline {
.adf-viewer-render {
&-main-loader {
position: unset;
}
&-layout-content > div {
height: 100%;
}
&__loading-screen {
height: 100%;
}
}
}

View File

@ -78,7 +78,9 @@
</mat-menu> </mat-menu>
</ng-container> </ng-container>
<adf-toolbar-divider /> @if (showToolbarDividers) {
<adf-toolbar-divider />
}
<ng-content select="adf-viewer-toolbar-custom-actions" /> <ng-content select="adf-viewer-toolbar-custom-actions" />
@ -123,8 +125,9 @@
</ng-container> </ng-container>
<ng-container *ngIf="allowGoBack && closeButtonPosition === CloseButtonPosition.Right"> <ng-container *ngIf="allowGoBack && closeButtonPosition === CloseButtonPosition.Right">
<adf-toolbar-divider /> @if (showToolbarDividers) {
<adf-toolbar-divider />
}
<button class="adf-viewer-close-button" <button class="adf-viewer-close-button"
data-automation-id="adf-toolbar-right-back" data-automation-id="adf-toolbar-right-back"
[attr.aria-label]="'ADF_VIEWER.ACTIONS.CLOSE' | translate" [attr.aria-label]="'ADF_VIEWER.ACTIONS.CLOSE' | translate"

View File

@ -53,6 +53,18 @@
} }
} }
&-inline {
display: flex;
width: 100%;
height: 100%;
position: unset;
.adf-viewer__file-title {
position: unset;
transform: unset;
}
}
&__display-name { &__display-name {
font-size: var(--theme-subheading-2-font-size); font-size: var(--theme-subheading-2-font-size);
line-height: 1.5; line-height: 1.5;

View File

@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, SimpleChanges } from '@angular/core'; import { Component, DebugElement, SimpleChanges } from '@angular/core';
import { ComponentFixture, discardPeriodicTasks, fakeAsync, flush, TestBed, tick } from '@angular/core/testing'; import { ComponentFixture, discardPeriodicTasks, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
@ -52,6 +52,7 @@ describe('ViewerComponent', () => {
let testingUtils: UnitTestingUtils; let testingUtils: UnitTestingUtils;
const getFileName = (): string => testingUtils.getByCSS('#adf-viewer-display-name').nativeElement.textContent; const getFileName = (): string => testingUtils.getByCSS('#adf-viewer-display-name').nativeElement.textContent;
const getDividers = (): DebugElement[] => testingUtils.getAllByCSS('.adf-toolbar-divider');
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
@ -364,6 +365,32 @@ describe('ViewerComponent', () => {
done(); done();
}); });
}); });
it('should display two toolbar dividers by default when close button is visible', () => {
component.allowGoBack = true;
component.showToolbar = true;
component.closeButtonPosition = CloseButtonPosition.Right;
fixture.detectChanges();
const dividers = getDividers();
expect(dividers.length).toBe(2);
});
it('should display only one toolbar divider when close button is hidden', () => {
component.allowGoBack = false;
component.showToolbar = true;
fixture.detectChanges();
const dividers = getDividers();
expect(dividers.length).toBe(1);
});
it('should not display any toolbar dividers when showToolbarDividers param is set to false', () => {
component.showToolbarDividers = false;
component.showToolbar = true;
component.allowGoBack = true;
fixture.detectChanges();
const dividers = getDividers();
expect(dividers.length).toBe(0);
});
}); });
describe('Base component', () => { describe('Base component', () => {

View File

@ -23,6 +23,7 @@ import {
DestroyRef, DestroyRef,
ElementRef, ElementRef,
EventEmitter, EventEmitter,
HostBinding,
HostListener, HostListener,
inject, inject,
Input, Input,
@ -95,6 +96,11 @@ const DEFAULT_NON_PREVIEW_CONFIG = {
export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges { export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
private thumbnailService = inject(ThumbnailService); private thumbnailService = inject(ThumbnailService);
@HostBinding('class.adf-viewer-inline')
get isInline() {
return !this.overlayMode;
}
@ContentChild(ViewerToolbarComponent) @ContentChild(ViewerToolbarComponent)
toolbar: ViewerToolbarComponent; toolbar: ViewerToolbarComponent;
@ -248,6 +254,10 @@ export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
@Input() @Input()
customError: string = undefined; customError: string = undefined;
/** Toggles dividers visibility */
@Input()
showToolbarDividers = true;
/** /**
* Enable dialog box to allow user to download the previewed file, in case the preview is not responding for a set period of time. * Enable dialog box to allow user to download the previewed file, in case the preview is not responding for a set period of time.
*/ */