Skip to content

Commit

Permalink
feat(analytics): 1631 Add analytics (#249)
Browse files Browse the repository at this point in the history
  • Loading branch information
tihuan authored May 6, 2022
1 parent 8544eb5 commit 8af586a
Show file tree
Hide file tree
Showing 23 changed files with 237 additions and 32 deletions.
45 changes: 45 additions & 0 deletions client/src/analytics/events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Plausible event namespace: EXPLORER_*
* Since Data Portal and Explorer share the same Plausible account, we need to
* namespace the events to differentiate between them.
*
* NOTE: If you modify this file, you must update Plausible custom event page for
* both staging and prod environments as well.
* Staging: https://plausible.io/cellxgene.staging.single-cell.czi.technology/settings/goals
* Prod: https://plausible.io/cellxgene.cziscience.com/settings/goals
*/
export enum EVENTS {
EXPLORER_DIFF_EXP_BUTTON_CLICKED = "EXPLORER_DIFF_EXP_BUTTON_CLICKED",
EXPLORER_CATEGORY_EXPAND_BUTTON_CLICKED = "EXPLORER_CATEGORY_EXPAND_BUTTON_CLICKED",
EXPLORER_CELLSET_BUTTON_CLICKED = "EXPLORER_CELLSET_BUTTON_CLICKED",
EXPLORER_SUBSET_BUTTON_CLICKED = "EXPLORER_SUBSET_BUTTON_CLICKED",
EXPLORER_RESET_SUBSET_BUTTON_CLICKED = "EXPLORER_RESET_SUBSET_BUTTON_CLICKED",
EXPLORER_MODE_LASSO_BUTTON_CLICKED = "EXPLORER_MODE_LASSO_BUTTON_CLICKED",
EXPLORER_MODE_PAN_ZOOM_BUTTON_CLICKED = "EXPLORER_MODE_PAN_ZOOM_BUTTON_CLICKED",
EXPLORER_CENTROID_LABEL_TOGGLE_BUTTON_CLICKED = "EXPLORER_CENTROID_LABEL_TOGGLE_BUTTON_CLICKED",
EXPLORER_VISUALIZATION_SETTINGS_BUTTON_CLICKED = "EXPLORER_VISUALIZATION_SETTINGS_BUTTON_CLICKED",
EXPLORER_UNDO_BUTTON_CLICKED = "EXPLORER_UNDO_BUTTON_CLICKED",
EXPLORER_REDO_BUTTON_CLICKED = "EXPLORER_REDO_BUTTON_CLICKED",
EXPLORER_LAYOUT_CHOICE_BUTTON_CLICKED = "EXPLORER_LAYOUT_CHOICE_BUTTON_CLICKED",
EXPLORER_LAYOUT_CHOICE_CHANGE_ITEM_CLICKED = "EXPLORER_LAYOUT_CHOICE_CHANGE_ITEM_CLICKED",
EXPLORER_FLOATING_BUTTON_CLICKED = "EXPLORER_FLOATING_BUTTON_CLICKED",
EXPLORER_COLORBY_AUTHOR_CATEGORIES_BUTTON_CLICKED = "EXPLORER_COLORBY_AUTHOR_CATEGORIES_BUTTON_CLICKED",
EXPLORER_COLORBY_HISTOGRAM_CONTINUOUS_BUTTON_CLICKED = "EXPLORER_COLORBY_HISTOGRAM_CONTINUOUS_BUTTON_CLICKED",
EXPLORER_COLORBY_GENE_BUTTON_CLICKED = "EXPLORER_COLORBY_GENE_BUTTON_CLICKED",
EXPLORER_SUGGEST_MENU_ITEM_CLICKED = "EXPLORER_SUGGEST_MENU_ITEM_CLICKED",
EXPLORER_GENESET_EXPAND_BUTTON_CLICKED = "EXPLORER_GENESET_EXPAND_BUTTON_CLICKED",
EXPLORER_GENESET_HEADING_EXPAND_BUTTON_CLICKED = "EXPLORER_GENESET_HEADING_EXPAND_BUTTON_CLICKED",
EXPLORER_HANDLE_ADD_NEW_GENE_TO_GENESET_BUTTON_CLICKED = "EXPLORER_HANDLE_ADD_NEW_GENE_TO_GENESET_BUTTON_CLICKED",
EXPLORER_SEE_ACTIONS_BUTTON_CLICKED = "EXPLORER_SEE_ACTIONS_BUTTON_CLICKED",
EXPLORER_COLOR_BY_ENTIRE_GENESET_BUTTON_CLICKED = "EXPLORER_COLOR_BY_ENTIRE_GENESET_BUTTON_CLICKED",
EXPLORER_MENU_BUTTON_CLICKED = "EXPLORER_MENU_BUTTON_CLICKED",
EXPLORER_OPEN_CREATE_GENESET_DIALOG_BUTTON_CLICKED = "EXPLORER_OPEN_CREATE_GENESET_DIALOG_BUTTON_CLICKED",
EXPLORER_SUBMIT_GENESET_BUTTON_CLICKED = "EXPLORER_SUBMIT_GENESET_BUTTON_CLICKED",
EXPLORER_SUBMIT_GENE_BUTTON_CLICKED = "EXPLORER_SUBMIT_GENE_BUTTON_CLICKED",
EXPLORER_DELETE_FROM_GENESET_BUTTON_CLICKED = "EXPLORER_DELETE_FROM_GENESET_BUTTON_CLICKED",
EXPLORER_PLOT_X_BUTTON_CLICKED = "EXPLORER_PLOT_X_BUTTON_CLICKED",
EXPLORER_PLOT_Y_BUTTON_CLICKED = "EXPLORER_PLOT_Y_BUTTON_CLICKED",
EXPLORER_MAXIMIZE_GENE_BUTTON_CLICKED = "EXPLORER_MAXIMIZE_GENE_BUTTON_CLICKED",
EXPLORER_CATEGORY_SELECT_BUTTON_CLICKED = "EXPLORER_CATEGORY_SELECT_BUTTON_CLICKED",
EXPLORER_CATEGORICAL_VALUE_SELECT_BUTTON_CLICKED = "EXPLORER_CATEGORICAL_VALUE_SELECT_BUTTON_CLICKED",
}
20 changes: 20 additions & 0 deletions client/src/analytics/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { EVENTS } from "./events";

declare global {
interface Window {
plausible: {
q: unknown[];
(event: EVENTS, options?: { props: { [key: string]: unknown } }): void;
};
}
}

export function track(event: EVENTS, props?: Record<string, unknown>): void {
const options = props ? { props } : undefined;

try {
window.plausible(event, options);
} catch (error) {
console.error(error);
}
}
10 changes: 6 additions & 4 deletions client/src/components/brushableHistogram/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import React, { useCallback } from "react";
import { Button, ButtonGroup, Tooltip, Icon } from "@blueprintjs/core";
import { IconNames } from "@blueprintjs/icons";
import * as globals from "../../globals";
import { EVENTS } from "../../analytics/events";
import { track } from "../../analytics";

const HistogramHeader = React.memo(
({
Expand Down Expand Up @@ -38,10 +40,10 @@ const HistogramHeader = React.memo(
Scatterplot controls will not render if either handler unspecified.
*/

const memoizedColorByCallback = useCallback(
() => onColorByClick(fieldId, isObs),
[fieldId, isObs, onColorByClick]
);
const memoizedColorByCallback = useCallback(() => {
track(EVENTS.EXPLORER_COLORBY_HISTOGRAM_CONTINUOUS_BUTTON_CLICKED);
onColorByClick(fieldId, isObs);
}, [fieldId, isObs, onColorByClick]);

return (
<div
Expand Down
6 changes: 6 additions & 0 deletions client/src/components/brushableHistogram/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import HistogramFooter from "./footer";
import StillLoading from "./loading";
import ErrorLoading from "./error";
import { Dataframe } from "../../util/dataframe";
import { track } from "../../analytics";
import { EVENTS } from "../../analytics/events";

const MARGIN = {
LEFT: 10, // Space for 0 tick label on X axis
Expand Down Expand Up @@ -197,6 +199,8 @@ class HistogramBrush extends React.PureComponent {

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
handleSetGeneAsScatterplotX = () => {
track(EVENTS.EXPLORER_PLOT_X_BUTTON_CLICKED);

// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
const { dispatch, field } = this.props;
dispatch({
Expand All @@ -207,6 +211,8 @@ class HistogramBrush extends React.PureComponent {

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
handleSetGeneAsScatterplotY = () => {
track(EVENTS.EXPLORER_PLOT_Y_BUTTON_CLICKED);

// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
const { dispatch, field } = this.props;
dispatch({
Expand Down
9 changes: 9 additions & 0 deletions client/src/components/categorical/category/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import {
} from "../../../util/stateManager/colorHelpers";
import actions from "../../../actions";
import { Dataframe } from "../../../util/dataframe";
import { track } from "../../../analytics";
import { EVENTS } from "../../../analytics/events";

const LABEL_WIDTH = globals.leftSidebarWidth - 100;
const ANNO_BUTTON_WIDTH = 50;
Expand Down Expand Up @@ -103,6 +105,9 @@ class Category extends React.PureComponent {
handleColorChange = () => {
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
const { dispatch, metadataField } = this.props;

track(EVENTS.EXPLORER_COLORBY_AUTHOR_CATEGORIES_BUTTON_CLICKED);

dispatch({
type: "color by categorical metadata",
colorAccessor: metadataField,
Expand All @@ -111,6 +116,8 @@ class Category extends React.PureComponent {

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
handleCategoryClick = () => {
track(EVENTS.EXPLORER_CATEGORY_EXPAND_BUTTON_CLICKED);

// @ts-expect-error ts-migrate(2339) FIXME: Property 'annotations' does not exist on type 'Rea... Remove this comment to see the full error message
const { annotations, metadataField, onExpansionChange } = this.props;
const editingCategory =
Expand All @@ -130,6 +137,8 @@ class Category extends React.PureComponent {

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
handleToggleAllClick = (categorySummary: any) => {
track(EVENTS.EXPLORER_CATEGORY_SELECT_BUTTON_CLICKED);

const isChecked = this.getSelectionState(categorySummary);
if (isChecked === "all") {
this.toggleNone(categorySummary);
Expand Down
4 changes: 4 additions & 0 deletions client/src/components/categorical/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import AnnoSelect from "./annoSelect";
import LabelInput from "../labelInput";
import { labelPrompt } from "./labelUtil";
import actions from "../../actions";
import { track } from "../../analytics";
import { EVENTS } from "../../analytics/events";

// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
type State = any;
Expand Down Expand Up @@ -58,6 +60,8 @@ class Categories extends React.Component<{}, State> {

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
handleEnableAnnoMode = () => {
track(EVENTS.EXPLORER_OPEN_CREATE_GENESET_DIALOG_BUTTON_CLICKED);

this.setState({ createAnnoModeActive: true });
};

Expand Down
11 changes: 9 additions & 2 deletions client/src/components/categorical/value/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import MiniHistogram from "../../miniHistogram";
import MiniStackedBar from "../../miniStackedBar";
import { CategoryCrossfilterContext } from "../categoryContext";
import { Dataframe, ContinuousHistogram } from "../../../util/dataframe";
import { track } from "../../../analytics";
import { EVENTS } from "../../../analytics/events";

const STACKED_BAR_HEIGHT = 11;
const STACKED_BAR_WIDTH = 100;
Expand Down Expand Up @@ -184,6 +186,8 @@ class CategoryValue extends React.Component<{}, State> {

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
toggleOff = () => {
track(EVENTS.EXPLORER_CATEGORICAL_VALUE_SELECT_BUTTON_CLICKED);

const {
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
dispatch,
Expand All @@ -194,6 +198,7 @@ class CategoryValue extends React.Component<{}, State> {
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categorySummary' does not exist on type ... Remove this comment to see the full error message
categorySummary,
} = this.props;

const label = categorySummary.categoryValues[categoryIndex];
dispatch(
actions.selectCategoricalMetadataAction(
Expand Down Expand Up @@ -267,6 +272,8 @@ class CategoryValue extends React.Component<{}, State> {

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
toggleOn = () => {
track(EVENTS.EXPLORER_CATEGORICAL_VALUE_SELECT_BUTTON_CLICKED);

const {
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
dispatch,
Expand Down Expand Up @@ -353,10 +360,10 @@ class CategoryValue extends React.Component<{}, State> {
50,
[range.min, range.max],
groupBy
);
);

const bins = histogramMap.has(categoryValue)
? histogramMap.get(categoryValue) as ContinuousHistogram
? (histogramMap.get(categoryValue) as ContinuousHistogram)
: new Array<number>(50).fill(0);

const xScale = d3.scaleLinear().domain([0, bins.length]).range([0, width]);
Expand Down
10 changes: 10 additions & 0 deletions client/src/components/embedding/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
import * as globals from "../../globals";
import actions from "../../actions";
import { getDiscreteCellEmbeddingRowIndex } from "../../util/stateManager/viewStackHelpers";
import { track } from "../../analytics";
import { EVENTS } from "../../analytics/events";

// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
type EmbeddingState = any;
Expand All @@ -35,10 +37,17 @@ class Embedding extends React.PureComponent<{}, EmbeddingState> {
this.state = {};
}

handleLayoutChoiceClick = (): void => {
track(EVENTS.EXPLORER_LAYOUT_CHOICE_BUTTON_CLICKED);
};

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
handleLayoutChoiceChange = (e: any) => {
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
const { dispatch } = this.props;

track(EVENTS.EXPLORER_LAYOUT_CHOICE_CHANGE_ITEM_CLICKED);

dispatch(actions.layoutChoiceAction(e.currentTarget.value));
};

Expand Down Expand Up @@ -73,6 +82,7 @@ class Embedding extends React.PureComponent<{}, EmbeddingState> {
style={{
cursor: "pointer",
}}
onClick={this.handleLayoutChoiceClick}
>
{layoutChoice?.current}: {crossfilter.countSelected()} out of{" "}
{crossfilter.size()} cells
Expand Down
10 changes: 9 additions & 1 deletion client/src/components/floatingButton/floatingButton.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/* Core dependencies */
import { Colors, Menu, MenuItem, Popover, Position } from "@blueprintjs/core";
import React, { useState } from "react";
import { track } from "../../analytics";
import { EVENTS } from "../../analytics/events";

/* App dependencies */
import { IconNames } from "../icon";
Expand All @@ -12,6 +14,11 @@ import Icon from "../icon/icon";
function FloatingButton(): JSX.Element {
const [helpMenuOpen, setHelpMenuOpen] = useState(false);

function handleHelpMenuClick() {
track(EVENTS.EXPLORER_FLOATING_BUTTON_CLICKED);
setHelpMenuOpen(true);
}

return (
<Popover
content={
Expand Down Expand Up @@ -44,7 +51,7 @@ function FloatingButton(): JSX.Element {
position={Position.TOP_RIGHT}
target={
<button
onClick={() => setHelpMenuOpen(true)}
onClick={handleHelpMenuClick}
style={{
alignItems: "center",
backgroundColor: Colors.DARK_GRAY1,
Expand All @@ -58,6 +65,7 @@ function FloatingButton(): JSX.Element {
width: 32,
}}
type="button"
data-testid="floating-button"
>
<Icon icon={IconNames.HELP} />
</button>
Expand Down
24 changes: 21 additions & 3 deletions client/src/components/geneExpression/gene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import HistogramBrush from "../brushableHistogram";

import actions from "../../actions";

import { track } from "../../analytics";
import { EVENTS } from "../../analytics/events";

const MINI_HISTOGRAM_WIDTH = 110;

// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
Expand Down Expand Up @@ -42,17 +45,24 @@ class Gene extends React.Component<{}, State> {
onColorChangeClick = () => {
// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
const { dispatch, gene } = this.props;

track(EVENTS.EXPLORER_COLORBY_GENE_BUTTON_CLICKED);

dispatch(actions.requestSingleGeneExpressionCountsForColoringPOST(gene));
};

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
handleGeneExpandClick = () => {
track(EVENTS.EXPLORER_MAXIMIZE_GENE_BUTTON_CLICKED);

const { geneIsExpanded } = this.state;
this.setState({ geneIsExpanded: !geneIsExpanded });
};

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
handleSetGeneAsScatterplotX = () => {
track(EVENTS.EXPLORER_PLOT_X_BUTTON_CLICKED);

// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
const { dispatch, gene } = this.props;
dispatch({
Expand All @@ -63,6 +73,8 @@ class Gene extends React.Component<{}, State> {

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
handleSetGeneAsScatterplotY = () => {
track(EVENTS.EXPLORER_PLOT_Y_BUTTON_CLICKED);

// @ts-expect-error ts-migrate(2339) FIXME: Property 'dispatch' does not exist on type 'Readon... Remove this comment to see the full error message
const { dispatch, gene } = this.props;
dispatch({
Expand Down Expand Up @@ -167,9 +179,15 @@ class Gene extends React.Component<{}, State> {
minimal
small
data-testid={`delete-from-geneset:${gene}`}
onClick={
quickGene ? removeGene(gene) : this.handleDeleteGeneFromSet
}
onClick={() => {
track(EVENTS.EXPLORER_DELETE_FROM_GENESET_BUTTON_CLICKED);

if (quickGene) {
removeGene(gene)();
} else {
this.handleDeleteGeneFromSet();
}
}}
intent="none"
style={{ fontWeight: 700, marginRight: 2 }}
icon={<Icon icon="trash" iconSize={10} />}
Expand Down
4 changes: 4 additions & 0 deletions client/src/components/geneExpression/geneSet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import EditGenesetNameDialogue from "./menus/editGenesetNameDialogue";
import HistogramBrush from "../brushableHistogram";

import { diffexpPopNamePrefix1, diffexpPopNamePrefix2 } from "../../globals";
import { track } from "../../analytics";
import { EVENTS } from "../../analytics/events";

// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
type State = any;
Expand All @@ -24,6 +26,8 @@ class GeneSet extends React.Component<{}, State> {

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
onGenesetMenuClick = () => {
track(EVENTS.EXPLORER_GENESET_EXPAND_BUTTON_CLICKED);

const { isOpen } = this.state;
this.setState({ isOpen: !isOpen });
};
Expand Down
Loading

0 comments on commit 8af586a

Please sign in to comment.