Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

release-2.1: ui: design updates to the Statements pages #30115

Merged
merged 29 commits into from
Sep 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
449a852
ui: add short mode for tooltips
couchand Aug 27, 2018
0ebbb83
ui: make tooltip hover area full size
couchand Aug 27, 2018
9667490
ui: remove unused css rules
couchand Aug 27, 2018
4da2734
ui: clean up styling of statements pages bar charts
couchand Aug 27, 2018
39ab543
ui: split statement retries into separate column
couchand Aug 27, 2018
b6a21b1
ui: right-align statements time
couchand Aug 27, 2018
5943f40
ui: add legend to tooltip on Statements pages
couchand Aug 27, 2018
c877933
ui: remove unuseful tooltips
couchand Aug 27, 2018
3c970e9
ui: tweaks to details page exec count bars
couchand Aug 28, 2018
38fb02d
ui: fix types for numeric stat table
couchand Aug 28, 2018
bebb109
ui: highlight summary rows in stats tables
couchand Aug 28, 2018
10e3e0b
ui: improve headers for stmt details tables
couchand Aug 28, 2018
aa31fa2
ui: add tooltips to stmt details tables
couchand Aug 28, 2018
6a78059
ui: reorder tables on stmt details page
couchand Aug 28, 2018
de72dac
ui: widen stmt details bar charts
couchand Aug 28, 2018
18d805c
ui: shorten node name tooltip
couchand Aug 28, 2018
584aae8
ui: add stmt summary for set keyword
couchand Aug 28, 2018
850a2b0
ui: improve layout of statements page
couchand Aug 28, 2018
9e459a7
ui: spread statements page header across page
couchand Sep 5, 2018
7f9342e
ui: fix statement details layout & heading style
couchand Sep 5, 2018
425edd1
ui: increase size of sortable table arrow
couchand Sep 5, 2018
e832ea7
ui: make numeric stats table summaries not look like links
couchand Sep 5, 2018
4ca59fb
ui: combine columns on statement details page
couchand Sep 5, 2018
04a4afd
ui: add tooltip to gateway node table on Statement Details page
couchand Sep 11, 2018
560a050
ui: show fraction of executions that failed on Statement Details page
couchand Sep 11, 2018
99541de
ui: highlight Statements link in sidebar on Statement Details page
couchand Sep 11, 2018
4fefd5d
ui: avoid line breaks in statements table
couchand Sep 6, 2018
63c68d9
ui: refrain from wrapping app name
couchand Sep 6, 2018
74c5f6b
ui: fix layout of sidebar on Statement Details page
couchand Sep 6, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pkg/ui/src/util/sql/summarize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const keywords: { [key: string]: RegExp } = {
insert: /^insert\s+into\s+([^ \t(]+)/i,
delete: /^delete\s+from\s+(\S+)/i,
create: /^create\s+table\s+(\S+)/i,
set: /^set\s+((cluster\s+setting\s+)?\S+)/i,
};

// summarize takes a string SQL statement and produces a structured summary
Expand Down
2 changes: 1 addition & 1 deletion pkg/ui/src/views/app/components/layoutSidebar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export default class Sidebar extends React.Component {
<IconLink to="/overview" icon={homeIcon} title="Overview" activeFor="/node" />
<IconLink to="/metrics" icon={metricsIcon} title="Metrics" />
<IconLink to="/databases" icon={databasesIcon} title="Databases" activeFor="/database" />
<IconLink to="/statements" icon={statementsIcon} title="Statements" />
<IconLink to="/statements" icon={statementsIcon} title="Statements" activeFor="/statement" />
<IconLink to="/jobs" icon={jobsIcon} title="Jobs" />
</ul>
<ul className="navigation-bar__list navigation-bar__list--bottom">
Expand Down
21 changes: 18 additions & 3 deletions pkg/ui/src/views/shared/components/pageconfig/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
import classnames from "classnames";
import React from "react";

export function PageConfig(props: {children?: React.ReactNode}) {
export interface PageConfigProps {
layout?: "list" | "spread";
children?: React.ReactNode;
}

export function PageConfig(props: PageConfigProps) {
const classes = classnames({
"page-config__list": props.layout !== "spread",
"page-config__spread": props.layout === "spread",
});

return (
<div className="page-config">
<ul className="page-config__list">
<ul className={ classes }>
{ props.children }
</ul>
</div>
);
}

export function PageConfigItem(props: {children?: React.ReactNode}) {
export interface PageConfigItemProps {
children?: React.ReactNode;
}

export function PageConfigItem(props: PageConfigItemProps) {
return (
<li className="page-config__item">
{ props.children }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
display inline-block
width 20px
line-height 12px
font-size 6px
font-size 10px
vertical-align middle
text-align center
content "▼"
Expand Down
2 changes: 1 addition & 1 deletion pkg/ui/src/views/shared/components/sortedtable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { SortableTable, SortableColumn, SortSetting } from "src/views/shared/com
*/
export interface ColumnDescriptor<T> {
// Title string that should appear in the header column.
title: string;
title: React.ReactNode;
// Function which generates the contents of an individual cell in this table.
cell: (obj: T) => React.ReactNode;
// Function which returns a value that can be used to sort the collection of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
text-transform uppercase
letter-spacing 2px
color $tooltip-color
white-space nowrap

&__value
font-weight 200
Expand Down
4 changes: 3 additions & 1 deletion pkg/ui/src/views/shared/components/toolTip/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "./tooltip.styl";

interface ToolTipWrapperProps {
text: React.ReactNode;
short?: boolean;
}

interface ToolTipWrapperState {
Expand Down Expand Up @@ -37,11 +38,12 @@ export class ToolTipWrapper extends React.Component<ToolTipWrapperProps, ToolTip
}

render() {
const { text } = this.props;
const { text, short } = this.props;
const { hovered } = this.state;
const tooltipClassNames = classNames({
"hover-tooltip": true,
"hover-tooltip--hovered": hovered,
"hover-tooltip--short": short,
});

return (
Expand Down
6 changes: 6 additions & 0 deletions pkg/ui/src/views/shared/components/toolTip/tooltip.styl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@

.hover-tooltip
position relative
width 100%
height 100%

&__text
visibility hidden
Expand All @@ -47,6 +49,10 @@
text-align left
color $body-color

&--short &__text
width unset
max-width 400px

&--hovered &__text
visibility visible

Expand Down
140 changes: 93 additions & 47 deletions pkg/ui/src/views/statements/barCharts.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import d3 from "d3";
import _ from "lodash";
import Long from "long";
import React from "react";

import { ToolTipWrapper } from "src/views/shared/components/toolTip";
Expand All @@ -12,11 +13,14 @@ import * as protos from "src/js/protos";

type StatementStatistics = protos.cockroach.server.serverpb.StatementsResponse.ICollectedStatementStatistics;

const longToInt = (d: number | Long) => FixLong(d).toInt();
const longToInt = (d: number | Long) => Long.fromValue(FixLong(d)).toInt();
const clamp = (i: number) => i < 0 ? 0 : i;

const countBars = [
bar("count-first-try", (d: StatementStatistics) => longToInt(d.stats.first_attempt_count)),
];

const retryBars = [
bar("count-retry", (d: StatementStatistics) => longToInt(d.stats.count) - longToInt(d.stats.first_attempt_count)),
];

Expand All @@ -38,8 +42,30 @@ function bar(name: string, value: (d: StatementStatistics) => number) {
return { name, value };
}

function renderNumericStatLegend(count: number | Long, stat: number, sd: number, formatter: (d: number) => string) {
return (
<table className="numeric-stat-legend">
<tbody>
<tr>
<th>
<div className="numeric-stat-legend__bar numeric-stat-legend__bar--mean" />
Mean
</th>
<td>{ formatter(stat) }</td>
</tr>
<tr>
<th>
<div className="numeric-stat-legend__bar numeric-stat-legend__bar--dev" />
Standard Deviation
</th>
<td>{ longToInt(count) < 2 ? "-" : sd ? formatter(sd) : "0" }</td>
</tr>
</tbody>
</table>
);
}

function makeBarChart(
title: string,
accessors: { name: string, value: (d: StatementStatistics) => number }[],
formatter: (d: number) => string = (x) => `${x}`,
stdDevAccessor?: { name: string, value: (d: StatementStatistics) => number },
Expand Down Expand Up @@ -97,23 +123,27 @@ function makeBarChart(
);
}

let titleText = title + ": " + formatter(sum);
if (stdDevAccessor) {
const sd = stdDevAccessor.value(d);
if (sd) {
titleText += " Std. Dev.: " + formatter(sd);
}
}
const titleText = renderNumericStatLegend(rows.length, sum, sd, formatter);

return (
<div className={ "bar-chart" + (rows.length === 0 ? " bar-chart--singleton" : "") }>
<ToolTipWrapper text={ titleText }>
return (
<div className={ "bar-chart" + (rows.length === 0 ? " bar-chart--singleton" : "") }>
<ToolTipWrapper text={ titleText } short>
<div className="label">{ formatter(getTotal(d)) }</div>
{ bars }
{ renderStdDev() }
</ToolTipWrapper>
</div>
);
} else {
return (
<div className={ "bar-chart" + (rows.length === 0 ? " bar-chart--singleton" : "") }>
<div className="label">{ formatter(getTotal(d)) }</div>
{ bars }
{ renderStdDev() }
</ToolTipWrapper>
</div>
);
</div>
);
}
};
};
}
Expand All @@ -135,9 +165,10 @@ export function approximify(value: number) {
return "" + Math.round(value);
}

export const countBarChart = makeBarChart("Execution Count", countBars, approximify);
export const rowsBarChart = makeBarChart("Rows Affected. Mean", rowsBars, approximify, rowsStdDev);
export const latencyBarChart = makeBarChart("Latency. Mean", latencyBars, v => Duration(v * 1e9), latencyStdDev);
export const countBarChart = makeBarChart(countBars, approximify);
export const retryBarChart = makeBarChart(retryBars, approximify);
export const rowsBarChart = makeBarChart(rowsBars, approximify, rowsStdDev);
export const latencyBarChart = makeBarChart(latencyBars, v => Duration(v * 1e9), latencyStdDev);

export function countBreakdown(s: StatementStatistics) {
const count = longToInt(s.stats.count);
Expand All @@ -153,38 +184,47 @@ export function countBreakdown(s: StatementStatistics) {
firstAttemptsBarChart() {
return (
<div className="bar-chart bar-chart--breakdown">
<ToolTipWrapper text={"First Try Count: " + firstAttempts}>
<div
className="count-first-try bar-chart__bar"
style={{ width: scale(firstAttempts) + "%" }}
/>
</ToolTipWrapper>
<div className="label">{ firstAttempts }</div>
<div
className="count-first-try bar-chart__bar"
style={{ width: scale(firstAttempts) + "%" }}
/>
</div>
);
},

retriesBarChart() {
return (
<div className="bar-chart bar-chart--breakdown">
<ToolTipWrapper text={ "Retry Count: " + retries }>
<div
className="count-retry bar-chart__bar"
style={{ width: scale(retries) + "%", position: "absolute", right: "0" }}
/>
</ToolTipWrapper>
<div className="label">{ retries }</div>
<div
className="count-retry bar-chart__bar"
style={{ width: scale(retries) + "%", position: "absolute", right: "0" }}
/>
</div>
);
},

maxRetriesBarChart() {
return (
<div className="bar-chart bar-chart--breakdown">
<ToolTipWrapper text={ "Max Retries: " + retries }>
<div
className="count-retry bar-chart__bar"
style={{ width: scale(maxRetries) + "%", position: "absolute", right: "0" }}
/>
</ToolTipWrapper>
<div className="label">{ maxRetries }</div>
<div
className="count-max-retries bar-chart__bar"
style={{ width: scale(maxRetries) + "%" }}
/>
</div>
);
},

totalCountBarChart() {
return (
<div className="bar-chart bar-chart--breakdown">
<div className="label">{ count }</div>
<div
className="count-total bar-chart__bar"
style={{ width: scale(count) + "%" }}
/>
</div>
);
},
Expand All @@ -206,10 +246,11 @@ export function rowsBreakdown(s: StatementStatistics) {
const width = scale(clamp(mean - sd));
const right = scale(mean);
const spread = scale(sd + (sd > mean ? mean : sd));
const title = "Row Count. Mean: " + format(mean) + " Std.Dev.: " + format(sd);
const title = renderNumericStatLegend(s.stats.count, mean, sd, format);
return (
<div className="bar-chart bar-chart--breakdown">
<ToolTipWrapper text={ title }>
<ToolTipWrapper text={ title } short>
<div className="label">{ Math.round(mean * 100) / 100 }</div>
<div
className="rows bar-chart__bar"
style={{ width: right + "%", position: "absolute", left: 0 }}
Expand Down Expand Up @@ -260,10 +301,11 @@ export function latencyBreakdown(s: StatementStatistics) {
const width = scale(clamp(parseMean - parseSd));
const right = scale(parseMean);
const spread = scale(parseSd + (parseSd > parseMean ? parseMean : parseSd));
const title = "Parse Latency. Mean: " + format(parseMean) + " Std. Dev.: " + format(parseSd);
const title = renderNumericStatLegend(s.stats.count, parseMean, parseSd, format);
return (
<div className="bar-chart bar-chart--breakdown">
<ToolTipWrapper text={ title }>
<ToolTipWrapper text={ title } short>
<div className="label">{ Duration(parseMean * 1e9) }</div>
<div
className="latency-parse bar-chart__bar"
style={{ width: right + "%", position: "absolute", left: 0 }}
Expand All @@ -282,10 +324,11 @@ export function latencyBreakdown(s: StatementStatistics) {
const width = scale(clamp(planMean - planSd));
const right = scale(planMean);
const spread = scale(planSd + (planSd > planMean ? planMean : planSd));
const title = "Plan Latency. Mean: " + format(planMean) + " Std. Dev.: " + format(planSd);
const title = renderNumericStatLegend(s.stats.count, planMean, planSd, format);
return (
<div className="bar-chart bar-chart--breakdown">
<ToolTipWrapper text={ title }>
<ToolTipWrapper text={ title } short>
<div className="label">{ Duration(planMean * 1e9) }</div>
<div
className="latency-plan bar-chart__bar"
style={{ width: right + "%", position: "absolute", left: left + "%" }}
Expand All @@ -304,10 +347,11 @@ export function latencyBreakdown(s: StatementStatistics) {
const width = scale(clamp(runMean - runSd));
const right = scale(runMean);
const spread = scale(runSd + (runSd > runMean ? runMean : runSd));
const title = "Run Latency. Mean: " + format(runMean) + " Std. Dev.: " + format(runSd);
const title = renderNumericStatLegend(s.stats.count, runMean, runSd, format);
return (
<div className="bar-chart bar-chart--breakdown">
<ToolTipWrapper text={ title }>
<ToolTipWrapper text={ title } short>
<div className="label">{ Duration(runMean * 1e9) }</div>
<div
className="latency-run bar-chart__bar"
style={{ width: right + "%", position: "absolute", left: left + "%" }}
Expand All @@ -326,10 +370,11 @@ export function latencyBreakdown(s: StatementStatistics) {
const width = scale(clamp(overheadMean - overheadSd));
const right = scale(overheadMean);
const spread = scale(overheadSd + (overheadSd > overheadMean ? overheadMean : overheadSd));
const title = "Overhead Latency. Mean: " + format(overheadMean) + " Std. Dev.: " + format(overheadSd);
const title = renderNumericStatLegend(s.stats.count, overheadMean, overheadSd, format);
return (
<div className="bar-chart bar-chart--breakdown">
<ToolTipWrapper text={ title }>
<ToolTipWrapper text={ title } short>
<div className="label">{ Duration(overheadMean * 1e9) }</div>
<div
className="latency-overhead bar-chart__bar"
style={{ width: right + "%", position: "absolute", left: left + "%" }}
Expand All @@ -350,10 +395,11 @@ export function latencyBreakdown(s: StatementStatistics) {
const overhead = scale(overheadMean);
const width = scale(clamp(overallMean - overallSd));
const spread = scale(overallSd + (overallSd > overallMean ? overallMean : overallSd));
const title = "Overall Latency. Mean: " + format(overallMean) + " Std. Dev.: " + format(overallSd);
const title = renderNumericStatLegend(s.stats.count, overallMean, overallSd, format);
return (
<div className="bar-chart bar-chart--breakdown">
<ToolTipWrapper text={ title }>
<ToolTipWrapper text={ title } short>
<div className="label">{ Duration(overallMean * 1e9) }</div>
<div
className="latency-parse bar-chart__bar"
style={{ width: parse + "%", position: "absolute", left: 0 }}
Expand Down
Loading