Edits existing non-BPMN workflow spec file details

This commit is contained in:
Aaron Louie 2020-03-18 13:11:44 -04:00
parent d0f4916667
commit d4d43537d6
10 changed files with 120 additions and 14 deletions

View File

@ -1,5 +1,8 @@
import {Component, Inject} from '@angular/core'; import {Component, Inject} from '@angular/core';
import {FormGroup} from '@angular/forms';
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';
import {FormlyFieldConfig, FormlyFormOptions} from '@ngx-formly/core';
import {FileType} from 'sartography-workflow-lib';
import {FileMetaDialogData} from '../../_interfaces/dialog-data'; import {FileMetaDialogData} from '../../_interfaces/dialog-data';
import {cleanUpFilename} from '../../_util/string-clean'; import {cleanUpFilename} from '../../_util/string-clean';
@ -9,11 +12,56 @@ import {cleanUpFilename} from '../../_util/string-clean';
styleUrls: ['./file-meta-dialog.component.scss'] styleUrls: ['./file-meta-dialog.component.scss']
}) })
export class FileMetaDialogComponent { export class FileMetaDialogComponent {
form: FormGroup = new FormGroup({});
model: any = {};
options: FormlyFormOptions = {};
fields: FormlyFieldConfig[] = [];
constructor( constructor(
public dialogRef: MatDialogRef<FileMetaDialogComponent>, public dialogRef: MatDialogRef<FileMetaDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: FileMetaDialogData @Inject(MAT_DIALOG_DATA) public data: FileMetaDialogData
) { ) {
const fileTypeOptions = Object.entries(FileType).map(ft => {
return {
label: ft[0],
value: ft[1]
};
});
this.fields = [
{
key: 'fileName',
type: 'input',
defaultValue: this.data.fileName,
templateOptions: {
label: 'File Name',
placeholder: 'Name of workflow specification',
description: 'Enter a name, in lowercase letters, separated by underscores, that is easy for you to remember.' +
'It will be converted to all_lowercase_with_underscores when you save.',
required: true,
},
},
{
key: 'fileType',
type: 'select',
defaultValue: this.data.fileType,
templateOptions: {
label: 'File Type',
placeholder: 'Extension of file',
required: true,
options: fileTypeOptions,
},
},
{
key: 'file',
type: 'file',
defaultValue: this.data.file,
templateOptions: {
label: 'File',
required: true,
},
}
];
} }
onNoClick() { onNoClick() {

View File

@ -60,6 +60,12 @@ describe('OpenFileDialogComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
}); });
afterEach(() => {
httpMock.verify();
fixture.destroy();
});
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });

View File

