Skip to content

Commit

Permalink
fix(attachments): fix PDF display and enable image/PDF opening in new…
Browse files Browse the repository at this point in the history
… tab (#1646)

* feat: enhance attachment handling and styling in dataset detail and file uploader components

* remove empty space in dataset details page and added unit test for the change

* added e2e test

* remove .only

* feat: add max file upload size configuration to app settings and update file uploader component

* implement AttachmentService for handling file attachments in dataset detail and file uploader components

* fix unit test fail

* fix failing unit test

* fix failing test

* fix failing test
  • Loading branch information
Junjiequan authored Nov 12, 2024
1 parent 105552a commit 578a106
Show file tree
Hide file tree
Showing 17 changed files with 376 additions and 67 deletions.
34 changes: 34 additions & 0 deletions cypress/e2e/datasets/datasets-attachment.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,40 @@ describe("Dataset attachments", () => {
);
});

it("should open a new tab when clicking the attachment thumbnail", () => {
cy.visit("/datasets");

cy.get(".dataset-table mat-table mat-header-row").should("exist");

cy.finishedLoading();

cy.get('[data-cy="text-search"] input[type="search"]')
.clear()
.type("Cypress");

cy.isLoading();

cy.get("mat-row").contains("Cypress Dataset").first().click();

cy.isLoading();

cy.get(".mat-mdc-tab-link").contains("Attachments").click();

cy.window().then((win) => {
cy.stub(win, "open").as("open");
});

cy.get('[data-cy="attachment-thumbnail"]').click();

cy.get("@open").should("be.calledWith", Cypress.sinon.match(/blob:.*/));

cy.get(".mat-mdc-tab-link").contains("Details").click();

cy.get('[data-cy="attachment-thumbnail"]').click();

cy.get("@open").should("be.calledWith", Cypress.sinon.match(/blob:.*/));
});

