From 27e27890d2dccc00a7812a4285252fd19d7e995a Mon Sep 17 00:00:00 2001 From: Charles Overbeck Date: Mon, 7 May 2018 17:52:43 -0700 Subject: [PATCH] Hide Launch with FireCloud if No Content ga4gh/dockstore#1372 Created a launch-third-party component to both more easily unit test and to add new upcoming third party integrations. Turned on Launch with FireCloud by default, as unit test was failing with flag set to false. Since the flag has been turned on in production, make it the default. --- .../my-workflow/my-workflow.component.ts | 2 +- src/app/shared/dockstore.model.ts | 2 +- src/app/shared/modules/workflow.module.ts | 2 + src/app/test/mocked-objects.ts | 7 ++ src/app/test/service-stubs.ts | 12 +++ .../launch-third-party.component.html | 21 +++++ .../launch-third-party.component.scss | 11 +++ .../launch-third-party.component.spec.ts | 82 +++++++++++++++++++ .../launch-third-party.component.ts | 78 ++++++++++++++++++ src/app/workflow/workflow.component.css | 12 --- src/app/workflow/workflow.component.html | 20 +---- src/app/workflow/workflow.component.ts | 33 +------- 12 files changed, 217 insertions(+), 65 deletions(-) create mode 100644 src/app/workflow/launch-third-party/launch-third-party.component.html create mode 100644 src/app/workflow/launch-third-party/launch-third-party.component.scss create mode 100644 src/app/workflow/launch-third-party/launch-third-party.component.spec.ts create mode 100644 src/app/workflow/launch-third-party/launch-third-party.component.ts diff --git a/src/app/myworkflows/my-workflow/my-workflow.component.ts b/src/app/myworkflows/my-workflow/my-workflow.component.ts index feab151751..0e60525759 100644 --- a/src/app/myworkflows/my-workflow/my-workflow.component.ts +++ b/src/app/myworkflows/my-workflow/my-workflow.component.ts @@ -44,7 +44,7 @@ import { MyWorkflowsService } from './../myworkflows.service'; }) export class MyWorkflowComponent extends MyEntry implements OnInit { - workflow: any; + workflow: Workflow; workflows: any; readonly pageName = '/my-workflows'; public refreshMessage: string; diff --git a/src/app/shared/dockstore.model.ts b/src/app/shared/dockstore.model.ts index 8445b007dd..087323ccad 100644 --- a/src/app/shared/dockstore.model.ts +++ b/src/app/shared/dockstore.model.ts @@ -55,6 +55,6 @@ export class Dockstore { static readonly FEATURES = { enableCwlViewer: false, - enableLaunchWithFireCloud: false + enableLaunchWithFireCloud: true }; } diff --git a/src/app/shared/modules/workflow.module.ts b/src/app/shared/modules/workflow.module.ts index c03405d52c..c6bac64f11 100644 --- a/src/app/shared/modules/workflow.module.ts +++ b/src/app/shared/modules/workflow.module.ts @@ -57,6 +57,7 @@ import { VersionModalService } from './../../workflow/version-modal/version-moda import { EntryModule } from './../entry/entry.module'; import { RefreshService } from './../refresh.service'; import { getTooltipConfig } from './../tooltip'; +import { LaunchThirdPartyComponent } from '../../workflow/launch-third-party/launch-third-party.component'; @NgModule({ declarations: [ @@ -65,6 +66,7 @@ import { getTooltipConfig } from './../tooltip'; FilesWorkflowComponent, ParamfilesWorkflowComponent, VersionsWorkflowComponent, + LaunchThirdPartyComponent, LaunchWorkflowComponent, ViewWorkflowComponent, VersionModalComponent, diff --git a/src/app/test/mocked-objects.ts b/src/app/test/mocked-objects.ts index aed978ee06..21ae336f0a 100644 --- a/src/app/test/mocked-objects.ts +++ b/src/app/test/mocked-objects.ts @@ -166,3 +166,10 @@ export const sampleTag = { 'image_id': 'sampleImageId', 'name': 'sampleName' }; + +export const wdlSourceFile: SourceFile = { + content: 'task foo {}', + id: 0, + path: '', + type: undefined +}; diff --git a/src/app/test/service-stubs.ts b/src/app/test/service-stubs.ts index 581cc0b69b..c49c1edc36 100644 --- a/src/app/test/service-stubs.ts +++ b/src/app/test/service-stubs.ts @@ -277,6 +277,8 @@ export class WorkflowStubService { return Observable.of({}); } replaceWorkflow(workflows: Workflow[], newWorkflow: Workflow) { } + get full_workflow_path() { return ''; } + get descriptorType() { return ''; } } export class MetadataStubService { @@ -596,6 +598,12 @@ export class WorkflowsStubService { getWorkflowDag(workflowId: number, workflowVersionId: number, extraHttpRequestParams?: any): Observable { return Observable.of('someDAG'); } + wdl(workflowId: number, tag: string ) { + return Observable.of({}); + } + secondaryWdl(workflowId: number, tag: string) { + return Observable.of([]); + } } export class ContainersStubService { @@ -676,6 +684,10 @@ export class VersionModalStubService { } +export class WorkflowVersionStubService { + get name() {return ''; } +} + export class StateStubService { publicPage$ = Observable.of(false); refreshMessage$: BehaviorSubject = new BehaviorSubject(null); diff --git a/src/app/workflow/launch-third-party/launch-third-party.component.html b/src/app/workflow/launch-third-party/launch-third-party.component.html new file mode 100644 index 0000000000..a965ab1838 --- /dev/null +++ b/src/app/workflow/launch-third-party/launch-third-party.component.html @@ -0,0 +1,21 @@ +
+
+

