From 7ba41108ba42af7381299ebcfc9b7ea7ce4b5368 Mon Sep 17 00:00:00 2001 From: gtr Date: Tue, 20 Dec 2022 14:18:18 -0500 Subject: [PATCH] ui: add missing filters for workload insights and active execution pages Fixes #87741, #87783. Previously, the workload insights page was missing a filter for insights type for both the statement and transaction tabs. Furthermore, the active execution pages for statement and transactions was also missing a status filter. This commit adds the ability to filter by insights type for the workload insights page and the ability to filter by execution status for the active execution pages. Release note (ui change): added an insights type filter for the workload insights page, added a execution status filter for the active execution pages. --- .../cluster-ui/src/insights/types.ts | 5 +- .../cluster-ui/src/insights/utils.ts | 24 +++++++ .../statementInsightsView.tsx | 8 ++- .../transactionInsightsView.tsx | 8 ++- .../workloadInsightsPageConnected.tsx | 4 ++ .../cluster-ui/src/queryFilter/filter.tsx | 71 +++++++++++++++++++ .../cluster-ui/src/queryFilter/utils.ts | 1 + .../recentExecutions/recentStatementUtils.ts | 18 +++++ .../recentTransactionsSection.tsx | 4 +- .../selectors/recentExecutions.selectors.ts | 18 ++++- .../recentStatementsPage.selectors.ts | 2 + .../statementsPage/recentStatementsView.tsx | 10 ++- .../statementInsights.selectors.ts | 21 ++++++ .../transactionInsights.selectors.ts | 21 ++++++ .../recentTransactionsPage.selectors.tsx | 2 + .../recentTransactionsView.tsx | 11 ++- .../selectors/recentExecutionsSelectors.ts | 14 ++++ .../src/views/insights/insightsSelectors.ts | 45 +++++++++++- .../views/insights/workloadInsightsPage.tsx | 4 ++ .../statements/recentStatementsSelectors.tsx | 12 +++- .../recentTransactionsSelectors.tsx | 12 +++- 21 files changed, 302 insertions(+), 13 deletions(-) diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/types.ts b/pkg/ui/workspaces/cluster-ui/src/insights/types.ts index fc860e48b28d..efdc979efbe5 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/types.ts +++ b/pkg/ui/workspaces/cluster-ui/src/insights/types.ts @@ -310,7 +310,10 @@ export const InsightExecOptions = new Map([ [InsightExecEnum.STATEMENT.toString(), "Statement Executions"], ]); -export type WorkloadInsightEventFilters = Pick; +export type WorkloadInsightEventFilters = Pick< + Filters, + "app" | "workloadInsightType" +>; export type SchemaInsightEventFilters = Pick< Filters, diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/utils.ts b/pkg/ui/workspaces/cluster-ui/src/insights/utils.ts index bcc730064e2a..fc1ce05268a5 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/utils.ts +++ b/pkg/ui/workspaces/cluster-ui/src/insights/utils.ts @@ -59,6 +59,18 @@ export const filterTransactionInsights = ( } else { filteredTransactions = filteredTransactions.filter(txn => !isInternal(txn)); } + if (filters.workloadInsightType) { + const workloadInsightTypes = filters.workloadInsightType + .toString() + .split(","); + filteredTransactions = filteredTransactions.filter( + transactionInsight => + workloadInsightTypes.length === 0 || + workloadInsightTypes.includes( + transactionInsight.insights.map(insight => insight.label).toString(), + ), + ); + } if (search) { search = search.toLowerCase(); @@ -201,6 +213,18 @@ export const filterStatementInsights = ( stmt => !isInternal(stmt.application), ); } + if (filters.workloadInsightType) { + const workloadInsightTypes = filters.workloadInsightType + .toString() + .split(","); + filteredStatements = filteredStatements.filter( + statementInsight => + workloadInsightTypes.length === 0 || + workloadInsightTypes.includes( + statementInsight.insights.map(insight => insight.label).toString(), + ), + ); + } if (search) { search = search.toLowerCase(); filteredStatements = filteredStatements.filter( 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 f442d2db1c86..ee7ea866c9bb 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 @@ -20,6 +20,7 @@ import { PageConfig, PageConfigItem } from "src/pageConfig/pageConfig"; import { Search } from "src/search/search"; import { calculateActiveFilters, + defaultFilters, Filter, getFullFiltersAsStringRecord, } from "src/queryFilter/filter"; @@ -53,6 +54,7 @@ const sortableTableCx = classNames.bind(sortableTableStyles); export type StatementInsightsViewStateProps = { statements: FlattenedStmtInsights; statementsError: Error | null; + insightTypes: string[]; filters: WorkloadInsightEventFilters; sortSetting: SortSetting; selectedColumnNames: string[]; @@ -80,6 +82,7 @@ export const StatementInsightsView: React.FC = ( sortSetting, statements, statementsError, + insightTypes, filters, refreshStatementInsights, onFiltersChange, @@ -187,7 +190,8 @@ export const StatementInsightsView: React.FC = ( const clearFilters = () => onSubmitFilters({ - app: "", + app: defaultFilters.app, + workloadInsightType: defaultFilters.workloadInsightType, }); const apps = getAppsFromStatementInsights( @@ -230,6 +234,8 @@ export const StatementInsightsView: React.FC = ( onSubmitFilters={onSubmitFilters} appNames={apps} filters={filters} + workloadInsightTypes={insightTypes} + showWorkloadInsightTypes={true} /> 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 4849c4a04b8a..fa99b6cb6d38 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 @@ -20,6 +20,7 @@ import { PageConfig, PageConfigItem } from "src/pageConfig/pageConfig"; import { Search } from "src/search/search"; import { calculateActiveFilters, + defaultFilters, Filter, getFullFiltersAsStringRecord, } from "src/queryFilter/filter"; @@ -49,6 +50,7 @@ const sortableTableCx = classNames.bind(sortableTableStyles); export type TransactionInsightsViewStateProps = { transactions: MergedTxnInsightEvent[]; transactionsError: Error | null; + insightTypes: string[]; filters: WorkloadInsightEventFilters; sortSetting: SortSetting; dropDownSelect?: React.ReactElement; @@ -74,6 +76,7 @@ export const TransactionInsightsView: React.FC = ( sortSetting, transactions, transactionsError, + insightTypes, filters, refreshTransactionInsights, onFiltersChange, @@ -173,7 +176,8 @@ export const TransactionInsightsView: React.FC = ( const clearFilters = () => onSubmitFilters({ - app: "", + app: defaultFilters.app, + workloadInsightType: defaultFilters.workloadInsightType, }); const transactionInsights = transactions; @@ -207,6 +211,8 @@ export const TransactionInsightsView: React.FC = ( onSubmitFilters={onSubmitFilters} appNames={apps} filters={filters} + workloadInsightTypes={insightTypes} + showWorkloadInsightTypes={true} /> 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 618ce804cbd3..6eb8e2ca0568 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/workloadInsightsPageConnected.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsights/workloadInsightsPageConnected.tsx @@ -31,11 +31,13 @@ import { selectColumns, selectStatementInsights, selectStatementInsightsError, + selectStatementInsightTypes, } from "src/store/insights/statementInsights"; import { actions as transactionInsights, selectTransactionInsights, selectTransactionInsightsError, + selectTransactionInsightTypes, selectFilters, selectSortSetting, } from "src/store/insights/transactionInsights"; @@ -49,6 +51,7 @@ const transactionMapStateToProps = ( ): TransactionInsightsViewStateProps => ({ transactions: selectTransactionInsights(state), transactionsError: selectTransactionInsightsError(state), + insightTypes: selectTransactionInsightTypes(state), filters: selectFilters(state), sortSetting: selectSortSetting(state), }); @@ -59,6 +62,7 @@ const statementMapStateToProps = ( ): StatementInsightsViewStateProps => ({ statements: selectStatementInsights(state), statementsError: selectStatementInsightsError(state), + insightTypes: selectStatementInsightTypes(state), filters: selectFilters(state), sortSetting: selectSortSetting(state), selectedColumnNames: selectColumns(state), diff --git a/pkg/ui/workspaces/cluster-ui/src/queryFilter/filter.tsx b/pkg/ui/workspaces/cluster-ui/src/queryFilter/filter.tsx index 8414b1ee6b50..653b2e622668 100644 --- a/pkg/ui/workspaces/cluster-ui/src/queryFilter/filter.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/queryFilter/filter.tsx @@ -39,14 +39,18 @@ interface QueryFilter { dbNames?: string[]; usernames?: string[]; sessionStatuses?: string[]; + executionStatuses?: string[]; schemaInsightTypes?: string[]; + workloadInsightTypes?: string[]; regions?: string[]; nodes?: string[]; hideAppNames?: boolean; showDB?: boolean; showUsername?: boolean; showSessionStatus?: boolean; + showExecutionStatus?: boolean; showSchemaInsightTypes?: boolean; + showWorkloadInsightTypes?: boolean; showSqlType?: boolean; showScan?: boolean; showRegions?: boolean; @@ -69,7 +73,9 @@ export interface Filters extends Record { nodes?: string; username?: string; sessionStatus?: string; + executionStatus?: string; schemaInsightType?: string; + workloadInsightType?: string; } const timeUnit = [ @@ -90,6 +96,8 @@ export const defaultFilters: Required = { username: "", sessionStatus: "", schemaInsightType: "", + workloadInsightType: "", + executionStatus: "", }; // getFullFiltersObject returns Filters with every field defined as @@ -251,6 +259,9 @@ export const inactiveFiltersState: Required> = { database: "", regions: "", nodes: "", + workloadInsightType: "", + schemaInsightType: "", + executionStatus: "", }; export const calculateActiveFilters = (filters: Filters): number => { @@ -383,7 +394,9 @@ export class Filter extends React.Component { dbNames, usernames, sessionStatuses, + executionStatuses, schemaInsightTypes, + workloadInsightTypes, regions, nodes, activeFilters, @@ -396,7 +409,9 @@ export class Filter extends React.Component { timeLabel, showUsername, showSessionStatus, + showExecutionStatus, showSchemaInsightTypes, + showWorkloadInsightTypes, } = this.props; const dropdownArea = hide ? hidden : dropdown; const customStyles = { @@ -527,6 +542,32 @@ export class Filter extends React.Component { ); + const executionStatusOptions = showExecutionStatus + ? executionStatuses.map(executionStatus => ({ + label: executionStatus, + value: executionStatus, + isSelected: this.isOptionSelected( + executionStatus, + filters.executionStatus, + ), + })) + : []; + const executionStatusValue = executionStatusOptions.filter(option => + filters.executionStatus.split(",").includes(option.label), + ); + const executionStatusFilter = ( +
+
Execution Status
+ +
+ ); + const schemaInsightTypeOptions = showSchemaInsightTypes ? schemaInsightTypes.map(schemaInsight => ({ label: schemaInsight, @@ -553,6 +594,34 @@ export class Filter extends React.Component { ); + const workloadInsightTypeOptions = showWorkloadInsightTypes + ? workloadInsightTypes.map(workloadInsight => ({ + label: workloadInsight, + value: workloadInsight, + isSelected: this.isOptionSelected( + workloadInsight, + filters.workloadInsightType, + ), + })) + : []; + const workloadInsightTypeValue = workloadInsightTypeOptions.filter( + option => { + return filters.workloadInsightType.split(",").includes(option.label); + }, + ); + const workloadInsightTypeFilter = ( +
+
Workload Insight Type
+ +
+ ); + const regionsOptions = showRegions ? regions.map(region => ({ label: region, @@ -668,7 +737,9 @@ export class Filter extends React.Component { {showDB ? dbFilter : ""} {showUsername ? usernameFilter : ""} {showSessionStatus ? sessionStatusFilter : ""} + {showExecutionStatus ? executionStatusFilter : ""} {showSchemaInsightTypes ? schemaInsightTypeFilter : ""} + {showWorkloadInsightTypes ? workloadInsightTypeFilter : ""} {showSqlType ? sqlTypeFilter : ""} {showRegions ? regionsFilter : ""} {showNodes ? nodesFilter : ""} diff --git a/pkg/ui/workspaces/cluster-ui/src/queryFilter/utils.ts b/pkg/ui/workspaces/cluster-ui/src/queryFilter/utils.ts index d5e605963042..2cd8aafb713e 100644 --- a/pkg/ui/workspaces/cluster-ui/src/queryFilter/utils.ts +++ b/pkg/ui/workspaces/cluster-ui/src/queryFilter/utils.ts @@ -79,6 +79,7 @@ export function getWorkloadInsightEventFiltersFromURL( const appFilters = { app: filters.app, + workloadInsightType: filters.workloadInsightType, }; // If every entry is null, there were no active filters. Return null. diff --git a/pkg/ui/workspaces/cluster-ui/src/recentExecutions/recentStatementUtils.ts b/pkg/ui/workspaces/cluster-ui/src/recentExecutions/recentStatementUtils.ts index c48cd6bbf350..75b693fd72fd 100644 --- a/pkg/ui/workspaces/cluster-ui/src/recentExecutions/recentStatementUtils.ts +++ b/pkg/ui/workspaces/cluster-ui/src/recentExecutions/recentStatementUtils.ts @@ -65,6 +65,16 @@ export function filterRecentStatements( ); } + if (filters.executionStatus) { + filteredStatements = filteredStatements.filter( + (statement: RecentStatement) => { + const executionStatuses = filters.executionStatus.toString().split(","); + + return executionStatuses.includes(statement.status); + }, + ); + } + if (search) { const searchCaseInsensitive = search.toLowerCase(); filteredStatements = filteredStatements.filter(stmt => @@ -206,6 +216,14 @@ export function filterRecentTransactions( filteredTxns = filteredTxns.filter(txn => !isInternal(txn)); } + if (filters.executionStatus) { + filteredTxns = filteredTxns.filter((txn: RecentTransaction) => { + const executionStatuses = filters.executionStatus.toString().split(","); + + return executionStatuses.includes(txn.status); + }); + } + if (search) { const searchCaseInsensitive = search.toLowerCase(); filteredTxns = filteredTxns.filter(txn => diff --git a/pkg/ui/workspaces/cluster-ui/src/recentExecutions/recentTransactionsSection.tsx b/pkg/ui/workspaces/cluster-ui/src/recentExecutions/recentTransactionsSection.tsx index 715ae90910f6..e77d6d12a74e 100644 --- a/pkg/ui/workspaces/cluster-ui/src/recentExecutions/recentTransactionsSection.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/recentExecutions/recentTransactionsSection.tsx @@ -11,8 +11,8 @@ import React, { useMemo } from "react"; import classNames from "classnames/bind"; import { - RecentStatementFilters, RecentTransaction, + RecentTransactionFilters, } from "src/recentExecutions/types"; import ColumnsSelector, { SelectOption, @@ -36,7 +36,7 @@ import { SortedTable } from "src/sortedtable"; const sortableTableCx = classNames.bind(sortableTableStyles); type RecentTransactionsSectionProps = { - filters: RecentStatementFilters; + filters: RecentTransactionFilters; isTenant?: boolean; pagination: ISortedTablePagination; search: string; diff --git a/pkg/ui/workspaces/cluster-ui/src/selectors/recentExecutions.selectors.ts b/pkg/ui/workspaces/cluster-ui/src/selectors/recentExecutions.selectors.ts index 20e8f9e7cf21..ab7f17d58d3b 100644 --- a/pkg/ui/workspaces/cluster-ui/src/selectors/recentExecutions.selectors.ts +++ b/pkg/ui/workspaces/cluster-ui/src/selectors/recentExecutions.selectors.ts @@ -9,7 +9,11 @@ // licenses/APL.txt. import { createSelector } from "reselect"; -import { RecentExecutions } from "src/recentExecutions/types"; +import { + RecentExecutions, + RecentStatement, + RecentTransaction, +} from "src/recentExecutions/types"; import { AppState } from "src/store"; import { selectRecentExecutionsCombiner } from "src/selectors/recentExecutionsCommon.selectors"; import { selectExecutionID } from "src/selectors/common"; @@ -39,6 +43,12 @@ export const selectRecentStatements = createSelector( (executions: RecentExecutions) => executions.statements, ); +export const selectStatementExecutionStatus = createSelector( + selectRecentStatements, + (statements: RecentStatement[]) => + Array.from(new Set(statements.map(statement => statement.status))), +); + export const selecteRecentStatement = createSelector( selectRecentStatements, selectExecutionID, @@ -50,6 +60,12 @@ export const selectRecentTransactions = createSelector( (executions: RecentExecutions) => executions.transactions, ); +export const selectTransactionExecutionStatus = createSelector( + selectRecentTransactions, + (transactions: RecentTransaction[]) => + Array.from(new Set(transactions.map(transaction => transaction.status))), +); + export const selectRecentTransaction = createSelector( selectRecentTransactions, selectExecutionID, diff --git a/pkg/ui/workspaces/cluster-ui/src/statementsPage/recentStatementsPage.selectors.ts b/pkg/ui/workspaces/cluster-ui/src/statementsPage/recentStatementsPage.selectors.ts index fd7393cf7dfc..e9ce20b3ad61 100644 --- a/pkg/ui/workspaces/cluster-ui/src/statementsPage/recentStatementsPage.selectors.ts +++ b/pkg/ui/workspaces/cluster-ui/src/statementsPage/recentStatementsPage.selectors.ts @@ -20,6 +20,7 @@ import { import { selectRecentStatements, selectAppName, + selectStatementExecutionStatus, } from "src/selectors/recentExecutions.selectors"; import { actions as localStorageActions } from "src/store/localStorage"; import { actions as sessionsActions } from "src/store/sessions"; @@ -54,6 +55,7 @@ export const mapStateToRecentStatementsPageProps = ( selectedColumns: selectColumns(state), sortSetting: selectSortSetting(state), filters: selectFilters(state), + executionStatus: selectStatementExecutionStatus(state), internalAppNamePrefix: selectAppName(state), isTenant: selectIsTenant(state), }); diff --git a/pkg/ui/workspaces/cluster-ui/src/statementsPage/recentStatementsView.tsx b/pkg/ui/workspaces/cluster-ui/src/statementsPage/recentStatementsView.tsx index 385716db859c..37fcf1d52ca4 100644 --- a/pkg/ui/workspaces/cluster-ui/src/statementsPage/recentStatementsView.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/statementsPage/recentStatementsView.tsx @@ -53,6 +53,7 @@ export type RecentStatementsViewStateProps = { sortSetting: SortSetting; sessionsError: Error | null; filters: RecentStatementFilters; + executionStatus: string[]; internalAppNamePrefix: string; isTenant?: boolean; }; @@ -70,6 +71,7 @@ export const RecentStatementsView: React.FC = ({ statements, sessionsError, filters, + executionStatus, internalAppNamePrefix, isTenant, }: RecentStatementsViewProps) => { @@ -154,7 +156,11 @@ export const RecentStatementsView: React.FC = ({ }; const clearSearch = () => onSubmitSearch(""); - const clearFilters = () => onSubmitFilters({ app: inactiveFiltersState.app }); + const clearFilters = () => + onSubmitFilters({ + app: inactiveFiltersState.app, + executionStatus: inactiveFiltersState.executionStatus, + }); const apps = getAppsFromRecentExecutions(statements, internalAppNamePrefix); const countActiveFilters = calculateActiveFilters(filters); @@ -180,6 +186,8 @@ export const RecentStatementsView: React.FC = ({ 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 index 2addc77bf133..256888adbb61 100644 --- 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 @@ -31,6 +31,27 @@ export const selectStatementInsightDetails = createSelector( selectStatementInsightDetailsCombiner, ); +export const selectStatementInsightTypes = createSelector( + selectStatementInsights, + statementInsights => { + if (!statementInsights) return []; + + const insightTypes = new Set(); + + statementInsights.forEach(stmtInsightEvent => { + if (stmtInsightEvent.insights) { + stmtInsightEvent.insights.forEach(insight => { + if (!insightTypes.has(insight.label)) { + insightTypes.add(insight.label); + } + }); + } + }); + + return Array.from(insightTypes).sort(); + }, +); + export const selectColumns = createSelector( localStorageSelector, localStorage => 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 index 6e09d061831a..6ad91e88f130 100644 --- 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 @@ -25,6 +25,27 @@ export const selectTransactionInsights = createSelector( export const selectTransactionInsightsError = (state: AppState) => state.adminUI.transactionInsights?.lastError; +export const selectTransactionInsightTypes = createSelector( + selectTransactionInsightsData, + transactionInsights => { + if (!transactionInsights) return []; + + const transactionInsightTypes = new Set(); + + transactionInsights.forEach(transactionInsightEvent => { + if (transactionInsightEvent.insights) { + transactionInsightEvent.insights.forEach(insight => { + if (!transactionInsightTypes.has(insight.label)) { + transactionInsightTypes.add(insight.label); + } + }); + } + }); + + return Array.from(transactionInsightTypes).sort(); + }, +); + export const selectSortSetting = createSelector( localStorageSelector, localStorage => localStorage["sortSetting/InsightsPage"], diff --git a/pkg/ui/workspaces/cluster-ui/src/transactionsPage/recentTransactionsPage.selectors.tsx b/pkg/ui/workspaces/cluster-ui/src/transactionsPage/recentTransactionsPage.selectors.tsx index 7c70af49cc8d..3ba0826a724b 100644 --- a/pkg/ui/workspaces/cluster-ui/src/transactionsPage/recentTransactionsPage.selectors.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/transactionsPage/recentTransactionsPage.selectors.tsx @@ -20,6 +20,7 @@ import { import { selectAppName, selectRecentTransactions, + selectTransactionExecutionStatus, } from "src/selectors/recentExecutions.selectors"; import { actions as localStorageActions } from "src/store/localStorage"; import { actions as sessionsActions } from "src/store/sessions"; @@ -54,6 +55,7 @@ export const mapStateToRecentTransactionsPageProps = ( selectedColumns: selectColumns(state), sortSetting: selectSortSetting(state), filters: selectFilters(state), + executionStatus: selectTransactionExecutionStatus(state), internalAppNamePrefix: selectAppName(state), isTenant: selectIsTenant(state), }); diff --git a/pkg/ui/workspaces/cluster-ui/src/transactionsPage/recentTransactionsView.tsx b/pkg/ui/workspaces/cluster-ui/src/transactionsPage/recentTransactionsView.tsx index fad329cc748b..2d7edeceba84 100644 --- a/pkg/ui/workspaces/cluster-ui/src/transactionsPage/recentTransactionsView.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/transactionsPage/recentTransactionsView.tsx @@ -52,6 +52,7 @@ export type RecentTransactionsViewStateProps = { transactions: RecentTransaction[]; sessionsError: Error | null; filters: RecentTransactionFilters; + executionStatus: string[]; sortSetting: SortSetting; internalAppNamePrefix: string; isTenant?: boolean; @@ -73,12 +74,14 @@ export const RecentTransactionsView: React.FC = ({ transactions, sessionsError, filters, + executionStatus, internalAppNamePrefix, }: RecentTransactionsViewProps) => { const [pagination, setPagination] = useState({ current: 1, pageSize: 20, }); + const history = useHistory(); const [search, setSearch] = useState( queryByName(history.location, RECENT_TXN_SEARCH_PARAM), @@ -155,7 +158,11 @@ export const RecentTransactionsView: React.FC = ({ }; const clearSearch = () => onSubmitSearch(""); - const clearFilters = () => onSubmitFilters({ app: inactiveFiltersState.app }); + const clearFilters = () => + onSubmitFilters({ + app: inactiveFiltersState.app, + executionStatus: inactiveFiltersState.executionStatus, + }); const apps = getAppsFromRecentExecutions(transactions, internalAppNamePrefix); const countActiveFilters = calculateActiveFilters(filters); @@ -181,6 +188,8 @@ export const RecentTransactionsView: React.FC = ({ diff --git a/pkg/ui/workspaces/db-console/src/selectors/recentExecutionsSelectors.ts b/pkg/ui/workspaces/db-console/src/selectors/recentExecutionsSelectors.ts index 713d3cd8c595..6c92143fdeb1 100644 --- a/pkg/ui/workspaces/db-console/src/selectors/recentExecutionsSelectors.ts +++ b/pkg/ui/workspaces/db-console/src/selectors/recentExecutionsSelectors.ts @@ -10,11 +10,13 @@ import { RecentExecutions, + RecentTransaction, selectRecentExecutionsCombiner, getRecentStatement, getRecentTransaction, getContentionDetailsFromLocksAndTxns, selectExecutionID, + RecentStatement, } from "@cockroachlabs/cluster-ui"; import { createSelector } from "reselect"; import { CachedDataReducerState } from "src/redux/apiReducers"; @@ -37,6 +39,12 @@ export const selectRecentStatements = createSelector( (executions: RecentExecutions) => executions.statements, ); +export const selectStatementExecutionStatus = createSelector( + selectRecentStatements, + (statements: RecentStatement[]) => + Array.from(new Set(statements.map(statement => statement.status))), +); + export const selectRecentStatement = createSelector( selectRecentStatements, selectExecutionID, @@ -58,6 +66,12 @@ export const selectRecentTransactions = createSelector( (executions: RecentExecutions) => executions.transactions, ); +export const selectTransactionExecutionStatus = createSelector( + selectRecentTransactions, + (transactions: RecentTransaction[]) => + Array.from(new Set(transactions.map(transaction => transaction.status))), +); + export const selectRecentTransaction = createSelector( selectRecentTransactions, selectExecutionID, 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 830140f72080..f28539656a07 100644 --- a/pkg/ui/workspaces/db-console/src/views/insights/insightsSelectors.ts +++ b/pkg/ui/workspaces/db-console/src/views/insights/insightsSelectors.ts @@ -23,13 +23,16 @@ import { selectTxnInsightsCombiner, TxnContentionInsightDetails, selectTxnInsightDetailsCombiner, + Insight, + FlattenedStmtInsightEvent, } from "@cockroachlabs/cluster-ui"; export const filtersLocalSetting = new LocalSetting< AdminUIState, WorkloadInsightEventFilters >("filters/InsightsPage", (state: AdminUIState) => state.localSettings, { - app: "", + app: defaultFilters.app, + workloadInsightType: defaultFilters.workloadInsightType, }); export const sortSettingLocalSetting = new LocalSetting< @@ -46,6 +49,26 @@ export const selectTransactionInsights = createSelector( selectTxnInsightsCombiner, ); +export const selectTransactionInsightTypes = createSelector( + selectTransactionInsights, + transactionInsights => { + if (!transactionInsights) return []; + + const transactionInsightTypes = new Set(); + transactionInsights.forEach(transactionInsightEvent => { + if (transactionInsightEvent.insights) { + transactionInsightEvent.insights.forEach((insight: Insight) => { + if (!transactionInsightTypes.has(insight.label)) { + transactionInsightTypes.add(insight.label); + } + }); + } + }); + + return Array.from(transactionInsightTypes).sort(); + }, +); + const selectTxnContentionInsightDetails = createSelector( [ (state: AdminUIState) => state.cachedData.transactionInsightDetails, @@ -89,6 +112,26 @@ export const selectStatementInsights = createSelector( selectFlattenedStmtInsightsCombiner, ); +export const selectStatementInsightTypes = createSelector( + selectStatementInsights, + statementInsights => { + if (!statementInsights) return []; + const insightTypes = new Set(); + + statementInsights.forEach((stmtInsightEvent: FlattenedStmtInsightEvent) => { + if (stmtInsightEvent.insights) { + stmtInsightEvent.insights.forEach(insight => { + if (!insightTypes.has(insight.label)) { + insightTypes.add(insight.label); + } + }); + } + }); + + return Array.from(insightTypes).sort(); + }, +); + export const selectStatementInsightDetails = createSelector( selectStatementInsights, selectID, diff --git a/pkg/ui/workspaces/db-console/src/views/insights/workloadInsightsPage.tsx b/pkg/ui/workspaces/db-console/src/views/insights/workloadInsightsPage.tsx index 955960309d93..c8d7003ef628 100644 --- a/pkg/ui/workspaces/db-console/src/views/insights/workloadInsightsPage.tsx +++ b/pkg/ui/workspaces/db-console/src/views/insights/workloadInsightsPage.tsx @@ -30,6 +30,8 @@ import { selectStatementInsights, sortSettingLocalSetting, selectTransactionInsights, + selectStatementInsightTypes, + selectTransactionInsightTypes, } from "src/views/insights/insightsSelectors"; import { bindActionCreators } from "redux"; import { LocalSetting } from "src/redux/localsettings"; @@ -50,6 +52,7 @@ const transactionMapStateToProps = ( ): TransactionInsightsViewStateProps => ({ transactions: selectTransactionInsights(state), transactionsError: state.cachedData?.transactionInsights?.lastError, + insightTypes: selectTransactionInsightTypes(state), filters: filtersLocalSetting.selector(state), sortSetting: sortSettingLocalSetting.selector(state), }); @@ -61,6 +64,7 @@ const statementMapStateToProps = ( statements: selectStatementInsights(state), statementsError: state.cachedData?.executionInsights?.lastError, filters: filtersLocalSetting.selector(state), + insightTypes: selectStatementInsightTypes(state), sortSetting: sortSettingLocalSetting.selector(state), selectedColumnNames: insightStatementColumnsLocalSetting.selectorToArray(state), diff --git a/pkg/ui/workspaces/db-console/src/views/statements/recentStatementsSelectors.tsx b/pkg/ui/workspaces/db-console/src/views/statements/recentStatementsSelectors.tsx index dc19a9cc51a0..74f0164cd495 100644 --- a/pkg/ui/workspaces/db-console/src/views/statements/recentStatementsSelectors.tsx +++ b/pkg/ui/workspaces/db-console/src/views/statements/recentStatementsSelectors.tsx @@ -13,7 +13,11 @@ import { defaultFilters, SortSetting, } from "@cockroachlabs/cluster-ui"; -import { selectRecentStatements, selectAppName } from "src/selectors"; +import { + selectRecentStatements, + selectAppName, + selectStatementExecutionStatus, +} from "src/selectors"; import { refreshLiveWorkload } from "src/redux/apiReducers"; import { LocalSetting } from "src/redux/localsettings"; import { AdminUIState } from "src/redux/state"; @@ -27,7 +31,10 @@ const selectedColumnsLocalSetting = new LocalSetting< null, ); -const defaultActiveFilters = { app: defaultFilters.app }; +const defaultActiveFilters = { + app: defaultFilters.app, + executionStatus: defaultFilters.executionStatus, +}; const filtersLocalSetting = new LocalSetting< AdminUIState, @@ -49,6 +56,7 @@ export const mapStateToRecentStatementViewProps = (state: AdminUIState) => ({ selectedColumns: selectedColumnsLocalSetting.selectorToArray(state), sortSetting: sortSettingLocalSetting.selector(state), statements: selectRecentStatements(state), + executionStatus: selectStatementExecutionStatus(state), sessionsError: state.cachedData?.sessions.lastError, internalAppNamePrefix: selectAppName(state), }); diff --git a/pkg/ui/workspaces/db-console/src/views/transactions/recentTransactionsSelectors.tsx b/pkg/ui/workspaces/db-console/src/views/transactions/recentTransactionsSelectors.tsx index 65706c651d54..50ca24cf23d7 100644 --- a/pkg/ui/workspaces/db-console/src/views/transactions/recentTransactionsSelectors.tsx +++ b/pkg/ui/workspaces/db-console/src/views/transactions/recentTransactionsSelectors.tsx @@ -14,7 +14,11 @@ import { defaultFilters, SortSetting, } from "@cockroachlabs/cluster-ui"; -import { selectAppName, selectRecentTransactions } from "src/selectors"; +import { + selectAppName, + selectRecentTransactions, + selectTransactionExecutionStatus, +} from "src/selectors"; import { refreshLiveWorkload } from "src/redux/apiReducers"; import { LocalSetting } from "src/redux/localsettings"; import { AdminUIState } from "src/redux/state"; @@ -28,7 +32,10 @@ const transactionsColumnsLocalSetting = new LocalSetting< null, ); -const defaultActiveTxnFilters = { app: defaultFilters.app }; +const defaultActiveTxnFilters = { + app: defaultFilters.app, + executionStatus: defaultFilters.executionStatus, +}; const filtersLocalSetting = new LocalSetting< AdminUIState, @@ -50,6 +57,7 @@ export const mapStateToRecentTransactionsPageProps = (state: AdminUIState) => ({ transactions: selectRecentTransactions(state), sessionsError: state.cachedData?.sessions.lastError, filters: filtersLocalSetting.selector(state), + executionStatus: selectTransactionExecutionStatus(state), sortSetting: sortSettingLocalSetting.selector(state), internalAppNamePrefix: selectAppName(state), });