Skip to content
This repository has been archived by the owner on Nov 15, 2019. It is now read-only.

Commit

Permalink
Export to firecloud (#1)
Browse files Browse the repository at this point in the history
Add Export to FireCloud button

Also remove items from menu that don't apply to Commons instance.
  • Loading branch information
coverbeck authored Mar 20, 2018
1 parent a16dce1 commit e13bb4a
Show file tree
Hide file tree
Showing 29 changed files with 436 additions and 49 deletions.
13 changes: 6 additions & 7 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@ RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
RUN npm install pm2 -g
# Install app dependencies
COPY package.json /usr/src/app/
COPY . /usr/src/app/
RUN npm install
# Bundle app source
COPY ./dist /usr/src/app/dist
COPY ./server/dist /usr/src/app/server/dist
COPY ./views /usr/src/app/views
RUN npm -g install grunt-cli
RUN npm -g install [email protected]
RUN grunt build
RUN rm boardwalk.zip
RUN rm -rf spa/node_modules

EXPOSE 3000
#Set the node env
ENV NODE_ENV local
CMD ["pm2-docker", "server/dist/server.js"]
#RUN chmod a+x run.sh
#CMD ["./run.sh"]
3 changes: 2 additions & 1 deletion server/src/lib/config/config-webcontroller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ import { Response as Res } from "express";
import { Req } from "../../boardwalk";
import { setupResponseCallback } from "cc-express-utils";
import { ConfigViewModel } from "./config-view.model";
import { Response } from "~express/lib/express";

/**
* Handle request for environment config. Default data URL to "https://carlos.ucsc-cgp-dev.org".
*
* @param {Req} req
* @param {Response} res
*/
export function getConfig(req: Req, res: Res): void {
export function getConfig(req: Req, res: Res): Response {

return setupResponseCallback(res)(null, {
dataURL: process.env.BW_DATA_URL || "https://carlos.ucsc-cgp-dev.org"
Expand Down
5 changes: 5 additions & 0 deletions spa/ExportToFireCloudTodo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
1. Fix ugly hack in cc-base.dao.ts where added getNoCatch method; but otherwise I don't get the error.
2. CORS errors provides no details.
3. `FilesService.exportToFireCloud` returns a string for success and error, then there is an ugly hardcoded test in
file.effects.ts to see if the string starts with `Error`.
4. In file.dao.ts, construct FireCloud url from response.
2 changes: 2 additions & 0 deletions spa/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { CCHamburgerDirective } from "./shared/cc-hamburger/cc-hamburger.directi
import { CGLSubnavComponent } from "./shared/cgl-subnav/cgl-subnav.component";
import { CGLToolbarComponent } from "./shared/cgl-toolbar/cgl-toolbar.component";
import { ConfigService } from "./config/config.service";
import { CCAlertDialogComponent } from "./shared/cc-alert-dialog/cc-alert-dialog.component";

@NgModule({
bootstrap: [AppComponent],
Expand Down Expand Up @@ -73,6 +74,7 @@ import { ConfigService } from "./config/config.service";
CCHamburgerDirective,
CGLSubnavComponent,
CGLToolbarComponent,
CCAlertDialogComponent,
],
providers: [
UserService,
Expand Down
8 changes: 6 additions & 2 deletions spa/src/app/cc-http/shared/cc-base.dao.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ export class CCBaseDAO {
*/
public get<T>(url: string, queryStringParams?: any): Observable<T> {

return this.getNoCatch(url, queryStringParams)
.catch(response => this.handleError(response));
}

public getNoCatch<T>(url: string, queryStringParams?: any): Observable<T> {
// Build up GET headers
let headers = new Headers();
this.addAcceptHeader(headers);
Expand All @@ -79,8 +84,7 @@ export class CCBaseDAO {

return <Observable<T>>this.http // TODO revisit typing here...
.get(url, requestOptions)
.map(response => this.toJSON(response))
.catch(response => this.handleError(response));
.map(response => this.toJSON(response));
}

/**
Expand Down
27 changes: 27 additions & 0 deletions spa/src/app/files/_ngrx/file-export/file-export.actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Action } from "@ngrx/store";
import { WorkspaceDescriptor } from "./file-export.state";

export class FileExportManifestRequestAction implements Action {
public static ACTION_TYPE = "FILE.MANIFEST_EXPORT_REQUEST";
public readonly type = FileExportManifestRequestAction.ACTION_TYPE;
constructor(public payload: WorkspaceDescriptor) {
}
}

export class FileExportManifestSuccessAction implements Action {
public static ACTION_TYPE = "FILE.MANIFEST_EXPORT_SUCCESS";
public readonly type = FileExportManifestSuccessAction.ACTION_TYPE;
constructor(public fireCloudUrl: string) {
}
}

export class FileExportManifestErrorAction implements Action {
public static ACTION_TYPE = "FILE.MANIFEST_EXPORT_ERROR";
public readonly type = FileExportManifestErrorAction.ACTION_TYPE;
constructor(public errorReason: string) {
}
}

export type All = FileExportManifestRequestAction
| FileExportManifestSuccessAction
| FileExportManifestErrorAction;
23 changes: 23 additions & 0 deletions spa/src/app/files/_ngrx/file-export/file-export.reducer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Action } from "@ngrx/store";
import {
FileExportManifestRequestAction, FileExportManifestErrorAction,
FileExportManifestSuccessAction
} from "./file-export.actions";
import { FileExportManifestState } from "./file-export.state";

export function reducer(state: FileExportManifestState = FileExportManifestState.getDefaultState(), action: Action): FileExportManifestState {
switch (action.type) {
case FileExportManifestSuccessAction.ACTION_TYPE: {
return new FileExportManifestState((action as FileExportManifestSuccessAction).fireCloudUrl, "success");
}
case FileExportManifestErrorAction.ACTION_TYPE: {
return new FileExportManifestState(null, "error",
(action as FileExportManifestErrorAction).errorReason);
}
case FileExportManifestRequestAction.ACTION_TYPE: {
return new FileExportManifestState(null, "request");
}
default:
return state;
}
}
19 changes: 19 additions & 0 deletions spa/src/app/files/_ngrx/file-export/file-export.state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export interface WorkspaceDescriptor {
name: string;
namespace: string;
}

export type FileExportManifestStatus = "request" | "success" | "error" | null;

// export interface FileExportStatus
export class FileExportManifestState {
constructor(public fireCloudUrl = "",
public status: FileExportManifestStatus = null,
public statusMessage = "") {
}

public static getDefaultState() {
return new FileExportManifestState();
}

}
28 changes: 24 additions & 4 deletions spa/src/app/files/_ngrx/file.effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ import {
} from "./table/table.actions";
import { TableModel } from "../table/table.model";
import { DEFAULT_TABLE_PARAMS } from "../table/table-params.model";
import {
FileExportManifestRequestAction, FileExportManifestErrorAction,
FileExportManifestSuccessAction
} from "./file-export/file-export.actions";

@Injectable()
export class FileEffects {
Expand Down Expand Up @@ -90,7 +94,7 @@ export class FileEffects {
*/

/**
* Trigger update of file summary if a facet changes (ie term is selected or deseclted. File summary includes the
* Trigger update of file summary if a facet changes (ie term is selected or deseclted. File summary includes the
* donor count, file count etc that is displayed above the facets.
*
* @type {Observable<Action>}
Expand Down Expand Up @@ -137,7 +141,7 @@ export class FileEffects {
});

/**
*
*
*/
@Effect()
fetchInitialTableData$: Observable<Action> = this.actions$
Expand Down Expand Up @@ -190,8 +194,24 @@ export class FileEffects {
return this.fileService.downloadFileManifest(query);
});

@Effect()
exportToFireCloud$: Observable<Action> = this.actions$
.ofType<FileExportManifestRequestAction>(FileExportManifestRequestAction.ACTION_TYPE)
.map(action => action.payload)
.withLatestFrom(this.store.select(selectSelectedFileFacets))
.switchMap((results) => {
const [payload, selectedFacets] = results;
return this.fileService.exportToFireCloud(selectedFacets, payload.name, payload.namespace);
})
.map((fcUrl) => {
if (fcUrl.startsWith("Error")) {
return new FileExportManifestErrorAction(fcUrl);
}
return new FileExportManifestSuccessAction(fcUrl);
});

private colorWheel: Map<string, string>;

/**
* Trigger update of facets once a facet term is selected/deselected.
*
Expand Down Expand Up @@ -224,7 +244,7 @@ export class FileEffects {
})
);
});

/**
* Trigger update of facet counts on init.
*
Expand Down
4 changes: 3 additions & 1 deletion spa/src/app/files/_ngrx/file.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import * as fileSummaryReducer from "./file-summary/file-summary.reducer";
import * as fileFacetListReducer from "./file-facet-list/file-facet-list.reducer";
import * as fileManifestSummaryReducer from "./file-manifest-summary/file-manifest-summary.reducer";
import * as fileFacetMetadataSummaryReducer from "./file-facet-metadata-summary/file-facet-metadata-summary.reducer";
import * as fileExportReducer from "./file-export/file-export.reducer";
import * as tableReducer from "./table/table.reducer";

export const reducer = {
fileSummary: fileSummaryReducer.reducer,
fileFacetList: fileFacetListReducer.reducer,
fileManifestSummary: fileManifestSummaryReducer.reducer,
fileFacetMetadataSummary: fileFacetMetadataSummaryReducer.reducer,
tableState: tableReducer.reducer
tableState: tableReducer.reducer,
fileExportState: fileExportReducer.reducer
};
5 changes: 3 additions & 2 deletions spa/src/app/files/_ngrx/file.selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { createFeatureSelector, createSelector } from "@ngrx/store";
import { FileSummaryState } from "./file-summary/file-summary.state";
import { FileFacetListState } from "./file-facet-list/file-facet-list.state";
import { FileFacetMetadataSummaryState } from "./file-facet-metadata-summary/file-facet-metadata-summary.state";
import { FileExportManifestState } from "./file-export/file-export.state";
import { TableState } from "./table/table.state";

export const selectFileFacets = createFeatureSelector<FileFacetListState>("fileFacetList");
Expand All @@ -32,7 +33,7 @@ export const selectTableState = createFeatureSelector<TableState>("tableState");

/**
* Returns current state of pagination, of file facet table.
*
*
* @type {MemoizedSelector<object, PaginationModel>}
*/
export const selectPagination = createSelector(selectTableState,(tableState: TableState) => {
Expand All @@ -50,5 +51,5 @@ export const selectTableQueryParams = createSelector(selectSelectedFacetsMap, se
return { selectedFacets, pagination };
});


export const selectExportFileState = createFeatureSelector<FileExportManifestState>("fileExportState");

2 changes: 2 additions & 0 deletions spa/src/app/files/_ngrx/file.state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { FileFacetListState } from "./file-facet-list/file-facet-list.state";
import { FileManifestSummaryState } from "./file-manifest-summary/file-manifest-summary.state";
import { FileFacetMetadataSummaryState } from "./file-facet-metadata-summary/file-facet-metadata-summary.state";
import { TableState } from "./table/table.state";
import { FileExportManifestState } from "./file-export/file-export.state";

export interface FileState {
fileSummary: FileSummaryState;
fileFacetList: FileFacetListState;
fileManifestSummary: FileManifestSummaryState;
fileFacetMetadataSummary: FileFacetMetadataSummaryState;
tableState: TableState;
exportFileManifestState: FileExportManifestState;
}
5 changes: 5 additions & 0 deletions spa/src/app/files/file-export/file-export.component.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.column-flex {
flex-direction: column;
display: flex;
font-size: large;
}
24 changes: 24 additions & 0 deletions spa/src/app/files/file-export/file-export.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<h1 mat-dialog-title>Export to FireCloud</h1>
<div mat-dialog-content>
<mat-progress-bar mode="indeterminate" *ngIf="exporting"></mat-progress-bar>
<p *ngIf="exported">The selected files were exported to the FireCloud <a [href]="firecloudUrl" target="_blank">{{data.workspace}} workspace.</a></p>
<p *ngIf="errorMessage">There was an error exporting to FireCloud: {{errorMessage}}</p>
<div *ngIf="!exported && !errorMessage">
<p>Export the selected facets into a new FireCloud workspace.</p>
<div class="column-flex">
<mat-form-field>
<input matInput [(ngModel)]="data.workspace" placeholder="Workspace name" required autofocus [disabled]="exporting">
</mat-form-field>
<mat-form-field>
<mat-select placeholder="Billing project" [(value)]="data.namespace" [disabled]="exporting" required>
<mat-option *ngFor="let namespace of data.namespaces" [value]="namespace">{{namespace}}</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
</div>
<div mat-dialog-actions align="end">
<button mat-button (click)="onClose()" *ngIf="!exported && !errorMessage">Cancel</button>
<button mat-button (click)="onExport()" *ngIf="!exported && !errorMessage" [disabled]="exporting || !data.workspace">Export</button>
<button mat-button (click)="onClose()" *ngIf="exported || errorMessage">Close</button>
</div>
25 changes: 25 additions & 0 deletions spa/src/app/files/file-export/file-export.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { FileExportComponent } from './file-export.component';

describe('FileExportComponent', () => {
let component: FileExportComponent;
let fixture: ComponentFixture<FileExportComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ FileExportComponent ]
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(FileExportComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should be created', () => {
expect(component).toBeTruthy();
});
});
Loading

0 comments on commit e13bb4a

Please sign in to comment.