diff --git a/pkg/ui/workspaces/cluster-ui/package.json b/pkg/ui/workspaces/cluster-ui/package.json index e7f0ac76b11b..e0b27fc20105 100644 --- a/pkg/ui/workspaces/cluster-ui/package.json +++ b/pkg/ui/workspaces/cluster-ui/package.json @@ -1,6 +1,6 @@ { "name": "@cockroachlabs/cluster-ui", - "version": "22.2.2", + "version": "22.2.3", "description": "Cluster UI is a library of large features shared between CockroachDB and CockroachCloud", "repository": { "type": "git", diff --git a/pkg/ui/workspaces/cluster-ui/src/indexDetailsPage/indexDetailsConnected.ts b/pkg/ui/workspaces/cluster-ui/src/indexDetailsPage/indexDetailsConnected.ts index c872521791ca..00ef7af80b03 100644 --- a/pkg/ui/workspaces/cluster-ui/src/indexDetailsPage/indexDetailsConnected.ts +++ b/pkg/ui/workspaces/cluster-ui/src/indexDetailsPage/indexDetailsConnected.ts @@ -17,6 +17,7 @@ import { connect } from "react-redux"; import { actions as indexStatsActions } from "src/store/indexStats/indexStats.reducer"; import { cockroach } from "@cockroachlabs/crdb-protobuf-client"; import { actions as nodesActions } from "../store/nodes"; +import { actions as analyticsActions } from "../store/analytics"; const mapStateToProps = (state: AppState, props: RouteComponentProps) => { return selectIndexDetails(state, props); @@ -40,6 +41,12 @@ const mapDispatchToProps = (dispatch: Dispatch): IndexDetailPageActions => ({ table, }), ); + dispatch( + analyticsActions.track({ + name: "Reset Index Usage", + page: "Index Details", + }), + ); }, refreshNodes: () => dispatch(nodesActions.refresh()), refreshUserSQLRoles: () => dispatch(uiConfigActions.refreshUserSQLRoles()), diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/schemaInsights/schemaInsightsPageConnected.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/schemaInsights/schemaInsightsPageConnected.tsx index f2784bccd581..a7243204828f 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/schemaInsights/schemaInsightsPageConnected.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insights/schemaInsights/schemaInsightsPageConnected.tsx @@ -30,6 +30,7 @@ import { SortSetting } from "src/sortedtable"; import { actions as localStorageActions } from "../../store/localStorage"; import { Dispatch } from "redux"; import { selectHasAdminRole } from "../../store/uiConfig"; +import { actions as analyticsActions } from "../../store/analytics"; const mapStateToProps = ( state: AppState, @@ -54,6 +55,14 @@ const mapDispatchToProps = ( value: filters, }), ); + dispatch( + analyticsActions.track({ + name: "Filter Clicked", + page: "Schema Insights", + filterName: "filters", + value: filters.toString(), + }), + ); }, onSortChange: (ss: SortSetting) => { dispatch( @@ -62,6 +71,14 @@ const mapDispatchToProps = ( value: ss, }), ); + dispatch( + analyticsActions.track({ + name: "Column Sorted", + page: "Schema Insights", + tableName: "Schema Insights Table", + columnName: ss.columnTitle, + }), + ); }, refreshSchemaInsights: () => { dispatch(actions.refresh()); diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetailsConnected.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetailsConnected.tsx index cd254cd19792..bbb70ed21877 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetailsConnected.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetailsConnected.tsx @@ -24,6 +24,7 @@ import { import { selectHasAdminRole, selectIsTenant } from "src/store/uiConfig"; import { TimeScale } from "../../timeScaleDropdown"; import { actions as sqlStatsActions } from "../../store/sqlStats"; +import { actions as analyticsActions } from "../../store/analytics"; const mapStateToProps = ( state: AppState, @@ -51,6 +52,13 @@ const mapDispatchToProps = ( ts: ts, }), ); + dispatch( + analyticsActions.track({ + name: "TimeScale changed", + page: "Statement Insight Details", + value: ts.key, + }), + ); }, refreshUserSQLRoles: () => dispatch(uiConfigActions.refreshUserSQLRoles()), }); diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/transactionInsightDetailsConnected.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/transactionInsightDetailsConnected.tsx index ad02700cdca0..8bc362a75be7 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/transactionInsightDetailsConnected.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/transactionInsightDetailsConnected.tsx @@ -25,6 +25,7 @@ import { actions as sqlStatsActions } from "../../store/sqlStats"; import { Dispatch } from "redux"; import { TransactionInsightEventDetailsRequest } from "src/api"; import { selectHasAdminRole } from "src/store/uiConfig"; +import { actions as analyticsActions } from "../../store/analytics"; const mapStateToProps = ( state: AppState, @@ -53,6 +54,13 @@ const mapDispatchToProps = ( ts: ts, }), ); + dispatch( + analyticsActions.track({ + name: "TimeScale changed", + page: "Transaction Insight Details", + value: ts.key, + }), + ); }, refreshUserSQLRoles: () => dispatch(uiConfigActions.refreshUserSQLRoles()), }); diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/workloadInsightsPageConnected.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/workloadInsightsPageConnected.tsx index 03e225781afb..8f74dfa5ca7a 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/workloadInsightsPageConnected.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/workloadInsightsPageConnected.tsx @@ -39,14 +39,10 @@ import { selectFilters, selectSortSetting, } from "src/store/insights/transactionInsights"; -import { bindActionCreators, Dispatch } from "redux"; +import { Dispatch } from "redux"; import { TimeScale } from "../../timeScaleDropdown"; import { actions as sqlStatsActions } from "../../store/sqlStats"; -import { - StatementInsightDetails, - StatementInsightDetailsDispatchProps, - StatementInsightDetailsStateProps, -} from "../workloadInsightDetails"; +import { actions as analyticsActions } from "../../store/analytics"; const transactionMapStateToProps = ( state: AppState, @@ -72,26 +68,51 @@ const statementMapStateToProps = ( const TransactionDispatchProps = ( dispatch: Dispatch, ): TransactionInsightsViewDispatchProps => ({ - onFiltersChange: (filters: WorkloadInsightEventFilters) => + onFiltersChange: (filters: WorkloadInsightEventFilters) => { dispatch( localStorageActions.update({ key: "filters/InsightsPage", value: filters, }), - ), - onSortChange: (ss: SortSetting) => + ); + dispatch( + analyticsActions.track({ + name: "Filter Clicked", + page: "Workload Insights - Transaction", + filterName: "filters", + value: filters.toString(), + }), + ); + }, + onSortChange: (ss: SortSetting) => { dispatch( localStorageActions.update({ key: "sortSetting/InsightsPage", value: ss, }), - ), + ); + dispatch( + analyticsActions.track({ + name: "Column Sorted", + page: "Workload Insights - Transaction", + tableName: "Workload Transaction Insights Table", + columnName: ss.columnTitle, + }), + ); + }, setTimeScale: (ts: TimeScale) => { dispatch( sqlStatsActions.updateTimeScale({ ts: ts, }), ); + dispatch( + analyticsActions.track({ + name: "TimeScale changed", + page: "Workload Insights - Transaction", + value: ts.key, + }), + ); }, refreshTransactionInsights: () => { dispatch(transactionInsights.refresh()); @@ -101,37 +122,71 @@ const TransactionDispatchProps = ( const StatementDispatchProps = ( dispatch: Dispatch, ): StatementInsightsViewDispatchProps => ({ - onFiltersChange: (filters: WorkloadInsightEventFilters) => + onFiltersChange: (filters: WorkloadInsightEventFilters) => { dispatch( localStorageActions.update({ key: "filters/InsightsPage", value: filters, }), - ), - onSortChange: (ss: SortSetting) => + ); + dispatch( + analyticsActions.track({ + name: "Filter Clicked", + page: "Workload Insights - Statement", + filterName: "filters", + value: filters.toString(), + }), + ); + }, + onSortChange: (ss: SortSetting) => { dispatch( localStorageActions.update({ key: "sortSetting/InsightsPage", value: ss, }), - ), + ); + dispatch( + analyticsActions.track({ + name: "Column Sorted", + page: "Workload Insights - Statement", + tableName: "Workload Statement Insights Table", + columnName: ss.columnTitle, + }), + ); + }, // We use `null` when the value was never set and it will show all columns. // If the user modifies the selection and no columns are selected, // the function will save the value as a blank space, otherwise // it gets saved as `null`. - onColumnsChange: (value: string[]) => + onColumnsChange: (value: string[]) => { + const columns = value.length === 0 ? " " : value.join(","); dispatch( localStorageActions.update({ key: "showColumns/StatementInsightsPage", - value: value.length === 0 ? " " : value.join(","), + value: columns, }), - ), + ); + dispatch( + analyticsActions.track({ + name: "Columns Selected change", + page: "Workload Insights - Statement", + value: columns, + }), + ); + }, setTimeScale: (ts: TimeScale) => { dispatch( sqlStatsActions.updateTimeScale({ ts: ts, }), ); + dispatch( + analyticsActions.track({ + name: "TimeScale changed", + page: "Workload Insights - Statement", + value: ts.key, + }), + ); }, refreshStatementInsights: () => { dispatch(statementInsights.refresh()); diff --git a/pkg/ui/workspaces/cluster-ui/src/jobs/jobsPage/jobsPageConnected.tsx b/pkg/ui/workspaces/cluster-ui/src/jobs/jobsPage/jobsPageConnected.tsx index 30fe407a58ca..3701b8f767a5 100644 --- a/pkg/ui/workspaces/cluster-ui/src/jobs/jobsPage/jobsPageConnected.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/jobs/jobsPage/jobsPageConnected.tsx @@ -19,7 +19,7 @@ import { selectTypeSetting, selectStatusSetting, selectColumns, -} from "../../store/jobs/jobs.selectors"; +} from "../../store/jobs"; import { JobsPageStateProps, JobsPageDispatchProps, @@ -30,6 +30,7 @@ import { actions as jobsActions } from "src/store/jobs"; import { actions as localStorageActions } from "../../store/localStorage"; import { Dispatch } from "redux"; import { SortSetting } from "../../sortedtable"; +import { actions as analyticsActions } from "../../store/analytics"; const mapStateToProps = ( state: AppState, @@ -72,6 +73,14 @@ const mapDispatchToProps = (dispatch: Dispatch): JobsPageDispatchProps => ({ value: ss, }), ); + dispatch( + analyticsActions.track({ + name: "Column Sorted", + page: "Jobs", + tableName: "Jobs Table", + columnName: ss.columnTitle, + }), + ); }, setStatus: (statusValue: string) => { dispatch( @@ -88,14 +97,31 @@ const mapDispatchToProps = (dispatch: Dispatch): JobsPageDispatchProps => ({ value: jobValue, }), ); + dispatch( + analyticsActions.track({ + name: "Job Type Selected", + page: "Jobs", + value: jobValue.toString(), + }), + ); }, - onColumnsChange: (selectedColumns: string[]) => + onColumnsChange: (selectedColumns: string[]) => { + const columns = + selectedColumns.length === 0 ? " " : selectedColumns.join(","); dispatch( localStorageActions.update({ key: "showColumns/JobsPage", - value: selectedColumns.length === 0 ? " " : selectedColumns.join(","), + value: columns, }), - ), + ); + dispatch( + analyticsActions.track({ + name: "Columns Selected change", + page: "Jobs", + value: columns, + }), + ); + }, refreshJobs: (req: JobsRequest) => dispatch(jobsActions.refresh(req)), }); diff --git a/pkg/ui/workspaces/cluster-ui/src/sessions/sessionsPageConnected.tsx b/pkg/ui/workspaces/cluster-ui/src/sessions/sessionsPageConnected.tsx index d278e67b9a8d..d97a288e29ff 100644 --- a/pkg/ui/workspaces/cluster-ui/src/sessions/sessionsPageConnected.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/sessions/sessionsPageConnected.tsx @@ -134,7 +134,7 @@ export const SessionsPageConnected = withRouter( analyticsActions.track({ name: "Filter Clicked", page: "Sessions", - filterName: "app", + filterName: "filters", value: value.toString(), }), ); diff --git a/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetailsConnected.ts b/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetailsConnected.ts index 077c44129266..3f11bc3f3e46 100644 --- a/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetailsConnected.ts +++ b/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetailsConnected.ts @@ -101,6 +101,13 @@ const mapDispatchToProps = ( ts: ts, }), ); + dispatch( + analyticsActions.track({ + name: "TimeScale changed", + page: "Statement Details", + value: ts.key, + }), + ); }, dismissStatementDiagnosticsAlertMessage: () => dispatch( diff --git a/pkg/ui/workspaces/cluster-ui/src/statementsPage/statementsPageConnected.tsx b/pkg/ui/workspaces/cluster-ui/src/statementsPage/statementsPageConnected.tsx index 4bc8bf2245b4..f9c5c89666c5 100644 --- a/pkg/ui/workspaces/cluster-ui/src/statementsPage/statementsPageConnected.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/statementsPage/statementsPageConnected.tsx @@ -205,7 +205,7 @@ export const ConnectedStatementsPage = withRouter( analyticsActions.track({ name: "Filter Clicked", page: "Statements", - filterName: "app", + filterName: "filters", value: value.toString(), }), ); diff --git a/pkg/ui/workspaces/cluster-ui/src/store/analytics/analytics.reducer.ts b/pkg/ui/workspaces/cluster-ui/src/store/analytics/analytics.reducer.ts index 4f9b4b995ba8..3f938e9e2ad0 100644 --- a/pkg/ui/workspaces/cluster-ui/src/store/analytics/analytics.reducer.ts +++ b/pkg/ui/workspaces/cluster-ui/src/store/analytics/analytics.reducer.ts @@ -12,81 +12,115 @@ import { createAction } from "@reduxjs/toolkit"; import { DOMAIN_NAME } from "../utils"; type Page = - | "Statements" - | "Statement Details" + | "Index Details" + | "Jobs" + | "Schema Insights" | "Sessions" | "Sessions Details" + | "Statements" + | "Statement Details" + | "Statement Insight Details" | "Transactions" - | "Transaction Details"; + | "Transaction Details" + | "Transaction Insight Details" + | "Workload Insights - Statement" + | "Workload Insights - Transaction"; -type SearchEvent = { - name: "Keyword Searched"; +type BackButtonClick = { + name: "Back Clicked"; page: Page; }; -type SortingEvent = { - name: "Column Sorted"; +type ColumnsChangeEvent = { + name: "Columns Selected change"; page: Page; - tableName: string; - columnName: string; + value: string; }; -type StatementDiagnosticEvent = { - name: "Statement Diagnostics Clicked"; +type FilterEvent = { + name: "Filter Clicked"; page: Page; - action: "Activated" | "Downloaded" | "Cancelled"; + filterName: string; + value: string; }; -type TabChangedEvent = { - name: "Tab Changed"; - tabName: string; +type JobTypeEvent = { + name: "Job Type Selected"; page: Page; + value: string; }; -type BackButtonClick = { - name: "Back Clicked"; +type ResetStats = { + name: "Reset Index Usage" | "Reset Stats"; page: Page; }; -type StatementClicked = { - name: "Statement Clicked"; +type SearchEvent = { + name: "Keyword Searched"; page: Page; }; +type SessionActionsClicked = { + name: "Session Actions Clicked"; + page: Page; + action: "Cancel Statement" | "Cancel Session"; +}; + type SessionClicked = { name: "Session Clicked"; page: Page; }; -type SessionActionsClicked = { - name: "Session Actions Clicked"; +type SortingEvent = { + name: "Column Sorted"; page: Page; - action: "Cancel Statement" | "Cancel Session"; + tableName: string; + columnName: string; }; -type FilterEvent = { - name: "Filter Clicked"; +type StatementClicked = { + name: "Statement Clicked"; + page: Page; +}; + +type StatementDiagnosticEvent = { + name: "Statement Diagnostics Clicked"; + page: Page; + action: "Activated" | "Downloaded" | "Cancelled"; +}; + +type TabChangedEvent = { + name: "Tab Changed"; + tabName: string; + page: Page; +}; + +type TimeScaleChangeEvent = { + name: "TimeScale changed"; page: Page; - filterName: string; value: string; }; type AnalyticsEvent = - | SortingEvent - | StatementDiagnosticEvent - | SearchEvent - | TabChangedEvent | BackButtonClick + | ColumnsChangeEvent | FilterEvent - | StatementClicked + | JobTypeEvent + | ResetStats + | SearchEvent + | SessionActionsClicked | SessionClicked - | SessionActionsClicked; + | SortingEvent + | StatementClicked + | StatementDiagnosticEvent + | TabChangedEvent + | TimeScaleChangeEvent; const PREFIX = `${DOMAIN_NAME}/analytics`; /** * actions accept payload with "page" field which specifies the page where - * action occurs and a value expected expected by specific action. + * action occurs and a value expected by specific action. */ export const actions = { track: createAction(`${PREFIX}/track`, (event: AnalyticsEvent) => ({ diff --git a/pkg/ui/workspaces/cluster-ui/src/transactionDetails/transactionDetailsConnected.tsx b/pkg/ui/workspaces/cluster-ui/src/transactionDetails/transactionDetailsConnected.tsx index b4a9ba2e4932..18093cf5dbb8 100644 --- a/pkg/ui/workspaces/cluster-ui/src/transactionDetails/transactionDetailsConnected.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/transactionDetails/transactionDetailsConnected.tsx @@ -35,6 +35,7 @@ import { selectTimeScale } from "src/statementsPage/statementsPage.selectors"; import { StatementsRequest } from "src/api/statementsApi"; import { txnFingerprintIdAttr, getMatchParamByName } from "../util"; import { TimeScale } from "../timeScaleDropdown"; +import { actions as analyticsActions } from "../store/analytics"; export const selectTransaction = createSelector( (state: AppState) => state.adminUI?.sqlStats, @@ -103,6 +104,13 @@ const mapDispatchToProps = ( ts: ts, }), ); + dispatch( + analyticsActions.track({ + name: "TimeScale changed", + page: "Transaction Details", + value: ts.key, + }), + ); }, }); diff --git a/pkg/ui/workspaces/cluster-ui/src/transactionsPage/transactionsPageConnected.tsx b/pkg/ui/workspaces/cluster-ui/src/transactionsPage/transactionsPageConnected.tsx index 2a0707e23376..aae225de504a 100644 --- a/pkg/ui/workspaces/cluster-ui/src/transactionsPage/transactionsPageConnected.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/transactionsPage/transactionsPageConnected.tsx @@ -132,7 +132,7 @@ export const TransactionsPageConnected = withRouter( analyticsActions.track({ name: "Filter Clicked", page: "Transactions", - filterName: "app", + filterName: "filters", value: value.toString(), }), );