diff --git a/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetails.selectors.ts b/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetails.selectors.ts index 307d2e98f5fb..5175fff0b3ea 100644 --- a/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetails.selectors.ts +++ b/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetails.selectors.ts @@ -8,6 +8,7 @@ // by the Apache License, Version 2.0, included in the file // licenses/APL.txt. +import Long from "long"; import { createSelector } from "@reduxjs/toolkit"; import { RouteComponentProps } from "react-router-dom"; import { AppState } from "../store"; @@ -16,47 +17,33 @@ import { statementAttr, getMatchParamByName, queryByName, + generateStmtDetailsToID, } from "../util"; import { cockroach } from "@cockroachlabs/crdb-protobuf-client"; +import { TimeScale, toRoundedDateRange } from "../timeScaleDropdown"; +import { selectTimeScale } from "../statementsPage/statementsPage.selectors"; type StatementDetailsResponseMessage = cockroach.server.serverpb.StatementDetailsResponse; -export const generateStmtDetailsToID = ( - fingerprintID: string, - appNames: string, -): string => { - if ( - appNames && - (appNames.includes("$ internal") || appNames.includes("unset")) - ) { - const apps = appNames.split(","); - for (let i = 0; i < apps.length; i++) { - if (apps[i].includes("$ internal")) { - apps[i] = "$ internal"; - } - if (apps[i].includes("unset")) { - apps[i] = ""; - } - } - appNames = apps.toString(); - } - if (appNames) { - return fingerprintID + appNames; - } - return fingerprintID; -}; - export const selectStatementDetails = createSelector( (_state: AppState, props: RouteComponentProps): string => getMatchParamByName(props.match, statementAttr), (_state: AppState, props: RouteComponentProps): string => queryByName(props.location, appNamesAttr), + (state: AppState): TimeScale => selectTimeScale(state), (state: AppState) => state.adminUI.sqlDetailsStats, ( fingerprintID, appNames, + timeScale, statementDetailsStats, ): StatementDetailsResponseMessage => { - const key = generateStmtDetailsToID(fingerprintID, appNames); + const [start, end] = toRoundedDateRange(timeScale); + const key = generateStmtDetailsToID( + fingerprintID, + appNames, + Long.fromNumber(start.unix()), + Long.fromNumber(end.unix()), + ); if (Object.keys(statementDetailsStats).includes(key)) { return statementDetailsStats[key].data; } diff --git a/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetails.tsx b/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetails.tsx index 83967cec098c..ba04259b7d57 100644 --- a/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetails.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetails.tsx @@ -56,7 +56,7 @@ import { commonStyles } from "src/common"; import { NodeSummaryStats } from "../nodes"; import { UIConfigState } from "../store"; import moment from "moment"; -import { TimeScale, toDateRange } from "../timeScaleDropdown"; +import { TimeScale, toRoundedDateRange } from "../timeScaleDropdown"; import { StatementDetailsRequest } from "src/api/statementsApi"; import SQLActivityError from "../sqlActivity/errorComponent"; import { @@ -162,7 +162,7 @@ const summaryCardStylesCx = classNames.bind(summaryCardStyles); function statementDetailsRequestFromProps( props: StatementDetailsProps, ): cockroach.server.serverpb.StatementDetailsRequest { - const [start, end] = toDateRange(props.timeScale); + const [start, end] = toRoundedDateRange(props.timeScale); const statementFingerprintID = getMatchParamByName( props.match, statementAttr, diff --git a/pkg/ui/workspaces/cluster-ui/src/store/statementDetails/statementDetails.sagas.spec.ts b/pkg/ui/workspaces/cluster-ui/src/store/statementDetails/statementDetails.sagas.spec.ts index 5465ee5f55e8..e055f0a152ab 100644 --- a/pkg/ui/workspaces/cluster-ui/src/store/statementDetails/statementDetails.sagas.spec.ts +++ b/pkg/ui/workspaces/cluster-ui/src/store/statementDetails/statementDetails.sagas.spec.ts @@ -39,7 +39,7 @@ describe("SQLDetailsStats sagas", () => { type: "request", }; const key = - "SELECT * FROM crdb_internal.node_build_info$ cockroach sql,newname"; + "SELECT * FROM crdb_internal.node_build_info/$ cockroach sql,newname/0/0"; const SQLDetailsStatsResponse = new cockroach.server.serverpb.StatementDetailsResponse( { statement: { @@ -659,7 +659,7 @@ describe("SQLDetailsStats sagas", () => { ) .withReducer(reducer) .hasFinalState>({ - "SELECT * FROM crdb_internal.node_build_info$ cockroach sql,newname": { + "SELECT * FROM crdb_internal.node_build_info/$ cockroach sql,newname/0/0": { data: SQLDetailsStatsResponse, lastError: null, valid: true, @@ -680,7 +680,7 @@ describe("SQLDetailsStats sagas", () => { ) .withReducer(reducer) .hasFinalState>({ - "SELECT * FROM crdb_internal.node_build_info$ cockroach sql,newname": { + "SELECT * FROM crdb_internal.node_build_info/$ cockroach sql,newname/0/0": { data: null, lastError: error, valid: false, diff --git a/pkg/ui/workspaces/cluster-ui/src/store/statementDetails/statementDetails.sagas.ts b/pkg/ui/workspaces/cluster-ui/src/store/statementDetails/statementDetails.sagas.ts index cc0c95560a0a..e5d8bb6612f6 100644 --- a/pkg/ui/workspaces/cluster-ui/src/store/statementDetails/statementDetails.sagas.ts +++ b/pkg/ui/workspaces/cluster-ui/src/store/statementDetails/statementDetails.sagas.ts @@ -18,7 +18,7 @@ import { } from "src/api/statementsApi"; import { actions as sqlDetailsStatsActions } from "./statementDetails.reducer"; import { CACHE_INVALIDATION_PERIOD } from "src/store/utils"; -import { generateStmtDetailsToID } from "../../statementDetails/statementDetails.selectors"; +import { generateStmtDetailsToID } from "../../util"; export function* refreshSQLDetailsStatsSaga( action: PayloadAction, @@ -33,6 +33,8 @@ export function* requestSQLDetailsStatsSaga( ? generateStmtDetailsToID( action.payload.fingerprint_id, action.payload.app_names.toString(), + action.payload.start, + action.payload.end, ) : ""; try { diff --git a/pkg/ui/workspaces/cluster-ui/src/timeScaleDropdown/timescale.spec.tsx b/pkg/ui/workspaces/cluster-ui/src/timeScaleDropdown/timescale.spec.tsx index a6f517de3590..56be93c30667 100644 --- a/pkg/ui/workspaces/cluster-ui/src/timeScaleDropdown/timescale.spec.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/timeScaleDropdown/timescale.spec.tsx @@ -18,7 +18,11 @@ import { TimeScaleDropdownProps, TimeScaleDropdown, } from "./timeScaleDropdown"; -import { defaultTimeScaleOptions, findClosestTimeScale } from "./utils"; +import { + defaultTimeScaleOptions, + findClosestTimeScale, + toRoundedDateRange, +} from "./utils"; import * as timescale from "./timeScaleTypes"; import moment from "moment"; import { MemoryRouter } from "react-router"; @@ -204,6 +208,32 @@ describe("", function() { }); describe("timescale utils", (): void => { + describe("toRoundedDateRange", () => { + it("round values", () => { + const ts: TimeScale = { + windowSize: moment.duration(5, "day"), + sampleSize: moment.duration(5, "minutes"), + fixedWindowEnd: moment.utc("2022.01.10 13:42"), + key: "Custom", + }; + const [start, end] = toRoundedDateRange(ts); + assert.equal(start.format("YYYY.MM.DD HH:mm:ss"), "2022.01.05 13:00:00"); + assert.equal(end.format("YYYY.MM.DD HH:mm:ss"), "2022.01.10 14:00:00"); + }); + + it("already rounded values", () => { + const ts: TimeScale = { + windowSize: moment.duration(5, "day"), + sampleSize: moment.duration(5, "minutes"), + fixedWindowEnd: moment.utc("2022.01.10 13:00"), + key: "Custom", + }; + const [start, end] = toRoundedDateRange(ts); + assert.equal(start.format("YYYY.MM.DD HH:mm:ss"), "2022.01.05 13:00:00"); + assert.equal(end.format("YYYY.MM.DD HH:mm:ss"), "2022.01.10 14:00:00"); + }); + }); + describe("findClosestTimeScale", () => { it("should find the correct time scale", () => { // `seconds` != window size of any of the default options, `startSeconds` not specified. diff --git a/pkg/ui/workspaces/cluster-ui/src/timeScaleDropdown/utils.ts b/pkg/ui/workspaces/cluster-ui/src/timeScaleDropdown/utils.ts index a3255b266db1..5b44eebc4df9 100644 --- a/pkg/ui/workspaces/cluster-ui/src/timeScaleDropdown/utils.ts +++ b/pkg/ui/workspaces/cluster-ui/src/timeScaleDropdown/utils.ts @@ -87,6 +87,18 @@ export const toDateRange = (ts: TimeScale): [moment.Moment, moment.Moment] => { return [start, end]; }; +export const toRoundedDateRange = ( + ts: TimeScale, +): [moment.Moment, moment.Moment] => { + const [start, end] = toDateRange(ts); + const startRounded = start.set({ minute: 0, second: 0, millisecond: 0 }); + const endRounded = end + .set({ minute: 0, second: 0, millisecond: 0 }) + .add(1, "hours"); + + return [startRounded, endRounded]; +}; + export const findClosestTimeScale = ( options: TimeScaleOptions, seconds: number, diff --git a/pkg/ui/workspaces/cluster-ui/src/util/appStats/appStats.ts b/pkg/ui/workspaces/cluster-ui/src/util/appStats/appStats.ts index 57a3565dff64..70fa99c20ceb 100644 --- a/pkg/ui/workspaces/cluster-ui/src/util/appStats/appStats.ts +++ b/pkg/ui/workspaces/cluster-ui/src/util/appStats/appStats.ts @@ -17,6 +17,7 @@ import { uniqueLong, unique, } from "src/util"; +import Long from "long"; export type StatementStatistics = protos.cockroach.sql.IStatementStatistics; export type ExecStats = protos.cockroach.sql.IExecStats; @@ -283,3 +284,39 @@ export function transactionScopedStatementKey( ): string { return statementKey(stmt) + stmt.transaction_fingerprint_id.toString(); } + +export const generateStmtDetailsToID = ( + fingerprintID: string, + appNames: string, + start: Long, + end: Long, +): string => { + if ( + appNames && + (appNames.includes("$ internal") || appNames.includes("unset")) + ) { + const apps = appNames.split(","); + for (let i = 0; i < apps.length; i++) { + if (apps[i].includes("$ internal")) { + apps[i] = "$ internal"; + } + if (apps[i].includes("unset")) { + apps[i] = ""; + } + } + appNames = unique(apps) + .sort() + .toString(); + } + let generatedID = fingerprintID; + if (appNames) { + generatedID += `/${appNames}`; + } + if (start) { + generatedID += `/${start}`; + } + if (end) { + generatedID += `/${end}`; + } + return generatedID; +}; diff --git a/pkg/ui/workspaces/cluster-ui/src/util/dataFromServer.ts b/pkg/ui/workspaces/cluster-ui/src/util/dataFromServer.ts index e73b26fd5f17..17fca0c36b0c 100644 --- a/pkg/ui/workspaces/cluster-ui/src/util/dataFromServer.ts +++ b/pkg/ui/workspaces/cluster-ui/src/util/dataFromServer.ts @@ -15,6 +15,9 @@ export interface DataFromServer { Tag: string; Version: string; NodeID: string; + OIDCAutoLogin: boolean; + OIDCLoginEnabled: boolean; + OIDCButtonText: string; } // Tell TypeScript about `window.dataFromServer`, which is set in a script diff --git a/pkg/ui/workspaces/db-console/package.json b/pkg/ui/workspaces/db-console/package.json index 600d687f10b7..41888b7f17c8 100644 --- a/pkg/ui/workspaces/db-console/package.json +++ b/pkg/ui/workspaces/db-console/package.json @@ -80,6 +80,7 @@ "@types/fetch-mock": "^5.8.1", "@types/highlight.js": "^10.1.0", "@types/lodash": "^4.14.149", + "@types/long": "^4.0.1", "@types/mocha": "^2.2.40", "@types/node": "^13.7.0", "@types/nvd3": "^1.8.36", diff --git a/pkg/ui/workspaces/db-console/src/redux/apiReducers.ts b/pkg/ui/workspaces/db-console/src/redux/apiReducers.ts index b93ee5001784..5b968f287277 100644 --- a/pkg/ui/workspaces/db-console/src/redux/apiReducers.ts +++ b/pkg/ui/workspaces/db-console/src/redux/apiReducers.ts @@ -11,6 +11,8 @@ import _ from "lodash"; import { combineReducers } from "redux"; import moment from "moment"; +import { util } from "@cockroachlabs/cluster-ui"; +const { generateStmtDetailsToID } = util; import { CachedDataReducer, @@ -314,40 +316,16 @@ const queriesReducerObj = new CachedDataReducer( export const invalidateStatements = queriesReducerObj.invalidateData; export const refreshStatements = queriesReducerObj.refresh; -// TODO (maryliag) add period selected to generate ID export const statementDetailsRequestToID = ( req: api.StatementDetailsRequestMessage, ): string => generateStmtDetailsToID( req.fingerprint_id.toString(), req.app_names.toString(), + req.start, + req.end, ); -export const generateStmtDetailsToID = ( - fingerprintID: string, - appNames: string, -): string => { - if ( - appNames && - (appNames.includes("$ internal") || appNames.includes("unset")) - ) { - const apps = appNames.split(","); - for (let i = 0; i < apps.length; i++) { - if (apps[i].includes("$ internal")) { - apps[i] = "$ internal"; - } - if (apps[i].includes("unset")) { - apps[i] = ""; - } - } - appNames = apps.toString(); - } - if (appNames) { - return fingerprintID + appNames; - } - return fingerprintID; -}; - const queryReducerObj = new KeyedCachedDataReducer( api.getStatementDetails, "statementDetails", diff --git a/pkg/ui/workspaces/db-console/src/views/statements/statementDetails.tsx b/pkg/ui/workspaces/db-console/src/views/statements/statementDetails.tsx index 6b82bda0f948..28da4cfcd4e9 100644 --- a/pkg/ui/workspaces/db-console/src/views/statements/statementDetails.tsx +++ b/pkg/ui/workspaces/db-console/src/views/statements/statementDetails.tsx @@ -10,6 +10,7 @@ import { connect } from "react-redux"; import { withRouter } from "react-router-dom"; import { createSelector } from "reselect"; +import Long from "long"; import { refreshLiveness, @@ -17,7 +18,6 @@ import { refreshStatementDiagnosticsRequests, refreshStatementDetails, refreshUserSQLRoles, - generateStmtDetailsToID, } from "src/redux/apiReducers"; import { RouteComponentProps } from "react-router"; import { @@ -30,6 +30,9 @@ import { StatementDetails, StatementDetailsDispatchProps, StatementDetailsStateProps, + TimeScale, + toRoundedDateRange, + util, } from "@cockroachlabs/cluster-ui"; import { cancelStatementDiagnosticsReportAction, @@ -50,18 +53,29 @@ import { getMatchParamByName, queryByName } from "src/util/query"; import { appNamesAttr, statementAttr } from "src/util/constants"; type IStatementDiagnosticsReport = protos.cockroach.server.serverpb.IStatementDiagnosticsReport; +const { generateStmtDetailsToID } = util; + export const selectStatementDetails = createSelector( (_state: AdminUIState, props: RouteComponentProps): string => getMatchParamByName(props.match, statementAttr), (_state: AdminUIState, props: RouteComponentProps): string => queryByName(props.location, appNamesAttr), + (state: AdminUIState): TimeScale => + statementsTimeScaleLocalSetting.selector(state), (state: AdminUIState) => state.cachedData.statementDetails, ( fingerprintID, appNames, + timeScale, statementDetailsStats, ): StatementDetailsResponseMessage => { - const key = generateStmtDetailsToID(fingerprintID, appNames); + const [start, end] = toRoundedDateRange(timeScale); + const key = generateStmtDetailsToID( + fingerprintID, + appNames, + Long.fromNumber(start.unix()), + Long.fromNumber(end.unix()), + ); if (Object.keys(statementDetailsStats).includes(key)) { return statementDetailsStats[key].data; } diff --git a/pkg/ui/workspaces/db-console/src/views/statements/statements.spec.tsx b/pkg/ui/workspaces/db-console/src/views/statements/statements.spec.tsx index d6ebea81b9ab..ff3562749b77 100644 --- a/pkg/ui/workspaces/db-console/src/views/statements/statements.spec.tsx +++ b/pkg/ui/workspaces/db-console/src/views/statements/statements.spec.tsx @@ -28,7 +28,8 @@ import { selectStatementDetails } from "./statementDetails"; import ISensitiveInfo = protos.cockroach.sql.ISensitiveInfo; import { AdminUIState, createAdminUIStore } from "src/redux/state"; import { util } from "@cockroachlabs/cluster-ui"; -import { generateStmtDetailsToID } from "src/redux/apiReducers"; + +const { generateStmtDetailsToID } = util; type CollectedStatementStatistics = util.CollectedStatementStatistics; type ExecStats = util.ExecStats; @@ -36,6 +37,11 @@ type StatementStatistics = util.StatementStatistics; const INTERNAL_STATEMENT_PREFIX = "$ internal"; +const timePeriod = { + start: new Long(1646250884), + end: new Long(1646337284), +}; + describe("selectStatements", () => { it("returns null if the statements data is invalid", () => { const state = makeInvalidState(); @@ -50,7 +56,11 @@ describe("selectStatements", () => { const stmtA = makeFingerprint(1); const stmtB = makeFingerprint(2, "foobar"); const stmtC = makeFingerprint(3, "another"); - const state = makeStateWithStatements([stmtA, stmtB, stmtC]); + const state = makeStateWithStatements( + [stmtA, stmtB, stmtC], + timePeriod.start, + timePeriod.end, + ); const props = makeEmptyRouteProps(); const result = selectStatements(state, props); @@ -70,7 +80,11 @@ describe("selectStatements", () => { const stmtB = makeFingerprint(2, INTERNAL_STATEMENT_PREFIX); const stmtC = makeFingerprint(3, INTERNAL_STATEMENT_PREFIX); const stmtD = makeFingerprint(3, "another"); - const state = makeStateWithStatements([stmtA, stmtB, stmtC, stmtD]); + const state = makeStateWithStatements( + [stmtA, stmtB, stmtC, stmtD], + timePeriod.start, + timePeriod.end, + ); const props = makeEmptyRouteProps(); const result = selectStatements(state, props); @@ -85,7 +99,11 @@ describe("selectStatements", () => { const sumCount = stmtA.stats.count .add(stmtB.stats.count.add(stmtC.stats.count)) .toNumber(); - const state = makeStateWithStatements([stmtA, stmtB, stmtC]); + const state = makeStateWithStatements( + [stmtA, stmtB, stmtC], + timePeriod.start, + timePeriod.end, + ); const props = makeEmptyRouteProps(); const result = selectStatements(state, props); @@ -96,11 +114,15 @@ describe("selectStatements", () => { }); it("coalesces statements with differing node ids", () => { - const state = makeStateWithStatements([ - makeFingerprint(1, "", 1), - makeFingerprint(1, "", 2), - makeFingerprint(1, "", 3), - ]); + const state = makeStateWithStatements( + [ + makeFingerprint(1, "", 1), + makeFingerprint(1, "", 2), + makeFingerprint(1, "", 3), + ], + timePeriod.start, + timePeriod.end, + ); const props = makeEmptyRouteProps(); const result = selectStatements(state, props); @@ -109,12 +131,16 @@ describe("selectStatements", () => { }); it("coalesces statements with differing distSQL and failed values", () => { - const state = makeStateWithStatements([ - makeFingerprint(1, "", 1, false, false), - makeFingerprint(1, "", 1, false, true), - makeFingerprint(1, "", 1, true, false), - makeFingerprint(1, "", 1, true, true), - ]); + const state = makeStateWithStatements( + [ + makeFingerprint(1, "", 1, false, false), + makeFingerprint(1, "", 1, false, true), + makeFingerprint(1, "", 1, true, false), + makeFingerprint(1, "", 1, true, true), + ], + timePeriod.start, + timePeriod.end, + ); const props = makeEmptyRouteProps(); const result = selectStatements(state, props); @@ -123,11 +149,15 @@ describe("selectStatements", () => { }); it("filters out statements when app param is set", () => { - const state = makeStateWithStatements([ - makeFingerprint(1, "foo"), - makeFingerprint(2, "bar"), - makeFingerprint(3, "baz"), - ]); + const state = makeStateWithStatements( + [ + makeFingerprint(1, "foo"), + makeFingerprint(2, "bar"), + makeFingerprint(3, "baz"), + ], + timePeriod.start, + timePeriod.end, + ); const props = makeRoutePropsWithApp("foo"); const result = selectStatements(state, props); @@ -136,11 +166,15 @@ describe("selectStatements", () => { }); it('filters out statements with app set when app param is "(unset)"', () => { - const state = makeStateWithStatements([ - makeFingerprint(1, ""), - makeFingerprint(2, "bar"), - makeFingerprint(3, "baz"), - ]); + const state = makeStateWithStatements( + [ + makeFingerprint(1, ""), + makeFingerprint(2, "bar"), + makeFingerprint(3, "baz"), + ], + timePeriod.start, + timePeriod.end, + ); const props = makeRoutePropsWithApp("(unset)"); const result = selectStatements(state, props); @@ -149,11 +183,15 @@ describe("selectStatements", () => { }); it('filters out statements with app set when app param is "$ internal"', () => { - const state = makeStateWithStatements([ - makeFingerprint(1, "$ internal_stmnt_app"), - makeFingerprint(2, "bar"), - makeFingerprint(3, "baz"), - ]); + const state = makeStateWithStatements( + [ + makeFingerprint(1, "$ internal_stmnt_app"), + makeFingerprint(2, "bar"), + makeFingerprint(3, "baz"), + ], + timePeriod.start, + timePeriod.end, + ); const props = makeRoutePropsWithApp("$ internal"); const result = selectStatements(state, props); assert.equal(result.length, 1); @@ -170,12 +208,16 @@ describe("selectApps", () => { }); it("returns all the apps that appear in the statements", () => { - const state = makeStateWithStatements([ - makeFingerprint(1), - makeFingerprint(1, "foobar"), - makeFingerprint(2, "foobar"), - makeFingerprint(3, "cockroach sql"), - ]); + const state = makeStateWithStatements( + [ + makeFingerprint(1), + makeFingerprint(1, "foobar"), + makeFingerprint(2, "foobar"), + makeFingerprint(3, "cockroach sql"), + ], + timePeriod.start, + timePeriod.end, + ); const result = selectApps(state); @@ -193,11 +235,11 @@ describe("selectTotalFingerprints", () => { }); it("returns the number of statement fingerprints", () => { - const state = makeStateWithStatements([ - makeFingerprint(1), - makeFingerprint(2), - makeFingerprint(3), - ]); + const state = makeStateWithStatements( + [makeFingerprint(1), makeFingerprint(2), makeFingerprint(3)], + timePeriod.start, + timePeriod.end, + ); const result = selectTotalFingerprints(state); @@ -205,11 +247,15 @@ describe("selectTotalFingerprints", () => { }); it("coalesces statements from different apps", () => { - const state = makeStateWithStatements([ - makeFingerprint(1), - makeFingerprint(1, "foobar"), - makeFingerprint(1, "another"), - ]); + const state = makeStateWithStatements( + [ + makeFingerprint(1), + makeFingerprint(1, "foobar"), + makeFingerprint(1, "another"), + ], + timePeriod.start, + timePeriod.end, + ); const result = selectTotalFingerprints(state); @@ -217,11 +263,15 @@ describe("selectTotalFingerprints", () => { }); it("coalesces statements with differing node ids", () => { - const state = makeStateWithStatements([ - makeFingerprint(1, "", 1), - makeFingerprint(1, "", 2), - makeFingerprint(1, "", 3), - ]); + const state = makeStateWithStatements( + [ + makeFingerprint(1, "", 1), + makeFingerprint(1, "", 2), + makeFingerprint(1, "", 3), + ], + timePeriod.start, + timePeriod.end, + ); const result = selectTotalFingerprints(state); @@ -229,12 +279,16 @@ describe("selectTotalFingerprints", () => { }); it("coalesces statements with differing distSQL and failed keys", () => { - const state = makeStateWithStatements([ - makeFingerprint(1, "", 1, false, false), - makeFingerprint(1, "", 1, false, true), - makeFingerprint(1, "", 1, true, false), - makeFingerprint(1, "", 1, true, true), - ]); + const state = makeStateWithStatements( + [ + makeFingerprint(1, "", 1, false, false), + makeFingerprint(1, "", 1, false, true), + makeFingerprint(1, "", 1, true, false), + makeFingerprint(1, "", 1, true, true), + ], + timePeriod.start, + timePeriod.end, + ); const result = selectTotalFingerprints(state); @@ -253,7 +307,11 @@ describe("selectLastReset", () => { it("returns the formatted timestamp if valid", () => { const timestamp = 92951700; - const state = makeStateWithLastReset(timestamp); + const state = makeStateWithLastReset( + timestamp, + timePeriod.start, + timePeriod.end, + ); const result = selectLastReset(state); @@ -275,7 +333,11 @@ describe("selectStatement", () => { const stmtA = makeFingerprint(1); const stmtB = makeFingerprint(2, "foobar"); const stmtC = makeFingerprint(3, "another"); - const state = makeStateWithStatements([stmtA, stmtB, stmtC]); + const state = makeStateWithStatements( + [stmtA, stmtB, stmtC], + timePeriod.start, + timePeriod.end, + ); const stmtAFingerprintID = stmtA.id.toString(); const props = makeRoutePropsWithStatement(stmtAFingerprintID); @@ -292,11 +354,11 @@ describe("selectStatement", () => { it("filters out statements when app param is set", () => { const stmtA = makeFingerprint(1, "foo"); - const state = makeStateWithStatements([ - stmtA, - makeFingerprint(2, "bar"), - makeFingerprint(3, "baz"), - ]); + const state = makeStateWithStatements( + [stmtA, makeFingerprint(2, "bar"), makeFingerprint(3, "baz")], + timePeriod.start, + timePeriod.end, + ); const stmtAFingerprintID = stmtA.id.toString(); const props = makeRoutePropsWithStatementAndApp(stmtAFingerprintID, "foo"); @@ -313,11 +375,11 @@ describe("selectStatement", () => { it('filters out statements with app set when app param is "(unset)"', () => { const stmtA = makeFingerprint(1, ""); - const state = makeStateWithStatements([ - stmtA, - makeFingerprint(2, "bar"), - makeFingerprint(3, "baz"), - ]); + const state = makeStateWithStatements( + [stmtA, makeFingerprint(2, "bar"), makeFingerprint(3, "baz")], + timePeriod.start, + timePeriod.end, + ); const stmtAFingerprintID = stmtA.id.toString(); const props = makeRoutePropsWithStatementAndApp( stmtAFingerprintID, @@ -337,11 +399,11 @@ describe("selectStatement", () => { it('filters out statements with app set when app param is "$ internal"', () => { const stmtA = makeFingerprint(1, "$ internal_stmnt_app"); - const state = makeStateWithStatements([ - stmtA, - makeFingerprint(2, "bar"), - makeFingerprint(3, "baz"), - ]); + const state = makeStateWithStatements( + [stmtA, makeFingerprint(2, "bar"), makeFingerprint(3, "baz")], + timePeriod.start, + timePeriod.end, + ); const stmtAFingerprintID = stmtA.id.toString(); const props = makeRoutePropsWithStatementAndApp( stmtAFingerprintID, @@ -459,6 +521,8 @@ function makeInvalidState(): AdminUIState { function makeStateWithStatementsAndLastReset( statements: CollectedStatementStatistics[], lastReset: number, + start: Long, + end: Long, ) { const store = createAdminUIStore(H.createMemoryHistory()); const state = merge(store.getState(), { @@ -485,7 +549,12 @@ function makeStateWithStatementsAndLastReset( for (const stmt of statements) { state.cachedData.statementDetails[ - generateStmtDetailsToID(stmt.id.toString(), stmt.key.key_data.app) + generateStmtDetailsToID( + stmt.id.toString(), + stmt.key.key_data.app, + start, + end, + ) ] = { data: protos.cockroach.server.serverpb.StatementDetailsResponse.fromObject( { @@ -508,12 +577,16 @@ function makeStateWithStatementsAndLastReset( return state; } -function makeStateWithStatements(statements: CollectedStatementStatistics[]) { - return makeStateWithStatementsAndLastReset(statements, 0); +function makeStateWithStatements( + statements: CollectedStatementStatistics[], + start: Long, + end: Long, +) { + return makeStateWithStatementsAndLastReset(statements, 0, start, end); } -function makeStateWithLastReset(lastReset: number) { - return makeStateWithStatementsAndLastReset([], lastReset); +function makeStateWithLastReset(lastReset: number, start: Long, end: Long) { + return makeStateWithStatementsAndLastReset([], lastReset, start, end); } function makeRoutePropsWithParams(params: { [key: string]: string }) {