Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions spa/src/app/_ngrx/app.effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

// App dependencies
import { ConfigEffects } from "../config/_ngrx/config.effects";
import { AnalysisProtocolEffects } from "../files/_ngrx/analysis-protocol/analysis-protocol.effects";
import { FileEffects } from "../files/_ngrx/file.effects";
import { FileManifestEffects } from "../files/_ngrx/file-manifest/file-manifest.effects";
import { IntegrationEffects } from "../files/_ngrx/integration/integration.effects";
Expand All @@ -19,6 +20,7 @@ import { TableEffects } from "../files/_ngrx/table/table.effects";
import { TerraEffects } from "../files/_ngrx/terra/terra.effects";

export const AppEffects = [
AnalysisProtocolEffects,
ConfigEffects,
FileEffects,
FileManifestEffects,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Human Cell Atlas
* https://www.humancellatlas.org/
*
* Side effects of analysis protocol-related actions.
*/

// Core dependencies
import { Injectable } from "@angular/core";
import { Actions, Effect, ofType } from "@ngrx/effects";
import { Store } from "@ngrx/store";
import { tap } from "rxjs/operators";

// App dependencies
import { AppState } from "../../../_ngrx/app.state";
import { GTMService } from "../../../shared/analytics/gtm.service";
import { ViewAnalysisProtocolAction } from "./view-analysis-protocol.action";

@Injectable()
export class AnalysisProtocolEffects {

/**
* @param {GTMService} gtmService
* @param {Store<AppState>} store
* @param {Actions} actions$
*/
constructor(private gtmService: GTMService,
private store: Store<AppState>,
private actions$: Actions) {}

/**
* Track click of link to analysis protocol in the Data Portal.
*/
@Effect({dispatch: false})
viewAnalysisProtocol$ = this.actions$.pipe(
ofType(ViewAnalysisProtocolAction.ACTION_TYPE),
tap((action: ViewAnalysisProtocolAction) => {
this.gtmService.trackEvent(action.asEvent());
})
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Human Cell Atlas
* https://www.humancellatlas.org/
*
* Action triggered when link to analysis protocol is clicked.
*/

// Core dependencies
import { Action } from "@ngrx/store";

// App dependencies
import { TrackingAction } from "../analytics/tracking.action";
import { GACategory } from "../../../shared/analytics/ga-category.model";
import { GADimension } from "../../../shared/analytics/ga-dimension.model";
import { GAEvent } from "../../../shared/analytics/ga-event.model";
import { GAAction } from "../../../shared/analytics/ga-action.model";
import { GASource } from "../../../shared/analytics/ga-source.model";

export class ViewAnalysisProtocolAction implements Action, TrackingAction {
public static ACTION_TYPE = "ANALYSIS_PROTOCOL.VIEW";
public readonly type = ViewAnalysisProtocolAction.ACTION_TYPE;

/**
* @param {string} workflow
* @param {string} url
* @param {GASource} source
* @param {string} currentQuery
*/
constructor(public workflow: string,
public url: string,
public source: GASource,
public currentQuery: string) {}

/**
* Return the clear action as a GA event.
*
* @returns {GAEvent}
*/
public asEvent(): GAEvent {

return {
category: GACategory.PORTAL_LINK,
action: GAAction.CLICK,
label: this.workflow,
dimensions: {
[GADimension.CURRENT_QUERY]: this.currentQuery,
[GADimension.ENTITY_URL]: this.url,
[GADimension.SOURCE]: this.source
}
};
}
}
2 changes: 1 addition & 1 deletion spa/src/app/files/_ngrx/project/project.effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class ProjectEffects {
* Trigger tracking of view of any project tab.
*/
@Effect({dispatch: false})
viewProjectTab: Observable<Action> = this.actions$.pipe(
viewProjectTab$ = this.actions$.pipe(
ofType(ViewProjectTabAction.ACTION_TYPE),
tap((action: ViewProjectTabAction) => {
this.gtmService.trackEvent(action.asEvent());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
<ng-container *ngFor="let analysisProtocol of listAnalysisProtocols(); last as lastAnalysisProtocol">
<ng-container [ngSwitch]="isAnalysisProtocolLinked(analysisProtocol)">
<a href="{{getPipelineLink(analysisProtocol)}}" rel="noopener noreferrer" target="_blank" *ngSwitchDefault>{{analysisProtocol}}<span class="comma" *ngIf="!lastAnalysisProtocol">, </span></a>
<a href="{{getPipelineLink(analysisProtocol)}}"
rel="noopener noreferrer"
target="_blank"
(click)="onAnalysisProtocolLinkClicked(analysisProtocol)"
*ngSwitchDefault>{{analysisProtocol}}<span class="comma" *ngIf="!lastAnalysisProtocol">, </span></a>
<span *ngSwitchCase="false">{{analysisProtocol}}<span class="comma" *ngIf="!lastAnalysisProtocol">, </span></span>
</ng-container>
</ng-container>
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
*/

// Core dependencies
import { Component, Input } from "@angular/core";
import { Component, EventEmitter, Input, Output } from "@angular/core";

// App dependencies
import { AnalysisProtocolViewedEvent } from "./analysis-protocol-viewed.event";
import { ConfigService } from "../../config/config.service";

@Component({
Expand All @@ -21,6 +22,9 @@ export class AnalysisProtocolPipelineLinkerComponent {

// Inputs
@Input() workflow: string;

// Outputs
@Output() analysisProtocolViewed = new EventEmitter<AnalysisProtocolViewedEvent>();

// Template variables
public portalURL: string;
Expand Down Expand Up @@ -86,6 +90,19 @@ export class AnalysisProtocolPipelineLinkerComponent {
return this.workflow.split(", ");
}

/**
* Let parents know analysis protocol link has been clicked.
*
* @param {string} analysisProtocol
*/
public onAnalysisProtocolLinkClicked(analysisProtocol: string) {

this.analysisProtocolViewed.emit({
analysisProtocol,
url: this.getPipelineLink(analysisProtocol)
});
}

/**
* Returns the analysis protocol key for the specified analysis protocol.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Human Cell Atlas
* https://www.humancellatlas.org/
*
* Event emitted when link to analysis protocol link is clicked.
*/
export interface AnalysisProtocolViewedEvent {

analysisProtocol: string;
url: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,12 @@
[ngClass]="getColumnClass('workflow')" [ngStyle]="getColumnStyle('workflow')">
<hca-table-cell [ngSwitch]="isElementUnspecified(element.workflow)">
<hca-content-unspecified-dash *ngSwitchCase="true"></hca-content-unspecified-dash>
<analysis-protocol-pipeline-linker *ngSwitchDefault class="fontsize-xxs" [workflow]="element.workflow"></analysis-protocol-pipeline-linker>
<ng-container *ngIf="(selectedSearchTermsBySearchKey$ | async) as selectedSearchTermsBySearchKey">
<analysis-protocol-pipeline-linker *ngSwitchDefault
class="fontsize-xxs"
[workflow]="element.workflow"
(analysisProtocolViewed)="onAnalysisProtocolViewed($event, selectedSearchTermsBySearchKey)"></analysis-protocol-pipeline-linker>
</ng-container>
</hca-table-cell>
</mat-cell>
</ng-container>
Expand Down
45 changes: 33 additions & 12 deletions spa/src/app/files/hca-table-files/hca-table-files.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import { TableScroll } from "../table-scroll/table-scroll.component";
import { FILES_TABLE_MODEL } from "./table-state-table-model-files.mock";
import { TableRendererService } from "../table/table-renderer.service";
import { PaginationService } from "../table/pagination/pagination.service";
import { SearchTermUrlService } from "../search/url/search-term-url.service";

describe("HCATableFilesComponent", () => {

Expand Down Expand Up @@ -151,6 +152,14 @@ describe("HCATableFilesComponent", () => {
provide: ResponsiveService,
useValue: jasmine.createSpyObj("ResponsiveService", ["isWindowWidthHCAMedium", "isWindowWidthSmallTablet", "isWindowWidthSmall"])
},
{
provide: SearchTermUrlService,
useValue: jasmine.createSpyObj("SearchTermUrlService", [
"getDefaultSearchState",
"parseQueryStringSearchTerms",
"stringifySearchTerms"
])
},
{
provide: TableRendererService,
useValue: jasmine.createSpyObj("TableRendererService", {
Expand Down Expand Up @@ -190,7 +199,8 @@ describe("HCATableFilesComponent", () => {
of(FILES_TABLE_MODEL.loading),
of(FILES_TABLE_MODEL.pagination),
of(FILES_TABLE_MODEL.termCountsByFacetName),
of(DEFAULT_FILE_SUMMARY)
of(DEFAULT_FILE_SUMMARY),
of([])
);

fixture.detectChanges();
Expand All @@ -211,7 +221,8 @@ describe("HCATableFilesComponent", () => {
of(FILES_TABLE_MODEL.loading),
of(FILES_TABLE_MODEL.pagination),
of(FILES_TABLE_MODEL.termCountsByFacetName),
of(DEFAULT_FILE_SUMMARY)
of(DEFAULT_FILE_SUMMARY),
of([])
);

fixture.detectChanges();
Expand Down Expand Up @@ -246,7 +257,8 @@ describe("HCATableFilesComponent", () => {
of(FILES_TABLE_MODEL.loading),
of(FILES_TABLE_MODEL.pagination),
of(FILES_TABLE_MODEL.termCountsByFacetName),
of(DEFAULT_FILE_SUMMARY)
of(DEFAULT_FILE_SUMMARY),
of([])
);

fixture.detectChanges();
Expand Down Expand Up @@ -285,7 +297,8 @@ describe("HCATableFilesComponent", () => {
of(FILES_TABLE_MODEL.loading),
of(FILES_TABLE_MODEL.pagination),
of(FILES_TABLE_MODEL.termCountsByFacetName),
of(DEFAULT_FILE_SUMMARY)
of(DEFAULT_FILE_SUMMARY),
of([])
);

fixture.detectChanges();
Expand All @@ -308,7 +321,8 @@ describe("HCATableFilesComponent", () => {
of(FILES_TABLE_MODEL.loading),
of(FILES_TABLE_MODEL.pagination),
of(FILES_TABLE_MODEL.termCountsByFacetName),
of(DEFAULT_FILE_SUMMARY)
of(DEFAULT_FILE_SUMMARY),
of([])
);

fixture.detectChanges();
Expand All @@ -329,7 +343,8 @@ describe("HCATableFilesComponent", () => {
of(FILES_TABLE_MODEL.loading),
of(FILES_TABLE_MODEL.pagination),
of(FILES_TABLE_MODEL.termCountsByFacetName),
of(DEFAULT_FILE_SUMMARY)
of(DEFAULT_FILE_SUMMARY),
of([])
);

fixture.detectChanges();
Expand All @@ -350,7 +365,8 @@ describe("HCATableFilesComponent", () => {
of(FILES_TABLE_MODEL.loading),
of(FILES_TABLE_MODEL.pagination),
of(FILES_TABLE_MODEL.termCountsByFacetName),
of(DEFAULT_FILE_SUMMARY)
of(DEFAULT_FILE_SUMMARY),
of([])
);

fixture.detectChanges();
Expand All @@ -371,7 +387,8 @@ describe("HCATableFilesComponent", () => {
of(FILES_TABLE_MODEL.loading),
of(FILES_TABLE_MODEL.pagination),
of(FILES_TABLE_MODEL.termCountsByFacetName),
of(DEFAULT_FILE_SUMMARY)
of(DEFAULT_FILE_SUMMARY),
of([])
);

fixture.detectChanges();
Expand All @@ -392,7 +409,8 @@ describe("HCATableFilesComponent", () => {
of(FILES_TABLE_MODEL.loading),
of(FILES_TABLE_MODEL.pagination),
of(FILES_TABLE_MODEL.termCountsByFacetName),
of(DEFAULT_FILE_SUMMARY)
of(DEFAULT_FILE_SUMMARY),
of([])
);

fixture.detectChanges();
Expand All @@ -413,7 +431,8 @@ describe("HCATableFilesComponent", () => {
of(FILES_TABLE_MODEL.loading),
of(FILES_TABLE_MODEL.pagination),
of(FILES_TABLE_MODEL.termCountsByFacetName),
of(DEFAULT_FILE_SUMMARY)
of(DEFAULT_FILE_SUMMARY),
of([])
);

fixture.detectChanges();
Expand All @@ -434,7 +453,8 @@ describe("HCATableFilesComponent", () => {
of(FILES_TABLE_MODEL.loading),
of(FILES_TABLE_MODEL.pagination),
of(FILES_TABLE_MODEL.termCountsByFacetName),
of(DEFAULT_FILE_SUMMARY)
of(DEFAULT_FILE_SUMMARY),
of([])
);

fixture.detectChanges();
Expand All @@ -457,7 +477,8 @@ describe("HCATableFilesComponent", () => {
of(FILES_TABLE_MODEL.loading),
of(FILES_TABLE_MODEL.pagination),
of(FILES_TABLE_MODEL.termCountsByFacetName),
of(DEFAULT_FILE_SUMMARY)
of(DEFAULT_FILE_SUMMARY),
of([])
);

fixture.detectChanges();
Expand Down
Loading