Skip to content

Commit

Permalink
ui: link insights to fingerprint details
Browse files Browse the repository at this point in the history
Now from the Insights page, clicking on the statement
or fingerprint ids, it will bring you to their respective
details page.

This commit also filter out transaction insights that didn't
have their value set yet (meaning they're still 0).

Finally, this commit fixes the start/end values being passed
to the combined statement endpoint, to the correct rounded
values, aligning what we say on the UI.

Fixes cockroachdb#87750

Release note (ui change): The fingerprint id values
for statement and transactions on the insights pages are
links that open the respective details page on the time period
of the execution of that statement/transaction.

Release note (bug fix): Sendind the proper start/end values
to the endpoint used on SQL Activity page, now returning the
full hour as described on the UI.
  • Loading branch information
maryliag committed Oct 25, 2022
1 parent 906a41f commit fd295c7
Show file tree
Hide file tree
Showing 25 changed files with 469 additions and 27 deletions.
4 changes: 4 additions & 0 deletions pkg/ui/workspaces/cluster-ui/src/api/insightsApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ const txnContentionQuery = `SELECT *
max(collection_ts) AS collection_ts,
sum(contention_duration) AS total_contention_duration
FROM crdb_internal.transaction_contention_events tce
WHERE waiting_txn_fingerprint_id != '\x0000000000000000'
GROUP BY waiting_txn_id, waiting_txn_fingerprint_id),
(SELECT txn_id FROM crdb_internal.cluster_execution_insights)
WHERE total_contention_duration > threshold
Expand Down Expand Up @@ -570,6 +571,7 @@ type ExecutionInsightsResponseRow = {
session_id: string;
txn_id: string;
txn_fingerprint_id: string; // hex string
implicit_txn: boolean;
stmt_id: string;
stmt_fingerprint_id: string; // hex string
query: string;
Expand Down Expand Up @@ -608,6 +610,7 @@ function getStatementInsightsFromClusterExecutionInsightsResponse(
return {
transactionID: row.txn_id,
transactionFingerprintID: row.txn_fingerprint_id,
implicitTxn: row.implicit_txn,
query: row.query,
startTime: start,
endTime: end,
Expand Down Expand Up @@ -651,6 +654,7 @@ const statementInsightsQuery: InsightQuery<
session_id,
txn_id,
encode(txn_fingerprint_id, 'hex') AS txn_fingerprint_id,
implicit_txn,
stmt_id,
encode(stmt_fingerprint_id, 'hex') AS stmt_fingerprint_id,
query AS non_prettified_query,
Expand Down
1 change: 1 addition & 0 deletions pkg/ui/workspaces/cluster-ui/src/insights/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export type StatementInsightEvent = {
transactionID: string;
statementFingerprintID: string;
transactionFingerprintID: string;
implicitTxn: boolean;
startTime: Moment;
elapsedTimeMillis: number;
sessionID: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import classNames from "classnames/bind";
import { commonStyles } from "src/common";
import { getExplainPlanFromGist } from "src/api/decodePlanGistApi";
import { StatementInsightDetailsOverviewTab } from "./statementInsightDetailsOverviewTab";
import { TimeScale } from "../../timeScaleDropdown";

// Styles
import insightsDetailsStyles from "src/insights/workloadInsightDetails/insightsDetails.module.scss";
Expand All @@ -42,12 +43,24 @@ export interface StatementInsightDetailsStateProps {
isTenant?: boolean;
}

export interface StatementInsightDetailsDispatchProps {
setTimeScale: (ts: TimeScale) => void;
}

export type StatementInsightDetailsProps = StatementInsightDetailsStateProps &
StatementInsightDetailsDispatchProps &
RouteComponentProps<unknown>;

export const StatementInsightDetails: React.FC<
StatementInsightDetailsProps
> = ({ history, insightEventDetails, insightError, match, isTenant }) => {
> = ({
history,
insightEventDetails,
insightError,
match,
isTenant,
setTimeScale,
}) => {
const [explain, setExplain] = useState<string>(null);

const prevPage = (): void => history.goBack();
Expand Down Expand Up @@ -111,6 +124,7 @@ export const StatementInsightDetails: React.FC<
<Tabs.TabPane tab="Overview" key={TabKeysEnum.OVERVIEW}>
<StatementInsightDetailsOverviewTab
insightEventDetails={insightEventDetails}
setTimeScale={setTimeScale}
/>
</Tabs.TabPane>
{!isTenant && (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// 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 { Dispatch } from "redux";
import { RouteComponentProps, withRouter } from "react-router-dom";
import {
StatementInsightDetails,
StatementInsightDetailsDispatchProps,
StatementInsightDetailsStateProps,
} from "./statementInsightDetails";
import { AppState } from "src/store";
import {
selectStatementInsightDetails,
selectStatementInsightsError,
} from "src/store/insights/statementInsights";
import { selectIsTenant } from "src/store/uiConfig";
import { TimeScale } from "../../timeScaleDropdown";
import { actions as sqlStatsActions } from "../../store/sqlStats";

const mapStateToProps = (
state: AppState,
props: RouteComponentProps,
): StatementInsightDetailsStateProps => {
const insightStatements = selectStatementInsightDetails(state, props);
const insightError = selectStatementInsightsError(state);
return {
insightEventDetails: insightStatements,
insightError: insightError,
isTenant: selectIsTenant(state),
};
};

const mapDispatchToProps = (
dispatch: Dispatch,
): StatementInsightDetailsDispatchProps => ({
setTimeScale: (ts: TimeScale) => {
dispatch(
sqlStatsActions.updateTimeScale({
ts: ts,
}),
);
},
});

export const StatementInsightDetailsConnected = withRouter(
connect<
StatementInsightDetailsStateProps,
StatementInsightDetailsDispatchProps,
RouteComponentProps
>(
mapStateToProps,
mapDispatchToProps,
)(StatementInsightDetails),
);
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ import summaryCardStyles from "src/summaryCard/summaryCard.module.scss";
import insightTableStyles from "src/insightsTable/insightsTable.module.scss";
import "antd/lib/col/style";
import "antd/lib/row/style";
import {
StatementDetailsLink,
TransactionDetailsLink,
} from "../workloadInsights/util";
import { TimeScale } from "../../timeScaleDropdown";

const cx = classNames.bind(insightsDetailsStyles);
const tableCx = classNames.bind(insightTableStyles);
Expand Down Expand Up @@ -114,11 +119,12 @@ const insightsTableData = (

export interface StatementInsightDetailsOverviewTabProps {
insightEventDetails: StatementInsightEvent;
setTimeScale: (ts: TimeScale) => void;
}

export const StatementInsightDetailsOverviewTab: React.FC<
StatementInsightDetailsOverviewTabProps
> = ({ insightEventDetails }) => {
> = ({ insightEventDetails, setTimeScale }) => {
const isCockroachCloud = useContext(CockroachCloudContext);

const insightsColumns = useMemo(
Expand Down Expand Up @@ -188,15 +194,19 @@ export const StatementInsightDetailsOverviewTab: React.FC<
/>
<SummaryCardItem
label="Transaction Fingerprint ID"
value={String(insightDetails.transactionFingerprintID)}
value={TransactionDetailsLink(
insightDetails.transactionFingerprintID,
insightDetails.startTime,
setTimeScale,
)}
/>
<SummaryCardItem
label="Transaction Execution ID"
value={String(insightDetails.transactionID)}
/>
<SummaryCardItem
label="Statement Fingerprint ID"
value={String(insightDetails.statementFingerprintID)}
value={StatementDetailsLink(insightDetails, setTimeScale)}
/>
</SummaryCard>
</Col>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ import { commonStyles } from "src/common";
import insightTableStyles from "src/insightsTable/insightsTable.module.scss";
import { CockroachCloudContext } from "../../contexts";
import { InsightsError } from "../insightsErrorComponent";
import { TransactionDetailsLink } from "../workloadInsights/util";
import { TimeScale } from "../../timeScaleDropdown";

const tableCx = classNames.bind(insightTableStyles);

Expand All @@ -55,6 +57,7 @@ export interface TransactionInsightDetailsDispatchProps {
refreshTransactionInsightDetails: (
req: TransactionInsightEventDetailsRequest,
) => void;
setTimeScale: (ts: TimeScale) => void;
}

export type TransactionInsightDetailsProps =
Expand Down Expand Up @@ -152,7 +155,11 @@ export class TransactionInsightDetails extends React.Component<TransactionInsigh
<SummaryCard>
<SummaryCardItem
label="Transaction Fingerprint ID"
value={String(insightDetails.fingerprintID)}
value={TransactionDetailsLink(
insightDetails.fingerprintID,
insightDetails.startTime,
this.props.setTimeScale,
)}
/>
</SummaryCard>
</Col>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// 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";
import { TimeScale } from "../../timeScaleDropdown";
import { actions as sqlStatsActions } from "../../store/sqlStats";
import { Dispatch } from "redux";

const mapStateToProps = (
state: AppState,
_props: RouteComponentProps,
): TransactionInsightDetailsStateProps => {
const insightDetails = selectTransactionInsightDetails(state);
const insightError = selectTransactionInsightDetailsError(state);
return {
insightEventDetails: insightDetails,
insightError: insightError,
};
};

const mapDispatchToProps = (
dispatch: Dispatch,
): TransactionInsightDetailsDispatchProps => ({
refreshTransactionInsightDetails: actions.refresh,
setTimeScale: (ts: TimeScale) => {
dispatch(
sqlStatsActions.updateTimeScale({
ts: ts,
}),
);
},
});

export const TransactionInsightDetailsConnected = withRouter(
connect<
TransactionInsightDetailsStateProps,
TransactionInsightDetailsDispatchProps,
RouteComponentProps
>(
mapStateToProps,
mapDispatchToProps,
)(TransactionInsightDetails),
);
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const statementInsightsPropsFixture: StatementInsightsViewProps = {
statementFingerprintID: "abc",
transactionFingerprintID: "defg",
transactionID: "f72f37ea-b3a0-451f-80b8-dfb27d0bc2a5",
implicitTxn: true,
query:
"SELECT IFNULL(a, b) FROM (SELECT (SELECT code FROM promo_codes WHERE code > $1 ORDER BY code LIMIT _) AS a, (SELECT code FROM promo_codes ORDER BY code LIMIT _) AS b)",
startTime: moment.utc("2022.08.10"),
Expand Down Expand Up @@ -47,6 +48,7 @@ export const statementInsightsPropsFixture: StatementInsightsViewProps = {
statementFingerprintID: "938x3",
transactionFingerprintID: "1971x3",
transactionID: "e72f37ea-b3a0-451f-80b8-dfb27d0bc2a5",
implicitTxn: true,
query: "INSERT INTO vehicles VALUES ($1, $2, __more1_10__)",
startTime: moment.utc("2022.08.10"),
endTime: moment.utc("2022.08.10 00:00:00.25"),
Expand All @@ -73,6 +75,7 @@ export const statementInsightsPropsFixture: StatementInsightsViewProps = {
statementFingerprintID: "hisas",
transactionFingerprintID: "3anc",
transactionID: "f72f37ea-b3a0-451f-80b8-dfb27d0bc2a0",
implicitTxn: true,
query:
"UPSERT INTO vehicle_location_histories VALUES ($1, $2, now(), $3, $4)",
startTime: moment.utc("2022.08.10"),
Expand Down Expand Up @@ -107,4 +110,5 @@ export const statementInsightsPropsFixture: StatementInsightsViewProps = {
refreshStatementInsights: () => {},
onSortChange: () => {},
onFiltersChange: () => {},
setTimeScale: () => {},
};
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,17 @@ import {
} from "src/sortedtable";
import { Count, DATE_FORMAT, Duration, limitText } from "src/util";
import { InsightExecEnum, StatementInsightEvent } from "src/insights";
import { InsightCell, insightsTableTitles } from "../util";
import {
InsightCell,
insightsTableTitles,
StatementDetailsLink,
} from "../util";
import { StatementInsights } from "../../../api";
import { Tooltip } from "@cockroachlabs/ui-components";
import { Link } from "react-router-dom";
import classNames from "classnames/bind";
import styles from "../util/workloadInsights.module.scss";
import { TimeScale } from "../../../timeScaleDropdown";

const cx = classNames.bind(styles);

Expand All @@ -35,7 +40,9 @@ interface StatementInsightsTable {
visibleColumns: ColumnDescriptor<StatementInsightEvent>[];
}

export function makeStatementInsightsColumns(): ColumnDescriptor<StatementInsightEvent>[] {
export function makeStatementInsightsColumns(
setTimeScale: (ts: TimeScale) => void,
): ColumnDescriptor<StatementInsightEvent>[] {
const execType = InsightExecEnum.STATEMENT;
return [
{
Expand All @@ -52,7 +59,8 @@ export function makeStatementInsightsColumns(): ColumnDescriptor<StatementInsigh
{
name: "statementFingerprintID",
title: insightsTableTitles.fingerprintID(execType),
cell: (item: StatementInsightEvent) => item.statementFingerprintID,
cell: (item: StatementInsightEvent) =>
StatementDetailsLink(item, setTimeScale),
sort: (item: StatementInsightEvent) => item.statementFingerprintID,
showByDefault: true,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import { PageConfig, PageConfigItem } from "src/pageConfig/pageConfig";
import { Search } from "src/search/search";
import {
calculateActiveFilters,
defaultFilters,
Filter,
getFullFiltersAsStringRecord,
} from "src/queryFilter/filter";
Expand All @@ -48,6 +47,7 @@ import styles from "src/statementsPage/statementsPage.module.scss";
import sortableTableStyles from "src/sortedtable/sortedtable.module.scss";
import ColumnsSelector from "../../../columnsSelector/columnsSelector";
import { SelectOption } from "../../../multiSelectCheckbox/multiSelectCheckbox";
import { TimeScale } from "../../../timeScaleDropdown";

const cx = classNames.bind(styles);
const sortableTableCx = classNames.bind(sortableTableStyles);
Expand All @@ -66,6 +66,7 @@ export type StatementInsightsViewDispatchProps = {
onSortChange: (ss: SortSetting) => void;
refreshStatementInsights: () => void;
onColumnsChange: (selectedColumns: string[]) => void;
setTimeScale: (ts: TimeScale) => void;
};

export type StatementInsightsViewProps = StatementInsightsViewStateProps &
Expand Down Expand Up @@ -101,6 +102,7 @@ export const StatementInsightsView: React.FC<StatementInsightsViewProps> = (
onFiltersChange,
onSortChange,
onColumnsChange,
setTimeScale,
selectedColumnNames,
dropDownSelect,
} = props;
Expand Down Expand Up @@ -194,7 +196,7 @@ export const StatementInsightsView: React.FC<StatementInsightsViewProps> = (
resetPagination();
};

const defaultColumns = makeStatementInsightsColumns();
const defaultColumns = makeStatementInsightsColumns(setTimeScale);

const visibleColumns = defaultColumns.filter(x =>
isSelected(x, selectedColumnNames),
Expand Down
Loading

0 comments on commit fd295c7

Please sign in to comment.