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

[Lens] Add metric Viz config options, title position and sizing #124124

Merged
merged 24 commits into from
Feb 16, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
dbdc290
Add lens config options
shahzad31 Jan 31, 2022
b093f5e
Merge branch 'main' of github.com:elastic/kibana into lens-metric
shahzad31 Feb 1, 2022
ba3448e
Merge branch 'main' of github.com:elastic/kibana into lens-metric
shahzad31 Feb 1, 2022
932545d
wip
shahzad31 Feb 1, 2022
b3329c2
Pr feedback
shahzad31 Feb 1, 2022
e1b2643
simplify align
shahzad31 Feb 1, 2022
c1934ed
improve typing
shahzad31 Feb 1, 2022
b0aaec6
update typing
shahzad31 Feb 1, 2022
00328a7
Merge branch 'main' of github.com:elastic/kibana into lens-metric
shahzad31 Feb 3, 2022
da64340
PR feedback
shahzad31 Feb 3, 2022
5ebd718
Design PR feedback
shahzad31 Feb 4, 2022
9384fa1
snapshot
shahzad31 Feb 8, 2022
a0514f8
Merge branch 'main' of github.com:elastic/kibana into lens-metric
shahzad31 Feb 8, 2022
b9f7a61
Merge branch 'main' of github.com:elastic/kibana into lens-metric
shahzad31 Feb 9, 2022
3bfdf0b
update snap
shahzad31 Feb 9, 2022
159ffd0
Merge branch 'main' of github.com:elastic/kibana into lens-metric
shahzad31 Feb 11, 2022
05c8b50
Merge branch 'main' into lens-metric
kibanamachine Feb 11, 2022
56c0bb4
design suggestions
shahzad31 Feb 11, 2022
71c3162
Merge branch 'lens-metric' of github.com:shahzad31/kibana into lens-m…
shahzad31 Feb 11, 2022
321f8f3
Merge branch 'main' into lens-metric
kibanamachine Feb 15, 2022
b139f93
Use bottom as default position for title and some other small refacto…
VladLasitsa Feb 15, 2022
e4d3b03
Fix test
VladLasitsa Feb 15, 2022
cd89b4e
Fix shapshot
VladLasitsa Feb 15, 2022
8726fb8
Fix shapshot
VladLasitsa Feb 15, 2022
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
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,24 @@ export const metricChart: ExpressionFunctionDefinition<
defaultMessage: 'The chart title.',
}),
},
titleSize: {
types: ['string'],
help: i18n.translate('xpack.lens.metric.titleSize.help', {
defaultMessage: 'The chart title size.',
}),
},
markov00 marked this conversation as resolved.
Show resolved Hide resolved
titlePosition: {
types: ['string'],
help: i18n.translate('xpack.lens.metric.titlePosition.help', {
defaultMessage: 'The chart title position.',
shahzad31 marked this conversation as resolved.
Show resolved Hide resolved
}),
},
MichaelMarcialis marked this conversation as resolved.
Show resolved Hide resolved
titleAlignPosition: {
types: ['string'],
help: i18n.translate('xpack.lens.metric.titleAlignPosition.help', {
defaultMessage: 'The chart title align position.',
}),
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have doubts on the namings here. title is usually referred to the title of the chart (the one that appears on the dashboard on the top/left corner of the embeddable).
In this case, this is a label on the visualization. In the Lens editor is called Display name so I think we should align the two namings.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, the terms used for these text-based elements in Lens are contextual depending on the current visualization and where the text is used. For example, we use all of the following in difference circumstances:

  • Display name: Used as text for layer dimension items. Also used as to supply default text for XY visualization axis names and single metric visualization titles.
  • Title: Used as the primary text in for single metric visualizations.
  • Subtitle: Used as the secondary text in for single metric visualizations.
  • Axis name: Used for text adjacent to axes in in XY visualizations.
  • Label: Used for text on individual pie/donut slices and text anchored to ticks in XY visualizations.

Dashboards does use the term "panel title" for top-left text in a dashboard panel. While there could be some potential for confusion between Lens' usage of "title" and Dashboard's usage of "panel title", I don't think it's a huge concern at the moment for the following reasons:

  1. Dashboard's term is prefixed with the word "panel".
  2. I don't believe there is a current situation where these two terms would exist simultaneously (i.e. editing a panel title and editing a visualization title). However, this may change in the future depending on the direction that the seamless UX endeavor goes.

For the time being, I'm personally fine with the term "title" in this circumstance, but I will defer to others if they feel strongly about it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MichaelMarcialis I'm a bit confused because I don't see where in Lens you are using the words title and subtitle in the single metric visualizations.
Screenshot 2022-02-03 at 12 55 05
I see a Display name field that I can change to change the metric name, but I don't see any title or subtitle in any of our options. The only place I see the title word is in the CSS class name.
In the other metric vis (aggregated) I can see a Custom label that can be used to change the metric name.
Screenshot 2022-02-03 at 12 56 22
This is actually badly aligned with the option to show and hide that name called Show title
Screenshot 2022-02-03 at 12 56 17

The title is used on the Axis instead, where you can configure the Axis title in the top menu that changes the Display name of the vertical or horizontal axis.
Screenshot 2022-02-03 at 13 12 39

When I think of a title, to me always refers to something more descriptive like: Memory consumption in the last week and is more suitable to be places on the top-left part of the visualization (aka panel title). A label instead, is used in various places and contains usually less information, just a tag: RAM, CPU %, really similar to what name is about.

As always is a matter of consistency across the interface and I don't see that neither with the term title or the label.
cc @gvnmagni

description: {
types: ['string'],
help: '',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ export interface MetricState {
layerType: LayerType;
colorMode?: ColorMode;
palette?: PaletteOutput<CustomPaletteParams>;
titlePosition?: string;
titleSize?: string;
titleAlignPosition?: string;
}

export interface MetricConfig extends Omit<MetricState, 'palette' | 'colorMode'> {
Expand Down
14 changes: 13 additions & 1 deletion x-pack/plugins/lens/public/metric_visualization/auto_scale.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@

import React from 'react';
import { throttle } from 'lodash';
import classNames from 'classnames';
import { EuiResizeObserver } from '@elastic/eui';

interface Props extends React.HTMLAttributes<HTMLDivElement> {
children: React.ReactNode | React.ReactNode[];
minScale?: number;
titleSize?: string;
titlePosition?: string;
titleAlignPosition?: string;
}

interface State {
Expand Down Expand Up @@ -56,7 +60,8 @@ export class AutoScale extends React.Component<Props, State> {
};

render() {
const { children, minScale, ...rest } = this.props;
const { children, minScale, titleSize, titleAlignPosition, titlePosition, ...rest } =
this.props;
const { scale } = this.state;
const style = this.props.style || {};

Expand Down Expand Up @@ -85,6 +90,13 @@ export class AutoScale extends React.Component<Props, State> {
style={{
transform: `scale(${scale})`,
}}
className={classNames('lnsMetricExpression_title_container', {
MichaelMarcialis marked this conversation as resolved.
Show resolved Hide resolved
rowDirection: ['left', 'right'].includes(titlePosition ?? ''),
alignStart: ['left', 'top'].includes(titleAlignPosition ?? ''),
alignEnd: ['right', 'bottom'].includes(titleAlignPosition ?? ''),
alignCenter: ['center', 'middle'].includes(titleAlignPosition ?? ''),
[`titleSize${(titleSize ?? 'xl').toUpperCase()}`]: true,
})}
>
{children}
</div>
Expand Down
74 changes: 72 additions & 2 deletions x-pack/plugins/lens/public/metric_visualization/expression.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,81 @@
font-size: $euiSizeXXL * 2;
font-weight: $euiFontWeightSemiBold;
border-radius: $euiBorderRadius;
padding: 0 $euiSize;
}

.lnsMetricExpression__title {
font-size: $euiSizeXL;
color: $euiTextColor;
&.reversOrder {
order: 1;
}
}
}

.lnsMetricExpression_title_container {
display: flex;
align-items: center;
flex-direction: column;
&.rowDirection {
flex-direction: row;
}
MichaelMarcialis marked this conversation as resolved.
Show resolved Hide resolved
&.alignStart {
align-items: start;
}
&.alignEnd {
align-items: end;
}
&.alignCenter {
align-items: center;
}
&.titleSizeXS {
.lnsMetricExpression__title {
font-size: $euiSizeXS;
MichaelMarcialis marked this conversation as resolved.
Show resolved Hide resolved
}
.lnsMetricExpression__value {
font-size: $euiSizeS * 2;
}
}
&.titleSizeS {
.lnsMetricExpression__title {
font-size: $euiSizeS * 1.5;
font-weight: 700;
}
.lnsMetricExpression__value {
font-size: $euiSizeM * 2.25;
}
markov00 marked this conversation as resolved.
Show resolved Hide resolved
}
&.titleSizeM {
.lnsMetricExpression__title {
font-size: $euiSizeM * 1.5;
}
.lnsMetricExpression__value {
font-size: $euiSizeL * 2;
}
}
&.titleSizeL {
.lnsMetricExpression__title {
font-size: $euiSizeL;
}
.lnsMetricExpression__value {
font-size: $euiSizeXL * 2;
}
}
&.titleSizeXL {
.lnsMetricExpression__title {
font-size: $euiSizeXL;
}
.lnsMetricExpression__value {
font-size: $euiSizeXXL * 2;
}
}

&.titleSizeXXL {
.lnsMetricExpression__title {
font-size: $euiSizeXXL;
}
.lnsMetricExpression__value {
font-size: $euiSizeXXL * 3;
}
}
MichaelMarcialis marked this conversation as resolved.
Show resolved Hide resolved
}
}
29 changes: 23 additions & 6 deletions x-pack/plugins/lens/public/metric_visualization/expression.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import './expression.scss';
import { I18nProvider } from '@kbn/i18n-react';
import React from 'react';
import ReactDOM from 'react-dom';
import classNames from 'classnames';
import { IUiSettingsClient, ThemeServiceStart } from 'kibana/public';
import { KibanaThemeProvider } from '../../../../../src/plugins/kibana_react/public';
import type {
Expand Down Expand Up @@ -109,7 +110,16 @@ export function MetricChart({
formatFactory,
uiSettings,
}: MetricChartProps & { formatFactory: FormatFactory; uiSettings: IUiSettingsClient }) {
const { metricTitle, accessor, mode, colorMode, palette } = args;
const {
metricTitle,
accessor,
mode,
colorMode,
palette,
titlePosition,
titleAlignPosition,
titleSize,
} = args;
const firstTable = Object.values(data.tables)[0];

const getEmptyState = () => (
Expand Down Expand Up @@ -144,19 +154,26 @@ export function MetricChart({

return (
<VisualizationContainer className="lnsMetricExpression__container" style={color}>
<AutoScale key={value}>
<div data-test-subj="lns_metric_value" className="lnsMetricExpression__value">
{value}
</div>
<AutoScale
key={value}
titlePosition={titlePosition}
titleAlignPosition={titleAlignPosition}
titleSize={titleSize}
>
{mode === 'full' && (
<div
data-test-subj="lns_metric_title"
className="lnsMetricExpression__title"
className={classNames('lnsMetricExpression__title', {
reversOrder: ['bottom', 'right'].includes(titlePosition ?? ''),
MichaelMarcialis marked this conversation as resolved.
Show resolved Hide resolved
})}
style={colorMode === ColorMode.Background ? color : undefined}
>
{metricTitle}
</div>
)}
<div data-test-subj="lns_metric_value" className="lnsMetricExpression__value">
{value}
</div>
</AutoScale>
</VisualizationContainer>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React, { memo } from 'react';
import { EuiFlexGroup, EuiFlexItem, htmlIdGenerator } from '@elastic/eui';
import type { VisualizationToolbarProps } from '../../types';

import { VisualOptionsPopover } from './visual_options_popover';
import { MetricState } from '../../../common/expressions';

export const MetricToolbar = memo(function MetricToolbar(
props: VisualizationToolbarProps<MetricState>
) {
const { state, setState, frame } = props;

return (
<EuiFlexGroup gutterSize="m" justifyContent="spaceBetween" responsive={false}>
<EuiFlexItem>
<EuiFlexGroup gutterSize="none" responsive={false}>
<VisualOptionsPopover
state={state}
setState={setState}
datasourceLayers={frame.datasourceLayers}
/>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
);
});

export const idPrefix = htmlIdGenerator()();
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
MichaelMarcialis marked this conversation as resolved.
Show resolved Hide resolved
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';
import { i18n } from '@kbn/i18n';
import { EuiFormRow, EuiSuperSelect } from '@elastic/eui';
import { MetricState } from '../../../common/expressions';

export interface TitlePositionProps {
state: MetricState;
setState: (newState: MetricState) => void;
}

const titleSizes = [
{ id: 'xs', label: 'XS' },
{ id: 's', label: 'S' },
{ id: 'm', label: 'M' },
{ id: 'l', label: 'L' },
{ id: 'xl', label: 'XL' },
{ id: 'xxl', label: 'XXL' },
MichaelMarcialis marked this conversation as resolved.
Show resolved Hide resolved
];
shahzad31 marked this conversation as resolved.
Show resolved Hide resolved

export const TitleSizeOptions: React.FC<TitlePositionProps> = ({ state, setState }) => {
return (
<EuiFormRow
display="columnCompressed"
label={
<>
{i18n.translate('xpack.lens.metricChart.titleSizeLabel', {
defaultMessage: 'Title size',
MichaelMarcialis marked this conversation as resolved.
Show resolved Hide resolved
})}
</>
}
>
<EuiSuperSelect
data-test-subj="lnsMissingValuesSelect"
compressed
options={titleSizes.map((position) => {
return {
value: position.id,
dropdownDisplay: position.label,
inputDisplay: position.label,
};
})}
valueOfSelected={state.titleSize ?? 'xl'}
onChange={(value) => {
setState({ ...state, titleSize: value });
}}
itemLayoutAlign="top"
hasDividers
/>
</EuiFormRow>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';
import { i18n } from '@kbn/i18n';
import { EuiFormRow, EuiSuperSelect } from '@elastic/eui';
import { MetricState } from '../../../common/expressions';

export interface TitlePositionProps {
state: MetricState;
setState: (newState: MetricState) => void;
}

const titleAlignPositions = [
{ id: 'top', label: 'Top', direction: 'column' },
{ id: 'bottom', label: 'Bottom', direction: 'column' },
{ id: 'middle', label: 'Middle', direction: 'column' },
{ id: 'left', label: 'Left', direction: 'row' },
{ id: 'right', label: 'Right', direction: 'row' },
{ id: 'center', label: 'Center', direction: 'row' },
];

export const TitleAlignOptions: React.FC<TitlePositionProps> = ({ state, setState }) => {
const direction = ['top', 'bottom'].includes(state.titlePosition ?? 'top') ? 'column' : 'row';

return (
<EuiFormRow
display="columnCompressed"
label={
<>
{i18n.translate('xpack.lens.metricChart.titleAlignLabel', {
defaultMessage: 'Title align',
MichaelMarcialis marked this conversation as resolved.
Show resolved Hide resolved
})}
</>
}
>
<EuiSuperSelect
data-test-subj="lnsMissingValuesSelect"
compressed
options={titleAlignPositions
.filter((pos) => pos.direction !== direction)
.map((position) => {
return {
value: position.id,
dropdownDisplay: position.label,
inputDisplay: position.label,
};
})}
valueOfSelected={state.titleAlignPosition ?? 'center'}
onChange={(value) => {
setState({ ...state, titleAlignPosition: value });
}}
itemLayoutAlign="top"
hasDividers
/>
MichaelMarcialis marked this conversation as resolved.
Show resolved Hide resolved
</EuiFormRow>
);
};
Loading