Compare commits
6 commits
main
...
issue-1040
Author | SHA1 | Date | |
---|---|---|---|
44ab603c83 | |||
51f84e9175 | |||
dddaf7a038 | |||
8d42acd376 | |||
b942c9781d | |||
4e0e3752ba |
|
@ -146,6 +146,7 @@ export function SavedViewsToolbarControls<ViewState>(props: Props<ViewState>) {
|
||||||
data-test-subj="savedViews-openPopover"
|
data-test-subj="savedViews-openPopover"
|
||||||
iconType="arrowDown"
|
iconType="arrowDown"
|
||||||
iconSide="right"
|
iconSide="right"
|
||||||
|
color="text"
|
||||||
>
|
>
|
||||||
{currentView
|
{currentView
|
||||||
? currentView.name
|
? currentView.name
|
||||||
|
|
|
@ -56,17 +56,6 @@ export const BottomDrawer: React.FC<{
|
||||||
{isOpen ? hideHistory : showHistory}
|
{isOpen ? hideHistory : showHistory}
|
||||||
</ShowHideButton>
|
</ShowHideButton>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
<EuiFlexItem
|
|
||||||
grow={false}
|
|
||||||
style={{
|
|
||||||
position: 'relative',
|
|
||||||
minWidth: 400,
|
|
||||||
height: '16px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</EuiFlexItem>
|
|
||||||
<RightSideSpacer />
|
|
||||||
</BottomActionTopBar>
|
</BottomActionTopBar>
|
||||||
<EuiFlexGroup style={{ marginTop: 0 }}>
|
<EuiFlexGroup style={{ marginTop: 0 }}>
|
||||||
<Timeline isVisible={isOpen} interval={interval} yAxisFormatter={formatter} />
|
<Timeline isVisible={isOpen} interval={interval} yAxisFormatter={formatter} />
|
||||||
|
|
|
@ -17,8 +17,13 @@ import { calculateBoundsFromNodes } from '../lib/calculate_bounds_from_nodes';
|
||||||
import { PageContent } from '../../../../components/page';
|
import { PageContent } from '../../../../components/page';
|
||||||
import { useWaffleTimeContext } from '../hooks/use_waffle_time';
|
import { useWaffleTimeContext } from '../hooks/use_waffle_time';
|
||||||
import { useWaffleFiltersContext } from '../hooks/use_waffle_filters';
|
import { useWaffleFiltersContext } from '../hooks/use_waffle_filters';
|
||||||
import { DEFAULT_LEGEND, useWaffleOptionsContext } from '../hooks/use_waffle_options';
|
import {
|
||||||
import { InfraFormatterType } from '../../../../lib/lib';
|
DEFAULT_LEGEND,
|
||||||
|
useWaffleOptionsContext,
|
||||||
|
WaffleLegendOptions,
|
||||||
|
} from '../hooks/use_waffle_options';
|
||||||
|
import { useSourceContext } from '../../../../containers/metrics_source';
|
||||||
|
import { InfraFormatterType, InfraWaffleMapBounds } from '../../../../lib/lib';
|
||||||
import { euiStyled } from '../../../../../../../../src/plugins/kibana_react/common';
|
import { euiStyled } from '../../../../../../../../src/plugins/kibana_react/common';
|
||||||
import { Toolbar } from './toolbars/toolbar';
|
import { Toolbar } from './toolbars/toolbar';
|
||||||
import { ViewSwitcher } from './waffle/view_switcher';
|
import { ViewSwitcher } from './waffle/view_switcher';
|
||||||
|
@ -27,6 +32,7 @@ import { createLegend } from '../lib/create_legend';
|
||||||
import { useWaffleViewState } from '../hooks/use_waffle_view_state';
|
import { useWaffleViewState } from '../hooks/use_waffle_view_state';
|
||||||
import { BottomDrawer } from './bottom_drawer';
|
import { BottomDrawer } from './bottom_drawer';
|
||||||
import { Legend } from './waffle/legend';
|
import { Legend } from './waffle/legend';
|
||||||
|
import { LegendControls } from './waffle/legend_controls';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
shouldLoadDefault: boolean;
|
shouldLoadDefault: boolean;
|
||||||
|
@ -37,6 +43,12 @@ interface Props {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface LegendControlOptions {
|
||||||
|
auto: boolean;
|
||||||
|
bounds: InfraWaffleMapBounds;
|
||||||
|
legend: WaffleLegendOptions;
|
||||||
|
}
|
||||||
|
|
||||||
export const Layout = React.memo(
|
export const Layout = React.memo(
|
||||||
({ shouldLoadDefault, currentView, reload, interval, nodes, loading }: Props) => {
|
({ shouldLoadDefault, currentView, reload, interval, nodes, loading }: Props) => {
|
||||||
const [showLoading, setShowLoading] = useState(true);
|
const [showLoading, setShowLoading] = useState(true);
|
||||||
|
@ -50,6 +62,9 @@ export const Layout = React.memo(
|
||||||
autoBounds,
|
autoBounds,
|
||||||
boundsOverride,
|
boundsOverride,
|
||||||
legend,
|
legend,
|
||||||
|
changeBoundsOverride,
|
||||||
|
changeAutoBounds,
|
||||||
|
changeLegend,
|
||||||
} = useWaffleOptionsContext();
|
} = useWaffleOptionsContext();
|
||||||
const { currentTime, jumpToTime, isAutoReloading } = useWaffleTimeContext();
|
const { currentTime, jumpToTime, isAutoReloading } = useWaffleTimeContext();
|
||||||
const { applyFilterQuery } = useWaffleFiltersContext();
|
const { applyFilterQuery } = useWaffleFiltersContext();
|
||||||
|
@ -115,6 +130,15 @@ export const Layout = React.memo(
|
||||||
setShowLoading(!hasNodes);
|
setShowLoading(!hasNodes);
|
||||||
}, [nodes]);
|
}, [nodes]);
|
||||||
|
|
||||||
|
const handleLegendControlChange = useCallback(
|
||||||
|
(opts: LegendControlOptions) => {
|
||||||
|
changeBoundsOverride(opts.bounds);
|
||||||
|
changeAutoBounds(opts.auto);
|
||||||
|
changeLegend(opts.legend);
|
||||||
|
},
|
||||||
|
[changeBoundsOverride, changeAutoBounds, changeLegend]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageContent>
|
<PageContent>
|
||||||
|
@ -134,6 +158,18 @@ export const Layout = React.memo(
|
||||||
gutterSize="m"
|
gutterSize="m"
|
||||||
>
|
>
|
||||||
<Toolbar nodeType={nodeType} currentTime={currentTime} />
|
<Toolbar nodeType={nodeType} currentTime={currentTime} />
|
||||||
|
{view === 'map' && (
|
||||||
|
<EuiFlexItem grow={false}>
|
||||||
|
<LegendControls
|
||||||
|
options={legend != null ? legend : DEFAULT_LEGEND}
|
||||||
|
dataBounds={dataBounds}
|
||||||
|
bounds={bounds}
|
||||||
|
autoBounds={autoBounds}
|
||||||
|
boundsOverride={boundsOverride}
|
||||||
|
onChange={handleLegendControlChange}
|
||||||
|
/>
|
||||||
|
</EuiFlexItem>
|
||||||
|
)}
|
||||||
<EuiFlexItem grow={false}>
|
<EuiFlexItem grow={false}>
|
||||||
<ViewSwitcher view={view} onChange={changeView} />
|
<ViewSwitcher view={view} onChange={changeView} />
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
|
@ -164,14 +200,7 @@ export const Layout = React.memo(
|
||||||
interval={interval}
|
interval={interval}
|
||||||
formatter={formatter}
|
formatter={formatter}
|
||||||
width={width}
|
width={width}
|
||||||
>
|
/>
|
||||||
<Legend
|
|
||||||
formatter={formatter}
|
|
||||||
bounds={bounds}
|
|
||||||
dataBounds={dataBounds}
|
|
||||||
legend={options.legend}
|
|
||||||
/>
|
|
||||||
</BottomDrawer>
|
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
@ -179,6 +208,14 @@ export const Layout = React.memo(
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</AutoSizer>
|
</AutoSizer>
|
||||||
|
{view === 'map' && (
|
||||||
|
<Legend
|
||||||
|
formatter={formatter}
|
||||||
|
bounds={bounds}
|
||||||
|
dataBounds={dataBounds}
|
||||||
|
legend={options.legend}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</MainContainer>
|
</MainContainer>
|
||||||
)}
|
)}
|
||||||
</AutoSizer>
|
</AutoSizer>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useCallback } from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { euiStyled } from '../../../../../../../../../src/plugins/kibana_react/common';
|
import { euiStyled } from '../../../../../../../../../src/plugins/kibana_react/common';
|
||||||
import {
|
import {
|
||||||
|
@ -17,13 +17,7 @@ import {
|
||||||
GradientLegendRT,
|
GradientLegendRT,
|
||||||
} from '../../../../../lib/lib';
|
} from '../../../../../lib/lib';
|
||||||
import { GradientLegend } from './gradient_legend';
|
import { GradientLegend } from './gradient_legend';
|
||||||
import { LegendControls } from './legend_controls';
|
|
||||||
import { StepLegend } from './steps_legend';
|
import { StepLegend } from './steps_legend';
|
||||||
import {
|
|
||||||
DEFAULT_LEGEND,
|
|
||||||
useWaffleOptionsContext,
|
|
||||||
WaffleLegendOptions,
|
|
||||||
} from '../../hooks/use_waffle_options';
|
|
||||||
import { SteppedGradientLegend } from './stepped_gradient_legend';
|
import { SteppedGradientLegend } from './stepped_gradient_legend';
|
||||||
interface Props {
|
interface Props {
|
||||||
legend: InfraWaffleMapLegend;
|
legend: InfraWaffleMapLegend;
|
||||||
|
@ -32,39 +26,9 @@ interface Props {
|
||||||
formatter: InfraFormatter;
|
formatter: InfraFormatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LegendControlOptions {
|
export const Legend: React.FC<Props> = ({ legend, bounds, formatter }) => {
|
||||||
auto: boolean;
|
|
||||||
bounds: InfraWaffleMapBounds;
|
|
||||||
legend: WaffleLegendOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Legend: React.FC<Props> = ({ dataBounds, legend, bounds, formatter }) => {
|
|
||||||
const {
|
|
||||||
changeBoundsOverride,
|
|
||||||
changeAutoBounds,
|
|
||||||
autoBounds,
|
|
||||||
legend: legendOptions,
|
|
||||||
changeLegend,
|
|
||||||
boundsOverride,
|
|
||||||
} = useWaffleOptionsContext();
|
|
||||||
const handleChange = useCallback(
|
|
||||||
(options: LegendControlOptions) => {
|
|
||||||
changeBoundsOverride(options.bounds);
|
|
||||||
changeAutoBounds(options.auto);
|
|
||||||
changeLegend(options.legend);
|
|
||||||
},
|
|
||||||
[changeBoundsOverride, changeAutoBounds, changeLegend]
|
|
||||||
);
|
|
||||||
return (
|
return (
|
||||||
<LegendContainer>
|
<LegendContainer>
|
||||||
<LegendControls
|
|
||||||
options={legendOptions != null ? legendOptions : DEFAULT_LEGEND}
|
|
||||||
dataBounds={dataBounds}
|
|
||||||
bounds={bounds}
|
|
||||||
autoBounds={autoBounds}
|
|
||||||
boundsOverride={boundsOverride}
|
|
||||||
onChange={handleChange}
|
|
||||||
/>
|
|
||||||
{GradientLegendRT.is(legend) && (
|
{GradientLegendRT.is(legend) && (
|
||||||
<GradientLegend formatter={formatter} legend={legend} bounds={bounds} />
|
<GradientLegend formatter={formatter} legend={legend} bounds={bounds} />
|
||||||
)}
|
)}
|
||||||
|
@ -78,7 +42,7 @@ export const Legend: React.FC<Props> = ({ dataBounds, legend, bounds, formatter
|
||||||
|
|
||||||
const LegendContainer = euiStyled.div`
|
const LegendContainer = euiStyled.div`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0px;
|
top: 0px;
|
||||||
left: 10px;
|
|
||||||
right: 10px;
|
right: 10px;
|
||||||
|
bottom: 0px;
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -26,7 +26,6 @@ import { i18n } from '@kbn/i18n';
|
||||||
import { FormattedMessage } from '@kbn/i18n/react';
|
import { FormattedMessage } from '@kbn/i18n/react';
|
||||||
import React, { SyntheticEvent, useState, useCallback, useEffect } from 'react';
|
import React, { SyntheticEvent, useState, useCallback, useEffect } from 'react';
|
||||||
import { first, last } from 'lodash';
|
import { first, last } from 'lodash';
|
||||||
import { euiStyled } from '../../../../../../../../../src/plugins/kibana_react/common';
|
|
||||||
import { InfraWaffleMapBounds, InventoryColorPalette, PALETTES } from '../../../../../lib/lib';
|
import { InfraWaffleMapBounds, InventoryColorPalette, PALETTES } from '../../../../../lib/lib';
|
||||||
import { WaffleLegendOptions } from '../../hooks/use_waffle_options';
|
import { WaffleLegendOptions } from '../../hooks/use_waffle_options';
|
||||||
import { getColorPalette } from '../../lib/get_color_palette';
|
import { getColorPalette } from '../../lib/get_color_palette';
|
||||||
|
@ -78,8 +77,10 @@ export const LegendControls = ({
|
||||||
|
|
||||||
const buttonComponent = (
|
const buttonComponent = (
|
||||||
<EuiButtonIcon
|
<EuiButtonIcon
|
||||||
iconType="controlsHorizontal"
|
iconType="color"
|
||||||
color="text"
|
color="text"
|
||||||
|
display="base"
|
||||||
|
size="s"
|
||||||
aria-label={i18n.translate('xpack.infra.legendControls.buttonLabel', {
|
aria-label={i18n.translate('xpack.infra.legendControls.buttonLabel', {
|
||||||
defaultMessage: 'configure legend',
|
defaultMessage: 'configure legend',
|
||||||
})}
|
})}
|
||||||
|
@ -179,182 +180,174 @@ export const LegendControls = ({
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ControlContainer>
|
<EuiPopover
|
||||||
<EuiPopover
|
isOpen={isPopoverOpen}
|
||||||
isOpen={isPopoverOpen}
|
closePopover={handleCancelClick}
|
||||||
closePopover={handleCancelClick}
|
id="legendControls"
|
||||||
id="legendControls"
|
button={buttonComponent}
|
||||||
button={buttonComponent}
|
anchorPosition="leftCenter"
|
||||||
>
|
>
|
||||||
<EuiPopoverTitle>Legend Options</EuiPopoverTitle>
|
<EuiPopoverTitle>Legend Options</EuiPopoverTitle>
|
||||||
<EuiForm style={{ minWidth: 400 }}>
|
<EuiForm style={{ minWidth: 400 }}>
|
||||||
<EuiFormRow
|
<EuiFormRow
|
||||||
display="columnCompressed"
|
display="columnCompressed"
|
||||||
label={i18n.translate('xpack.infra.legendControls.colorPaletteLabel', {
|
label={i18n.translate('xpack.infra.legendControls.colorPaletteLabel', {
|
||||||
defaultMessage: 'Color palette',
|
defaultMessage: 'Color palette',
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<>
|
<>
|
||||||
<EuiSelect
|
<EuiSelect
|
||||||
options={PALETTE_OPTIONS}
|
options={PALETTE_OPTIONS}
|
||||||
value={draftLegend.palette}
|
value={draftLegend.palette}
|
||||||
id="palette"
|
id="palette"
|
||||||
onChange={handlePaletteChange}
|
onChange={handlePaletteChange}
|
||||||
compressed
|
compressed
|
||||||
/>
|
/>
|
||||||
<EuiSpacer size="m" />
|
<EuiSpacer size="m" />
|
||||||
<PalettePreview
|
<PalettePreview
|
||||||
palette={draftLegend.palette}
|
palette={draftLegend.palette}
|
||||||
steps={draftLegend.steps}
|
steps={draftLegend.steps}
|
||||||
reverse={draftLegend.reverseColors}
|
reverse={draftLegend.reverseColors}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
</EuiFormRow>
|
</EuiFormRow>
|
||||||
<EuiFormRow
|
<EuiFormRow
|
||||||
display="columnCompressed"
|
display="columnCompressed"
|
||||||
label={i18n.translate('xpack.infra.legendControls.stepsLabel', {
|
label={i18n.translate('xpack.infra.legendControls.stepsLabel', {
|
||||||
defaultMessage: 'Number of colors',
|
defaultMessage: 'Number of colors',
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<EuiRange
|
<EuiRange
|
||||||
id="steps"
|
id="steps"
|
||||||
min={2}
|
min={2}
|
||||||
max={18}
|
max={18}
|
||||||
|
step={1}
|
||||||
|
value={draftLegend.steps}
|
||||||
|
onChange={handleStepsChange}
|
||||||
|
showValue
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</EuiFormRow>
|
||||||
|
<EuiFormRow
|
||||||
|
fullWidth
|
||||||
|
display="columnCompressed"
|
||||||
|
label={i18n.translate('xpack.infra.legendControls.reverseDirectionLabel', {
|
||||||
|
defaultMessage: 'Reverse direction',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<EuiSwitch
|
||||||
|
showLabel={false}
|
||||||
|
name="reverseColors"
|
||||||
|
label="reverseColors"
|
||||||
|
checked={draftLegend.reverseColors}
|
||||||
|
onChange={handleReverseColors}
|
||||||
|
compressed
|
||||||
|
style={{
|
||||||
|
position: 'relative',
|
||||||
|
top: '8px',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</EuiFormRow>
|
||||||
|
<EuiFormRow
|
||||||
|
fullWidth
|
||||||
|
display="columnCompressed"
|
||||||
|
label={i18n.translate('xpack.infra.legendControls.switchLabel', {
|
||||||
|
defaultMessage: 'Auto calculate range',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<EuiSwitch
|
||||||
|
showLabel={false}
|
||||||
|
name="bounds"
|
||||||
|
label="bounds"
|
||||||
|
checked={draftAuto}
|
||||||
|
onChange={handleAutoChange}
|
||||||
|
compressed
|
||||||
|
style={{
|
||||||
|
position: 'relative',
|
||||||
|
top: '8px',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</EuiFormRow>
|
||||||
|
<EuiFormRow
|
||||||
|
fullWidth
|
||||||
|
label={
|
||||||
|
<SwatchLabel
|
||||||
|
color={first(paletteColors)!}
|
||||||
|
label={i18n.translate('xpack.infra.legendControls.minLabel', {
|
||||||
|
defaultMessage: 'Minimum',
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
isInvalid={!boundsValidRange}
|
||||||
|
display="columnCompressed"
|
||||||
|
error={errors}
|
||||||
|
>
|
||||||
|
<div style={{ maxWidth: 150 }}>
|
||||||
|
<EuiFieldNumber
|
||||||
|
disabled={draftAuto}
|
||||||
step={1}
|
step={1}
|
||||||
value={draftLegend.steps}
|
value={isNaN(draftBounds.min) ? '' : draftBounds.min}
|
||||||
onChange={handleStepsChange}
|
isInvalid={!boundsValidRange}
|
||||||
showValue
|
name="legendMin"
|
||||||
fullWidth
|
onChange={handleMinBounds}
|
||||||
/>
|
append="%"
|
||||||
</EuiFormRow>
|
|
||||||
<EuiFormRow
|
|
||||||
fullWidth
|
|
||||||
display="columnCompressed"
|
|
||||||
label={i18n.translate('xpack.infra.legendControls.reverseDirectionLabel', {
|
|
||||||
defaultMessage: 'Reverse direction',
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<EuiSwitch
|
|
||||||
showLabel={false}
|
|
||||||
name="reverseColors"
|
|
||||||
label="reverseColors"
|
|
||||||
checked={draftLegend.reverseColors}
|
|
||||||
onChange={handleReverseColors}
|
|
||||||
compressed
|
compressed
|
||||||
style={{
|
|
||||||
position: 'relative',
|
|
||||||
top: '8px',
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</EuiFormRow>
|
</div>
|
||||||
<EuiFormRow
|
</EuiFormRow>
|
||||||
fullWidth
|
<EuiFormRow
|
||||||
display="columnCompressed"
|
fullWidth
|
||||||
label={i18n.translate('xpack.infra.legendControls.switchLabel', {
|
display="columnCompressed"
|
||||||
defaultMessage: 'Auto calculate range',
|
label={
|
||||||
})}
|
<SwatchLabel
|
||||||
>
|
color={last(paletteColors)!}
|
||||||
<EuiSwitch
|
label={i18n.translate('xpack.infra.legendControls.maxLabel', {
|
||||||
showLabel={false}
|
defaultMessage: 'Maxium',
|
||||||
name="bounds"
|
})}
|
||||||
label="bounds"
|
/>
|
||||||
checked={draftAuto}
|
}
|
||||||
onChange={handleAutoChange}
|
isInvalid={!boundsValidRange}
|
||||||
|
error={errors}
|
||||||
|
>
|
||||||
|
<div style={{ maxWidth: 150 }}>
|
||||||
|
<EuiFieldNumber
|
||||||
|
disabled={draftAuto}
|
||||||
|
step={1}
|
||||||
|
isInvalid={!boundsValidRange}
|
||||||
|
value={isNaN(draftBounds.max) ? '' : draftBounds.max}
|
||||||
|
name="legendMax"
|
||||||
|
onChange={handleMaxBounds}
|
||||||
|
append="%"
|
||||||
compressed
|
compressed
|
||||||
style={{
|
|
||||||
position: 'relative',
|
|
||||||
top: '8px',
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</EuiFormRow>
|
</div>
|
||||||
<EuiFormRow
|
</EuiFormRow>
|
||||||
fullWidth
|
<EuiSpacer size="m" />
|
||||||
label={
|
<EuiFlexGroup justifyContent="flexEnd" responsive={false}>
|
||||||
<SwatchLabel
|
<EuiFlexItem grow={false}>
|
||||||
color={first(paletteColors)!}
|
<EuiButtonEmpty type="submit" size="s" onClick={handleCancelClick}>
|
||||||
label={i18n.translate('xpack.infra.legendControls.minLabel', {
|
<FormattedMessage
|
||||||
defaultMessage: 'Minimum',
|
id="xpack.infra.legendControls.cancelButton"
|
||||||
})}
|
defaultMessage="Cancel"
|
||||||
/>
|
/>
|
||||||
}
|
</EuiButtonEmpty>
|
||||||
isInvalid={!boundsValidRange}
|
</EuiFlexItem>
|
||||||
display="columnCompressed"
|
<EuiFlexItem grow={false}>
|
||||||
error={errors}
|
<EuiButton
|
||||||
>
|
type="submit"
|
||||||
<div style={{ maxWidth: 150 }}>
|
size="s"
|
||||||
<EuiFieldNumber
|
fill
|
||||||
disabled={draftAuto}
|
disabled={commited || !boundsValidRange}
|
||||||
step={1}
|
onClick={handleApplyClick}
|
||||||
value={isNaN(draftBounds.min) ? '' : draftBounds.min}
|
>
|
||||||
isInvalid={!boundsValidRange}
|
<FormattedMessage
|
||||||
name="legendMin"
|
id="xpack.infra.legendControls.applyButton"
|
||||||
onChange={handleMinBounds}
|
defaultMessage="Apply"
|
||||||
append="%"
|
|
||||||
compressed
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</EuiButton>
|
||||||
</EuiFormRow>
|
</EuiFlexItem>
|
||||||
<EuiFormRow
|
</EuiFlexGroup>
|
||||||
fullWidth
|
</EuiForm>
|
||||||
display="columnCompressed"
|
</EuiPopover>
|
||||||
label={
|
|
||||||
<SwatchLabel
|
|
||||||
color={last(paletteColors)!}
|
|
||||||
label={i18n.translate('xpack.infra.legendControls.maxLabel', {
|
|
||||||
defaultMessage: 'Maxium',
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
isInvalid={!boundsValidRange}
|
|
||||||
error={errors}
|
|
||||||
>
|
|
||||||
<div style={{ maxWidth: 150 }}>
|
|
||||||
<EuiFieldNumber
|
|
||||||
disabled={draftAuto}
|
|
||||||
step={1}
|
|
||||||
isInvalid={!boundsValidRange}
|
|
||||||
value={isNaN(draftBounds.max) ? '' : draftBounds.max}
|
|
||||||
name="legendMax"
|
|
||||||
onChange={handleMaxBounds}
|
|
||||||
append="%"
|
|
||||||
compressed
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</EuiFormRow>
|
|
||||||
<EuiSpacer size="m" />
|
|
||||||
<EuiFlexGroup justifyContent="flexEnd" responsive={false}>
|
|
||||||
<EuiFlexItem grow={false}>
|
|
||||||
<EuiButtonEmpty type="submit" size="s" onClick={handleCancelClick}>
|
|
||||||
<FormattedMessage
|
|
||||||
id="xpack.infra.legendControls.cancelButton"
|
|
||||||
defaultMessage="Cancel"
|
|
||||||
/>
|
|
||||||
</EuiButtonEmpty>
|
|
||||||
</EuiFlexItem>
|
|
||||||
<EuiFlexItem grow={false}>
|
|
||||||
<EuiButton
|
|
||||||
type="submit"
|
|
||||||
size="s"
|
|
||||||
fill
|
|
||||||
disabled={commited || !boundsValidRange}
|
|
||||||
onClick={handleApplyClick}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id="xpack.infra.legendControls.applyButton"
|
|
||||||
defaultMessage="Apply"
|
|
||||||
/>
|
|
||||||
</EuiButton>
|
|
||||||
</EuiFlexItem>
|
|
||||||
</EuiFlexGroup>
|
|
||||||
</EuiForm>
|
|
||||||
</EuiPopover>
|
|
||||||
</ControlContainer>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const ControlContainer = euiStyled.div`
|
|
||||||
position: absolute;
|
|
||||||
top: -20px;
|
|
||||||
right: 6px;
|
|
||||||
bottom: 0;
|
|
||||||
`;
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { EuiText } from '@elastic/eui';
|
||||||
import { euiStyled } from '../../../../../../../../../src/plugins/kibana_react/common';
|
import { euiStyled } from '../../../../../../../../../src/plugins/kibana_react/common';
|
||||||
import {
|
import {
|
||||||
InfraWaffleMapBounds,
|
InfraWaffleMapBounds,
|
||||||
|
@ -22,10 +23,7 @@ type TickValue = 0 | 1;
|
||||||
export const SteppedGradientLegend: React.FC<Props> = ({ legend, bounds, formatter }) => {
|
export const SteppedGradientLegend: React.FC<Props> = ({ legend, bounds, formatter }) => {
|
||||||
return (
|
return (
|
||||||
<LegendContainer>
|
<LegendContainer>
|
||||||
<Ticks>
|
<TickLabel value={0} bounds={bounds} formatter={formatter} />
|
||||||
<TickLabel value={0} bounds={bounds} formatter={formatter} />
|
|
||||||
<TickLabel value={1} bounds={bounds} formatter={formatter} />
|
|
||||||
</Ticks>
|
|
||||||
<GradientContainer>
|
<GradientContainer>
|
||||||
{legend.rules.map((rule, index) => (
|
{legend.rules.map((rule, index) => (
|
||||||
<GradientStep
|
<GradientStep
|
||||||
|
@ -34,6 +32,7 @@ export const SteppedGradientLegend: React.FC<Props> = ({ legend, bounds, formatt
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</GradientContainer>
|
</GradientContainer>
|
||||||
|
<TickLabel value={1} bounds={bounds} formatter={formatter} />
|
||||||
</LegendContainer>
|
</LegendContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -46,62 +45,41 @@ interface TickProps {
|
||||||
|
|
||||||
const TickLabel = ({ value, bounds, formatter }: TickProps) => {
|
const TickLabel = ({ value, bounds, formatter }: TickProps) => {
|
||||||
const normalizedValue = value === 0 ? bounds.min : bounds.max * value;
|
const normalizedValue = value === 0 ? bounds.min : bounds.max * value;
|
||||||
const style = { left: `${value * 100}%` };
|
|
||||||
const label = formatter(normalizedValue);
|
const label = formatter(normalizedValue);
|
||||||
return <Tick style={style}>{label}</Tick>;
|
return (
|
||||||
|
<div>
|
||||||
|
<EuiText size="xs">{label}</EuiText>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const GradientStep = euiStyled.div`
|
|
||||||
height: ${(props) => props.theme.eui.paddingSizes.s};
|
|
||||||
flex: 1 1 auto;
|
|
||||||
&:first-child {
|
|
||||||
border-radius: ${(props) => props.theme.eui.euiBorderRadius} 0 0 ${(props) =>
|
|
||||||
props.theme.eui.euiBorderRadius};
|
|
||||||
}
|
|
||||||
&:last-child {
|
|
||||||
border-radius: 0 ${(props) => props.theme.eui.euiBorderRadius} ${(props) =>
|
|
||||||
props.theme.eui.euiBorderRadius} 0;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Ticks = euiStyled.div`
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
top: -18px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Tick = euiStyled.div`
|
|
||||||
position: absolute;
|
|
||||||
font-size: 11px;
|
|
||||||
text-align: center;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
white-space: nowrap;
|
|
||||||
transform: translate(-50%, 0);
|
|
||||||
&:first-child {
|
|
||||||
padding-left: 5px;
|
|
||||||
transform: translate(0, 0);
|
|
||||||
}
|
|
||||||
&:last-child {
|
|
||||||
padding-right: 5px;
|
|
||||||
transform: translate(-100%, 0);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const GradientContainer = euiStyled.div`
|
|
||||||
display: flex;
|
|
||||||
flex-direction; row;
|
|
||||||
align-items: stretch;
|
|
||||||
flex-grow: 1;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const LegendContainer = euiStyled.div`
|
const LegendContainer = euiStyled.div`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
height: 10px;
|
top: 0;
|
||||||
|
right: -16px;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
display: flex;
|
||||||
right: 40px;
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const GradientContainer = euiStyled.div`
|
||||||
|
height: 200px;
|
||||||
|
width: 10px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const GradientStep = euiStyled.div`
|
||||||
|
flex: 1 1 auto;
|
||||||
|
&:first-child {
|
||||||
|
border-radius: ${(props) => props.theme.eui.euiBorderRadius} ${(props) =>
|
||||||
|
props.theme.eui.euiBorderRadius} 0 0;
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
border-radius: 0 0 ${(props) => props.theme.eui.euiBorderRadius} ${(props) =>
|
||||||
|
props.theme.eui.euiBorderRadius};
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -37,8 +37,8 @@ export const ViewSwitcher = ({ view, onChange }: Props) => {
|
||||||
defaultMessage: 'Switch between table and map view',
|
defaultMessage: 'Switch between table and map view',
|
||||||
})}
|
})}
|
||||||
options={buttons}
|
options={buttons}
|
||||||
color="primary"
|
color="text"
|
||||||
buttonSize="m"
|
buttonSize="s"
|
||||||
idSelected={view}
|
idSelected={view}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
isIconOnly
|
isIconOnly
|
||||||
|
|
Loading…
Reference in a new issue