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
49 changes: 48 additions & 1 deletion google-analytics.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,63 @@

The following custom dimensions are configured in Google Analytics, allowing additional data (in addition to Category, Action and Label) to be included in each data layer event fired from the front end.

- `currentQuery`
- `entityType`
- `entityUrl`
- `fileType`
- `facet`
- `fileFormat`
- `fileName`
- `fileType`
- `min`
- `max`
- `releaseName`
- `source`
- `term`
- `toolName`

#### Tracked Events

##### Search Events

###### De/Select Search Value

- Category: "Search"
- Action: "Select" or "Deselect"
- Label: `termName` or `between 0 and 100 years`


- Entity Type: "Facet"
- Current Query: `currentQuery`
- Facet: `facetName`
- Term: `termName` or `between 0 and 100 years`
- Source: "Cohort Export", "Manifest Export", "Cohort Matrix", "Facet Browser", "Search" or "Selected Terms"
- Min: `min`
- Max: `max`

###### Clear Search Terms

- Category: "Search"
- Action: "Clear"
- Label: "Clear All"


- Entity Type: "Facet"
- Current Query: `currentQuery`
- Source: "Selected Terms"


##### Sort Events

###### Sort Data Table

- Category: "Search Results"
- Action: "Sort"
- Label: `sortBy`

- Entity Type: "Projects", "Samples" or "Files"
- Direction: "Asc" or "Desc"
- Current Query: `currentQuery`

##### Manifest Events

###### Cohort Manifest Request
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* Human Cell Atlas
* https://www.humancellatlas.org/
*
* Action dispatched when sort order has been changed on data table.
*/

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

// App dependencies
import { TrackingAction } from "../analytics/tracking.action";
import { GAAction } from "../../../shared/analytics/ga-action.model";
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 { GASource } from "../../../shared/analytics/ga-source.model";
import { TableParams } from "../../table/pagination/table-params.model";

export class FetchSortedTableDataRequestAction implements Action, TrackingAction {

public static ACTION_TYPE = "TABLE.SORTED_DATA_REQUEST";
public readonly type = FetchSortedTableDataRequestAction.ACTION_TYPE;

/**
* @param {TableParams} tableParams
* @param {string} selectedEntity
* @param {GASource} source
* @param {string} currentQuery
*/
constructor(public tableParams: TableParams,
public selectedEntity: string,
public source: GASource,
public currentQuery: string) {}

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

return {
category: GACategory.SEARCH_RESULTS,
action: GAAction.SORT,
label: this.tableParams.sort,
dimensions: {
[GADimension.CURRENT_QUERY]: this.currentQuery,
[GADimension.DIRECTION]: this.tableParams.order,
[GADimension.ENTITY_TYPE]: this.selectedEntity,
[GADimension.SOURCE]: this.source,
}
};
}
}
7 changes: 0 additions & 7 deletions spa/src/app/files/_ngrx/table/table.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,6 @@ export class TableOrderByAction implements Action {
constructor(public field: string, public dir: string) {}
}

export class FetchPagedOrSortedTableDataRequestAction implements Action {
public static ACTION_TYPE = "TABLE.PAGED_OR_SORTED_DATA_REQUEST";
public readonly type = FetchPagedOrSortedTableDataRequestAction.ACTION_TYPE;

constructor(public tableParams: TableParams) {}
}

/**
* Action dispatched when tab is selected (eg Files or Samples).
*/
Expand Down
20 changes: 16 additions & 4 deletions spa/src/app/files/_ngrx/table/table.effects.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { FileState } from "../file.state";
import { FetchFileFacetsRequestAction } from "../facet/file-facet-list.actions";
import { DEFAULT_FILES_STATE, DEFAULT_PROJECTS_STATE, DEFAULT_SAMPLES_STATE } from "../file.state.mock";
import { FetchFileSummaryRequestAction } from "../file-summary/file-summary.actions";
import { FetchSortedTableDataRequestAction } from "./fetch-sorted-table-data-request.action";
import { FetchTableDataRequestAction } from "./fetch-table-data-request.action";
import { FetchTableDataSuccessAction } from "./fetch-table-data-success.action";
import { PROJECT_1M_NEURONS } from "../search/search.state.mock";
Expand All @@ -32,7 +33,9 @@ import { TableNextPageAction } from "./table-next-page.action";
import { TableNextPageSuccessAction } from "./table-next-page-success.action";
import { TablePreviousPageAction } from "./table-previous-page.action";
import { TablePreviousPageSuccessAction } from "./table-previous-page-success.action";
import { FetchPagedOrSortedTableDataRequestAction } from "./table.actions";
import { GTMService } from "../../../shared/analytics/gtm.service";
import { EntityName } from "../../shared/entity-name.model";
import { GASource } from "../../../shared/analytics/ga-source.model";

