From 15e83552f6d498a308897b85dbdf1424a4b52e9a Mon Sep 17 00:00:00 2001 From: Eric Harmeling Date: Wed, 21 Sep 2022 19:24:10 -0400 Subject: [PATCH] ui: add connected components for insights This commit adds connected components for the workload and schema insights pages, for use in the CC Console. Fixes #87693. Release note: None --- .../src/insights/schemaInsights/index.ts | 1 + .../schemaInsightsPageConnected.tsx | 67 ++++++++ .../schemaInsights/schemaInsightsView.tsx | 4 +- .../cluster-ui/src/insights/utils.ts | 24 +-- .../insights/workloadInsightDetails/index.ts | 2 + .../statementInsightDetails.tsx | 7 +- .../statementInsightDetailsConnected.tsx | 38 +++++ .../transactionInsightDetailsConnected.tsx | 49 ++++++ .../src/insights/workloadInsights/index.ts | 1 + .../statementInsightsView.tsx | 13 +- .../transactionInsightsView.tsx | 2 +- .../workloadInsightsPageConnected.tsx | 143 ++++++++++++++++++ .../index.ts} | 13 +- .../transactionInsightDetails.reducer.ts} | 15 +- .../transactionInsightDetails.sagas.ts} | 10 +- .../transactionInsightDetails.selectors.ts | 36 +++++ .../statementInsights}/index.ts | 6 +- .../statementInsights.reducer.ts | 53 +++++++ .../statementInsights.sagas.ts | 53 +++++++ .../statementInsights.selectors.ts | 64 ++++++++ .../insights/transactionInsights.selectors.ts | 17 --- .../{ => transactionInsights}/index.ts | 0 .../transactionInsights.reducer.ts | 12 +- .../transactionInsights.sagas.ts | 4 +- .../transactionInsights.selectors.ts | 49 ++++++ .../localStorage/localStorage.reducer.ts | 17 ++- .../cluster-ui/src/store/reducers.ts | 25 ++- .../workspaces/cluster-ui/src/store/sagas.ts | 6 +- .../schemaInsights.selectors.ts | 34 ++++- pkg/ui/workspaces/db-console/src/app.spec.tsx | 26 ++-- pkg/ui/workspaces/db-console/src/app.tsx | 10 +- .../src/views/insights/insightsOverview.tsx | 8 +- .../src/views/insights/insightsSelectors.ts | 2 +- ...geConnected.tsx => schemaInsightsPage.tsx} | 4 +- ...ed.tsx => statementInsightDetailsPage.tsx} | 4 +- ....tsx => transactionInsightDetailsPage.tsx} | 4 +- ...Connected.tsx => workloadInsightsPage.tsx} | 4 +- 37 files changed, 705 insertions(+), 122 deletions(-) create mode 100644 pkg/ui/workspaces/cluster-ui/src/insights/schemaInsights/schemaInsightsPageConnected.tsx create mode 100644 pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetailsConnected.tsx create mode 100644 pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/transactionInsightDetailsConnected.tsx create mode 100644 pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/workloadInsightsPageConnected.tsx rename pkg/ui/workspaces/cluster-ui/src/store/insightDetails/{insightDetails.selectors.ts => transactionInsightDetails/index.ts} (56%) rename pkg/ui/workspaces/cluster-ui/src/store/insightDetails/{insightDetails.reducer.ts => transactionInsightDetails/transactionInsightDetails.reducer.ts} (78%) rename pkg/ui/workspaces/cluster-ui/src/store/insightDetails/{insightDetails.sagas.ts => transactionInsightDetails/transactionInsightDetails.sagas.ts} (76%) create mode 100644 pkg/ui/workspaces/cluster-ui/src/store/insightDetails/transactionInsightDetails/transactionInsightDetails.selectors.ts rename pkg/ui/workspaces/cluster-ui/src/store/{insightDetails => insights/statementInsights}/index.ts (73%) create mode 100644 pkg/ui/workspaces/cluster-ui/src/store/insights/statementInsights/statementInsights.reducer.ts create mode 100644 pkg/ui/workspaces/cluster-ui/src/store/insights/statementInsights/statementInsights.sagas.ts create mode 100644 pkg/ui/workspaces/cluster-ui/src/store/insights/statementInsights/statementInsights.selectors.ts delete mode 100644 pkg/ui/workspaces/cluster-ui/src/store/insights/transactionInsights.selectors.ts rename pkg/ui/workspaces/cluster-ui/src/store/insights/{ => transactionInsights}/index.ts (100%) rename pkg/ui/workspaces/cluster-ui/src/store/insights/{ => transactionInsights}/transactionInsights.reducer.ts (80%) rename pkg/ui/workspaces/cluster-ui/src/store/insights/{ => transactionInsights}/transactionInsights.sagas.ts (93%) create mode 100644 pkg/ui/workspaces/cluster-ui/src/store/insights/transactionInsights/transactionInsights.selectors.ts rename pkg/ui/workspaces/db-console/src/views/insights/{schemaInsightsPageConnected.tsx => schemaInsightsPage.tsx} (95%) rename pkg/ui/workspaces/db-console/src/views/insights/{statementInsightDetailsPageConnected.tsx => statementInsightDetailsPage.tsx} (91%) rename pkg/ui/workspaces/db-console/src/views/insights/{transactionInsightDetailsPageConnected.tsx => transactionInsightDetailsPage.tsx} (93%) rename pkg/ui/workspaces/db-console/src/views/insights/{workloadInsightsPageConnected.tsx => workloadInsightsPage.tsx} (97%) diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/schemaInsights/index.ts b/pkg/ui/workspaces/cluster-ui/src/insights/schemaInsights/index.ts index 45c5dbc2f62a..5ca0b716c425 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/schemaInsights/index.ts +++ b/pkg/ui/workspaces/cluster-ui/src/insights/schemaInsights/index.ts @@ -11,3 +11,4 @@ export * from "./indexUsageStatsRec"; export * from "./schemaInsightsView"; export * from "./emptySchemaInsightsTablePlaceholder"; +export * from "./schemaInsightsPageConnected"; diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/schemaInsights/schemaInsightsPageConnected.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/schemaInsights/schemaInsightsPageConnected.tsx new file mode 100644 index 000000000000..50962a067826 --- /dev/null +++ b/pkg/ui/workspaces/cluster-ui/src/insights/schemaInsights/schemaInsightsPageConnected.tsx @@ -0,0 +1,67 @@ +// Copyright 2022 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +import { connect } from "react-redux"; +import { RouteComponentProps, withRouter } from "react-router-dom"; +import { + actions, + selectSchemaInsights, + selectSchemaInsightsDatabases, + selectSchemaInsightsError, + selectSchemaInsightsTypes, + selectFilters, + selectSortSetting, +} from "src/store/schemaInsights"; +import { AppState } from "src/store"; +import { + SchemaInsightsView, + SchemaInsightsViewDispatchProps, + SchemaInsightsViewStateProps, +} from "./schemaInsightsView"; +import { SchemaInsightEventFilters } from "../types"; +import { SortSetting } from "src/sortedtable"; +import { actions as localStorageActions } from "../../store/localStorage"; + +const mapStateToProps = ( + state: AppState, + _props: RouteComponentProps, +): SchemaInsightsViewStateProps => ({ + schemaInsights: selectSchemaInsights(state), + schemaInsightsDatabases: selectSchemaInsightsDatabases(state), + schemaInsightsTypes: selectSchemaInsightsTypes(state), + schemaInsightsError: selectSchemaInsightsError(state), + filters: selectFilters(state), + sortSetting: selectSortSetting(state), +}); + +const mapDispatchToProps = { + onFiltersChange: (filters: SchemaInsightEventFilters) => + localStorageActions.update({ + key: "filters/SchemaInsightsPage", + value: filters, + }), + onSortChange: (ss: SortSetting) => + localStorageActions.update({ + key: "sortSetting/SchemaInsightsPage", + value: ss, + }), + refreshSchemaInsights: actions.refresh, +}; + +export const SchemaInsightsPageConnected = withRouter( + connect< + SchemaInsightsViewStateProps, + SchemaInsightsViewDispatchProps, + RouteComponentProps + >( + mapStateToProps, + mapDispatchToProps, + )(SchemaInsightsView), +); diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/schemaInsights/schemaInsightsView.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/schemaInsights/schemaInsightsView.tsx index 5b23dfd16a16..e6a8521ed83b 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/schemaInsights/schemaInsightsView.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insights/schemaInsights/schemaInsightsView.tsx @@ -202,7 +202,7 @@ export const SchemaInsightsView: React.FC = ({
InsightsError()} @@ -227,7 +227,7 @@ export const SchemaInsightsView: React.FC = ({ renderNoResult={ 0 && filteredSchemaInsights?.length == 0 + search?.length > 0 && filteredSchemaInsights?.length === 0 } /> } diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/utils.ts b/pkg/ui/workspaces/cluster-ui/src/insights/utils.ts index 509129e9fa3f..5141a4ce6c00 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/utils.ts +++ b/pkg/ui/workspaces/cluster-ui/src/insights/utils.ts @@ -90,9 +90,9 @@ export function getTransactionInsightEventDetailsFromState( insightEventDetailsResponse, ); if (insightsForEventDetails.length > 0) { - delete insightEventDetailsResponse.insightName; + const { insightName, ...resp } = insightEventDetailsResponse; insightEventDetails = { - ...insightEventDetailsResponse, + ...resp, insights: insightsForEventDetails, }; } @@ -305,32 +305,36 @@ export function getAppsFromStatementInsights( export function populateStatementInsightsFromProblemAndCauses( statements: StatementInsightEvent[], -): void { +): StatementInsightEvent[] { if (!statements || statements?.length === 0) { return; } - statements.map(x => { + const stmts: StatementInsightEvent[] = []; + statements.forEach(statement => { + const stmt = Object.assign({}, statement); // TODO(ericharmeling,todd): Replace these strings when using the insights protos. - if (x.problem === "SlowExecution") { - if (x.causes?.length === 0) { - x.insights = [ + if (statement.problem === "SlowExecution") { + if (statement.causes?.length === 0) { + stmt.insights = [ getInsightFromProblem( InsightNameEnum.slowExecution, InsightExecEnum.STATEMENT, ), ]; } else { - x.insights = x.causes?.map(x => + stmt.insights = statement.causes?.map(x => getInsightFromProblem(x, InsightExecEnum.STATEMENT), ); } - } else if (x.problem === "FailedExecution") { - x.insights = [ + } else if (statement.problem === "FailedExecution") { + stmt.insights = [ getInsightFromProblem( InsightNameEnum.failedExecution, InsightExecEnum.STATEMENT, ), ]; } + stmts.push(stmt); }); + return stmts; } diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/index.ts b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/index.ts index 3f0d771b189e..839b869cd7ae 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/index.ts +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/index.ts @@ -9,4 +9,6 @@ // licenses/APL.txt. export * from "./transactionInsightDetails"; +export * from "./transactionInsightDetailsConnected"; export * from "./statementInsightDetails"; +export * from "./statementInsightDetailsConnected"; diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetails.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetails.tsx index 8250e822c8d3..9b363c61cc48 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetails.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetails.tsx @@ -55,11 +55,13 @@ export class StatementInsightDetails extends React.Component this.props.history.goBack(); renderContent = (): React.ReactElement => { - const insightDetailsArr = [this.props.insightEventDetails]; - populateStatementInsightsFromProblemAndCauses(insightDetailsArr); + const insightDetailsArr = populateStatementInsightsFromProblemAndCauses([ + this.props.insightEventDetails, + ]); const insightDetails = insightDetailsArr[0]; const isCockroachCloud = useContext(CockroachCloudContext); const insightsColumns = makeInsightsColumns(isCockroachCloud); @@ -71,7 +73,6 @@ export class StatementInsightDetails extends React.Component { switch (insight.name) { case InsightNameEnum.highContention: diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetailsConnected.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetailsConnected.tsx new file mode 100644 index 000000000000..d868ee7bde72 --- /dev/null +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetailsConnected.tsx @@ -0,0 +1,38 @@ +// Copyright 2022 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. +import { connect } from "react-redux"; +import { RouteComponentProps, withRouter } from "react-router-dom"; +import { + StatementInsightDetails, + StatementInsightDetailsStateProps, +} from "./statementInsightDetails"; +import { AppState } from "src/store"; +import { + selectStatementInsightDetails, + selectStatementInsightsError, +} from "src/store/insights/statementInsights"; + +const mapStateToProps = ( + state: AppState, + props: RouteComponentProps, +): StatementInsightDetailsStateProps => { + const insightStatements = selectStatementInsightDetails(state, props); + const insightError = selectStatementInsightsError(state); + return { + insightEventDetails: insightStatements, + insightError: insightError, + }; +}; + +export const StatementInsightDetailsConnected = withRouter( + connect( + mapStateToProps, + )(StatementInsightDetails), +); diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/transactionInsightDetailsConnected.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/transactionInsightDetailsConnected.tsx new file mode 100644 index 000000000000..bb5aa21caa91 --- /dev/null +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/transactionInsightDetailsConnected.tsx @@ -0,0 +1,49 @@ +// Copyright 2022 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. +import { + TransactionInsightDetails, + TransactionInsightDetailsStateProps, + TransactionInsightDetailsDispatchProps, +} from "./transactionInsightDetails"; +import { connect } from "react-redux"; +import { RouteComponentProps, withRouter } from "react-router-dom"; +import { AppState } from "src/store"; +import { + selectTransactionInsightDetails, + selectTransactionInsightDetailsError, + actions, +} from "src/store/insightDetails/transactionInsightDetails"; + +const mapStateToProps = ( + state: AppState, + _props: RouteComponentProps, +): TransactionInsightDetailsStateProps => { + const insightDetails = selectTransactionInsightDetails(state); + const insightError = selectTransactionInsightDetailsError(state); + return { + insightEventDetails: insightDetails, + insightError: insightError, + }; +}; + +const mapDispatchToProps = { + refreshTransactionInsightDetails: actions.refresh, +}; + +export const TransactionInsightDetailsConnected = withRouter( + connect< + TransactionInsightDetailsStateProps, + TransactionInsightDetailsDispatchProps, + RouteComponentProps + >( + mapStateToProps, + mapDispatchToProps, + )(TransactionInsightDetails), +); diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/index.ts b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/index.ts index cc0bf8c133ad..f4c2823e3518 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/index.ts +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/index.ts @@ -11,3 +11,4 @@ export * from "./transactionInsights"; export * from "./statementInsights"; export * from "./workloadInsightRootControl"; +export * from "./workloadInsightsPageConnected"; diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/statementInsights/statementInsightsView.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/statementInsights/statementInsightsView.tsx index ee61bcc88700..161405f53cfc 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/statementInsights/statementInsightsView.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/statementInsights/statementInsightsView.tsx @@ -202,7 +202,7 @@ export const StatementInsightsView: React.FC = ( const clearFilters = () => onSubmitFilters({ - app: defaultFilters.app, + app: "", }); const apps = getAppsFromStatementInsights( @@ -217,7 +217,8 @@ export const StatementInsightsView: React.FC = ( search, ); - populateStatementInsightsFromProblemAndCauses(filteredStatements); + const statementInsights = + populateStatementInsightsFromProblemAndCauses(filteredStatements); const tableColumns = defaultColumns .filter(c => !c.alwaysShow) .map( @@ -266,21 +267,21 @@ export const StatementInsightsView: React.FC = (
0 && filteredStatements?.length === 0 + search?.length > 0 && statementInsights?.length === 0 } /> } @@ -290,7 +291,7 @@ export const StatementInsightsView: React.FC = ( diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/transactionInsights/transactionInsightsView.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/transactionInsights/transactionInsightsView.tsx index 3cad40750804..7bc1fc06af8e 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/transactionInsights/transactionInsightsView.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/transactionInsights/transactionInsightsView.tsx @@ -172,7 +172,7 @@ export const TransactionInsightsView: React.FC = ( const clearFilters = () => onSubmitFilters({ - app: defaultFilters.app, + app: "", }); const transactionInsights = getInsightsFromState(transactions); diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/workloadInsightsPageConnected.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/workloadInsightsPageConnected.tsx new file mode 100644 index 000000000000..40d07acce4d0 --- /dev/null +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/workloadInsightsPageConnected.tsx @@ -0,0 +1,143 @@ +// Copyright 2022 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +import { connect } from "react-redux"; +import { RouteComponentProps, withRouter } from "react-router-dom"; +import { AppState } from "src/store"; +import { actions as localStorageActions } from "src/store/localStorage"; +import { + TransactionInsightsViewDispatchProps, + TransactionInsightsViewStateProps, +} from "./transactionInsights"; +import { + StatementInsightsViewDispatchProps, + StatementInsightsViewStateProps, +} from "./statementInsights"; +import { WorkloadInsightEventFilters } from "../types"; +import { + WorkloadInsightsViewProps, + WorkloadInsightsRootControl, +} from "./workloadInsightRootControl"; +import { SortSetting } from "src/sortedtable"; +import { + actions as statementInsights, + selectColumns, + selectStatementInsights, + selectStatementInsightsError, +} from "src/store/insights/statementInsights"; +import { + actions as transactionInsights, + selectTransactionInsights, + selectTransactionInsightsError, + selectFilters, + selectSortSetting, +} from "src/store/insights/transactionInsights"; +import { bindActionCreators } from "redux"; + +const transactionMapStateToProps = ( + state: AppState, + _props: RouteComponentProps, +): TransactionInsightsViewStateProps => ({ + transactions: selectTransactionInsights(state), + transactionsError: selectTransactionInsightsError(state), + filters: selectFilters(state), + sortSetting: selectSortSetting(state), +}); + +const statementMapStateToProps = ( + state: AppState, + _props: RouteComponentProps, +): StatementInsightsViewStateProps => ({ + statements: selectStatementInsights(state), + statementsError: selectStatementInsightsError(state), + filters: selectFilters(state), + sortSetting: selectSortSetting(state), + selectedColumnNames: selectColumns(state), +}); + +const TransactionDispatchProps = { + onFiltersChange: (filters: WorkloadInsightEventFilters) => + localStorageActions.update({ + key: "filters/InsightsPage", + value: filters, + }), + onSortChange: (ss: SortSetting) => + localStorageActions.update({ + key: "sortSetting/InsightsPage", + value: ss, + }), + refreshTransactionInsights: transactionInsights.refresh, +}; + +const StatementDispatchProps: StatementInsightsViewDispatchProps = { + onFiltersChange: (filters: WorkloadInsightEventFilters) => + localStorageActions.update({ + key: "filters/InsightsPage", + value: filters, + }), + onSortChange: (ss: SortSetting) => + localStorageActions.update({ + key: "sortSetting/InsightsPage", + value: ss, + }), + onColumnsChange: (value: string[]) => + localStorageActions.update({ + key: "showColumns/StatementInsightsPage", + value: value.join(","), + }), + refreshStatementInsights: statementInsights.refresh, +}; + +type StateProps = { + transactionInsightsViewStateProps: TransactionInsightsViewStateProps; + statementInsightsViewStateProps: StatementInsightsViewStateProps; +}; + +type DispatchProps = { + transactionInsightsViewDispatchProps: TransactionInsightsViewDispatchProps; + statementInsightsViewDispatchProps: StatementInsightsViewDispatchProps; +}; + +export const WorkloadInsightsPageConnected = withRouter( + connect< + StateProps, + DispatchProps, + RouteComponentProps, + WorkloadInsightsViewProps + >( + (state: AppState, props: RouteComponentProps) => ({ + transactionInsightsViewStateProps: transactionMapStateToProps( + state, + props, + ), + statementInsightsViewStateProps: statementMapStateToProps(state, props), + }), + dispatch => ({ + transactionInsightsViewDispatchProps: bindActionCreators( + TransactionDispatchProps, + dispatch, + ), + statementInsightsViewDispatchProps: bindActionCreators( + StatementDispatchProps, + dispatch, + ), + }), + (stateProps, dispatchProps) => ({ + transactionInsightsViewProps: { + ...stateProps.transactionInsightsViewStateProps, + ...dispatchProps.transactionInsightsViewDispatchProps, + }, + statementInsightsViewProps: { + ...stateProps.statementInsightsViewStateProps, + ...dispatchProps.statementInsightsViewDispatchProps, + }, + }), + )(WorkloadInsightsRootControl), +); diff --git a/pkg/ui/workspaces/cluster-ui/src/store/insightDetails/insightDetails.selectors.ts b/pkg/ui/workspaces/cluster-ui/src/store/insightDetails/transactionInsightDetails/index.ts similarity index 56% rename from pkg/ui/workspaces/cluster-ui/src/store/insightDetails/insightDetails.selectors.ts rename to pkg/ui/workspaces/cluster-ui/src/store/insightDetails/transactionInsightDetails/index.ts index 946e01ea6b9b..a8c144de2326 100644 --- a/pkg/ui/workspaces/cluster-ui/src/store/insightDetails/insightDetails.selectors.ts +++ b/pkg/ui/workspaces/cluster-ui/src/store/insightDetails/transactionInsightDetails/index.ts @@ -8,13 +8,6 @@ // by the Apache License, Version 2.0, included in the file // licenses/APL.txt. -import { createSelector } from "reselect"; -import { adminUISelector } from "../utils/selectors"; - -export const selectInsightDetails = createSelector( - adminUISelector, - adminUiState => { - if (!adminUiState.insights) return []; - return adminUiState.insightDetails.data; - }, -); +export * from "./transactionInsightDetails.reducer"; +export * from "./transactionInsightDetails.sagas"; +export * from "./transactionInsightDetails.selectors"; diff --git a/pkg/ui/workspaces/cluster-ui/src/store/insightDetails/insightDetails.reducer.ts b/pkg/ui/workspaces/cluster-ui/src/store/insightDetails/transactionInsightDetails/transactionInsightDetails.reducer.ts similarity index 78% rename from pkg/ui/workspaces/cluster-ui/src/store/insightDetails/insightDetails.reducer.ts rename to pkg/ui/workspaces/cluster-ui/src/store/insightDetails/transactionInsightDetails/transactionInsightDetails.reducer.ts index a1a4784aa9d4..50c916f3f619 100644 --- a/pkg/ui/workspaces/cluster-ui/src/store/insightDetails/insightDetails.reducer.ts +++ b/pkg/ui/workspaces/cluster-ui/src/store/insightDetails/transactionInsightDetails/transactionInsightDetails.reducer.ts @@ -9,29 +9,29 @@ // licenses/APL.txt. import { createSlice, PayloadAction } from "@reduxjs/toolkit"; -import { DOMAIN_NAME } from "../utils"; +import { DOMAIN_NAME } from "src/store/utils"; import moment, { Moment } from "moment"; import { TransactionInsightEventDetailsRequest, TransactionInsightEventDetailsResponse, } from "src/api/insightsApi"; -export type InsightDetailsState = { +export type TransactionInsightDetailsState = { data: TransactionInsightEventDetailsResponse | null; lastUpdated: Moment | null; lastError: Error; valid: boolean; }; -const initialState: InsightDetailsState = { +const initialState: TransactionInsightDetailsState = { data: null, lastUpdated: null, lastError: null, valid: true, }; -const insightDetailsSlice = createSlice({ - name: `${DOMAIN_NAME}/insightDetailsSlice`, +const transactionInsightDetailsSlice = createSlice({ + name: `${DOMAIN_NAME}/transactionInsightDetailsSlice`, initialState, reducers: { received: ( @@ -47,6 +47,9 @@ const insightDetailsSlice = createSlice({ state.valid = false; state.lastError = action.payload; }, + invalidated: state => { + state.valid = false; + }, refresh: ( _, action: PayloadAction, @@ -58,4 +61,4 @@ const insightDetailsSlice = createSlice({ }, }); -export const { reducer, actions } = insightDetailsSlice; +export const { reducer, actions } = transactionInsightDetailsSlice; diff --git a/pkg/ui/workspaces/cluster-ui/src/store/insightDetails/insightDetails.sagas.ts b/pkg/ui/workspaces/cluster-ui/src/store/insightDetails/transactionInsightDetails/transactionInsightDetails.sagas.ts similarity index 76% rename from pkg/ui/workspaces/cluster-ui/src/store/insightDetails/insightDetails.sagas.ts rename to pkg/ui/workspaces/cluster-ui/src/store/insightDetails/transactionInsightDetails/transactionInsightDetails.sagas.ts index 9957911917a2..e3fb96491d08 100644 --- a/pkg/ui/workspaces/cluster-ui/src/store/insightDetails/insightDetails.sagas.ts +++ b/pkg/ui/workspaces/cluster-ui/src/store/insightDetails/transactionInsightDetails/transactionInsightDetails.sagas.ts @@ -8,9 +8,9 @@ // by the Apache License, Version 2.0, included in the file // licenses/APL.txt. -import { all, call, put, takeLatest } from "redux-saga/effects"; +import { all, call, delay, put, takeLatest } from "redux-saga/effects"; -import { actions } from "./insightDetails.reducer"; +import { actions } from "./transactionInsightDetails.reducer"; import { getTransactionInsightEventDetailsState, TransactionInsightEventDetailsRequest, @@ -37,8 +37,14 @@ export function* requestTransactionInsightDetailsSaga( } } +export function* receivedTransactionInsightDetailsSaga() { + yield put(actions.invalidated()); +} + export function* transactionInsightDetailsSaga() { yield all([ + takeLatest(actions.refresh, refreshTransactionInsightDetailsSaga), takeLatest(actions.request, requestTransactionInsightDetailsSaga), + takeLatest(actions.received, receivedTransactionInsightDetailsSaga), ]); } diff --git a/pkg/ui/workspaces/cluster-ui/src/store/insightDetails/transactionInsightDetails/transactionInsightDetails.selectors.ts b/pkg/ui/workspaces/cluster-ui/src/store/insightDetails/transactionInsightDetails/transactionInsightDetails.selectors.ts new file mode 100644 index 000000000000..8694d199c3ed --- /dev/null +++ b/pkg/ui/workspaces/cluster-ui/src/store/insightDetails/transactionInsightDetails/transactionInsightDetails.selectors.ts @@ -0,0 +1,36 @@ +// Copyright 2022 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +import { createSelector } from "reselect"; +import { adminUISelector } from "src/store/utils/selectors"; + +const selectTransactionInsightDetailsState = createSelector( + adminUISelector, + adminUiState => { + if (!adminUiState.transactionInsightDetails) return null; + return adminUiState.transactionInsightDetails; + }, +); + +export const selectTransactionInsightDetails = createSelector( + selectTransactionInsightDetailsState, + txnInsightDetailsState => { + if (!txnInsightDetailsState) return null; + return txnInsightDetailsState.data; + }, +); + +export const selectTransactionInsightDetailsError = createSelector( + selectTransactionInsightDetailsState, + txnInsightDetailsState => { + if (!txnInsightDetailsState) return null; + return txnInsightDetailsState.lastError; + }, +); diff --git a/pkg/ui/workspaces/cluster-ui/src/store/insightDetails/index.ts b/pkg/ui/workspaces/cluster-ui/src/store/insights/statementInsights/index.ts similarity index 73% rename from pkg/ui/workspaces/cluster-ui/src/store/insightDetails/index.ts rename to pkg/ui/workspaces/cluster-ui/src/store/insights/statementInsights/index.ts index 129097315975..488275ec89ff 100644 --- a/pkg/ui/workspaces/cluster-ui/src/store/insightDetails/index.ts +++ b/pkg/ui/workspaces/cluster-ui/src/store/insights/statementInsights/index.ts @@ -8,6 +8,6 @@ // by the Apache License, Version 2.0, included in the file // licenses/APL.txt. -export * from "./insightDetails.reducer"; -export * from "./insightDetails.sagas"; -export * from "./insightDetails.selectors"; +export * from "./statementInsights.reducer"; +export * from "./statementInsights.sagas"; +export * from "./statementInsights.selectors"; diff --git a/pkg/ui/workspaces/cluster-ui/src/store/insights/statementInsights/statementInsights.reducer.ts b/pkg/ui/workspaces/cluster-ui/src/store/insights/statementInsights/statementInsights.reducer.ts new file mode 100644 index 000000000000..ca67df47b8a2 --- /dev/null +++ b/pkg/ui/workspaces/cluster-ui/src/store/insights/statementInsights/statementInsights.reducer.ts @@ -0,0 +1,53 @@ +// Copyright 2022 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; +import { DOMAIN_NAME, noopReducer } from "../../utils"; +import moment, { Moment } from "moment"; +import { StatementInsights } from "src/api/insightsApi"; + +export type StatementInsightsState = { + data: StatementInsights; + lastUpdated: Moment; + lastError: Error; + valid: boolean; +}; + +const initialState: StatementInsightsState = { + data: null, + lastUpdated: null, + lastError: null, + valid: true, +}; + +const statementInsightsSlice = createSlice({ + name: `${DOMAIN_NAME}/statementInsightsSlice`, + initialState, + reducers: { + received: (state, action: PayloadAction) => { + state.data = action.payload; + state.valid = true; + state.lastError = null; + state.lastUpdated = moment.utc(); + }, + failed: (state, action: PayloadAction) => { + state.valid = false; + state.lastError = action.payload; + }, + invalidated: state => { + state.valid = false; + }, + // Define actions that don't change state. + refresh: noopReducer, + request: noopReducer, + }, +}); + +export const { reducer, actions } = statementInsightsSlice; diff --git a/pkg/ui/workspaces/cluster-ui/src/store/insights/statementInsights/statementInsights.sagas.ts b/pkg/ui/workspaces/cluster-ui/src/store/insights/statementInsights/statementInsights.sagas.ts new file mode 100644 index 000000000000..19b061e29482 --- /dev/null +++ b/pkg/ui/workspaces/cluster-ui/src/store/insights/statementInsights/statementInsights.sagas.ts @@ -0,0 +1,53 @@ +// Copyright 2022 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +import { all, call, delay, put, takeLatest } from "redux-saga/effects"; + +import { actions } from "./statementInsights.reducer"; +import { getStatementInsightsApi } from "src/api/insightsApi"; +import { throttleWithReset } from "../../utils"; +import { rootActions } from "../../reducers"; + +export function* refreshStatementInsightsSaga() { + yield put(actions.request()); +} + +export function* requestStatementInsightsSaga(): any { + try { + const result = yield call(getStatementInsightsApi); + yield put(actions.received(result)); + } catch (e) { + yield put(actions.failed(e)); + } +} + +export function* receivedStatementInsightsSaga(delayMs: number) { + yield delay(delayMs); + yield put(actions.invalidated()); +} + +export function* statementInsightsSaga( + cacheInvalidationPeriod: number = 10 * 1000, +) { + yield all([ + throttleWithReset( + cacheInvalidationPeriod, + actions.refresh, + [actions.invalidated, rootActions.resetState], + refreshStatementInsightsSaga, + ), + takeLatest(actions.request, requestStatementInsightsSaga), + takeLatest( + actions.received, + receivedStatementInsightsSaga, + cacheInvalidationPeriod, + ), + ]); +} diff --git a/pkg/ui/workspaces/cluster-ui/src/store/insights/statementInsights/statementInsights.selectors.ts b/pkg/ui/workspaces/cluster-ui/src/store/insights/statementInsights/statementInsights.selectors.ts new file mode 100644 index 000000000000..4694e1fb5e0b --- /dev/null +++ b/pkg/ui/workspaces/cluster-ui/src/store/insights/statementInsights/statementInsights.selectors.ts @@ -0,0 +1,64 @@ +// Copyright 2022 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +import { createSelector } from "reselect"; +import { + adminUISelector, + localStorageSelector, +} from "src/store/utils/selectors"; +import { getMatchParamByName } from "../../../util"; +import { RouteComponentProps } from "react-router"; +import { StatementInsightEvent } from "../../../insights"; +import { AppState } from "../../reducers"; + +const selectStatementInsightsState = createSelector( + adminUISelector, + adminUiState => { + if (!adminUiState.statementInsights) return null; + return adminUiState.statementInsights; + }, +); + +export const selectStatementInsights = createSelector( + selectStatementInsightsState, + stmtInsightsState => { + if (!stmtInsightsState) return []; + return stmtInsightsState.data; + }, +); + +export const selectStatementInsightsError = createSelector( + selectStatementInsightsState, + stmtInsightsState => { + if (!stmtInsightsState) return null; + return stmtInsightsState.lastError; + }, +); + +export const selectStatementInsightDetails = createSelector( + selectStatementInsightsState, + (_state: AppState, props: RouteComponentProps) => props, + (statementInsights, props): StatementInsightEvent => { + if (!statementInsights) return null; + + const insightId = getMatchParamByName(props.match, "id"); + return statementInsights.data?.find( + statementInsight => statementInsight.statementID === insightId, + ); + }, +); + +export const selectColumns = createSelector( + localStorageSelector, + localStorage => + localStorage["showColumns/StatementInsightsPage"] + ? localStorage["showColumns/StatementInsightsPage"].split(",") + : null, +); diff --git a/pkg/ui/workspaces/cluster-ui/src/store/insights/transactionInsights.selectors.ts b/pkg/ui/workspaces/cluster-ui/src/store/insights/transactionInsights.selectors.ts deleted file mode 100644 index de77aad385b0..000000000000 --- a/pkg/ui/workspaces/cluster-ui/src/store/insights/transactionInsights.selectors.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2020 The Cockroach Authors. -// -// Use of this software is governed by the Business Source License -// included in the file licenses/BSL.txt. -// -// As of the Change Date specified in that file, in accordance with -// the Business Source License, use of this software will be governed -// by the Apache License, Version 2.0, included in the file -// licenses/APL.txt. - -import { createSelector } from "reselect"; -import { adminUISelector } from "../utils/selectors"; - -export const selectInsights = createSelector(adminUISelector, adminUiState => { - if (!adminUiState.insights) return []; - return adminUiState.insights.data; -}); diff --git a/pkg/ui/workspaces/cluster-ui/src/store/insights/index.ts b/pkg/ui/workspaces/cluster-ui/src/store/insights/transactionInsights/index.ts similarity index 100% rename from pkg/ui/workspaces/cluster-ui/src/store/insights/index.ts rename to pkg/ui/workspaces/cluster-ui/src/store/insights/transactionInsights/index.ts diff --git a/pkg/ui/workspaces/cluster-ui/src/store/insights/transactionInsights.reducer.ts b/pkg/ui/workspaces/cluster-ui/src/store/insights/transactionInsights/transactionInsights.reducer.ts similarity index 80% rename from pkg/ui/workspaces/cluster-ui/src/store/insights/transactionInsights.reducer.ts rename to pkg/ui/workspaces/cluster-ui/src/store/insights/transactionInsights/transactionInsights.reducer.ts index d62171350e6f..44c4d2005af9 100644 --- a/pkg/ui/workspaces/cluster-ui/src/store/insights/transactionInsights.reducer.ts +++ b/pkg/ui/workspaces/cluster-ui/src/store/insights/transactionInsights/transactionInsights.reducer.ts @@ -9,26 +9,26 @@ // licenses/APL.txt. import { createSlice, PayloadAction } from "@reduxjs/toolkit"; -import { DOMAIN_NAME, noopReducer } from "../utils"; +import { DOMAIN_NAME, noopReducer } from "src/store/utils"; import moment, { Moment } from "moment"; import { TransactionInsightEventsResponse } from "src/api/insightsApi"; -export type InsightsState = { +export type TransactionInsightsState = { data: TransactionInsightEventsResponse; lastUpdated: Moment; lastError: Error; valid: boolean; }; -const initialState: InsightsState = { +const initialState: TransactionInsightsState = { data: null, lastUpdated: null, lastError: null, valid: true, }; -const insightsSlice = createSlice({ - name: `${DOMAIN_NAME}/insightsSlice`, +const transactionInsightsSlice = createSlice({ + name: `${DOMAIN_NAME}/transactionInsightsSlice`, initialState, reducers: { received: ( @@ -53,4 +53,4 @@ const insightsSlice = createSlice({ }, }); -export const { reducer, actions } = insightsSlice; +export const { reducer, actions } = transactionInsightsSlice; diff --git a/pkg/ui/workspaces/cluster-ui/src/store/insights/transactionInsights.sagas.ts b/pkg/ui/workspaces/cluster-ui/src/store/insights/transactionInsights/transactionInsights.sagas.ts similarity index 93% rename from pkg/ui/workspaces/cluster-ui/src/store/insights/transactionInsights.sagas.ts rename to pkg/ui/workspaces/cluster-ui/src/store/insights/transactionInsights/transactionInsights.sagas.ts index 29518bd608cc..ae93cc3fec93 100644 --- a/pkg/ui/workspaces/cluster-ui/src/store/insights/transactionInsights.sagas.ts +++ b/pkg/ui/workspaces/cluster-ui/src/store/insights/transactionInsights/transactionInsights.sagas.ts @@ -12,8 +12,8 @@ import { all, call, delay, put, takeLatest } from "redux-saga/effects"; import { actions } from "./transactionInsights.reducer"; import { getTransactionInsightEventState } from "src/api/insightsApi"; -import { throttleWithReset } from "../utils"; -import { rootActions } from "../reducers"; +import { throttleWithReset } from "src/store/utils"; +import { rootActions } from "src/store/reducers"; export function* refreshTransactionInsightsSaga() { yield put(actions.request()); diff --git a/pkg/ui/workspaces/cluster-ui/src/store/insights/transactionInsights/transactionInsights.selectors.ts b/pkg/ui/workspaces/cluster-ui/src/store/insights/transactionInsights/transactionInsights.selectors.ts new file mode 100644 index 000000000000..2c9ddebc8b1a --- /dev/null +++ b/pkg/ui/workspaces/cluster-ui/src/store/insights/transactionInsights/transactionInsights.selectors.ts @@ -0,0 +1,49 @@ +// Copyright 2022 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +import { createSelector } from "reselect"; +import { + adminUISelector, + localStorageSelector, +} from "src/store/utils/selectors"; + +const selectTransactionInsightsState = createSelector( + adminUISelector, + adminUiState => { + if (!adminUiState.transactionInsights) return null; + return adminUiState.transactionInsights; + }, +); + +export const selectTransactionInsights = createSelector( + selectTransactionInsightsState, + txnInsightsState => { + if (!txnInsightsState) return []; + return txnInsightsState.data; + }, +); + +export const selectTransactionInsightsError = createSelector( + selectTransactionInsightsState, + txnInsightsState => { + if (!txnInsightsState) return null; + return txnInsightsState.lastError; + }, +); + +export const selectSortSetting = createSelector( + localStorageSelector, + localStorage => localStorage["sortSetting/InsightsPage"], +); + +export const selectFilters = createSelector( + localStorageSelector, + localStorage => localStorage["filters/InsightsPage"], +); diff --git a/pkg/ui/workspaces/cluster-ui/src/store/localStorage/localStorage.reducer.ts b/pkg/ui/workspaces/cluster-ui/src/store/localStorage/localStorage.reducer.ts index 5e2ac26a815a..a7304d4baf71 100644 --- a/pkg/ui/workspaces/cluster-ui/src/store/localStorage/localStorage.reducer.ts +++ b/pkg/ui/workspaces/cluster-ui/src/store/localStorage/localStorage.reducer.ts @@ -10,8 +10,9 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { DOMAIN_NAME } from "../utils"; -import { defaultFilters, Filters } from "../../queryFilter"; +import { defaultFilters, Filters } from "src/queryFilter/"; import { TimeScale, defaultTimeScaleSelected } from "../../timeScaleDropdown"; +import { WorkloadInsightEventFilters } from "src/insights"; type SortSetting = { ascending: boolean; @@ -25,6 +26,7 @@ export type LocalStorageState = { "showColumns/StatementsPage": string; "showColumns/TransactionPage": string; "showColumns/SessionsPage": string; + "showColumns/StatementInsightsPage": string; "timeScale/SQLActivity": TimeScale; "sortSetting/ActiveStatementsPage": SortSetting; "sortSetting/ActiveTransactionsPage": SortSetting; @@ -39,7 +41,7 @@ export type LocalStorageState = { "filters/StatementsPage": Filters; "filters/TransactionsPage": Filters; "filters/SessionsPage": Filters; - "filters/InsightsPage": Filters; + "filters/InsightsPage": WorkloadInsightEventFilters; "filters/SchemaInsightsPage": Filters; "search/StatementsPage": string; "search/TransactionsPage": string; @@ -74,16 +76,16 @@ const defaultSortSettingSchemaInsights: SortSetting = { }; const defaultFiltersActiveExecutions = { - app: defaultFilters.app, + app: "", }; const defaultFiltersInsights = { - app: defaultFilters.app, + app: "", }; const defaultFiltersSchemaInsights = { - database: defaultFilters.database, - schemaInsightType: defaultFilters.schemaInsightType, + database: "", + schemaInsightType: "", }; const defaultSessionsSortSetting: SortSetting = { @@ -119,6 +121,9 @@ const initialState: LocalStorageState = { JSON.parse(localStorage.getItem("showColumns/TransactionPage")) || null, "showColumns/SessionsPage": JSON.parse(localStorage.getItem("showColumns/SessionsPage")) || null, + "showColumns/StatementInsightsPage": + JSON.parse(localStorage.getItem("showColumns/StatementInsightsPage")) || + null, "showSetting/JobsPage": JSON.parse(localStorage.getItem("showSetting/JobsPage")) || defaultJobShowSetting, diff --git a/pkg/ui/workspaces/cluster-ui/src/store/reducers.ts b/pkg/ui/workspaces/cluster-ui/src/store/reducers.ts index fd639758947e..6fef2628cb10 100644 --- a/pkg/ui/workspaces/cluster-ui/src/store/reducers.ts +++ b/pkg/ui/workspaces/cluster-ui/src/store/reducers.ts @@ -39,15 +39,22 @@ import { ClusterLocksReqState, reducer as clusterLocks, } from "./clusterLocks/clusterLocks.reducer"; -import { InsightsState, reducer as insights } from "./insights"; import { - InsightDetailsState, - reducer as insightDetails, -} from "./insightDetails"; + TransactionInsightsState, + reducer as transactionInsights, +} from "./insights/transactionInsights"; +import { + StatementInsightsState, + reducer as statementInsights, +} from "./insights/statementInsights"; import { SchemaInsightsState, reducer as schemaInsights, } from "./schemaInsights"; +import { + TransactionInsightDetailsState, + reducer as transactionInsightDetails, +} from "./insightDetails/transactionInsightDetails"; export type AdminUiState = { statementDiagnostics: StatementDiagnosticsState; @@ -63,8 +70,9 @@ export type AdminUiState = { jobs: JobsState; job: JobState; clusterLocks: ClusterLocksReqState; - insights: InsightsState; - insightDetails: InsightDetailsState; + transactionInsights: TransactionInsightsState; + transactionInsightDetails: TransactionInsightDetailsState; + statementInsights: StatementInsightsState; schemaInsights: SchemaInsightsState; }; @@ -78,8 +86,9 @@ export const reducers = combineReducers({ nodes, liveness, sessions, - insights, - insightDetails, + transactionInsights, + transactionInsightDetails, + statementInsights, terminateQuery, uiConfig, sqlStats, diff --git a/pkg/ui/workspaces/cluster-ui/src/store/sagas.ts b/pkg/ui/workspaces/cluster-ui/src/store/sagas.ts index 8de25ef346ee..7a0ad282634a 100644 --- a/pkg/ui/workspaces/cluster-ui/src/store/sagas.ts +++ b/pkg/ui/workspaces/cluster-ui/src/store/sagas.ts @@ -24,8 +24,9 @@ import { sqlStatsSaga } from "./sqlStats"; import { sqlDetailsStatsSaga } from "./statementDetails"; import { indexStatsSaga } from "./indexStats"; import { clusterLocksSaga } from "./clusterLocks/clusterLocks.saga"; -import { transactionInsightsSaga } from "./insights"; -import { transactionInsightDetailsSaga } from "./insightDetails"; +import { transactionInsightsSaga } from "./insights/transactionInsights"; +import { transactionInsightDetailsSaga } from "./insightDetails/transactionInsightDetails"; +import { statementInsightsSaga } from "./insights/statementInsights"; import { schemaInsightsSaga } from "./schemaInsights"; export function* sagas(cacheInvalidationPeriod?: number): SagaIterator { @@ -36,6 +37,7 @@ export function* sagas(cacheInvalidationPeriod?: number): SagaIterator { fork(livenessSaga, cacheInvalidationPeriod), fork(transactionInsightsSaga), fork(transactionInsightDetailsSaga), + fork(statementInsightsSaga), fork(jobsSaga), fork(jobSaga), fork(sessionsSaga), diff --git a/pkg/ui/workspaces/cluster-ui/src/store/schemaInsights/schemaInsights.selectors.ts b/pkg/ui/workspaces/cluster-ui/src/store/schemaInsights/schemaInsights.selectors.ts index 8266fc36a761..e4462deea97b 100644 --- a/pkg/ui/workspaces/cluster-ui/src/store/schemaInsights/schemaInsights.selectors.ts +++ b/pkg/ui/workspaces/cluster-ui/src/store/schemaInsights/schemaInsights.selectors.ts @@ -9,14 +9,30 @@ // licenses/APL.txt. import { createSelector } from "reselect"; -import { adminUISelector } from "../utils/selectors"; +import { adminUISelector, localStorageSelector } from "../utils/selectors"; import { insightType } from "../../insights"; -export const selectSchemaInsights = createSelector( +const selectSchemaInsightState = createSelector( adminUISelector, adminUiState => { - if (!adminUiState.schemaInsights) return []; - return adminUiState.schemaInsights.data; + if (!adminUiState.schemaInsights) return null; + return adminUiState.schemaInsights; + }, +); + +export const selectSchemaInsights = createSelector( + selectSchemaInsightState, + schemaInsightState => { + if (!schemaInsightState.data) return null; + return schemaInsightState.data; + }, +); + +export const selectSchemaInsightsError = createSelector( + selectSchemaInsightState, + schemaInsightState => { + if (!schemaInsightState) return null; + return schemaInsightState.lastError; }, ); @@ -41,3 +57,13 @@ export const selectSchemaInsightsTypes = createSelector( ).sort(); }, ); + +export const selectSortSetting = createSelector( + localStorageSelector, + localStorage => localStorage["sortSetting/SchemaInsightsPage"], +); + +export const selectFilters = createSelector( + localStorageSelector, + localStorage => localStorage["filters/SchemaInsightsPage"], +); diff --git a/pkg/ui/workspaces/db-console/src/app.spec.tsx b/pkg/ui/workspaces/db-console/src/app.spec.tsx index 8a9793d8abce..efb5d1b2f3d4 100644 --- a/pkg/ui/workspaces/db-console/src/app.spec.tsx +++ b/pkg/ui/workspaces/db-console/src/app.spec.tsx @@ -31,22 +31,16 @@ stubComponentInModule( "src/views/transactions/activeTransactionDetailsConnected", "default", ); +stubComponentInModule("src/views/insights/workloadInsightsPage", "default"); stubComponentInModule( - "src/views/insights/workloadInsightsPageConnected", + "src/views/insights/transactionInsightDetailsPage", "default", ); stubComponentInModule( - "src/views/insights/transactionInsightDetailsPageConnected", - "default", -); -stubComponentInModule( - "src/views/insights/statementInsightDetailsPageConnected", - "default", -); -stubComponentInModule( - "src/views/insights/schemaInsightsPageConnected", + "src/views/insights/statementInsightDetailsPage", "default", ); +stubComponentInModule("src/views/insights/schemaInsightsPage", "default"); stubComponentInModule("src/views/schedules/schedulesPage", "default"); stubComponentInModule("src/views/schedules/scheduleDetails", "default"); @@ -451,23 +445,23 @@ describe("Routing to", () => { describe("'/insights' path", () => { test("routes to component - workload insights page", () => { navigateToPath("/insights"); - screen.getByTestId("workloadInsightsPageConnected"); + screen.getByTestId("workloadInsightsPage"); }); test("routes to component - schema insights page", () => { navigateToPath("/insights?tab=Schema+Insights"); - screen.getByTestId("schemaInsightsPageConnected"); + screen.getByTestId("schemaInsightsPage"); }); }); describe("'/insights/transaction/insightID' path", () => { - test("routes to component", () => { + test("routes to component", () => { navigateToPath("/insights/transaction/insightID"); - screen.getByTestId("transactionInsightDetailsPageConnected"); + screen.getByTestId("transactionInsightDetailsPage"); }); }); describe("'/insights/statement/insightID' path", () => { - test("routes to component", () => { + test("routes to component", () => { navigateToPath("/insights/statement/insightID"); - screen.getByTestId("statementInsightDetailsPageConnected"); + screen.getByTestId("statementInsightDetailsPage"); }); }); { diff --git a/pkg/ui/workspaces/db-console/src/app.tsx b/pkg/ui/workspaces/db-console/src/app.tsx index 3cd8310128fb..aaa89e44cb3b 100644 --- a/pkg/ui/workspaces/db-console/src/app.tsx +++ b/pkg/ui/workspaces/db-console/src/app.tsx @@ -80,9 +80,9 @@ import ActiveStatementDetails from "./views/statements/activeStatementDetailsCon import ActiveTransactionDetails from "./views/transactions/activeTransactionDetailsConnected"; import "styl/app.styl"; import { Tracez } from "src/views/tracez/tracez"; -import InsightsOverviewPage from "src/views/insights/insightsOverview"; -import TransactionInsightDetailsPageConnected from "src/views/insights/transactionInsightDetailsPageConnected"; -import StatementInsightDetailsPageConnected from "src/views/insights/statementInsightDetailsPageConnected"; +import InsightsOverviewPage from "./views/insights/insightsOverview"; +import TransactionInsightDetailsPage from "./views/insights/transactionInsightDetailsPage"; +import StatementInsightDetailsPage from "./views/insights/statementInsightDetailsPage"; import { CockroachCloudContext } from "@cockroachlabs/cluster-ui"; // NOTE: If you are adding a new path to the router, and that path contains any @@ -312,11 +312,11 @@ export const App: React.FC = (props: AppProps) => { /> {/* debug pages */} diff --git a/pkg/ui/workspaces/db-console/src/views/insights/insightsOverview.tsx b/pkg/ui/workspaces/db-console/src/views/insights/insightsOverview.tsx index fc401f659a3b..19845bf762f7 100644 --- a/pkg/ui/workspaces/db-console/src/views/insights/insightsOverview.tsx +++ b/pkg/ui/workspaces/db-console/src/views/insights/insightsOverview.tsx @@ -18,8 +18,8 @@ import "antd/lib/tabs/style"; import { commonStyles, util } from "@cockroachlabs/cluster-ui"; import { RouteComponentProps } from "react-router-dom"; import { tabAttr, viewAttr } from "src/util/constants"; -import WorkloadInsightsPageConnected from "src/views/insights/workloadInsightsPageConnected"; -import SchemaInsightsPageConnected from "src/views/insights/schemaInsightsPageConnected"; +import WorkloadInsightsPage from "./workloadInsightsPage"; +import SchemaInsightsPage from "./schemaInsightsPage"; const { TabPane } = Tabs; @@ -63,10 +63,10 @@ const InsightsOverviewPage = (props: RouteComponentProps) => { destroyInactiveTabPane > - + - + diff --git a/pkg/ui/workspaces/db-console/src/views/insights/insightsSelectors.ts b/pkg/ui/workspaces/db-console/src/views/insights/insightsSelectors.ts index 64cd53723c60..a40c717b9e88 100644 --- a/pkg/ui/workspaces/db-console/src/views/insights/insightsSelectors.ts +++ b/pkg/ui/workspaces/db-console/src/views/insights/insightsSelectors.ts @@ -28,7 +28,7 @@ export const filtersLocalSetting = new LocalSetting< AdminUIState, WorkloadInsightEventFilters >("filters/InsightsPage", (state: AdminUIState) => state.localSettings, { - app: defaultFilters.app, + app: "", }); export const sortSettingLocalSetting = new LocalSetting< diff --git a/pkg/ui/workspaces/db-console/src/views/insights/schemaInsightsPageConnected.tsx b/pkg/ui/workspaces/db-console/src/views/insights/schemaInsightsPage.tsx similarity index 95% rename from pkg/ui/workspaces/db-console/src/views/insights/schemaInsightsPageConnected.tsx rename to pkg/ui/workspaces/db-console/src/views/insights/schemaInsightsPage.tsx index 1131c72d5a14..d057e5556d26 100644 --- a/pkg/ui/workspaces/db-console/src/views/insights/schemaInsightsPageConnected.tsx +++ b/pkg/ui/workspaces/db-console/src/views/insights/schemaInsightsPage.tsx @@ -46,7 +46,7 @@ const mapDispatchToProps = { refreshSchemaInsights: refreshSchemaInsights, }; -const SchemaInsightsPageConnected = withRouter( +const SchemaInsightsPage = withRouter( connect< SchemaInsightsViewStateProps, SchemaInsightsViewDispatchProps, @@ -57,4 +57,4 @@ const SchemaInsightsPageConnected = withRouter( )(SchemaInsightsView), ); -export default SchemaInsightsPageConnected; +export default SchemaInsightsPage; diff --git a/pkg/ui/workspaces/db-console/src/views/insights/statementInsightDetailsPageConnected.tsx b/pkg/ui/workspaces/db-console/src/views/insights/statementInsightDetailsPage.tsx similarity index 91% rename from pkg/ui/workspaces/db-console/src/views/insights/statementInsightDetailsPageConnected.tsx rename to pkg/ui/workspaces/db-console/src/views/insights/statementInsightDetailsPage.tsx index 864a8b550c63..86d16c15d642 100644 --- a/pkg/ui/workspaces/db-console/src/views/insights/statementInsightDetailsPageConnected.tsx +++ b/pkg/ui/workspaces/db-console/src/views/insights/statementInsightDetailsPage.tsx @@ -28,10 +28,10 @@ const mapStateToProps = ( }; }; -const StatementInsightDetailsPageConnected = withRouter( +const StatementInsightDetailsPage = withRouter( connect( mapStateToProps, )(StatementInsightDetails), ); -export default StatementInsightDetailsPageConnected; +export default StatementInsightDetailsPage; diff --git a/pkg/ui/workspaces/db-console/src/views/insights/transactionInsightDetailsPageConnected.tsx b/pkg/ui/workspaces/db-console/src/views/insights/transactionInsightDetailsPage.tsx similarity index 93% rename from pkg/ui/workspaces/db-console/src/views/insights/transactionInsightDetailsPageConnected.tsx rename to pkg/ui/workspaces/db-console/src/views/insights/transactionInsightDetailsPage.tsx index f197c43d3920..12401e70f5eb 100644 --- a/pkg/ui/workspaces/db-console/src/views/insights/transactionInsightDetailsPageConnected.tsx +++ b/pkg/ui/workspaces/db-console/src/views/insights/transactionInsightDetailsPage.tsx @@ -37,7 +37,7 @@ const mapDispatchToProps = { refreshTransactionInsightDetails: refreshTransactionInsightDetails, }; -const TransactionInsightDetailsPageConnected = withRouter( +const TransactionInsightDetailsPage = withRouter( connect< TransactionInsightDetailsStateProps, TransactionInsightDetailsDispatchProps, @@ -48,4 +48,4 @@ const TransactionInsightDetailsPageConnected = withRouter( )(TransactionInsightDetails), ); -export default TransactionInsightDetailsPageConnected; +export default TransactionInsightDetailsPage; diff --git a/pkg/ui/workspaces/db-console/src/views/insights/workloadInsightsPageConnected.tsx b/pkg/ui/workspaces/db-console/src/views/insights/workloadInsightsPage.tsx similarity index 97% rename from pkg/ui/workspaces/db-console/src/views/insights/workloadInsightsPageConnected.tsx rename to pkg/ui/workspaces/db-console/src/views/insights/workloadInsightsPage.tsx index e12a92efa928..45ff91ba834b 100644 --- a/pkg/ui/workspaces/db-console/src/views/insights/workloadInsightsPageConnected.tsx +++ b/pkg/ui/workspaces/db-console/src/views/insights/workloadInsightsPage.tsx @@ -91,7 +91,7 @@ type DispatchProps = { statementInsightsViewDispatchProps: StatementInsightsViewDispatchProps; }; -const WorkloadInsightsPageConnected = withRouter( +const WorkloadInsightsPage = withRouter( connect< StateProps, DispatchProps, @@ -128,4 +128,4 @@ const WorkloadInsightsPageConnected = withRouter( )(WorkloadInsightsRootControl), ); -export default WorkloadInsightsPageConnected; +export default WorkloadInsightsPage;