Skip to content

Commit

Permalink
fix: fixed and improved some user interface issues. (#1666)
Browse files Browse the repository at this point in the history
* disabled sample edit

* enhanced large file download instructions and update config

* commented out sample edit test

* fix the issue of the red cross icon appearing for PDF images in the dataset table

* fix for thumbnail image being cut off

* fixes based on AI PR review

* added unit test for the change

* rename for large file message function

* fix based on comments

* fix failing test

---------

Co-authored-by: Martin <[email protected]>
Co-authored-by: Max Novelli <[email protected]>
  • Loading branch information
3 people authored Nov 28, 2024
1 parent 5f490c0 commit 0d37dfb
Show file tree
Hide file tree
Showing 16 changed files with 95 additions and 91 deletions.
2 changes: 2 additions & 0 deletions src/app/app-config.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ const appConfig: AppConfig = {
searchPublicDataEnabled: true,
searchSamples: true,
sftpHost: "login.esss.dk",
sourceFolder: "default",
maxFileSizeWarning: "Some files are above the max size",
shareEnabled: true,
shoppingCartEnabled: true,
shoppingCartOnHeader: true,
Expand Down
2 changes: 2 additions & 0 deletions src/app/app-config.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ export interface AppConfig {
searchPublicDataEnabled: boolean;
searchSamples: boolean;
sftpHost: string | null;
sourceFolder?: string;
maxFileSizeWarning?: string;
shareEnabled: boolean;
shoppingCartEnabled: boolean;
shoppingCartOnHeader: boolean;
Expand Down
1 change: 0 additions & 1 deletion src/app/datasets/dashboard/dashboard.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ export class DashboardComponent implements OnInit, OnDestroy {
subscriptions: Subscription[] = [];

appConfig = this.appConfigService.getConfig();

currentUser: User = new User();
userGroups: string[] = [];
clearColumnSearch = false;
Expand Down
15 changes: 3 additions & 12 deletions src/app/datasets/datafiles/datafiles.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,7 @@
<ng-template [ngIf]="maxFileSize && tooLargeFile">
<span>
<mat-icon class="warning-icon"> warning </mat-icon>
One or more files are too large to be downloaded directly.
{{
sftpHost
? "These files are available via sftp host " +
sftpHost +
" in directory " +
sourcefolder +
"."
: ""
}}
<span [innerHTML]="hasFileAboveMaxSizeWarning()"></span>
</span>
</ng-template>

Expand Down Expand Up @@ -54,7 +45,7 @@ <h3>No files associated to this dataset</h3>
<input type="hidden" name="auth_token" [value]="auth_token" />
<input type="hidden" name="jwt" [value]="jwt?.jwt" />
<input type="hidden" name="dataset" [value]="datasetPid" />
<input type="hidden" name="directory" [value]="sourcefolder" />
<input type="hidden" name="directory" [value]="sourceFolder" />
<input
*ngFor="let file of getAllFiles(); index as i"
type="hidden"
Expand Down Expand Up @@ -86,7 +77,7 @@ <h3>No files associated to this dataset</h3>
<input type="hidden" name="jwt" [value]="jwt?.jwt" />
<input type="hidden" name="auth_token" [value]="auth_token" />
<input type="hidden" name="dataset" [value]="datasetPid" />
<input type="hidden" name="directory" [value]="sourcefolder" />
<input type="hidden" name="directory" [value]="sourceFolder" />
<input
*ngFor="let file of getSelectedFiles(); index as i"
type="hidden"
Expand Down
4 changes: 3 additions & 1 deletion src/app/datasets/datafiles/datafiles.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { MatButtonModule } from "@angular/material/button";
import { AppConfigService } from "app-config.service";
import { MatDialogModule, MatDialogRef } from "@angular/material/dialog";
import { DatafilesActionsComponent } from "datasets/datafiles-actions/datafiles-actions.component";
import { FileSizePipe } from "shared/pipes/filesize.pipe";

describe("DatafilesComponent", () => {
let component: DatafilesComponent;
Expand Down Expand Up @@ -100,6 +101,7 @@ describe("DatafilesComponent", () => {
provide: DatafilesActionsComponent,
useClass: MockDatafilesActionsComponent,
},
{ provide: FileSizePipe },
],
},
});
Expand Down Expand Up @@ -140,7 +142,7 @@ describe("DatafilesComponent", () => {
},
];
component.tableData = component.files;
component.sourcefolder = "/test/";
component.sourceFolder = "/test/";
fixture.detectChanges();
});

Expand Down
42 changes: 38 additions & 4 deletions src/app/datasets/datafiles/datafiles.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ export class DatafilesComponent
subscriptions: Subscription[] = [];

files: Array<any> = [];
sourcefolder = "";
datasetPid = "";
actionDataset: ActionDataset;

Expand All @@ -76,7 +75,12 @@ export class DatafilesComponent
this.appConfig.fileserverButtonLabel || "Download";
multipleDownloadAction: string | null = this.appConfig.multipleDownloadAction;
maxFileSize: number | null = this.appConfig.maxDirectDownloadSize;
sftpHost: string | null = this.appConfig.sftpHost;
sourceFolder: string =
this.appConfig.sourceFolder || "No source folder provided";
sftpHost: string = this.appConfig.sftpHost || "No sftp host provided";
maxFileSizeWarning: string | null =
this.appConfig.maxFileSizeWarning ||
`Some files are above the max size ${this.fileSizePipe.transform(this.maxFileSize)}`;
jwt: any;
auth_token: any;

Expand Down Expand Up @@ -110,6 +114,7 @@ export class DatafilesComponent
private store: Store,
private cdRef: ChangeDetectorRef,
private dialog: MatDialog,
private fileSizePipe: FileSizePipe,
private userApi: UserApi,
) {}

