From 28c4f9e41bc4e2ebea04d50b3578ffa6b444b572 Mon Sep 17 00:00:00 2001 From: Andrii Vorobiov Date: Fri, 2 Oct 2020 12:36:07 +0300 Subject: [PATCH] ui: extend diagnostics column to allow activate and download reports Previously, Statements table had a Diagnostics column which allowed users to request diagnostics reports for the first time and then displayed status for requested report only. As result it wasn't possible to download already generated report or request new one report from statements table. With current changes, Diagnostics column allows to request new reports everytime when previous reports are generated. Also it provides a list with links to download previous reports. The main change is to provide a list of available (or requested) reports for every statement (instead of a single, most recent report as it was before). Then extracted `StatementsPage` component (from `admin-ui-components` package) handles all rendering logic for this list of reports. Minor changes: - `WAITING FOR QUERY` status is renamed to `WAITING` for new design - `getDiagnosticsStatus` utility function is reused to reduce code duplication Resolves: #50824 Release note (admin ui change): Diagnostics column (on statements table) has been changed and includes `Activate` button and dropdown list to download completed reports. Also diagnostics badge status is changed from `WAITING FOR QUERY` to `WAITING`. --- pkg/ui/package.json | 2 +- pkg/ui/src/redux/statements/statementsSelectors.ts | 9 ++++----- .../statements/diagnostics/diagnosticStatusBadge.tsx | 4 ++-- .../statements/diagnostics/diagnosticStatuses.ts | 2 +- .../views/statements/diagnostics/diagnosticsUtils.ts | 2 +- pkg/ui/src/views/statements/statementsPage.tsx | 11 +++++++---- pkg/ui/src/views/statements/statementsTable.tsx | 3 ++- .../src/views/statements/statementsTableContent.tsx | 5 +++-- pkg/ui/yarn-vendor | 2 +- pkg/ui/yarn.lock | 8 ++++---- 10 files changed, 26 insertions(+), 22 deletions(-) diff --git a/pkg/ui/package.json b/pkg/ui/package.json index 65a68d58c34c..36ac354d896b 100644 --- a/pkg/ui/package.json +++ b/pkg/ui/package.json @@ -13,7 +13,7 @@ "cypress:update-snapshots": "yarn cypress run --env updateSnapshots=true --spec 'cypress/integration/**/*.visual.spec.ts'" }, "dependencies": { - "@cockroachlabs/admin-ui-components": "^0.1.17", + "@cockroachlabs/admin-ui-components": "^0.1.20", "analytics-node": "^3.4.0-beta.1", "antd": "^3.25.2", "babel-polyfill": "^6.26.0", diff --git a/pkg/ui/src/redux/statements/statementsSelectors.ts b/pkg/ui/src/redux/statements/statementsSelectors.ts index 0aa192cf8273..02bae177cd9e 100644 --- a/pkg/ui/src/redux/statements/statementsSelectors.ts +++ b/pkg/ui/src/redux/statements/statementsSelectors.ts @@ -8,7 +8,7 @@ // by the Apache License, Version 2.0, included in the file // licenses/APL.txt. -import { chain, sortBy, last } from "lodash"; +import { chain, orderBy } from "lodash"; import { createSelector } from "reselect"; import { AdminUIState } from "src/redux/state"; import { cockroach } from "src/js/protos"; @@ -44,14 +44,13 @@ export const statementDiagnosticsReportsInFlight = createSelector( ); type StatementDiagnosticsDictionary = { - [statementFingerprint: string]: IStatementDiagnosticsReport; + [statementFingerprint: string]: IStatementDiagnosticsReport[]; }; -export const selectLastDiagnosticsReportPerStatement = createSelector( +export const selectDiagnosticsReportsPerStatement = createSelector( selectStatementDiagnosticsReports, (diagnosticsReports: IStatementDiagnosticsReport[]): StatementDiagnosticsDictionary => chain(diagnosticsReports) .groupBy(diagnosticsReport => diagnosticsReport.statement_fingerprint) - // Perform ASC sorting and take the last item - .mapValues(diagnostics => last(sortBy(diagnostics, d => d.requested_at.seconds.toNumber()))) + .mapValues(diagnostics => orderBy(diagnostics, d => d.requested_at.seconds.toNumber(), ["desc"])) .value(), ); diff --git a/pkg/ui/src/views/statements/diagnostics/diagnosticStatusBadge.tsx b/pkg/ui/src/views/statements/diagnostics/diagnosticStatusBadge.tsx index cfa44170a33d..01748eaada9b 100644 --- a/pkg/ui/src/views/statements/diagnostics/diagnosticStatusBadge.tsx +++ b/pkg/ui/src/views/statements/diagnostics/diagnosticStatusBadge.tsx @@ -24,7 +24,7 @@ function mapDiagnosticsStatusToBadge(diagnosticsStatus: DiagnosticStatuses) { switch (diagnosticsStatus) { case "READY": return "success"; - case "WAITING FOR QUERY": + case "WAITING": return "info"; case "ERROR": return "danger"; @@ -50,7 +50,7 @@ function mapStatusToDescription(diagnosticsStatus: DiagnosticStatuses) {

); - case "WAITING FOR QUERY": + case "WAITING": return (

diff --git a/pkg/ui/src/views/statements/diagnostics/diagnosticStatuses.ts b/pkg/ui/src/views/statements/diagnostics/diagnosticStatuses.ts index 5657edb92279..96ae8058a55a 100644 --- a/pkg/ui/src/views/statements/diagnostics/diagnosticStatuses.ts +++ b/pkg/ui/src/views/statements/diagnostics/diagnosticStatuses.ts @@ -8,4 +8,4 @@ // by the Apache License, Version 2.0, included in the file // licenses/APL.txt. -export type DiagnosticStatuses = "READY" | "WAITING FOR QUERY" | "ERROR"; +export type DiagnosticStatuses = "READY" | "WAITING" | "ERROR"; diff --git a/pkg/ui/src/views/statements/diagnostics/diagnosticsUtils.ts b/pkg/ui/src/views/statements/diagnostics/diagnosticsUtils.ts index 650da86e0616..3bdb418d817d 100644 --- a/pkg/ui/src/views/statements/diagnostics/diagnosticsUtils.ts +++ b/pkg/ui/src/views/statements/diagnostics/diagnosticsUtils.ts @@ -19,7 +19,7 @@ export function getDiagnosticsStatus(diagnosticsRequest: IStatementDiagnosticsRe return "READY"; } - return "WAITING FOR QUERY"; + return "WAITING"; } export function sortByRequestedAtField(a: IStatementDiagnosticsReport, b: IStatementDiagnosticsReport) { diff --git a/pkg/ui/src/views/statements/statementsPage.tsx b/pkg/ui/src/views/statements/statementsPage.tsx index 4f144e21180e..2820cd6ca52f 100644 --- a/pkg/ui/src/views/statements/statementsPage.tsx +++ b/pkg/ui/src/views/statements/statementsPage.tsx @@ -30,7 +30,7 @@ import { appAttr } from "src/util/constants"; import { TimestampToMoment } from "src/util/convert"; import { PrintTime } from "src/views/reports/containers/range/print"; import { - selectLastDiagnosticsReportPerStatement, + selectDiagnosticsReportsPerStatement, } from "src/redux/statements/statementsSelectors"; import { createStatementDiagnosticsAlertLocalSetting } from "src/redux/alerts"; import { getMatchParamByName } from "src/util/query"; @@ -42,8 +42,10 @@ import { trackStatementsSearchAction, trackTableSortAction, } from "src/redux/analyticsActions"; +import { trackDownloadDiagnosticsBundle } from "src/util/analytics"; type ICollectedStatementStatistics = protos.cockroach.server.serverpb.StatementsResponse.ICollectedStatementStatistics; +type IStatementDiagnosticsReport = protos.cockroach.server.serverpb.IStatementDiagnosticsReport; interface StatementsSummaryData { statement: string; @@ -60,11 +62,11 @@ function keyByStatementAndImplicitTxn(stmt: ExecutionStatistics): string { export const selectStatements = createSelector( (state: AdminUIState) => state.cachedData.statements, (_state: AdminUIState, props: RouteComponentProps) => props, - selectLastDiagnosticsReportPerStatement, + selectDiagnosticsReportsPerStatement, ( state: CachedDataReducerState, props: RouteComponentProps, - lastDiagnosticsReportPerStatement, + diagnosticsReportsPerStatement, ) => { if (!state.data) { return null; @@ -108,7 +110,7 @@ export const selectStatements = createSelector( label: stmt.statement, implicitTxn: stmt.implicitTxn, stats: combineStatementStats(stmt.stats), - diagnosticsReport: lastDiagnosticsReportPerStatement[stmt.statement], + diagnosticsReports: diagnosticsReportsPerStatement[stmt.statement], }; }); }, @@ -185,6 +187,7 @@ const StatementsPageConnected = withRouter(connect( onSearchComplete: (results: AggregateStatistics[]) => trackStatementsSearchAction(results.length), onPageChanged: trackStatementsPaginationAction, onSortingChange: trackTableSortAction, + onDiagnosticsReportDownload: (report: IStatementDiagnosticsReport) => trackDownloadDiagnosticsBundle(report.statement_fingerprint), }, )(StatementsPage)); diff --git a/pkg/ui/src/views/statements/statementsTable.tsx b/pkg/ui/src/views/statements/statementsTable.tsx index 920d4991a142..865316c1f553 100644 --- a/pkg/ui/src/views/statements/statementsTable.tsx +++ b/pkg/ui/src/views/statements/statementsTable.tsx @@ -22,6 +22,7 @@ import IStatementDiagnosticsReport = cockroach.server.serverpb.IStatementDiagnos import { ActivateDiagnosticsModalRef } from "./diagnostics/activateDiagnosticsModal"; import styles from "./statementsTable.module.styl"; import { StatementTableTitle, StatementTableCell, NodeNames } from "./statementsTableContent"; +import { getDiagnosticsStatus } from "src/views/statements/diagnostics"; const cx = classNames.bind(styles); const longToInt = (d: number | Long) => FixLong(d).toInt(); @@ -78,7 +79,7 @@ export function makeStatementsColumns( cell: StatementTableCell.diagnostics(activateDiagnosticsRef), sort: (stmt) => { if (stmt.diagnosticsReport) { - return stmt.diagnosticsReport.completed ? "READY" : "WAITING FOR QUERY"; + return getDiagnosticsStatus(stmt.diagnosticsReport); } return null; }, diff --git a/pkg/ui/src/views/statements/statementsTableContent.tsx b/pkg/ui/src/views/statements/statementsTableContent.tsx index dc275e1d729d..ef14983b4e9a 100644 --- a/pkg/ui/src/views/statements/statementsTableContent.tsx +++ b/pkg/ui/src/views/statements/statementsTableContent.tsx @@ -19,6 +19,7 @@ import { ActivateDiagnosticsModalRef } from "./diagnostics/activateDiagnosticsMo import { DiagnosticStatusBadge } from "./diagnostics/diagnosticStatusBadge"; import { shortStatement } from "./statementsTable"; import styles from "./statementsTableContent.module.styl"; +import { getDiagnosticsStatus } from "src/views/statements/diagnostics"; export type NodeNames = { [nodeId: string]: string }; @@ -90,7 +91,7 @@ export const StatementTableTitle = { diagnostics {" for each statement. If activated, this displays the status of diagnostics collection ("} - WAITING FOR QUERY, READY, OR ERROR). + WAITING, READY, OR ERROR).

} @@ -202,7 +203,7 @@ export const StatementTableCell = { ), diagnostics: (activateDiagnosticsRef: React.RefObject) => (stmt: any) => { if (stmt.diagnosticsReport) { - return ; + return ; } return (