describe("Table Effects", () => {

Expand All @@ -56,7 +59,12 @@ describe("Table Effects", () => {
providers: [
TableEffects,
provideMockActions(() => actions),
{provide: FilesService, useValue: filesService},
{provide: FilesService, useValue: filesService}, {
provide: GTMService,
useValue: jasmine.createSpyObj("GTMService", [
"trackEvent"
])
},
{provide: ProjectService, useClass: ProjectMockService},
provideMockStore({initialState: DEFAULT_PROJECTS_STATE})
],
Expand Down Expand Up @@ -192,14 +200,18 @@ describe("Table Effects", () => {
store.setState(DEFAULT_FILES_STATE);

actions = hot("--a-", {
a: new FetchPagedOrSortedTableDataRequestAction({"search_before":"Assessing the relevance of organoids to model inter-individual variation","search_before_uid":"doc#2c4724a4-7252-409e-b008-ff5c127c7e89","size":15,"sort":"projectTitle","order":"desc"})
a: new FetchSortedTableDataRequestAction(
{"search_before":"Assessing the relevance of organoids to model inter-individual variation","search_before_uid":"doc#2c4724a4-7252-409e-b008-ff5c127c7e89","size":15,"sort":"projectTitle","order":"desc"},
EntityName.PROJECTS,
GASource.SEARCH_RESULTS,
"")
});

const tableModel = DEFAULT_PROJECTS_ENTITY_SEARCH_RESULTS.tableModel;
const expected = cold("--b", {
b: new FetchTableDataSuccessAction(tableModel.data, tableModel.pagination, DEFAULT_PROJECTS_ENTITY_SEARCH_RESULTS.tableModel.termCountsByFacetName)
});

expect(effects.fetchPagedOrSortedTableData$).toBeObservable(expected);
expect(effects.fetchSortedTableData$).toBeObservable(expected);
});
});
27 changes: 18 additions & 9 deletions spa/src/app/files/_ngrx/table/table.effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ import { AppState } from "../../../_ngrx/app.state";
import { Project } from "../../shared/project.model";
import { ProjectService } from "../../project/project.service";
import {
FetchPagedOrSortedTableDataRequestAction,
FetchProjectRequestAction,
FetchProjectSuccessAction,
} from "./table.actions";
import { FetchFileFacetsRequestAction } from "../facet/file-facet-list.actions";
import { selectTableQueryParams } from "../file.selectors";
import { FetchFileSummaryRequestAction } from "../file-summary/file-summary.actions";
import { FetchSortedTableDataRequestAction } from "./fetch-sorted-table-data-request.action";
import { FetchTableDataRequestAction } from "./fetch-table-data-request.action";
import { FetchTableDataSuccessAction } from "./fetch-table-data-success.action";
import { FetchTableModelRequestAction } from "./fetch-table-model-request.action";
Expand All @@ -34,10 +34,12 @@ import { SelectProjectIdAction } from "../search/select-project-id.action";
import { EntitySearchResults } from "../../shared/entity-search-results.model";
import { DEFAULT_TABLE_PARAMS } from "../../table/pagination/table-params.model";
import { FilesService } from "../../shared/files.service";
import { GTMService } from "../../../shared/analytics/gtm.service";
import { TableNextPageAction } from "./table-next-page.action";
import { TableNextPageSuccessAction } from "./table-next-page-success.action";
import { TablePreviousPageAction } from "./table-previous-page.action";
import { TablePreviousPageSuccessAction } from "./table-previous-page-success.action";
import { TrackingAction } from "../analytics/tracking.action";

@Injectable()
export class TableEffects {
Expand All @@ -46,11 +48,13 @@ export class TableEffects {
* @param {Store<AppState>} store
* @param {Actions} actions$
* @param {FilesService} fileService
* @param {GTMService} gtmService
* @param {ProjectService} projectService
*/
constructor(private store: Store<AppState>,
private actions$: Actions,
private fileService: FilesService,
private gtmService: GTMService,
private projectService: ProjectService) {
}

Expand All @@ -62,18 +66,18 @@ export class TableEffects {
.pipe(
ofType(TableNextPageAction.ACTION_TYPE),
withLatestFrom(this.store.pipe(select(selectTableQueryParams))),
switchMap(this.fetchPagedOrSortedTableModel.bind(this)),
switchMap(this.fetchSortedTableModel.bind(this)),
map((entitySearchResults: EntitySearchResults) =>
new TableNextPageSuccessAction(entitySearchResults.tableModel))
);

/**
* Sort order or page size of entity table has been updated, update table model data (but not the term counts).
* Sort order of entity table has been updated, update table model data (but not the term counts).
*/
@Effect()
fetchPagedOrSortedTableData$: Observable<Action> = this.actions$
fetchSortedTableData$: Observable<Action> = this.actions$
.pipe(
ofType(FetchPagedOrSortedTableDataRequestAction.ACTION_TYPE),
ofType(FetchSortedTableDataRequestAction.ACTION_TYPE),
switchMap((action) =>
this.store.pipe(
select(selectTableQueryParams),
Expand All @@ -84,8 +88,13 @@ export class TableEffects {
)
),
switchMap(({action, tableQueryParams}) => {

// If this action is a tracking action, send tracking event.
if ( (action as TrackingAction).asEvent ) {
this.gtmService.trackEvent((action as TrackingAction).asEvent());
}

return this.fetchPagedOrSortedTableModel([action, tableQueryParams]).pipe(
return this.fetchSortedTableModel([action, tableQueryParams]).pipe(
map((entitySearchResults) => {
return {entitySearchResults, tableQueryParams};
})
Expand All @@ -109,7 +118,7 @@ export class TableEffects {
.pipe(
ofType(TablePreviousPageAction.ACTION_TYPE),
withLatestFrom(this.store.pipe(select(selectTableQueryParams))),
switchMap(this.fetchPagedOrSortedTableModel.bind(this)),
switchMap(this.fetchSortedTableModel.bind(this)),
map((entitySearchResults: EntitySearchResults) =>
new TablePreviousPageSuccessAction(entitySearchResults.tableModel))
);
Expand Down Expand Up @@ -242,12 +251,12 @@ export class TableEffects {
/**
* Fetch the paged/sorted table data and map to appropriate format for FE.
*
* @param {[FetchPagedOrSortedTableDataRequestAction | TableNextPageAction | TablePreviousPageAction,
* @param {[FetchSortedTableDataRequestAction | TableNextPageAction | TablePreviousPageAction,
* Map<string, FileFacet> & Pagination & TableState]} [action, tableQueryParams]
* @param {any} tableQueryParams
* @returns {Observable<EntitySearchResults>}
*/
private fetchPagedOrSortedTableModel([action , tableQueryParams]): Observable<EntitySearchResults> {
private fetchSortedTableModel([action , tableQueryParams]): Observable<EntitySearchResults> {

const selectedSearchTermsByFacetName = tableQueryParams.selectedSearchTermsBySearchKey;
const tableParams = action.tableParams;
Expand Down
9 changes: 6 additions & 3 deletions spa/src/app/files/files.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@
</hca-file-summary>
<hca-tab [tabs]="state.entities" [activeTab]="state.selectedEntity"
(tabSelected)="onTabSelected($event)"></hca-tab>
<hca-table-samples *ngIf="(state.selectedEntity).key == 'samples'"></hca-table-samples>
<hca-table-files *ngIf="(state.selectedEntity).key == 'files'"></hca-table-files>
<hca-table-samples *ngIf="(state.selectedEntity).key == 'samples'"
[selectedSearchTerms]="state.selectedSearchTerms"></hca-table-samples>
<hca-table-files *ngIf="(state.selectedEntity).key == 'files'"
[selectedSearchTerms]="state.selectedSearchTerms"></hca-table-files>
<hca-table-projects *ngIf="(state.selectedEntity).key == 'projects'"
[selectedProjectIds]="state.selectedProjectIds"></hca-table-projects>
[selectedProjectIds]="state.selectedProjectIds"
[selectedSearchTerms]="state.selectedSearchTerms"></hca-table-projects>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<table-scroll [dataLoaded]="dataLoaded$">
<mat-table *ngIf="pagination$ | async; let pagination" #table [dataSource]="dataSource" matSort
matSortDirection="{{defaultSortOrder.order}}" matSortActive="{{defaultSortOrder.sort}}"
(matSortChange)="sortTable(pagination, $event)">
(matSortChange)="sortTable(pagination, $event, selectedSearchTerms)">
<ng-container matColumnDef="fileName">
<mat-header-cell *matHeaderCellDef [ngClass]="getColumnClass('fileName')"
[ngStyle]="getColumnStyle('fileName')">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { HCATablePaginationComponent } from "../hca-table-pagination/hca-table-p
import { HCATableSortComponent } from "../hca-table-sort/hca-table-sort.component";
import { PipeModule } from "../../pipe/pipe.module";
import { ProjectDownloadTSVComponent } from "../project-download-tsv/project-download-tsv.component";
import { SearchTermHttpService } from "../search/http/search-term-http.service";
import { CopyToClipboardComponent } from "../../shared/copy-to-clipboard/copy-to-clipboard.component";
import { DownloadService } from "../shared/download.service";
import { DownloadButtonComponent } from "../../shared/download-button/download-button.component";
Expand Down Expand Up @@ -139,6 +140,12 @@ describe("HCATableFilesComponent", () => {
{
provide: "PAGINATION_SERVICE",
useClass: PaginationService
}, {
provide: SearchTermHttpService,
useValue: jasmine.createSpyObj("SearchTermService", [
"bindSearchTerms",
"marshallSearchTerms"
])
},
{
provide: ResponsiveService,
Expand Down
Loading