Expand Down Expand Up @@ -204,11 +209,40 @@ export class DatafilesComponent
}
}

hasFileAboveMaxSizeWarning() {
/**
* Template for a file size warning message.
* Placeholders:
* - <maxDirectDownloadSize>: Maximum file size allowed (e.g., "10 MB").
* - <sftpHost>: SFTP host for downloading large files.
* - <sourceFolder>: Directory path on the SFTP host.
*
* Example usage:
* Some files are above <maxDirectDownloadSize>. These file can be accessed via sftp host: <sftpHost> in directory: <sourceFolder>
*/

const valueMapping = {
sftpHost: this.sftpHost,
sourceFolder: this.sourceFolder,
maxDirectDownloadSize: this.fileSizePipe.transform(this.maxFileSize),
};

let warning = this.maxFileSizeWarning;

Object.keys(valueMapping).forEach((key) => {
warning = warning.replace(
"<" + key + ">",
`<strong>${valueMapping[key]}</strong>`,
);
});

return warning;
}
ngAfterViewInit() {
this.subscriptions.push(
this.dataset$.subscribe((dataset) => {
if (dataset) {
this.sourcefolder = dataset.sourceFolder;
this.sourceFolder = dataset.sourceFolder;
this.datasetPid = dataset.pid;
this.actionDataset = <ActionDataset>dataset;
}
Expand Down Expand Up @@ -287,7 +321,7 @@ export class DatafilesComponent
return (
this.fileserverBaseURL +
"&origin_path=" +
encodeURIComponent(this.sourcefolder)
encodeURIComponent(this.sourceFolder)
);
}
}
7 changes: 0 additions & 7 deletions src/app/datasets/dataset-detail/dataset-detail.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -268,13 +268,6 @@
<a (click)="onClickSample(sample.sampleId)">
<span>{{ sample.description }}</span>
</a>
<span
class="sample-edit"
(click)="openSampleEditDialog()"
*ngIf="appConfig.editDatasetSampleEnabled && editingAllowed"
>
<mat-icon>edit</mat-icon>
</span>
</td>
</tr>
<tr *ngIf="dataset['instrumentId'] && instrument">
Expand Down
28 changes: 0 additions & 28 deletions src/app/datasets/dataset-detail/dataset-detail.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -341,34 +341,6 @@ describe("DatasetDetailComponent", () => {
});
});

describe("#openSampleEditDialog()", () => {
it("should open the sample edit dialog and dispatch updatePropertyAction", () => {
const dispatchSpy = spyOn(store, "dispatch");
component.dataset = new Dataset();
component.dataset.ownerGroup = "test";
component.sample = new Sample();
const sampleId = "testId";
component.sample.sampleId = sampleId;
const pid = "testPid";
component.dataset.pid = pid;
const property = { sampleId };
const dialogOpenSpy = spyOn(component.dialog, "open").and.returnValue({
afterClosed: () => of({ sample: { sampleId: "testId" } }),
} as MatDialogRef<SampleEditComponent>);
component.openSampleEditDialog();

expect(dialogOpenSpy).toHaveBeenCalledTimes(1);
expect(dialogOpenSpy).toHaveBeenCalledWith(SampleEditComponent, {
width: "1000px",
data: { ownerGroup: "test", sampleId: "testId" },
});
expect(dispatchSpy).toHaveBeenCalledTimes(1);
expect(dispatchSpy).toHaveBeenCalledWith(
updatePropertyAction({ pid, property }),
);
});
});

