-
Notifications
You must be signed in to change notification settings - Fork 122
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
feat(metric): Metric visualization #1658
Changes from all commits
0b3265e
0c2357a
2b27347
7060f59
d939d4e
51e5977
be80e67
5dc1fcf
bb06992
8768f0f
4e72633
e538ac0
bc406cf
e9842b4
8777acd
ea28f38
2213696
14805b6
84f9802
c70c557
a0df3bc
897a664
5d398b4
fc03e21
3c080b1
6d011a8
fc91ca4
b2abab6
4784459
b34deef
cfd1e3b
55da629
5f57e2b
031a232
b09c05f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
import { common } from '../page_objects'; | ||
|
||
describe('Metric', () => { | ||
it('should render horizontal progress bar', async () => { | ||
await common.expectChartAtUrlToMatchScreenshot( | ||
'http://localhost:9001/?path=/story/metric-alpha--grid&globals=theme:light&knob-use progress bar=true&knob-progress bar direction=horizontal&knob-max trend data points=30&knob-layout=grid', | ||
); | ||
}); | ||
it('should render no progress bar', async () => { | ||
await common.expectChartAtUrlToMatchScreenshot( | ||
'http://localhost:9001/?path=/story/metric-alpha--grid&globals=theme:light&knob-use progress bar=&knob-progress bar direction=horizontal&knob-max trend data points=30&knob-layout=grid', | ||
); | ||
}); | ||
it('should render vertical progress bar in dark mode', async () => { | ||
await common.expectChartAtUrlToMatchScreenshot( | ||
'http://localhost:9001/?path=/story/metric-alpha--grid&globals=theme:eui-dark&knob-layout=grid&knob-max trend data points=30&knob-progress bar direction=vertical&knob-use progress bar=true', | ||
); | ||
}); | ||
it('should render horizontal progress bar in dark mode', async () => { | ||
await common.expectChartAtUrlToMatchScreenshot( | ||
'http://localhost:9001/?path=/story/metric-alpha--grid&globals=theme:eui-dark&knob-layout=grid&knob-max trend data points=30&knob-progress bar direction=horizontal&knob-use progress bar=true', | ||
); | ||
}); | ||
it('should render no progress bar in dark mode', async () => { | ||
await common.expectChartAtUrlToMatchScreenshot( | ||
'http://localhost:9001/?path=/story/metric-alpha--grid&globals=theme:eui-dark&knob-layout=grid&knob-max trend data points=30&knob-progress bar direction=horizontal&knob-use progress bar=', | ||
); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,7 @@ import { LegacyRef } from 'react'; | |
import { OptionalKeys } from 'utility-types'; | ||
import { default as React_2 } from 'react'; | ||
import { ReactChild } from 'react'; | ||
import { ReactElement } from 'react'; | ||
import { ReactNode } from 'react'; | ||
import { RequiredKeys } from 'utility-types'; | ||
|
||
|
@@ -523,6 +524,7 @@ export const ChartType: Readonly<{ | |
XYAxis: "xy_axis"; | ||
Heatmap: "heatmap"; | ||
Wordcloud: "wordcloud"; | ||
Metric: "metric"; | ||
}>; | ||
|
||
// @public (undocumented) | ||
|
@@ -1663,6 +1665,76 @@ export function mergeWithDefaultAnnotationRect(config?: RecursivePartial<RectAnn | |
// @public @deprecated | ||
export function mergeWithDefaultTheme(theme: PartialTheme, defaultTheme?: Theme, auxiliaryThemes?: PartialTheme[]): Theme; | ||
|
||
// @alpha (undocumented) | ||
export const Metric: FC<SFProps<MetricSpec, "chartType" | "specType", "data", never, "id">>; | ||
|
||
// @alpha (undocumented) | ||
export type MetricBase = { | ||
value: number; | ||
valueFormatter: (d: number) => string; | ||
color: Color; | ||
title?: string; | ||
subtitle?: string; | ||
extra?: ReactElement; | ||
}; | ||
|
||
// @alpha (undocumented) | ||
export interface MetricSpec extends Spec { | ||
// (undocumented) | ||
chartType: typeof ChartType.Metric; | ||
// (undocumented) | ||
data: (MetricBase | MetricWProgress | MetricWTrend | undefined)[][]; | ||
// (undocumented) | ||
specType: typeof SpecType.Series; | ||
} | ||
|
||
// @alpha (undocumented) | ||
export type MetricSpecProps = ComponentProps<typeof Metric>; | ||
|
||
// @public (undocumented) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All the docs are for a next PR, right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, unfortunately docs are always for the next PR.... |
||
export interface MetricStyle { | ||
// (undocumented) | ||
background: Color; | ||
// (undocumented) | ||
barBackground: Color; | ||
// (undocumented) | ||
nonFiniteText: string; | ||
// (undocumented) | ||
text: { | ||
darkColor: Color; | ||
lightColor: Color; | ||
}; | ||
} | ||
|
||
// @alpha (undocumented) | ||
export const MetricTrendShape: Readonly<{ | ||
Bars: "bars"; | ||
Area: "area"; | ||
}>; | ||
|
||
// @alpha (undocumented) | ||
export type MetricTrendShape = $Values<typeof MetricTrendShape>; | ||
|
||
// @alpha (undocumented) | ||
export type MetricWProgress = MetricBase & { | ||
domain: { | ||
min: number; | ||
max: number; | ||
}; | ||
progressBarDirection?: LayoutDirection; | ||
}; | ||
|
||
// @alpha (undocumented) | ||
export type MetricWTrend = MetricBase & { | ||
trend: { | ||
x: number; | ||
y: number; | ||
}[]; | ||
trendShape?: MetricTrendShape; | ||
trendA11yTitle?: string; | ||
trendA11yDescription?: string; | ||
Comment on lines
+1733
to
+1735
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we make the strings non-optional, if necessary, using the empty string if none is supplied? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
}; | ||
|
||
// @public (undocumented) | ||
export const MODEL_KEY = "parent"; | ||
|
||
|
@@ -2532,6 +2604,8 @@ export interface Theme { | |
legend: LegendStyle; | ||
lineSeriesStyle: LineSeriesStyle; | ||
markSizeRatio?: number; | ||
// (undocumented) | ||
metric: MetricStyle; | ||
partition: PartitionStyle; | ||
// (undocumented) | ||
scales: ScalesConfig; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
.echMetricContainer { | ||
display: grid; | ||
width: 100%; | ||
height: 100%; | ||
align-content: start; | ||
justify-content: stretch; | ||
align-items: stretch; | ||
user-select: text; | ||
} | ||
|
||
.echMetric { | ||
position: relative; | ||
overflow: hidden; | ||
|
||
&--rightBorder { | ||
border-right: 1px solid #343741; | ||
nickofthyme marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
&--bottomBorder { | ||
border-bottom: 1px solid #343741; | ||
} | ||
|
||
&--vertical { | ||
&.echMetric--small { | ||
padding-left: 10px; | ||
} | ||
} | ||
|
||
&--horizontal { | ||
&.echMetric--small { | ||
padding-bottom: 10px; | ||
} | ||
} | ||
} | ||
|
||
@import 'dom/text'; | ||
@import 'dom/progress'; | ||
@import 'dom/sparkline'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
.echSingleMetricProgress { | ||
position: absolute; | ||
overflow: hidden; | ||
|
||
&--vertical { | ||
left: 0; | ||
right: 0; | ||
top: 0; | ||
bottom: 0; | ||
height: 100%; | ||
width: 100%; | ||
&.echSingleMetricProgress--small { | ||
right: auto; | ||
width: 10px; | ||
} | ||
} | ||
|
||
&--horizontal { | ||
left: 0; | ||
right: 0; | ||
width: 100%; | ||
top: 0; | ||
bottom: 0; | ||
height: 100%; | ||
&.echSingleMetricProgress--small { | ||
top: auto; | ||
height: 10px; | ||
} | ||
} | ||
} | ||
|
||
.echSingleMetricProgressBar { | ||
&--vertical { | ||
position: absolute; | ||
left: 0; | ||
right: 0; | ||
bottom: 0; | ||
width: 100%; | ||
} | ||
&--horizontal { | ||
position: absolute; | ||
top: 0; | ||
bottom: 0; | ||
left: 0; | ||
height: 100%; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
.echSingleMetricSparkline { | ||
position: absolute; | ||
overflow: hidden; | ||
top: 0; | ||
bottom: 0; | ||
left: 0; | ||
right: 0; | ||
} | ||
|
||
.echSingleMetricSparkline__svg { | ||
position: absolute; | ||
top: 0; | ||
bottom: 0; | ||
left: 0; | ||
right: 0; | ||
width: 100%; | ||
height: 100%; | ||
} | ||
|
||
.echSingleMetricChart--small { | ||
position: absolute; | ||
top: auto; | ||
left: auto; | ||
bottom: 0; | ||
right: 0; | ||
width: 100px; | ||
height: 30px; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
@mixin lineClamp($maxLines) { | ||
text-overflow: ellipsis; | ||
display: -webkit-box; | ||
-webkit-line-clamp: $maxLines; /* number of lines to show */ | ||
line-clamp: $maxLines; | ||
-webkit-box-orient: vertical; | ||
overflow: hidden; | ||
} | ||
|
||
.echMetricText { | ||
position: relative; | ||
padding: 8px; | ||
height: 100%; | ||
z-index: 1; | ||
display: grid; | ||
grid-template-columns: 100%; | ||
grid-template-rows: min-content min-content auto min-content min-content; | ||
|
||
&__title { | ||
font-weight: 400; | ||
} | ||
|
||
&__subtitle { | ||
padding-top: 5px; | ||
font-weight: 300; | ||
} | ||
|
||
&__extra { | ||
text-align: right; | ||
font-weight: 400; | ||
} | ||
|
||
&__value { | ||
position: relative; | ||
font-weight: 600; | ||
text-align: right; | ||
white-space: nowrap; | ||
} | ||
|
||
&__part { | ||
font-weight: 400; | ||
} | ||
|
||
&__gap { | ||
position: relative; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can
MetricSpec
be generic on the use case? Ternaries have some extra cost compared to generics. Also, why do we need to admitundefined
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MetricSpec
with generic: with the current config no. Because you can mix a simple metric with a static background color with one with a trend and with another with a progress bar.why
undefined
because we allow gaps between metrics in a row/column.