Skip to content

Commit

Permalink
ui: add column selector to transation page
Browse files Browse the repository at this point in the history
Add column selector to Transaction Page

Fixes cockroachdb#70148

Release justification: Category 4
Release note (ui change): Add column selector to transaction page
  • Loading branch information
maryliag committed Sep 15, 2021
1 parent 5add02d commit 926ef9c
Show file tree
Hide file tree
Showing 11 changed files with 244 additions and 88 deletions.
4 changes: 2 additions & 2 deletions pkg/ui/workspaces/cluster-ui/src/sortedtable/sortedtable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ export class SortedTable<T> extends React.Component<
return this.props.expandableConfig.expansionKey(this.getItemAt(rowIndex));
}

onChangeExpansion = (rowIndex: number, expanded: boolean) => {
onChangeExpansion = (rowIndex: number, expanded: boolean): void => {
const key = this.getKeyAt(rowIndex);
const expandedRows = this.state.expandedRows;
if (expanded) {
Expand All @@ -308,7 +308,7 @@ export class SortedTable<T> extends React.Component<
return this.props.expandableConfig.expandedContent(item);
};

paginatedData = (sortData?: T[]) => {
paginatedData = (sortData?: T[]): T[] => {
const { pagination, data } = this.props;
if (!pagination) {
return sortData || data;
Expand Down
42 changes: 20 additions & 22 deletions pkg/ui/workspaces/cluster-ui/src/statementsPage/statementsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ type IStatementDiagnosticsReport = cockroach.server.serverpb.IStatementDiagnosti
import sortableTableStyles from "src/sortedtable/sortedtable.module.scss";
import ColumnsSelector from "../columnsSelector/columnsSelector";
import { SelectOption } from "../multiSelectCheckbox/multiSelectCheckbox";
import { UIConfigState } from "../store/uiConfig";
import { UIConfigState } from "../store";
import { StatementsRequest } from "src/api/statementsApi";
import Long from "long";

Expand Down Expand Up @@ -195,7 +195,7 @@ export class StatementsPage extends React.Component<
history.replace(history.location);
};

changeSortSetting = (ss: SortSetting) => {
changeSortSetting = (ss: SortSetting): void => {
this.setState({
sortSetting: ss,
});
Expand Down Expand Up @@ -223,7 +223,7 @@ export class StatementsPage extends React.Component<
);
};

selectApp = (value: string) => {
selectApp = (value: string): void => {
if (value == "All") value = "";
const { history, onFilterChange } = this.props;
history.location.pathname = `/statements/${encodeURIComponent(value)}`;
Expand All @@ -234,7 +234,7 @@ export class StatementsPage extends React.Component<
}
};

resetPagination = () => {
resetPagination = (): void => {
this.setState(prevState => {
return {
pagination: {
Expand All @@ -245,12 +245,12 @@ export class StatementsPage extends React.Component<
});
};

refreshStatements = () => {
refreshStatements = (): void => {
const req = statementsRequestFromProps(this.props);
this.props.refreshStatements(req);
};

componentDidMount() {
componentDidMount(): void {
this.refreshStatements();
if (!this.props.isTenant) {
this.props.refreshStatementDiagnosticsRequests();
Expand All @@ -260,7 +260,7 @@ export class StatementsPage extends React.Component<
componentDidUpdate = (
__: StatementsPageProps,
prevState: StatementsPageState,
) => {
): void => {
if (this.state.search && this.state.search !== prevState.search) {
this.props.onSearchComplete(this.filteredStatementsData());
}
Expand All @@ -270,25 +270,25 @@ export class StatementsPage extends React.Component<
}
};

componentWillUnmount() {
componentWillUnmount(): void {
this.props.dismissAlertMessage();
}

onChangePage = (current: number) => {
onChangePage = (current: number): void => {
const { pagination } = this.state;
this.setState({ pagination: { ...pagination, current } });
this.props.onPageChanged(current);
};

onSubmitSearchField = (search: string) => {
onSubmitSearchField = (search: string): void => {
this.setState({ search });
this.resetPagination();
this.syncHistory({
q: search,
});
};

onSubmitFilters = (filters: Filters) => {
onSubmitFilters = (filters: Filters): void => {
this.setState({
filters: {
...this.state.filters,
Expand All @@ -310,14 +310,14 @@ export class StatementsPage extends React.Component<
this.selectApp(filters.app);
};

onClearSearchField = () => {
onClearSearchField = (): void => {
this.setState({ search: "" });
this.syncHistory({
q: undefined,
});
};

onClearFilters = () => {
onClearFilters = (): void => {
this.setState({
filters: {
...defaultFilters,
Expand All @@ -337,7 +337,7 @@ export class StatementsPage extends React.Component<
this.selectApp("");
};

filteredStatementsData = () => {
filteredStatementsData = (): AggregateStatistics[] => {
const { search, filters } = this.state;
const { statements, nodeRegions, isTenant } = this.props;
const timeValue = getTimeValueInSeconds(filters);
Expand Down Expand Up @@ -452,7 +452,9 @@ export class StatementsPage extends React.Component<
: unique(nodes.map(node => nodeRegions[node.toString()])).sort();
populateRegionNodeForStatements(statements, nodeRegions, isTenant);

// Creates a list of all possible columns
// Creates a list of all possible columns,
// hiding nodeRegions if is not multi-region and
// hiding columns that won't be displayed for tenants.
const columns = makeStatementsColumns(
statements,
selectedApp,
Expand All @@ -464,13 +466,9 @@ export class StatementsPage extends React.Component<
this.activateDiagnosticsRef,
onDiagnosticsReportDownload,
onStatementClick,
).filter(c => !(isTenant && c.hideIfTenant));

// If it's multi-region, we want to show the Regions/Nodes column by default
// and hide otherwise.
if (regions.length > 1) {
columns.filter(c => c.name === "regionNodes")[0].showByDefault = true;
}
)
.filter(c => !(c.name === "regionNodes" && regions.length < 2))
.filter(c => !(isTenant && c.hideIfTenant));

const isColumnSelected = (c: ColumnDescriptor<AggregateStatistics>) => {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ function makeCommonColumns(
);
const retryBar = retryBarChart(statements, defaultBarChartOptions);

const columns: ColumnDescriptor<AggregateStatistics>[] = [
return [
{
name: "executionCount",
title: statisticsTableTitles.executionCount(statType),
Expand Down Expand Up @@ -173,11 +173,9 @@ function makeCommonColumns(
return longListWithTooltip(stmt.regionNodes.sort().join(", "), 50);
},
sort: (stmt: AggregateStatistics) => stmt.regionNodes.sort().join(", "),
showByDefault: false,
hideIfTenant: true,
},
];
return columns;
}

export interface AggregateStatistics {
Expand Down Expand Up @@ -309,12 +307,14 @@ export function makeNodesColumns(
* node it was executed on.
* @param nodeRegions: object with keys being the node id and the value
* which region it belongs to.
* @param isTenant: boolean indicating if the cluster is tenant, since
* node information doesn't need to be populated on this case.
*/
export function populateRegionNodeForStatements(
statements: AggregateStatistics[],
nodeRegions: { [p: string]: string },
isTenant: boolean,
) {
): void {
statements.forEach(stmt => {
if (isTenant) {
stmt.regionNodes = [];
Expand Down
52 changes: 45 additions & 7 deletions pkg/ui/workspaces/cluster-ui/src/statsTableUtil/statsTableUtil.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,21 @@ export type NodeNames = { [nodeId: string]: string };

// Single place for column names. Used in table columns and in columns selector.
export const statisticsColumnLabels = {
statements: "Statements",
database: "Database",
executionCount: "Execution Count",
rowsRead: "Rows Read",
bytesRead: "Bytes Read",
time: "Time",
contention: "Contention",
database: "Database",
diagnostics: "Diagnostics",
executionCount: "Execution Count",
maxMemUsage: "Max Memory",
networkBytes: "Network",
regionNodes: "Regions/Nodes",
retries: "Retries",
rowsRead: "Rows Read",
statements: "Statements",
statementsCount: "Statements",
time: "Time",
transactions: "Transactions",
workloadPct: "% of All Runtime",
regionNodes: "Regions/Nodes",
diagnostics: "Diagnostics",
};

export const contentModifiers = {
Expand Down Expand Up @@ -114,6 +116,25 @@ export const statisticsTableTitles: StatisticTableTitleType = {
</Tooltip>
);
},
transactions: (statType: StatisticType) => {
return (
<Tooltip
placement="bottom"
style="tableTitle"
content={
<>
<p>
{`A transaction fingerprint represents one or more SQL transactions by replacing the literal values (e.g., numbers and strings) with
underscores (_). To view additional details of a SQL transaction fingerprint, click the fingerprint to
open the Transaction Details page.`}
</p>
</>
}
>
{getLabel("transactions")}
</Tooltip>
);
},
executionCount: (statType: StatisticType) => {
let contentModifier = "";
let fingerprintModifier = "";
Expand Down Expand Up @@ -564,4 +585,21 @@ export const statisticsTableTitles: StatisticTableTitleType = {
</Tooltip>
);
},
statementsCount: (statType: StatisticType) => {
return (
<Tooltip
placement="bottom"
style="tableTitle"
content={
<>
<p>
{`The number of statements being executed on this transaction fingerprint`}
</p>
</>
}
>
{getLabel("statementsCount")}
</Tooltip>
);
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type StatementsDateRangeState = {
export type LocalStorageState = {
"adminUi/showDiagnosticsModal": boolean;
"showColumns/StatementsPage": string;
"showColumns/TransactionPage": string;
"dateRange/StatementsPage": StatementsDateRangeState;
};

Expand All @@ -43,6 +44,8 @@ const initialState: LocalStorageState = {
false,
"showColumns/StatementsPage":
JSON.parse(localStorage.getItem("showColumns/StatementsPage")) || null,
"showColumns/TransactionPage":
JSON.parse(localStorage.getItem("showColumns/TransactionPage")) || null,
"dateRange/StatementsPage":
JSON.parse(localStorage.getItem("dateRange/StatementsPage")) ||
defaultDateRange,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@

import { createSelector } from "reselect";

import { adminUISelector } from "../statementsPage/statementsPage.selectors";
import {
adminUISelector,
localStorageSelector,
} from "../statementsPage/statementsPage.selectors";

export const selectTransactionsSlice = createSelector(
adminUISelector,
Expand All @@ -26,3 +29,12 @@ export const selectTransactionsLastError = createSelector(
selectTransactionsSlice,
state => state.lastError,
);

export const selectTxnColumns = createSelector(
localStorageSelector,
// return array of columns if user have customized it or `null` otherwise
localStorage =>
localStorage["showColumns/TransactionPage"]
? localStorage["showColumns/TransactionPage"].split(",")
: null,
);
Loading

0 comments on commit 926ef9c

Please sign in to comment.