vmui: ui improvements (#4872)

* vmui: chart refactoring to enhance code structure

* vmui: improve ui

(cherry picked from commit 72167a697e)
This commit is contained in:
Yury Molodov 2023-08-25 15:39:21 +02:00 committed by hagen1778
parent 6c99e5445d
commit 2aff0ce327
No known key found for this signature in database
GPG Key ID: 3BF75F3741CA9640
38 changed files with 157 additions and 57 deletions

View File

@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5" />
<meta name="theme-color" content="#000000" />
<meta
name="description"

View File

@ -7,6 +7,7 @@ import uPlot from "uplot";
import Button from "../../Main/Button/Button";
import { CloseIcon, DragIcon } from "../../Main/Icons";
import { SeriesItemStats } from "../../../types";
import { STATS_ORDER } from "../../../constants/graph";
export interface ChartTooltipProps {
u?: uPlot;
@ -134,6 +135,7 @@ const ChartTooltip: FC<ChartTooltipProps> = ({
size="small"
startIcon={<DragIcon/>}
onMouseDown={handleMouseDown}
ariaLabel="drag the tooltip"
/>
<Button
className="vm-chart-tooltip-header__close"
@ -141,6 +143,7 @@ const ChartTooltip: FC<ChartTooltipProps> = ({
size="small"
startIcon={<CloseIcon/>}
onClick={handleClose}
ariaLabel="close the tooltip"
/>
</>
)}
@ -152,25 +155,24 @@ const ChartTooltip: FC<ChartTooltipProps> = ({
style={{ background: marker }}
/>
)}
<div>
<p className="vm-chart-tooltip-data__value">
<b>{value}</b>{unit}
</p>
{stats && (
<p className="vm-chart-tooltip-data__stats">
{Object.keys(stats).filter(key => key !== "last").map((key, i) => (
<span key={i}>
{key}:<b>{stats[key as keyof SeriesItemStats]}</b>
</span>
)
)}
</p>
)}
</div>
</div>
<div className="vm-chart-tooltip-info">
{info}
<p className="vm-chart-tooltip-data__value">
<b>{value}</b>{unit}
</p>
</div>
{stats && (
<table className="vm-chart-tooltip-stats">
{STATS_ORDER.map((key, i) => (
<div
className="vm-chart-tooltip-stats-row"
key={i}
>
<span className="vm-chart-tooltip-stats-row__key">{key}:</span>
<span className="vm-chart-tooltip-stats-row__value">{stats[key]}</span>
</div>
))}
</table>
)}
{info && <p className="vm-chart-tooltip__info">{info}</p>}
</div>
), u.root);
};

View File

@ -1,18 +1,18 @@
@use "src/styles/variables" as *;
$chart-tooltip-width: 325px;
$chart-tooltip-width: 370px;
$chart-tooltip-icon-width: 25px;
$chart-tooltip-half-icon: calc($chart-tooltip-icon-width/2);
$chart-tooltip-date-width: $chart-tooltip-width - (2*$chart-tooltip-icon-width) - (2*$padding-global) - $padding-small;
$chart-tooltip-half-icon: calc($chart-tooltip-icon-width / 2);
$chart-tooltip-date-width: $chart-tooltip-width - (2*$chart-tooltip-icon-width) - (3*$padding-global);
$chart-tooltip-x: -1 * ($padding-small + $padding-global + $chart-tooltip-date-width + $chart-tooltip-half-icon);
$chart-tooltip-y: -1 * ($padding-small + $chart-tooltip-half-icon);
$chart-tooltip-y: -1 * ($padding-global + $chart-tooltip-half-icon);
.vm-chart-tooltip {
position: absolute;
display: grid;
gap: $padding-global;
width: $chart-tooltip-width;
padding: $padding-small;
padding: $padding-global;
border-radius: $border-radius-medium;
background: $color-background-tooltip;
color: $color-white;
@ -44,45 +44,76 @@ $chart-tooltip-y: -1 * ($padding-small + $chart-tooltip-half-icon);
justify-content: center;
min-height: 25px;
&__title {
grid-row: 1;
}
&__close {
grid-row: 1;
grid-column: 3;
color: $color-white;
}
&__drag {
grid-row: 1;
grid-column: 2;
color: $color-white;
cursor: move;
}
&__date {
grid-column: 1;
display: grid;
gap: 2px;
}
}
&-data {
display: grid;
grid-template-columns: auto 1fr;
display: flex;
align-items: center;
justify-content: flex-start;
gap: $padding-small;
align-items: flex-start;
word-break: break-all;
line-height: $font-size;
&__stats {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: $padding-small;
}
&__marker {
width: 12px;
height: 12px;
width: $font-size;
height: $font-size;
border: 1px solid rgba($color-white, 0.5);
}
&__value {
line-height: 1;
font-size: $font-size;
}
}
&-info {
display: grid;
grid-gap: 4px;
&-stats {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-start;
gap: $padding-small $padding-global;
&-row {
display: grid;
align-items: center;
justify-content: flex-start;
&:not(:last-child) {
padding-right: $padding-small;
}
&__key {
line-height: 1;
margin-right: calc($padding-small/2);
}
&__value {
font-weight: bold;
}
}
}
&__info {
word-break: break-all;
white-space: pre-wrap;
}

View File

@ -22,6 +22,7 @@ const GraphTips: FC = () => {
color={"gray"}
startIcon={<TipIcon/>}
onClick={handleOpenTips}
ariaLabel="open the tips"
/>
</Tooltip>
{showTips && (

View File

@ -5,6 +5,7 @@ import "./style.scss";
import classNames from "classnames";
import { getFreeFields } from "./helpers";
import useCopyToClipboard from "../../../../../hooks/useCopyToClipboard";
import { STATS_ORDER } from "../../../../../constants/graph";
interface LegendItemProps {
legend: LegendItemType;
@ -70,8 +71,16 @@ const LegendItem: FC<LegendItemProps> = ({ legend, onChange, isHeatmap }) => {
</span>
</div>
{!isHeatmap && showCalculations && (
<div className="vm-legend-item-values">
median:{calculations.median}, min:{calculations.min}, max:{calculations.max}, last:{calculations.last}
<div className="vm-legend-item-stats">
{STATS_ORDER.map((key, i) => (
<div
className="vm-legend-item-stats-row"
key={i}
>
<span className="vm-legend-item-stats-row__key">{key}:</span>
<span className="vm-legend-item-stats-row__value">{calculations[key]}</span>
</div>
))}
</div>
)}
</div>

View File

@ -34,6 +34,7 @@
}
&__marker {
position: relative;
width: 14px;
height: 14px;
box-sizing: border-box;
@ -59,10 +60,29 @@
}
}
&-values {
&-stats {
grid-column: 2;
display: flex;
align-items: center;
gap: $padding-small;
&-row {
display: flex;
align-items: center;
justify-content: flex-start;
&:not(:last-child) {
padding-right: $padding-global;
}
&__key {
line-height: 1;
color: $color-text-secondary;
margin-right: calc($padding-small / 2);
}
&__value {
}
}
}
}

View File

@ -76,6 +76,7 @@ const AdditionalSettings: FC = () => {
variant="outlined"
startIcon={<TuneIcon/>}
onClick={handleToggleList}
ariaLabel="additional the query settings"
/>
</div>
<Popper

View File

@ -131,6 +131,7 @@ const GlobalSettings: FC = () => {
color="primary"
startIcon={<SettingsIcon/>}
onClick={handleOpen}
ariaLabel="settings"
/>
</Tooltip>
)}

View File

@ -34,6 +34,7 @@ const GraphSettings: FC<GraphSettingsProps> = ({ yaxis, setYaxisLimits, toggleEn
variant="text"
startIcon={<SettingsIcon/>}
onClick={toggleOpen}
ariaLabel="settings"
/>
</div>
</Tooltip>

View File

@ -171,6 +171,7 @@ const StepConfigurator: FC = () => {
color="primary"
startIcon={<RestartIcon/>}
onClick={handleReset}
ariaLabel="reset step"
/>
</Tooltip>
)}

View File

@ -93,6 +93,7 @@ export const ExecutionControls: FC = () => {
color="primary"
onClick={handleUpdate}
startIcon={<RefreshIcon/>}
ariaLabel="refresh dashboard"
/>
</Tooltip>
)}

View File

@ -133,6 +133,7 @@ export const TimeSelector: FC = () => {
color="primary"
startIcon={<ClockIcon/>}
onClick={toggleOpenOptions}
ariaLabel="time range controls"
>
{displayFullDate && <span>{dateTitle}</span>}
</Button>

View File

@ -59,6 +59,7 @@ const ExploreMetricItemHeader: FC<ExploreMetricItemControlsProps> = ({
size="small"
startIcon={<MoreIcon/>}
onClick={handleOpenOptions}
ariaLabel="open panel settings"
/>
{openOptions && (
<Modal
@ -72,6 +73,7 @@ const ExploreMetricItemHeader: FC<ExploreMetricItemControlsProps> = ({
variant="outlined"
onClick={handleOrderUp}
disabled={index === 0}
ariaLabel="move graph up"
/>
<p>position:
<span className="vm-explore-metrics-item-header-modal-order__index">#{index + 1}</span>
@ -81,6 +83,7 @@ const ExploreMetricItemHeader: FC<ExploreMetricItemControlsProps> = ({
variant="outlined"
onClick={handleOrderDown}
disabled={index === length - 1}
ariaLabel="move graph down"
/>
</div>
{!isBucket && (
@ -123,6 +126,7 @@ const ExploreMetricItemHeader: FC<ExploreMetricItemControlsProps> = ({
color="gray"
size="small"
onClick={handleOrderUp}
ariaLabel="move graph up"
/>
</Tooltip>
<div className="vm-explore-metrics-item-header__index">#{index+1}</div>
@ -134,6 +138,7 @@ const ExploreMetricItemHeader: FC<ExploreMetricItemControlsProps> = ({
color="gray"
size="small"
onClick={handleOrderDown}
ariaLabel="move graph down"
/>
</Tooltip>
</div>
@ -157,6 +162,7 @@ const ExploreMetricItemHeader: FC<ExploreMetricItemControlsProps> = ({
color="gray"
size="small"
onClick={handleClickRemove}
ariaLabel="close graph"
/>
</Tooltip>
</div>

View File

@ -100,6 +100,7 @@ const ExploreMetricsHeader: FC<ExploreMetricsHeaderProps> = ({
color={showTips ? "warning" : "gray"}
startIcon={<TipIcon/>}
onClick={toggleShowTips}
ariaLabel="visibility tips"
/>
</Tooltip>
</div>
@ -134,6 +135,7 @@ const ExploreMetricsHeader: FC<ExploreMetricsHeaderProps> = ({
size="small"
startIcon={<CloseIcon/>}
onClick={setHideTips}
ariaLabel="close tips"
/>
</div>
</Alert>

View File

@ -7,6 +7,7 @@ interface ButtonProps {
variant?: "contained" | "outlined" | "text"
color?: "primary" | "secondary" | "success" | "error" | "gray" | "warning"
size?: "small" | "medium" | "large"
ariaLabel?: string // https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-label
endIcon?: ReactNode
startIcon?: ReactNode
fullWidth?: boolean
@ -21,6 +22,7 @@ const Button: FC<ButtonProps> = ({
variant = "contained",
color = "primary",
size = "medium",
ariaLabel,
children,
endIcon,
startIcon,
@ -46,6 +48,7 @@ const Button: FC<ButtonProps> = ({
<button
className={classesButton}
disabled={disabled}
aria-label={ariaLabel}
onClick={onClick}
onMouseDown={onMouseDown}
>

View File

@ -35,6 +35,7 @@ const CodeExample: FC<{code: string}> = ({ code }) => {
variant="text"
onClick={handlerCopy}
startIcon={<CopyIcon/>}
ariaLabel="close"
/>
</Tooltip>
</div>

View File

@ -111,6 +111,7 @@ const DateTimeInput: FC<DateTimeInputProps> = ({
color="gray"
size="small"
startIcon={<CalendarIcon/>}
ariaLabel="calendar"
/>
</div>
<DatePicker

View File

@ -8,6 +8,7 @@ const MenuBurger = ({ open }: {open: boolean}) => (
"vm-menu-burger": true,
"vm-menu-burger_opened": open
})}
aria-label="menu"
>
<span></span>
</button>

View File

@ -82,6 +82,7 @@ const Modal: FC<ModalProps> = ({
variant="text"
size="small"
onClick={onClose}
ariaLabel="close"
>
<CloseIcon/>
</Button>

View File

@ -162,6 +162,7 @@ const Popper: FC<PopperProps> = ({
variant="text"
size="small"
onClick={handleClickClose}
ariaLabel="close"
>
<CloseIcon/>
</Button>

View File

@ -45,6 +45,7 @@ const ShortcutKeys: FC<{ showTitle?: boolean }> = ({ showTitle }) => {
color="primary"
startIcon={<KeyboardIcon/>}
onClick={handleOpen}
ariaLabel={title}
>
{showTitle && title}
</Button>

View File

@ -11,7 +11,6 @@ interface TextFieldErrorProps {
}
const TextFieldMessage: FC<TextFieldErrorProps> = ({ error, warning, info }) => {
console.log(warning);
const messageRef = useRef<HTMLSpanElement>(null);
const [isMessageTruncated, setIsMessageTruncated] = useState(false);
const [showFull, setShowFull] = useState(false);

View File

@ -110,6 +110,7 @@ const Table = <T extends object>({ rows, columns, defaultOrderBy, copyToClipboar
size="small"
startIcon={copied === rowIndex ? <DoneIcon/> : <CopyIcon/>}
onClick={createCopyHandler(row[copyToClipboard], rowIndex)}
ariaLabel="copy row"
/>
</Tooltip>
</div>

View File

@ -67,6 +67,7 @@ const TableSettings: FC<TableSettingsProps> = ({
startIcon={<SettingsIcon/>}
onClick={toggleOpenSettings}
disabled={disabledButton}
ariaLabel="table settings"
/>
</div>
</Tooltip>
@ -100,6 +101,7 @@ const TableSettings: FC<TableSettingsProps> = ({
size="small"
onClick={handleResetColumns}
startIcon={<RestartIcon/>}
ariaLabel="reset columns"
/>
</Tooltip>
</div>

View File

@ -88,9 +88,8 @@ const NestedNav: FC<RecursiveProps> = ({ trace, totalMsec }) => {
</div>
{(isExpanded || showFullMessage) && (
<Button
variant="outlined"
variant="text"
size="small"
color="secondary"
onClick={handleClickShowMore}
>
{showFullMessage ? "Hide" : "Show full query"}

View File

@ -69,6 +69,7 @@ const TracingsView: FC<TraceViewProps> = ({ traces, jsonEditor = false, onDelete
variant="text"
startIcon={<CodeIcon/>}
onClick={handleJsonClick(trace)}
ariaLabel="open JSON"
/>
</Tooltip>
<Tooltip title={"Remove trace"}>
@ -77,6 +78,7 @@ const TracingsView: FC<TraceViewProps> = ({ traces, jsonEditor = false, onDelete
color="error"
startIcon={<DeleteIcon/>}
onClick={handleDeleteClick(trace)}
ariaLabel="remove trace"
/>
</Tooltip>
</div>

View File

@ -164,6 +164,7 @@ const TableView: FC<GraphViewProps> = ({ data, displayColumns }) => {
size="small"
startIcon={<CopyIcon/>}
onClick={createCopyHandler(row.copyValue)}
ariaLabel="copy row"
/>
</Tooltip>
</div>

View File

@ -1,4 +1,4 @@
import { GraphSize } from "../types";
import { GraphSize, SeriesItemStats } from "../types";
export const MAX_QUERY_FIELDS = 4;
export const DEFAULT_MAX_SERIES = {
@ -22,3 +22,5 @@ export const GRAPH_SIZES: GraphSize[] = [
height: () => window.innerHeight * 0.8
},
];
export const STATS_ORDER: (keyof SeriesItemStats)[] = ["min", "median", "max"];

View File

@ -26,7 +26,7 @@ export const lightPalette = {
"color-success": "#4CAF50",
"color-background-body": "#FEFEFF",
"color-background-block": "#FFFFFF",
"color-background-tooltip": "rgba(97,97,97, 0.92)",
"color-background-tooltip": "rgba(80,80,80,0.9)",
"color-text": "#110f0f",
"color-text-secondary": "#706F6F",
"color-text-disabled": "#A09F9F",

View File

@ -58,6 +58,7 @@ const HeaderControls: FC<ControlsProps & HeaderProps> = ({
})}
startIcon={<MoreIcon/>}
onClick={handleToggleList}
ariaLabel={"controls"}
/>
</div>
<Modal

View File

@ -23,7 +23,7 @@
&-item {
position: relative;
padding: $padding-global $padding-small;
opacity: 0.7;
opacity: 1;
cursor: pointer;
transition: opacity 200ms ease-in;
text-transform: capitalize;
@ -40,11 +40,11 @@
}
&:hover {
opacity: 1;
opacity: 0.7;
}
&_active {
opacity: 1;
border-bottom: 2px solid rgba($color-black, 0.2);
}
svg {

View File

@ -122,6 +122,7 @@ const CardinalityConfigurator: FC<CardinalityTotalsProps> = (props) => {
color={showTips ? "warning" : "gray"}
startIcon={<TipIcon/>}
onClick={handleToggleTips}
ariaLabel="visibility tips"
/>
</Tooltip>
<Button

View File

@ -186,6 +186,7 @@ const QueryConfigurator: FC<QueryConfiguratorProps> = ({
color={"gray"}
startIcon={hideQuery.includes(i) ? <VisibilityOffIcon/> : <VisibilityIcon/>}
onClick={createHandlerHideQuery(i)}
ariaLabel="visibility query"
/>
</div>
</Tooltip>
@ -198,6 +199,7 @@ const QueryConfigurator: FC<QueryConfiguratorProps> = ({
startIcon={<Prettify/>}
onClick={async () => await handlePrettifyQuery(i)}
className="prettify"
ariaLabel="prettify the query"
/>
</div>
</Tooltip>
@ -210,6 +212,7 @@ const QueryConfigurator: FC<QueryConfiguratorProps> = ({
color={"error"}
startIcon={<DeleteIcon/>}
onClick={createHandlerRemoveQuery(i)}
ariaLabel="remove query"
/>
</div>
</Tooltip>

View File

@ -108,6 +108,7 @@ const PredefinedDashboard: FC<PredefinedDashboardProps> = ({
<button
className="vm-predefined-dashboard-panels-panel__resizer"
onMouseDown={createHandlerResize(i)}
aria-label="resize the panel"
/>
</div>
)

View File

@ -85,6 +85,7 @@ const TopQueryTable:FC<TopQueryPanelProps> = ({ rows, columns, defaultOrderBy })
variant="text"
size="small"
startIcon={<PlayCircleOutlineIcon/>}
ariaLabel="execute query"
/>
</Link>
</Tooltip>
@ -94,6 +95,7 @@ const TopQueryTable:FC<TopQueryPanelProps> = ({ rows, columns, defaultOrderBy })
size="small"
startIcon={<CopyIcon/>}
onClick={createCopyHandler(row)}
ariaLabel="copy query"
/>
</Tooltip>
</div>

View File

@ -3,6 +3,7 @@
src: url('../assets/fonts/Lato/Lato-Regular.ttf');
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
@ -10,4 +11,5 @@
src: url('../assets/fonts/Lato/Lato-Bold.ttf');
font-weight: bold;
font-style: normal;
font-display: swap;
}

View File

@ -32,7 +32,7 @@
/* backgrounds */
--color-background-body: #FEFEFF;
--color-background-block: #FFFFFF;
--color-background-tooltip: rgba(97,97,97, 0.92);
--color-background-tooltip: rgba(80,80,80,0.9);
/* text */
--color-text: #110f0f;

View File

@ -32,11 +32,9 @@ export const formatPrettyNumber = (
// This precision should be enough for most UX cases,
// since the remaining digits are usually a white noise.
let digits = 3 + Math.floor(1 + Math.log10(Math.max(Math.abs(min), Math.abs(max))) - Math.log10(range));
if (isNaN(digits) || digits > 20) {
digits = 20;
}
if (isNaN(digits) || digits > 20) digits = 20;
return n.toLocaleString("en-US", {
minimumSignificantDigits: digits,
minimumSignificantDigits: 1,
maximumSignificantDigits: digits,
});
};