Launch with

+
+
+
+
+ +
+
+
+
diff --git a/src/app/workflow/launch-third-party/launch-third-party.component.scss b/src/app/workflow/launch-third-party/launch-third-party.component.scss new file mode 100644 index 0000000000..c92882a30d --- /dev/null +++ b/src/app/workflow/launch-third-party/launch-third-party.component.scss @@ -0,0 +1,11 @@ +.button-wrap { + display: inline-block; +} + +.button-wrap > .button { + display: block; +} + +.button-wrap > .button:not(:last-child) { + margin-bottom: 10px; +} diff --git a/src/app/workflow/launch-third-party/launch-third-party.component.spec.ts b/src/app/workflow/launch-third-party/launch-third-party.component.spec.ts new file mode 100644 index 0000000000..29bac6729e --- /dev/null +++ b/src/app/workflow/launch-third-party/launch-third-party.component.spec.ts @@ -0,0 +1,82 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LaunchThirdPartyComponent } from './launch-third-party.component'; +import { WorkflowsService } from '../../shared/swagger/api/workflows.service'; +import { WorkflowsStubService, WorkflowStubService, WorkflowVersionStubService } from '../../test/service-stubs'; +import { Workflow, WorkflowVersion } from '../../shared/swagger'; +import { Observable } from 'rxjs/Observable'; +import { wdlSourceFile } from '../../test/mocked-objects'; + +describe('LaunchThirdPartyComponent', () => { + let component: LaunchThirdPartyComponent; + let fixture: ComponentFixture; + let workflowVersion: WorkflowVersion; + let workflow: Workflow; + let workflowsService: WorkflowsService; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ LaunchThirdPartyComponent ], + providers: [ + { provide: WorkflowsService, useClass: WorkflowsStubService}, + { provide: WorkflowVersion, useClass: WorkflowVersionStubService}, + { provide: Workflow, useClass: WorkflowStubService} + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(LaunchThirdPartyComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + workflowVersion = TestBed.get(WorkflowVersion); + workflow = TestBed.get(Workflow); + workflowsService = TestBed.get(WorkflowsService); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should not set urls if CWL', () => { + spyOnProperty(workflowVersion, 'name', 'get').and.returnValue('master'); + component.selectedVersion = workflowVersion; + spyOnProperty(workflow, 'full_workflow_path', 'get').and + .returnValue('github.com/DataBiosphere/topmed-workflows/Functional_Equivalence'); + spyOnProperty(workflow, 'descriptorType', 'get').and.returnValue('cwl'); + expect(component.dnastackURL).toBeFalsy(); + expect(component.fireCloudURL).toBeFalsy(); + }); + + it('should set urls if WDL with no secondary files', () => { + spyOnProperty(workflowVersion, 'name', 'get').and.returnValue('master'); + component.selectedVersion = workflowVersion; + spyOnProperty(workflow, 'full_workflow_path', 'get').and + .returnValue('github.com/DataBiosphere/topmed-workflows/Functional_Equivalence'); + spyOnProperty(workflow, 'descriptorType', 'get').and.returnValue('wdl'); + spyOn(workflowsService, 'wdl').and.returnValue(Observable.of(wdlSourceFile)); + component.workflow = workflow; + expect(component.dnastackURL) + // tslint:disable-next-line:max-line-length + .toEqual('https://app.dnastack.com/#/app/workflow/import/dockstore?path=github.com/DataBiosphere/topmed-workflows/Functional_Equivalence&descriptorType=wdl'); + expect(component.fireCloudURL) + // tslint:disable-next-line:max-line-length + .toEqual('https://portal.firecloud.org/#import/dockstore/github.com/DataBiosphere/topmed-workflows/Functional_Equivalence:master'); + }); + + it('should set dnastack but not Firecloud if WDL with secondary files', () => { + spyOnProperty(workflowVersion, 'name', 'get').and.returnValue('master'); + component.selectedVersion = workflowVersion; + spyOnProperty(workflow, 'full_workflow_path', 'get').and + .returnValue('github.com/DataBiosphere/topmed-workflows/Functional_Equivalence'); + spyOnProperty(workflow, 'descriptorType', 'get').and.returnValue('wdl'); + spyOn(workflowsService, 'wdl').and.returnValue(Observable.of(wdlSourceFile)); + spyOn(workflowsService, 'secondaryWdl').and.returnValue(Observable.of([wdlSourceFile])); + component.workflow = workflow; + expect(component.dnastackURL) + // tslint:disable-next-line:max-line-length + .toEqual('https://app.dnastack.com/#/app/workflow/import/dockstore?path=github.com/DataBiosphere/topmed-workflows/Functional_Equivalence&descriptorType=wdl'); + expect(component.fireCloudURL).toBeFalsy(); + }); +}); diff --git a/src/app/workflow/launch-third-party/launch-third-party.component.ts b/src/app/workflow/launch-third-party/launch-third-party.component.ts new file mode 100644 index 0000000000..4fca35d5f6 --- /dev/null +++ b/src/app/workflow/launch-third-party/launch-third-party.component.ts @@ -0,0 +1,78 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { Workflow, WorkflowVersion } from '../../shared/swagger'; +import { Dockstore } from '../../shared/dockstore.model'; +import { ExtendedWorkflow } from '../../shared/models/ExtendedWorkflow'; +import { SourceFile } from '../../shared/swagger/model/sourceFile'; +import { WorkflowsService } from '../../shared/swagger/api/workflows.service'; +import { URLSearchParams } from '@angular/http'; + +@Component({ + selector: 'app-launch-third-party', + templateUrl: './launch-third-party.component.html', + styleUrls: ['./launch-third-party.component.scss'] +}) +export class LaunchThirdPartyComponent { + + private _workflow: Workflow; + private _selectedVersion: WorkflowVersion; + + @Input() set workflow(value: Workflow) { + this._workflow = value; + this.onChange(); + } + + get workflow(): Workflow { + return this._workflow; + } + + @Input() set selectedVersion(value: WorkflowVersion) { + this._selectedVersion = value; + this.onChange(); + } + + get selectedVersion() { + return this._selectedVersion; + } + + dnastackURL: string; + fireCloudURL: string; + + constructor(private workflowsService: WorkflowsService) { } + + private onChange() { + this.setupFireCloudUrl(this.workflow); + this.setupDnaStackUrl(this.workflow); + } + + private isWdl(workflowRef: ExtendedWorkflow) { + return workflowRef && workflowRef.full_workflow_path && workflowRef.descriptorType === 'wdl'; + } + + + private setupFireCloudUrl(workflowRef: ExtendedWorkflow) { + if (Dockstore.FEATURES.enableLaunchWithFireCloud) { + this.fireCloudURL = null; + const version: WorkflowVersion = this.selectedVersion; + if (version && this.isWdl(workflowRef)) { + this.workflowsService.wdl(workflowRef.id, version.name).subscribe((sourceFile: SourceFile) => { + if (sourceFile && sourceFile.content && sourceFile.content.length) { + this.workflowsService.secondaryWdl(workflowRef.id, version.name).subscribe((sourceFiles: Array) => { + if (!sourceFiles || sourceFiles.length === 0) { + this.fireCloudURL = `${Dockstore.FIRECLOUD_IMPORT_URL}/${workflowRef.full_workflow_path}:${version.name}`; + } + }); + } + }); + } + } + } + + private setupDnaStackUrl(workflow: ExtendedWorkflow) { + if (this.isWdl(workflow)) { + const myParams = new URLSearchParams(); + myParams.set('path', workflow.full_workflow_path); + myParams.set('descriptorType', workflow.descriptorType); + this.dnastackURL = Dockstore.DNASTACK_IMPORT_URL + '?' + myParams; + } + } +} diff --git a/src/app/workflow/workflow.component.css b/src/app/workflow/workflow.component.css index 2e6cf08e36..5f9194976b 100644 --- a/src/app/workflow/workflow.component.css +++ b/src/app/workflow/workflow.component.css @@ -22,15 +22,3 @@ pre { white-space: pre-wrap; word-break: normal; } - -.button-wrap { - display: inline-block; -} - -.button-wrap > .button { - display: block; -} - -.button-wrap > .button:not(:last-child) { - margin-bottom: 10px; -} diff --git a/src/app/workflow/workflow.component.html b/src/app/workflow/workflow.component.html index 9bfb94eac9..fe5854bd56 100644 --- a/src/app/workflow/workflow.component.html +++ b/src/app/workflow/workflow.component.html @@ -210,25 +210,7 @@

Source Repositories

-
-
-

Launch with

-
-
-
-
- -
-
-
-
+

Verified

diff --git a/src/app/workflow/workflow.component.ts b/src/app/workflow/workflow.component.ts index 63ca82568f..6834ca3c38 100644 --- a/src/app/workflow/workflow.component.ts +++ b/src/app/workflow/workflow.component.ts @@ -15,12 +15,10 @@ */ import { Location } from '@angular/common'; import { Component } from '@angular/core'; -import { URLSearchParams } from '@angular/http'; import { Router, ActivatedRoute } from '@angular/router'; import { Subscription } from 'rxjs/Subscription'; import { DateService } from '../shared/date.service'; -import { Dockstore } from '../shared/dockstore.model'; import { DockstoreService } from '../shared/dockstore.service'; import { Entry } from '../shared/entry'; import { ProviderService } from '../shared/provider.service'; @@ -36,7 +34,6 @@ import { WorkflowsService } from './../shared/swagger/api/workflows.service'; import { PublishRequest } from './../shared/swagger/model/publishRequest'; import { Workflow } from './../shared/swagger/model/workflow'; import { UrlResolverService } from './../shared/url-resolver.service'; -import { SourceFile } from '../shared/swagger/model/sourceFile'; @Component({ selector: 'app-workflow', @@ -45,9 +42,7 @@ import { SourceFile } from '../shared/swagger/model/sourceFile'; }) export class WorkflowComponent extends Entry { workflowEditData: any; - dnastackURL: string; - fireCloudURL: string; - public workflow; + public workflow: Workflow; public missingWarning: boolean; public title: string; private workflowSubscription: Subscription; @@ -102,30 +97,6 @@ export class WorkflowComponent extends Entry { workflowRef.versionVerified = this.dockstoreService.getVersionVerified(workflowRef.workflowVersions); workflowRef.verifiedSources = this.dockstoreService.getVerifiedWorkflowSources(workflowRef); this.resetWorkflowEditData(); - if (this.isWdl(workflowRef)) { - const myParams = new URLSearchParams(); - myParams.set('path', workflowRef.full_workflow_path); - myParams.set('descriptorType', workflowRef.descriptorType); - this.dnastackURL = Dockstore.DNASTACK_IMPORT_URL + '?' + myParams; - } - } - - private isWdl(workflowRef: ExtendedWorkflow) { - return workflowRef.full_workflow_path && workflowRef.descriptorType === 'wdl'; - } - - private setupFireCloudUrl(workflowRef: ExtendedWorkflow) { - if (Dockstore.FEATURES.enableLaunchWithFireCloud) { - this.fireCloudURL = null; - const version: WorkflowVersion = this.selectedVersion; - if (version && this.isWdl(workflowRef)) { - this.workflowsService.secondaryWdl(workflowRef.id, version.name).subscribe((sourceFiles: Array) => { - if (!sourceFiles || sourceFiles.length === 0) { - this.fireCloudURL = `${Dockstore.FIRECLOUD_IMPORT_URL}/${workflowRef.full_workflow_path}:${version.name}`; - } - }); - } - } } public getDefaultVersionName(): string { @@ -142,7 +113,6 @@ export class WorkflowComponent extends Entry { this.title = this.workflow.full_workflow_path; this.initTool(); this.sortedVersions = this.getSortedVersions(this.workflow.workflowVersions, this.defaultVersion); - this.setupFireCloudUrl(this.workflow); } } @@ -297,7 +267,6 @@ export class WorkflowComponent extends Entry { if (this.workflow != null) { this.updateUrl(this.workflow.full_workflow_path, 'my-workflows', 'workflows'); } - this.setupFireCloudUrl(this.workflow); } setEntryTab(tabName: string): void {