describe("#onSaveMetadata()", () => {
it("should dispatch an updatePropertyAction", () => {
const dispatchSpy = spyOn(store, "dispatch");
Expand Down
31 changes: 2 additions & 29 deletions src/app/datasets/dataset-detail/dataset-detail.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ENTER, COMMA, SPACE } from "@angular/cdk/keycodes";
import { MatChipInputEvent } from "@angular/material/chips";

import { MatDialog } from "@angular/material/dialog";
import { SampleEditComponent } from "datasets/sample-edit/sample-edit.component";
// import { SampleEditComponent } from "datasets/sample-edit/sample-edit.component";
import { DialogComponent } from "shared/modules/dialog/dialog.component";
import { combineLatest, fromEvent, Observable, Subscription } from "rxjs";
import { Store } from "@ngrx/store";
Expand Down Expand Up @@ -277,29 +277,6 @@ export class DatasetDetailComponent
this.router.navigateByUrl("/samples/" + id);
}

openSampleEditDialog() {
if (this.dataset) {
this.dialog
.open(SampleEditComponent, {
width: "1000px",
data: {
ownerGroup: this.dataset.ownerGroup,
sampleId: this.sample?.sampleId,
},
})
.afterClosed()
.subscribe((res) => {
if (res && this.dataset) {
const { sample } = res;
this.sample = sample;
const pid = this.dataset.pid;
const property = { sampleId: sample.sampleId };
this.store.dispatch(updatePropertyAction({ pid, property }));
}
});
}
}

onSlidePublic(event: MatSlideToggleChange) {
if (this.dataset) {
const pid = this.dataset.pid;
Expand Down Expand Up @@ -351,11 +328,7 @@ export class DatasetDetailComponent
}

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

openAttachment(encoded: string) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@
<mat-cell *matCellDef="let dataset">
<img
src="{{ dataset.pid | thumbnail | async }}"
height="60px"
height="42px"
loading="lazy"
/>
</mat-cell>
Expand Down
1 change: 0 additions & 1 deletion src/app/datasets/datasets.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ 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
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,7 @@ export class FileUploaderComponent {
}

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

openAttachment(encoded: string) {
Expand Down
16 changes: 15 additions & 1 deletion src/app/shared/services/attachment.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,25 @@ describe("AttachmentService", () => {
});

it("should return null for non-string input", () => {
const mimeType = service.base64MimeType(null as any);
const mimeType = service.base64MimeType(null);
expect(mimeType).toBeNull();
});
});

describe("getImageUrl", () => {
it("should return the pdf icon if the file is pdf", () => {
const encoded = "data:application/pdf;base64,SGVsbG8sIFdvcmxkIQ==";
const imageUrl = service.getImageUrl(encoded);
expect(imageUrl).toBe("assets/images/pdf-icon.svg");
});

it("should return the encoded string if the file is not pdf", () => {
const encoded = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA";
const imageUrl = service.getImageUrl(encoded);
expect(imageUrl).toBe(encoded);
});
});

describe("openAttachment", () => {
it("should open a new window with the correct object URL", () => {
const encoded = "data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==";
Expand Down
21 changes: 21 additions & 0 deletions src/app/shared/services/attachment.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import { Injectable } from "@angular/core";
@Injectable()
export class AttachmentService {
base64MimeType(encoded: string): string {
if (!encoded) {
return null;
}

let result = null;

if (typeof encoded !== "string") {
Expand All @@ -17,7 +21,24 @@ export class AttachmentService {

return result;
}

getImageUrl(encoded: string) {
if (!encoded) {
return null;
}

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

openAttachment(encoded: string) {
if (!encoded) {
return null;
}

const mimeType = this.base64MimeType(encoded);
const strippedData = encoded.replace(
new RegExp(`^data:${mimeType};base64,`),
Expand Down
4 changes: 4 additions & 0 deletions src/app/shared/services/thumbnail.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ThumbnailService } from "./thumbnail.service";
import { selectDatasetsPerPage } from "state-management/selectors/datasets.selectors";
import { MockStore, provideMockStore } from "@ngrx/store/testing";
import { of, throwError } from "rxjs";
import { AttachmentService } from "./attachment.service";

describe("ThumbnailService", () => {
let service: ThumbnailService;
Expand All @@ -27,6 +28,9 @@ describe("ThumbnailService", () => {
provide: AppConfigService,
useValue: { getConfig },
},
{
provide: AttachmentService,
},
provideMockStore({
selectors: [
{
Expand Down
Loading

0 comments on commit 0d37dfb

Please sign in to comment.