it("should be able to download dataset attachment", () => {
cy.visit("/datasets");

Expand Down
1 change: 1 addition & 0 deletions src/app/app-config.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const appConfig: AppConfig = {
logbookEnabled: true,
loginFormEnabled: true,
thumbnailFetchLimitPerPage: 500,
maxFileUploadSizeInMb: "16mb",
maxDirectDownloadSize: 5000000000,
metadataPreviewEnabled: true,
metadataStructure: "",
Expand Down
1 change: 1 addition & 0 deletions src/app/app-config.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export interface AppConfig {
defaultDatasetsListSettings: DatasetsListSettings;
labelMaps: LabelMaps;
thumbnailFetchLimitPerPage: number;
maxFileUploadSizeInMb?: string;
}

@Injectable()
Expand Down
21 changes: 16 additions & 5 deletions src/app/datasets/dataset-detail/dataset-detail.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
</div>
<div style="clear: both"></div>
<div fxLayout="row" fxLayout.xs="column" *ngIf="dataset">
<div fxFlex="80%">
<div [fxFlex]="(attachments$ | async)?.length > 0 ? '90%' : '100%'">
<mat-card [formGroup]="form" data-cy="general-info">
<mat-card-header class="general-header">
<div mat-card-avatar class="section-icon">
Expand Down Expand Up @@ -437,7 +437,7 @@

<br />

<div *ngIf="show">
<div *ngIf="show" class="jsonViewOverFlow">
<ngx-json-viewer
[json]="datasetWithout$ | async"
[expanded]="false"
Expand All @@ -448,11 +448,22 @@
</mat-card>
</div>

<div fxFlex="30%" *ngIf="attachments$ | async as attachments">
<div
[fxFlex]="(attachments$ | async)?.length > 0 ? '10%' : '0'"
*ngIf="attachments$ | async as attachments"
>
<ng-container *ngFor="let da of attachments">
<mat-card>
<img mat-card-image src="{{ da.thumbnail }}" />
<mat-card-actions>{{ da.caption }}</mat-card-actions>
<img
data-cy="attachment-thumbnail"
mat-card-image
[src]="getImageUrl(da.thumbnail)"
(click)="openAttachment(da.thumbnail)"
class="thumbnail-image"
/>
<mat-card-actions class="caption-text">{{
da.caption
}}</mat-card-actions>
</mat-card>
</ng-container>
</div>
Expand Down
13 changes: 13 additions & 0 deletions src/app/datasets/dataset-detail/dataset-detail.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ mat-card {
vertical-align: middle;
}
}
.caption-text {
word-break: break-all;
}

table {
th {
Expand Down Expand Up @@ -52,3 +55,13 @@ mat-card {
margin: 1em 1em 0 0;
float: right;
}
.attachment-card {
display: flex;
align-items: center;
}
.thumbnail-image {
cursor: pointer;
max-width: 14em; /* Set maximum width */
width: 100%; /* Make it responsive within the card */
height: auto; /* Maintain aspect ratio */
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { ActivatedRoute, Router } from "@angular/router";
import { MockActivatedRoute } from "shared/MockStubs";
import { DialogComponent } from "shared/modules/dialog/dialog.component";
import { AppConfigService } from "app-config.service";
import { AttachmentService } from "shared/services/attachment.service";

describe("DatasetDetailComponent", () => {
let component: DatasetDetailComponent;
Expand Down Expand Up @@ -70,6 +71,7 @@ describe("DatasetDetailComponent", () => {
SharedScicatFrontendModule,
StoreModule.forRoot({}),
],
providers: [AttachmentService],
declarations: [DatasetDetailComponent, DatafilesComponent, LinkyPipe],
});
TestBed.overrideComponent(DatasetDetailComponent, {
Expand Down
17 changes: 17 additions & 0 deletions src/app/datasets/dataset-detail/dataset-detail.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import {
} from "@angular/forms";
import { Message, MessageType } from "state-management/models";
import { DOCUMENT } from "@angular/common";
import { AttachmentService } from "shared/services/attachment.service";

/**
* Component to show details for a data set, using the
Expand Down Expand Up @@ -88,6 +89,7 @@ export class DatasetDetailComponent
constructor(
@Inject(DOCUMENT) private document: Document,
public appConfigService: AppConfigService,
private attachmentService: AttachmentService,
public dialog: MatDialog,
private store: Store,
private router: Router,
Expand Down Expand Up @@ -345,4 +347,19 @@ export class DatasetDetailComponent
);
this.store.dispatch(showMessageAction({ message }));
}
base64MimeType(encoded: string): string {
return this.attachmentService.base64MimeType(encoded);
}

getImageUrl(encoded: string) {
const mimeType = this.base64MimeType(encoded);
if (mimeType === "application/pdf") {
return "assets/images/pdf-icon.svg";
}
return encoded;
}

openAttachment(encoded: string) {
this.attachmentService.openAttachment(encoded);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,16 @@ import {

import { DatasetFileUploaderComponent } from "./dataset-file-uploader.component";
import { SharedScicatFrontendModule } from "shared/shared.module";
import { AppConfigService } from "app-config.service";
import { HttpClient } from "@angular/common/http";
import { MockHttp } from "shared/MockStubs";

const router = {
navigateByUrl: jasmine.createSpy("navigateByUrl"),
};

const getConfig = () => ({});

describe("DatasetFileUploaderComponent", () => {
let component: DatasetFileUploaderComponent;
let fixture: ComponentFixture<DatasetFileUploaderComponent>;
Expand All @@ -25,6 +32,10 @@ describe("DatasetFileUploaderComponent", () => {
await TestBed.configureTestingModule({
declarations: [DatasetFileUploaderComponent],
imports: [SharedScicatFrontendModule, StoreModule.forRoot({})],
providers: [
{ provide: AppConfigService, useValue: { getConfig } },
{ provide: HttpClient, useClass: MockHttp },
],
}).compileComponents();
TestBed.overrideComponent(DatasetFileUploaderComponent, {
set: {
Expand Down
1 change: 1 addition & 0 deletions src/app/datasets/datasets.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ import { DatasetsFilterSettingsComponent } from "./datasets-filter/settings/data
import { CdkDrag, CdkDragHandle, CdkDropList } from "@angular/cdk/drag-drop";
import { FiltersModule } from "shared/modules/filters/filters.module";
import { userReducer } from "state-management/reducers/user.reducer";
import { AttachmentService } from "shared/services/attachment.service";

@NgModule({
imports: [
Expand Down
88 changes: 49 additions & 39 deletions src/app/shared/modules/file-uploader/file-uploader.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -38,44 +38,54 @@
</button>
</mat-card-content>
</mat-card>
<div class="grid-container">
<ng-template ngFor let-attachment [ngForOf]="attachments">
<mat-card class="attachment-card">
<mat-card-content class="attachment-content">
<img
data-cy="attachment-thumbnail"
[src]="getImageUrl(attachment.thumbnail)"
(click)="openAttachment(attachment.thumbnail)"
/>

<ng-template ngFor let-attachment [ngForOf]="attachments">
<mat-card class="attachment-card">
<mat-card-content>
<img src="{{ attachment.thumbnail }}" />

<form (submit)="onSubmitCaption(attachment.id, caption.value)">
<mat-form-field>
<mat-label>Caption</mat-label>
<input
matInput
id="caption"
value="{{ attachment.caption }}"
#caption
/>
</mat-form-field>
<button mat-button type="submit" color="primary" class="submit-button">
Submit
<form (submit)="onSubmitCaption(attachment.id, caption.value)">
<mat-form-field>
<mat-label>Caption</mat-label>
<input
matInput
id="caption"
value="{{ attachment.caption }}"
#caption
/>
</mat-form-field>
<button
mat-stroked-button
type="submit"
color="primary"
class="submit-button"
>
Submit
</button>
</form>
</mat-card-content>
<mat-card-actions>
<button
mat-button
class="download-button"
(click)="onDownloadAttachment(attachment)"
>
<mat-icon>download</mat-icon>
Download
</button>
<button
mat-button
class="delete-button"
(click)="onDeleteAttachment(attachment.id)"
>
<mat-icon>delete</mat-icon>
Remove
</button>
</form>
</mat-card-content>
<mat-card-actions align="end">
<button
mat-button
class="download-button"
(click)="onDownloadAttachment(attachment)"
>
<mat-icon>download</mat-icon>
Download
</button>
<button
mat-button
class="delete-button"
(click)="onDeleteAttachment(attachment.id)"
>
<mat-icon>delete</mat-icon>
Remove
</button>
</mat-card-actions>
</mat-card>
</ng-template>
</mat-card-actions>
</mat-card>
</ng-template>
</div>
30 changes: 21 additions & 9 deletions src/app/shared/modules/file-uploader/file-uploader.component.scss
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
.attachment-card {
width: 22em;
float: left;
margin: 1em 2em 1em 0;
.grid-container {
display: grid;
margin-top: 2em;
grid-template-columns: repeat(auto-fill, minmax(14em, 1fr));
gap: 1em;
}

.grid-item {
display: flex;
flex-direction: column; /* Align content vertically */
height: 100%; /* Ensures the card takes full height */
}

.attachment-card {
img {
width: 20em;
height: 20em;
cursor: pointer;
width: 12em;
height: 14em;
}

button {
float: right;
width: 100%; /* Makes the button fill the width of the parent container */
display: flex; /* Use Flexbox for centering */
justify-content: center; /* Center the text horizontally */
align-items: center; /* Center the text vertically */
}

.submit-button {
Expand Down Expand Up @@ -43,8 +56,7 @@
border: dashed 1px grey;
display: flex;
justify-content: center;
height: 350px;
width: 500px;
height: 14em;

input {
display: none;
Expand Down
Loading

0 comments on commit 578a106

Please sign in to comment.