From 297b198f1ab72158ed0a650b836b414ea03c3a4f Mon Sep 17 00:00:00 2001 From: Aaron Louie Date: Fri, 31 Jan 2020 09:41:37 -0500 Subject: [PATCH] Enables user to mark a file as primary --- src/app/file-list/file-list.component.html | 10 +++++ src/app/file-list/file-list.component.spec.ts | 41 ++++++++++++++++++- src/app/file-list/file-list.component.ts | 31 +++++++++++++- 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/src/app/file-list/file-list.component.html b/src/app/file-list/file-list.component.html index d9d3345..ad52451 100644 --- a/src/app/file-list/file-list.component.html +++ b/src/app/file-list/file-list.component.html @@ -1,6 +1,16 @@ {{fm.type | getIconCode}} + + + +

{{fm.name}}

{{fm.last_updated | date}}

diff --git a/src/app/file-list/file-list.component.spec.ts b/src/app/file-list/file-list.component.spec.ts index da988f2..4aa0c01 100644 --- a/src/app/file-list/file-list.component.spec.ts +++ b/src/app/file-list/file-list.component.spec.ts @@ -8,7 +8,14 @@ import {BrowserDynamicTestingModule} from '@angular/platform-browser-dynamic/tes import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {RouterTestingModule} from '@angular/router/testing'; import {of} from 'rxjs'; -import {ApiService, MockEnvironment, mockFileMeta0, mockFileMetas, mockWorkflowSpec0} from 'sartography-workflow-lib'; +import { + ApiService, + FileMeta, + MockEnvironment, + mockFileMeta0, + mockFileMetas, + mockWorkflowSpec0 +} from 'sartography-workflow-lib'; import {DeleteFileDialogComponent} from '../_dialogs/delete-file-dialog/delete-file-dialog.component'; import {DeleteFileDialogData} from '../_interfaces/dialog-data'; import {GetIconCodePipe} from '../_pipes/get-icon-code.pipe'; @@ -64,10 +71,27 @@ describe('FileListComponent', () => { component.workflowSpec = mockWorkflowSpec0; fixture.detectChanges(); + const justFiles: File[] = []; + const fmsNoFiles: FileMeta[] = mockFileMetas.map(fm => { + justFiles.push(fm.file); + delete fm['file']; + return fm; + }); + expect(justFiles.length).toEqual(mockFileMetas.length); + expect(fmsNoFiles.every(fm => !fm.file)).toEqual(true); + expect(justFiles.every(f => !!f.name)).toEqual(true); + const fmsReq = httpMock.expectOne(`apiRoot/file?spec_id=${mockWorkflowSpec0.id}`); expect(fmsReq.request.method).toEqual('GET'); - fmsReq.flush(mockFileMetas); + fmsReq.flush(fmsNoFiles); expect(component.fileMetas.length).toBeGreaterThan(0); + + fmsNoFiles.forEach((fm, i) => { + const fReq = httpMock.expectOne(`apiRoot/file/${fm.id}/data`); + expect(fReq.request.method).toEqual('GET'); + fReq.flush(justFiles[i]); + expect(component.fileMetas[i].file).toBeTruthy(); + }); }); afterEach(() => { @@ -116,4 +140,17 @@ describe('FileListComponent', () => { component.editFile(mockFileMeta0.id); expect(routerNavigateSpy).toHaveBeenCalledWith([`/modeler/${mockWorkflowSpec0.id}/${mockFileMeta0.id}`]); }); + + it('should flag a file as primary', () => { + const updateFileMetaSpy = spyOn((component as any).api, 'updateFileMeta').and.returnValue(of(mockFileMeta0)); + const _loadFileMetasSpy = spyOn((component as any), '_loadFileMetas').and.stub(); + expect(component.fileMetas.length).toEqual(mockFileMetas.length); + component.makePrimary(mockFileMeta0); + + expect(updateFileMetaSpy).toHaveBeenCalledTimes(mockFileMetas.length); + expect(component.fileMetas.length).toEqual(mockFileMetas.length); + expect(component.fileMetas.every(fm => !!fm.file)).toEqual(true); + expect(component.fileMetas.reduce((sum, fm) => fm.primary ? sum + 1 : sum, 0)).toEqual(1); + expect(_loadFileMetasSpy).toHaveBeenCalled(); + }); }); diff --git a/src/app/file-list/file-list.component.ts b/src/app/file-list/file-list.component.ts index ef7bd11..2c69eb4 100644 --- a/src/app/file-list/file-list.component.ts +++ b/src/app/file-list/file-list.component.ts @@ -2,7 +2,7 @@ import {Component, Input, OnInit} from '@angular/core'; import {MatDialog} from '@angular/material/dialog'; import {MatSnackBar} from '@angular/material/snack-bar'; import {Router} from '@angular/router'; -import {ApiService, FileMeta, WorkflowSpec} from 'sartography-workflow-lib'; +import {ApiService, FileMeta, FileType, WorkflowSpec} from 'sartography-workflow-lib'; import {DeleteFileDialogComponent} from '../_dialogs/delete-file-dialog/delete-file-dialog.component'; import {DeleteFileDialogData} from '../_interfaces/dialog-data'; @@ -14,6 +14,7 @@ import {DeleteFileDialogData} from '../_interfaces/dialog-data'; export class FileListComponent implements OnInit { @Input() workflowSpec: WorkflowSpec; fileMetas: FileMeta[]; + fileType = FileType; constructor( private api: ApiService, @@ -46,6 +47,23 @@ export class FileListComponent implements OnInit { }); } + makePrimary(fm: FileMeta) { + if (fm.type === FileType.BPMN) { + let numUpdated = 0; + this.fileMetas.forEach(f => { + f.primary = (fm.id === f.id); + this.api.updateFileMeta(this.workflowSpec.id, f).subscribe(() => { + numUpdated++; + + // Reload all fileMetas when all have been updated. + if (numUpdated === this.fileMetas.length) { + this._loadFileMetas(); + } + }); + }); + } + } + private _deleteFile(fileMeta: FileMeta) { this.api.deleteFileMeta(fileMeta.id).subscribe(() => { this._loadFileMetas(); @@ -54,6 +72,15 @@ export class FileListComponent implements OnInit { } private _loadFileMetas() { - this.api.listBpmnFiles(this.workflowSpec.id).subscribe(fms => this.fileMetas = fms); + this.api.listBpmnFiles(this.workflowSpec.id).subscribe(fms => { + this.fileMetas = fms; + this._loadFileData(); + }); + } + + private _loadFileData() { + this.fileMetas.forEach(fm => { + this.api.getFileData(fm.id).subscribe((fd: File) => fm.file = fd); + }); } }