@ -1,3 +1,4 @@
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
import {async, ComponentFixture, TestBed} from '@angular/core/testing'; import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {FormsModule, ReactiveFormsModule} from '@angular/forms'; import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {MAT_DIALOG_DATA, MatDialogModule, MatDialogRef} from '@angular/material/dialog'; import {MAT_DIALOG_DATA, MatDialogModule, MatDialogRef} from '@angular/material/dialog';
@ -7,11 +8,12 @@ import {MatInputModule} from '@angular/material/input';
import {BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations'; import {BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations';
import {FormlyModule} from '@ngx-formly/core'; import {FormlyModule} from '@ngx-formly/core';
import {FormlyMaterialModule} from '@ngx-formly/material'; import {FormlyMaterialModule} from '@ngx-formly/material';
import {mockWorkflowSpecCategory0} from 'sartography-workflow-lib'; import {ApiService, MockEnvironment, mockWorkflowSpecCategory0} from 'sartography-workflow-lib';
import {WorkflowSpecCategoryDialogData} from '../../_interfaces/dialog-data'; import {WorkflowSpecCategoryDialogData} from '../../_interfaces/dialog-data';
import {WorkflowSpecCategoryDialogComponent} from './workflow-spec-category-dialog.component'; import {WorkflowSpecCategoryDialogComponent} from './workflow-spec-category-dialog.component';
describe('WorkflowSpecDialogComponent', () => { describe('WorkflowSpecDialogComponent', () => {
let httpMock: HttpTestingController;
let component: WorkflowSpecCategoryDialogComponent; let component: WorkflowSpecCategoryDialogComponent;
let fixture: ComponentFixture<WorkflowSpecCategoryDialogComponent>; let fixture: ComponentFixture<WorkflowSpecCategoryDialogComponent>;
@ -22,6 +24,7 @@ describe('WorkflowSpecDialogComponent', () => {
FormlyModule.forRoot(), FormlyModule.forRoot(),
FormlyMaterialModule, FormlyMaterialModule,
FormsModule, FormsModule,
HttpClientTestingModule,
MatDialogModule, MatDialogModule,
MatFormFieldModule, MatFormFieldModule,
MatIconModule, MatIconModule,
@ -31,6 +34,8 @@ describe('WorkflowSpecDialogComponent', () => {
], ],
declarations: [WorkflowSpecCategoryDialogComponent], declarations: [WorkflowSpecCategoryDialogComponent],
providers: [ providers: [
ApiService,
{provide: 'APP_ENVIRONMENT', useClass: MockEnvironment},
{ {
provide: MatDialogRef, provide: MatDialogRef,
useValue: { useValue: {
@ -45,11 +50,17 @@ describe('WorkflowSpecDialogComponent', () => {
})); }));
beforeEach(() => { beforeEach(() => {
httpMock = TestBed.inject(HttpTestingController);
fixture = TestBed.createComponent(WorkflowSpecCategoryDialogComponent); fixture = TestBed.createComponent(WorkflowSpecCategoryDialogComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });
afterEach(() => {
httpMock.verify();
fixture.destroy();
});
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });

View File

@ -3,6 +3,7 @@ import {FileMeta, FileType, WorkflowSpec, WorkflowSpecCategory} from 'sartograph
export interface FileMetaDialogData { export interface FileMetaDialogData {
fileName: string; fileName: string;
fileType: FileType; fileType: FileType;
file?: File;
} }
export interface NewFileDialogData { export interface NewFileDialogData {

View File

@ -14,6 +14,8 @@ export class GetIconCodePipe implements PipeTransform {
return 'image'; return 'image';
case FileType.DMN: case FileType.DMN:
return 'view_list'; return 'view_list';
default:
return 'insert_drive_file';
} }
} }
} }

View File

@ -5,7 +5,7 @@
[attr.data-file-meta-id]="fm.id" [attr.data-file-meta-id]="fm.id"
[attr.data-workflow-spec-id]="workflowSpec.id" [attr.data-workflow-spec-id]="workflowSpec.id"
> >
<mat-icon (click)="editFile(fm.id)" mat-list-icon>{{fm.type | getIconCode}}</mat-icon> <mat-icon (click)="editFile(fm)" mat-list-icon>{{fm.type | getIconCode}}</mat-icon>
<ng-container *ngIf="fm.type === fileType.BPMN"> <ng-container *ngIf="fm.type === fileType.BPMN">
<button (click)="makePrimary(fm)" *ngIf="!fm.primary" mat-flat-button> <button (click)="makePrimary(fm)" *ngIf="!fm.primary" mat-flat-button>
<mat-icon>radio_button_unchecked</mat-icon> <mat-icon>radio_button_unchecked</mat-icon>
@ -16,9 +16,9 @@
Primary process Primary process
</button> </button>
</ng-container> </ng-container>
<h4 (click)="editFile(fm.id)" mat-line>{{fm.name}}</h4> <h4 (click)="editFile(fm)" mat-line>{{fm.name}}</h4>
<p (click)="editFile(fm.id)" mat-line>{{fm.last_updated | date}}</p> <p (click)="editFile(fm)" mat-line>{{fm.last_updated | date}}</p>
<button (click)="editFile(fm.id)" class="mat-elevation-z0" color="primary" mat-icon-button> <button (click)="editFile(fm)" class="mat-elevation-z0" color="primary" mat-icon-button>
<mat-icon>edit</mat-icon> <mat-icon>edit</mat-icon>
</button> </button>
<button (click)="confirmDelete(fm)" class="mat-elevation-z0" color="warn" mat-icon-button> <button (click)="confirmDelete(fm)" class="mat-elevation-z0" color="warn" mat-icon-button>

View File

@ -149,7 +149,7 @@ describe('FileListComponent', () => {
it('should navigate to modeler to edit a file', () => { it('should navigate to modeler to edit a file', () => {
const routerNavigateSpy = spyOn((component as any).router, 'navigate'); const routerNavigateSpy = spyOn((component as any).router, 'navigate');
component.workflowSpec = mockWorkflowSpec0; component.workflowSpec = mockWorkflowSpec0;
component.editFile(mockFileMeta0.id); component.editFile(mockFileMeta0);
expect(routerNavigateSpy).toHaveBeenCalledWith([`/modeler/${mockWorkflowSpec0.id}/${mockFileMeta0.id}`]); expect(routerNavigateSpy).toHaveBeenCalledWith([`/modeler/${mockWorkflowSpec0.id}/${mockFileMeta0.id}`]);
}); });

View File

@ -4,7 +4,8 @@ import {MatSnackBar} from '@angular/material/snack-bar';
import {Router} from '@angular/router'; import {Router} from '@angular/router';
import {ApiService, FileMeta, FileType, 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 {DeleteFileDialogComponent} from '../_dialogs/delete-file-dialog/delete-file-dialog.component';
import {DeleteFileDialogData} from '../_interfaces/dialog-data'; import {FileMetaDialogComponent} from '../_dialogs/file-meta-dialog/file-meta-dialog.component';
import {DeleteFileDialogData, FileMetaDialogData} from '../_interfaces/dialog-data';
@Component({ @Component({
selector: 'app-file-list', selector: 'app-file-list',
@ -28,8 +29,38 @@ export class FileListComponent implements OnInit {
this._loadFileMetas(); this._loadFileMetas();
} }
editFile(fileMetaId: number) { editFile(fileMeta: FileMeta) {
this.router.navigate([`/modeler/${this.workflowSpec.id}/${fileMetaId}`]); if (fileMeta.type === FileType.BPMN ||fileMeta.type === FileType.DMN) {
this.router.navigate([`/modeler/${this.workflowSpec.id}/${fileMeta.id}`]);
} else {
// Show edit file meta dialog
this.editFileMeta(fileMeta);
}
}
editFileMeta(fm: FileMeta) {
const dialogRef = this.dialog.open(FileMetaDialogComponent, {
data: {
fileName: fm.name,
fileType: fm.type,
file: fm.file,
}
});
dialogRef.afterClosed().subscribe((data: FileMetaDialogData) => {
if (data && data.fileName && data.fileType) {
const newFileMeta: FileMeta = {
content_type: data.fileType,
name: data.fileName,
type: data.fileType,
file: data.file,
};
this.api.updateFileMeta(newFileMeta).subscribe(() => {
// Reload all fileMetas when all have been updated.
this._loadFileMetas();
});
}
});
} }
confirmDelete(fm: FileMeta) { confirmDelete(fm: FileMeta) {

View File

@ -14,7 +14,7 @@ import {
ApiService, ApiService,
MockEnvironment, MockEnvironment,
mockWorkflowSpec0, mockWorkflowSpec0,
mockWorkflowSpec1, mockWorkflowSpec1, mockWorkflowSpecCategories,
mockWorkflowSpecs mockWorkflowSpecs
} from 'sartography-workflow-lib'; } from 'sartography-workflow-lib';
import {DeleteWorkflowSpecDialogComponent} from '../_dialogs/delete-workflow-spec-dialog/delete-workflow-spec-dialog.component'; import {DeleteWorkflowSpecDialogComponent} from '../_dialogs/delete-workflow-spec-dialog/delete-workflow-spec-dialog.component';
@ -69,15 +69,19 @@ describe('WorkflowSpecListComponent', () => {
})); }));
beforeEach(() => { beforeEach(() => {
httpMock = TestBed.inject(HttpTestingController);
fixture = TestBed.createComponent(WorkflowSpecListComponent); fixture = TestBed.createComponent(WorkflowSpecListComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
httpMock = TestBed.inject(HttpTestingController);
fixture.detectChanges(); fixture.detectChanges();
const sReq = httpMock.expectOne('apiRoot/workflow-specification'); const catReq = httpMock.expectOne('apiRoot/workflow-specification-category');
expect(sReq.request.method).toEqual('GET'); expect(catReq.request.method).toEqual('GET');
sReq.flush(mockWorkflowSpecs); catReq.flush(mockWorkflowSpecCategories);
expect(component.categories.length).toBeGreaterThan(0);
const specReq = httpMock.expectOne('apiRoot/workflow-specification');
expect(specReq.request.method).toEqual('GET');
specReq.flush(mockWorkflowSpecs);
expect(component.workflowSpecs.length).toBeGreaterThan(0); expect(component.workflowSpecs.length).toBeGreaterThan(0);
}); });

View File

@ -118,6 +118,8 @@ export class WorkflowSpecListComponent implements OnInit {
} }
private _loadWorkflowSpecCategories() { private _loadWorkflowSpecCategories() {
console.log('=== _loadWorkflowSpecCategories ===');
this.api.getWorkflowSpecCategoryList().subscribe(cats => { this.api.getWorkflowSpecCategoryList().subscribe(cats => {
this.categories = cats; this.categories = cats;
this.workflowSpecsByCategory = [{ this.workflowSpecsByCategory = [{
@ -137,6 +139,7 @@ export class WorkflowSpecListComponent implements OnInit {
} }
private _loadWorkflowSpecs() { private _loadWorkflowSpecs() {
console.log('=== _loadWorkflowSpecs ===');
this.api.getWorkflowSpecList().subscribe(wfs => { this.api.getWorkflowSpecList().subscribe(wfs => {
this.workflowSpecs = wfs; this.workflowSpecs = wfs;
this.workflowSpecsByCategory.forEach(cat => { this.workflowSpecsByCategory.forEach(cat => {