mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Stack Monitoring] Visual refresh changes (#204258)
## Summary This PR introduces changes to `x-pack/plugins/monitoring` necessary for the Visual Refresh project (https://github.com/elastic/kibana/issues/199715): - replacing `euiThemeVars` with `euiTheme` context - replacing old tokens with `euiTheme` - making sure all color palette functions are run within the context of the `EuiProvider` Additionally: - I migrated Sass to `@emotion/react` - I migrated `euiStyled` to `@emotion/react` - I extended `emotion.d.ts` in `tsconfig.json` for typing of the EUI theme closes [#8228](https://github.com/elastic/eui/issues/8228) ### QA We need to test the critical paths in the Stack monitoring, paying close attention to: - [ ] color palette, visibility and contrast ratio of elements in Amsterdam / Borealis Specific paths: - [ ] Monitoring time-series "Zoom out" button hover behavior - `x-pack/plugins/monitoring/public/components/chart/monitoring_timeseries_container.tsx` - [ ] Shard allocation (especially color mapping with shard type and status): - [ ] `x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/assigned.js` - [ ] `x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/shard.js` - [ ] Kuery bar suggestions and autocomplete field: - [ ] `x-pack/plugins/monitoring/public/components/kuery_bar/autocomplete_field.tsx` - [ ] `x-pack/plugins/monitoring/public/components/kuery_bar/suggestion_item.tsx` ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
750ccb10f0
commit
b95211bc50
75 changed files with 1169 additions and 969 deletions
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
@ -2543,7 +2543,6 @@ x-pack/solutions/security/plugins/security_solution/server/lib/security_integrat
|
|||
|
||||
# Observability design
|
||||
/x-pack/platform/plugins/shared/fleet/**/*.scss @elastic/observability-design
|
||||
/x-pack/platform/plugins/private/monitoring/**/*.scss @elastic/observability-design
|
||||
|
||||
# Ent. Search design
|
||||
/x-pack/solutions/search/plugins/enterprise_search/**/*.scss @elastic/search-design
|
||||
|
|
|
@ -99,7 +99,7 @@ export const LogStashNodePipelinesPage: React.FC<ComponentProps> = ({ clusters }
|
|||
{data.pipelines && (
|
||||
<div data-test-subj="logstashPipelinesListing">
|
||||
<PipelineListing
|
||||
className="monitoringLogstashPipelinesTable"
|
||||
data-test-subj="monitoringLogstashPipelinesTable"
|
||||
onBrush={onBrush}
|
||||
zoomInfo={zoomInfo}
|
||||
stats={data.nodeSummary}
|
||||
|
|
|
@ -87,7 +87,7 @@ export const LogStashPipelinesPage: React.FC<ComponentProps> = ({ clusters }) =>
|
|||
const upgradeMessage = pageData ? makeUpgradeMessage(clusterStatus.versions) : null;
|
||||
return (
|
||||
<PipelineListing
|
||||
className="monitoringLogstashPipelinesTable"
|
||||
data-test-subj="monitoringLogstashPipelinesTable"
|
||||
onBrush={(xaxis: any) => onBrush({ xaxis })}
|
||||
stats={clusterStatus}
|
||||
data={pipelines}
|
||||
|
|
|
@ -65,14 +65,12 @@ function getColumns(setupMode: SetupMode, cgroup: unknown) {
|
|||
};
|
||||
|
||||
setupModeStatus = (
|
||||
<div className="monTableCell__setupModeStatus">
|
||||
<SetupModeBadge
|
||||
setupMode={setupMode}
|
||||
status={status}
|
||||
instance={instance}
|
||||
productName={APM_SYSTEM_ID}
|
||||
/>
|
||||
</div>
|
||||
<SetupModeBadge
|
||||
setupMode={setupMode}
|
||||
status={status}
|
||||
instance={instance}
|
||||
productName={APM_SYSTEM_ID}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -187,7 +185,7 @@ export function ApmServerInstances({ apms, setupMode, alerts }: Props) {
|
|||
<EuiPanel>
|
||||
{setupModeCallout}
|
||||
<EuiMonitoringTable
|
||||
className="apmInstancesTable"
|
||||
data-test-subj="apmInstancesTable"
|
||||
rows={data.apms}
|
||||
columns={getColumns(setupMode, data.cgroup)}
|
||||
sorting={sorting}
|
||||
|
|
|
@ -48,14 +48,12 @@ export class Listing extends PureComponent {
|
|||
};
|
||||
|
||||
setupModeStatus = (
|
||||
<div className="monTableCell__setupModeStatus">
|
||||
<SetupModeBadge
|
||||
setupMode={setupMode}
|
||||
status={status}
|
||||
instance={instance}
|
||||
productName={BEATS_SYSTEM_ID}
|
||||
/>
|
||||
</div>
|
||||
<SetupModeBadge
|
||||
setupMode={setupMode}
|
||||
status={status}
|
||||
instance={instance}
|
||||
productName={BEATS_SYSTEM_ID}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -161,7 +159,7 @@ export class Listing extends PureComponent {
|
|||
<EuiPanel>
|
||||
{setupModeCallOut}
|
||||
<EuiMonitoringTable
|
||||
className="beatsTable"
|
||||
data-test-subj="beatsTable"
|
||||
rows={data}
|
||||
setupMode={setupMode}
|
||||
productName={BEATS_SYSTEM_ID}
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
.monRhythmChart__legendItem {
|
||||
font-size: $euiFontSizeXS;
|
||||
cursor: pointer;
|
||||
color: $euiTextColor;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
&-isDisabled {
|
||||
opacity: .5;
|
||||
}
|
||||
}
|
||||
|
||||
.monRhythmChart__legendHorizontal {
|
||||
margin-top: $euiSizeXS;
|
||||
}
|
||||
|
||||
.monRhythmChart__legendLabel {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.monRhythmChart__legendValue {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
margin-left: $euiSizeXS;
|
||||
}
|
|
@ -5,16 +5,71 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { MouseEvent } from 'react';
|
||||
import {
|
||||
EuiFlexItem,
|
||||
EuiFlexGroup,
|
||||
EuiIcon,
|
||||
UseEuiTheme,
|
||||
euiFontSize,
|
||||
logicalCSS,
|
||||
} from '@elastic/eui';
|
||||
import { css } from '@emotion/react';
|
||||
import { includes, isFunction } from 'lodash';
|
||||
import { EuiFlexItem, EuiFlexGroup, EuiIcon } from '@elastic/eui';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import './horizontal_legend.scss';
|
||||
|
||||
export class HorizontalLegend extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
const legendItemStyle = (isDisabled: boolean) => (theme: UseEuiTheme) =>
|
||||
css`
|
||||
display: flex;
|
||||
font-size: ${euiFontSize(theme, 'xs').fontSize};
|
||||
cursor: pointer;
|
||||
color: ${theme.euiTheme.colors.textParagraph};
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
${isDisabled ? 'opacity: 0.5;' : ''}
|
||||
`;
|
||||
|
||||
const legendHorizontalStyle = ({ euiTheme }: UseEuiTheme) => css`
|
||||
${logicalCSS('margin-top', euiTheme.size.xs)}
|
||||
`;
|
||||
|
||||
const legendLabelStyle = css`
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const legendValueStyle = ({ euiTheme }: UseEuiTheme) => css`
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
${logicalCSS('margin-left', euiTheme.size.xs)}
|
||||
`;
|
||||
|
||||
interface Row {
|
||||
id: string;
|
||||
label: string;
|
||||
legend?: boolean;
|
||||
color?: string;
|
||||
tickFormatter?: (arg: number) => number;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
series: Row[];
|
||||
seriesValues: { [key: string]: number };
|
||||
seriesFilter: string[];
|
||||
onToggle: (event: MouseEvent<HTMLButtonElement>, id: string) => void;
|
||||
legendFormatter?: (value: number) => number;
|
||||
tickFormatter?: (value: number) => number;
|
||||
}
|
||||
|
||||
export class HorizontalLegend extends React.Component<Props> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.formatter = this.formatter.bind(this);
|
||||
this.createSeries = this.createSeries.bind(this);
|
||||
}
|
||||
|
@ -22,14 +77,14 @@ export class HorizontalLegend extends React.Component {
|
|||
/**
|
||||
* @param {Number} value Final value to display
|
||||
*/
|
||||
displayValue(value) {
|
||||
return <span className="monRhythmChart__legendValue">{value}</span>;
|
||||
displayValue(value: number) {
|
||||
return <span css={legendValueStyle}>{value}</span>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number} value True if value is falsy and/or not a number
|
||||
*/
|
||||
validValue(value) {
|
||||
validValue(value: number) {
|
||||
return value !== null && value !== undefined && (typeof value === 'string' || !isNaN(value));
|
||||
}
|
||||
|
||||
|
@ -38,7 +93,7 @@ export class HorizontalLegend extends React.Component {
|
|||
* A null means no data for the time bucket and will be formatted as 'N/A'
|
||||
* @param {Object} row Props passed form a parent by row index
|
||||
*/
|
||||
formatter(value, row) {
|
||||
formatter(value: number, row: Row) {
|
||||
if (!this.validValue(value)) {
|
||||
return (
|
||||
<FormattedMessage
|
||||
|
@ -48,7 +103,7 @@ export class HorizontalLegend extends React.Component {
|
|||
);
|
||||
}
|
||||
|
||||
if (row && row.tickFormatter) {
|
||||
if (row?.tickFormatter) {
|
||||
return this.displayValue(row.tickFormatter(value));
|
||||
}
|
||||
|
||||
|
@ -60,12 +115,7 @@ export class HorizontalLegend extends React.Component {
|
|||
return this.displayValue(value);
|
||||
}
|
||||
|
||||
createSeries(row, rowIdx) {
|
||||
const classes = ['monRhythmChart__legendItem'];
|
||||
|
||||
if (!includes(this.props.seriesFilter, row.id)) {
|
||||
classes.push('monRhythmChart__legendItem-isDisabled');
|
||||
}
|
||||
createSeries(row: Row, rowIdx: number) {
|
||||
if (!row.label || row.legend === false) {
|
||||
return <div key={rowIdx} style={{ display: 'none' }} />;
|
||||
}
|
||||
|
@ -73,12 +123,11 @@ export class HorizontalLegend extends React.Component {
|
|||
return (
|
||||
<EuiFlexItem grow={false} key={rowIdx}>
|
||||
<button
|
||||
className={classes.join(' ')}
|
||||
css={legendItemStyle(!includes(this.props.seriesFilter, row.id))}
|
||||
onClick={(event) => this.props.onToggle(event, row.id)}
|
||||
>
|
||||
<span className="monRhythmChart__legendLabel">
|
||||
<span css={legendLabelStyle}>
|
||||
<EuiIcon
|
||||
className="monRhythmChart__legendIndicator"
|
||||
aria-label={i18n.translate(
|
||||
'xpack.monitoring.chart.horizontalLegend.toggleButtonAriaLabel',
|
||||
{ defaultMessage: 'toggle button' }
|
||||
|
@ -87,7 +136,7 @@ export class HorizontalLegend extends React.Component {
|
|||
type="dot"
|
||||
color={row.color}
|
||||
/>
|
||||
{' ' + row.label + ' '}
|
||||
{` ${row.label} `}
|
||||
</span>
|
||||
{this.formatter(this.props.seriesValues[row.id], row)}
|
||||
</button>
|
||||
|
@ -99,8 +148,8 @@ export class HorizontalLegend extends React.Component {
|
|||
const rows = this.props.series.map(this.createSeries);
|
||||
|
||||
return (
|
||||
<div className="monRhythmChart__legendHorizontal">
|
||||
<EuiFlexGroup wrap={true} gutterSize="s" className="monRhythmChart__legendSeries">
|
||||
<div css={legendHorizontalStyle}>
|
||||
<EuiFlexGroup wrap={true} gutterSize="s">
|
||||
{rows}
|
||||
</EuiFlexGroup>
|
||||
</div>
|
|
@ -1,12 +0,0 @@
|
|||
.monChart__tooltipLabel,
|
||||
.monChart__tooltipValue {
|
||||
text-align: left;
|
||||
font-size: $euiFontSizeXS;
|
||||
padding: $euiSizeXS;
|
||||
word-wrap: break-word;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.monChart__tooltipLabel {
|
||||
font-weight: $euiFontWeightBold;
|
||||
}
|
|
@ -6,10 +6,36 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import './info_tooltip.scss';
|
||||
import { css } from '@emotion/react';
|
||||
import { euiFontSize, UseEuiTheme } from '@elastic/eui';
|
||||
|
||||
export function InfoTooltip({ series, bucketSize }) {
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
||||
import { Series } from './types';
|
||||
|
||||
const tooltipLabelStyle = (theme: UseEuiTheme) => css`
|
||||
text-align: left;
|
||||
font-size: ${euiFontSize(theme, 'xs').fontSize};
|
||||
padding: ${theme.euiTheme.size.xs};
|
||||
word-wrap: break-word;
|
||||
white-space: normal;
|
||||
font-weight: ${theme.euiTheme.font.weight.bold};
|
||||
`;
|
||||
|
||||
const tooltipValueStyle = (theme: UseEuiTheme) => css`
|
||||
text-align: left;
|
||||
font-size: ${euiFontSize(theme, 'xs').fontSize};
|
||||
padding: ${theme.euiTheme.size.xs};
|
||||
word-wrap: break-word;
|
||||
white-space: normal;
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
series: Series[];
|
||||
bucketSize?: string;
|
||||
}
|
||||
|
||||
export function InfoTooltip({ series, bucketSize }: Props) {
|
||||
const tableRows = series.map((item, index) => {
|
||||
return (
|
||||
<tr
|
||||
|
@ -19,8 +45,8 @@ export function InfoTooltip({ series, bucketSize }) {
|
|||
data-debug-metric-is-derivative={item.metric.isDerivative}
|
||||
data-debug-metric-has-calculation={item.metric.hasCalculation}
|
||||
>
|
||||
<td className="monChart__tooltipLabel">{item.metric.label}</td>
|
||||
<td className="monChart__tooltipValue">{item.metric.description}</td>
|
||||
<td css={tooltipLabelStyle}>{item.metric.label}</td>
|
||||
<td css={tooltipValueStyle}>{item.metric.description}</td>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
|
@ -29,13 +55,13 @@ export function InfoTooltip({ series, bucketSize }) {
|
|||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="monChart__tooltipLabel">
|
||||
<td css={tooltipLabelStyle}>
|
||||
<FormattedMessage
|
||||
id="xpack.monitoring.chart.infoTooltip.intervalLabel"
|
||||
defaultMessage="Interval"
|
||||
/>
|
||||
</td>
|
||||
<td className="monChart__tooltipValue">{bucketSize}</td>
|
||||
<td css={tooltipValueStyle}>{bucketSize}</td>
|
||||
</tr>
|
||||
{tableRows}
|
||||
</tbody>
|
|
@ -1,8 +0,0 @@
|
|||
.monRhythmChart__wrapper .monRhythmChart__zoom {
|
||||
visibility: hidden;
|
||||
padding-right: $euiSizeM;
|
||||
}
|
||||
|
||||
.monRhythmChart__wrapper:hover .monRhythmChart__zoom {
|
||||
visibility: visible;
|
||||
}
|
|
@ -6,9 +6,8 @@
|
|||
*/
|
||||
|
||||
import React, { Fragment } from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import { get, first } from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import {
|
||||
EuiBadge,
|
||||
EuiIconTip,
|
||||
|
@ -18,7 +17,13 @@ import {
|
|||
EuiScreenReaderOnly,
|
||||
EuiTextAlign,
|
||||
EuiButtonEmpty,
|
||||
UseEuiTheme,
|
||||
logicalCSS,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
||||
import { getTechnicalPreview } from './get_technical_preview';
|
||||
import { getTitle } from './get_title';
|
||||
import { getUnits } from './get_units';
|
||||
|
@ -26,8 +31,18 @@ import { MonitoringTimeseries } from './monitoring_timeseries';
|
|||
import { InfoTooltip } from './info_tooltip';
|
||||
import { AlertsBadge } from '../../alerts/badge';
|
||||
import type { AlertsByName } from '../../alerts/types';
|
||||
import { Series } from './types';
|
||||
|
||||
import './monitoring_timeseries_container.scss';
|
||||
const zoomStyle = ({ euiTheme }: UseEuiTheme) => css`
|
||||
visibility: hidden;
|
||||
${logicalCSS('padding-right', euiTheme.size.m)}
|
||||
`;
|
||||
|
||||
const wrapperStyle = css`
|
||||
&:hover .rhythmChart__zoom {
|
||||
visibility: visible;
|
||||
}
|
||||
`;
|
||||
|
||||
interface ZoomInfo {
|
||||
showZoomOutBtn: () => boolean;
|
||||
|
@ -37,9 +52,7 @@ interface ZoomInfo {
|
|||
interface SeriesAlert {
|
||||
alerts: AlertsByName;
|
||||
}
|
||||
interface Series {
|
||||
metric: { title: string; label: string; description: string };
|
||||
}
|
||||
|
||||
interface Props {
|
||||
series?: Series[] | SeriesAlert;
|
||||
onBrush?: ({ xaxis }: any) => void;
|
||||
|
@ -56,7 +69,7 @@ const zoomOutBtn = (zoomInfo?: ZoomInfo) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<EuiFlexItem className="monRhythmChart__zoom">
|
||||
<EuiFlexItem className="rhythmChart__zoom" css={zoomStyle}>
|
||||
<EuiTextAlign textAlign="right">
|
||||
<EuiButtonEmpty
|
||||
color="primary"
|
||||
|
@ -114,6 +127,7 @@ export function MonitoringTimeseriesContainer({ series, onBrush, zoomInfo }: Pro
|
|||
|
||||
let alertStatus = null;
|
||||
const seriesAlert = isSeriesAlert(series) ? series : undefined;
|
||||
|
||||
if (seriesAlert?.alerts) {
|
||||
alertStatus = (
|
||||
<EuiFlexItem grow={false}>
|
||||
|
@ -123,7 +137,7 @@ export function MonitoringTimeseriesContainer({ series, onBrush, zoomInfo }: Pro
|
|||
}
|
||||
|
||||
return (
|
||||
<EuiFlexGroup direction="column" gutterSize="s" className={`monRhythmChart__wrapper`}>
|
||||
<EuiFlexGroup direction="column" gutterSize="s" css={wrapperStyle}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup alignItems="center" justifyContent="spaceBetween">
|
||||
<EuiFlexItem grow={false}>
|
||||
|
@ -147,7 +161,7 @@ export function MonitoringTimeseriesContainer({ series, onBrush, zoomInfo }: Pro
|
|||
<EuiFlexItem grow={false}>
|
||||
<Fragment>
|
||||
<EuiIconTip
|
||||
anchorClassName="eui-textRight eui-alignMiddle monChart__tooltipTrigger"
|
||||
anchorClassName="eui-textRight eui-alignMiddle"
|
||||
type="iInCircle"
|
||||
position="right"
|
||||
content={<InfoTooltip series={seriesMetrics} bucketSize={bucketSize} />}
|
||||
|
|
|
@ -5,14 +5,50 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { debounce, keys, has, includes, isFunction, difference, assign } from 'lodash';
|
||||
import React from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import { debounce, keys, has, includes, isFunction, difference, assign } from 'lodash';
|
||||
|
||||
import { getLastValue } from './get_last_value';
|
||||
import { TimeseriesContainer } from './timeseries_container';
|
||||
import { HorizontalLegend } from './horizontal_legend';
|
||||
import { getValuesForSeriesIndex, getValuesByX } from './get_values_for_legend';
|
||||
import { DEBOUNCE_SLOW_MS } from '../../../common/constants';
|
||||
import './timeseries_visualization.scss';
|
||||
|
||||
const rhythmChartStyle = css`
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 0 auto;
|
||||
`;
|
||||
|
||||
const rhythmChartContentStyle = css`
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
flex: 1 0 auto;
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
const rhythmChartVisualizationStyle = css`
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 0 auto;
|
||||
|
||||
& > div {
|
||||
min-width: 1px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
div {
|
||||
user-select: none;
|
||||
}
|
||||
`;
|
||||
|
||||
export class TimeseriesVisualization extends React.Component {
|
||||
constructor(props) {
|
||||
|
@ -116,11 +152,6 @@ export class TimeseriesVisualization extends React.Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const className = 'monRhythmChart';
|
||||
const style = {
|
||||
flexDirection: 'column', // for legend position = bottom
|
||||
};
|
||||
|
||||
const legend = this.props.hasLegend ? (
|
||||
<HorizontalLegend
|
||||
seriesFilter={this.state.seriesToShow}
|
||||
|
@ -131,9 +162,9 @@ export class TimeseriesVisualization extends React.Component {
|
|||
) : null;
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<div style={style} className="monRhythmChart__content">
|
||||
<div className="monRhythmChart__visualization">
|
||||
<div css={rhythmChartStyle}>
|
||||
<div css={rhythmChartContentStyle}>
|
||||
<div css={rhythmChartVisualizationStyle}>
|
||||
<TimeseriesContainer
|
||||
seriesToShow={this.state.seriesToShow}
|
||||
updateLegend={this.debouncedUpdateLegend}
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
.monRhythmChart {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
.monRhythmChart__content {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
@mixin monitoringNoUserSelect {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.monRhythmChart__visualization {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 0 auto;
|
||||
position: relative;
|
||||
|
||||
// SASSTODO: generic selector
|
||||
& > div {
|
||||
min-width: 1px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
// SASSTODO: generic selector
|
||||
div {
|
||||
@include monitoringNoUserSelect;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export interface Series {
|
||||
metric: {
|
||||
description: string;
|
||||
field: any;
|
||||
hasCalculation: any;
|
||||
isDerivative: any;
|
||||
label: string;
|
||||
metricAgg: any;
|
||||
title: string;
|
||||
};
|
||||
}
|
|
@ -6,9 +6,9 @@
|
|||
*/
|
||||
|
||||
import React, { Fragment } from 'react';
|
||||
import { Legacy } from '../../../legacy_shims';
|
||||
import moment from 'moment';
|
||||
import numeral from '@elastic/numeral';
|
||||
import { css } from '@emotion/react';
|
||||
import { capitalize, partial } from 'lodash';
|
||||
import {
|
||||
EuiHealth,
|
||||
|
@ -20,17 +20,32 @@ import {
|
|||
EuiSpacer,
|
||||
EuiIcon,
|
||||
EuiToolTip,
|
||||
euiFontSize,
|
||||
} from '@elastic/eui';
|
||||
import { EuiMonitoringTable } from '../../table';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { Legacy } from '../../../legacy_shims';
|
||||
import { EuiMonitoringTable } from '../../table';
|
||||
import { AlertsStatus } from '../../../alerts/status';
|
||||
import { STANDALONE_CLUSTER_CLUSTER_UUID } from '../../../../common/constants';
|
||||
import { getSafeForExternalLink } from '../../../lib/get_safe_for_external_link';
|
||||
import './listing.scss';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import { toMountPoint } from '@kbn/react-kibana-mount';
|
||||
|
||||
const clusterCellExpiredStyle = ({ euiTheme }) => css`
|
||||
color: ${euiTheme.colors.textParagraph};
|
||||
`;
|
||||
|
||||
const clusterCellLicenseStyle = (theme) => css`
|
||||
font-size: ${euiFontSize(theme, 'm').fontSize};
|
||||
`;
|
||||
|
||||
const clusterCellExpirationStyle = ({ euiTheme }) => css`
|
||||
color: ${euiTheme.colors.darkShade};
|
||||
`;
|
||||
|
||||
const IsClusterSupported = ({ isSupported, children }) => {
|
||||
return isSupported ? children : '-';
|
||||
};
|
||||
|
@ -64,7 +79,7 @@ const STANDALONE_CLUSTER_STORAGE_KEY = 'viewedStandaloneCluster';
|
|||
|
||||
const getColumns = (
|
||||
showLicenseExpiration,
|
||||
changeCluster,
|
||||
_changeCluster,
|
||||
handleClickIncompatibleLicense,
|
||||
handleClickInvalidLicense
|
||||
) => {
|
||||
|
@ -193,18 +208,14 @@ const getColumns = (
|
|||
const license = cluster.license;
|
||||
|
||||
if (!licenseType) {
|
||||
return (
|
||||
<div>
|
||||
<div className="monTableCell__clusterCellLicense">N/A</div>
|
||||
</div>
|
||||
);
|
||||
return <div css={clusterCellLicenseStyle}>N/A</div>;
|
||||
}
|
||||
|
||||
if (license) {
|
||||
const licenseExpiry = () => {
|
||||
if (license.expiry_date_in_millis < moment().valueOf()) {
|
||||
// license is expired
|
||||
return <span className="monTableCell__clusterCellExpired">Expired</span>;
|
||||
return <span css={clusterCellExpiredStyle}>Expired</span>;
|
||||
}
|
||||
|
||||
// license is fine
|
||||
|
@ -213,8 +224,8 @@ const getColumns = (
|
|||
|
||||
return (
|
||||
<div>
|
||||
<div className="monTableCell__clusterCellLicense">{capitalize(licenseType)}</div>
|
||||
<div className="monTableCell__clusterCellExpiration">
|
||||
<div css={clusterCellLicenseStyle}>{capitalize(licenseType)}</div>
|
||||
<div css={clusterCellExpirationStyle}>
|
||||
{showLicenseExpiration ? licenseExpiry() : null}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -419,7 +430,7 @@ export const Listing = ({ angular, clusters, sorting, pagination, onTableChange
|
|||
<StandaloneClusterCallout changeCluster={_changeCluster} storage={storage} />
|
||||
) : null}
|
||||
<EuiMonitoringTable
|
||||
className="clusterTable"
|
||||
data-test-subj="clusterTable"
|
||||
rows={clusters}
|
||||
columns={getColumns(
|
||||
showLicenseExpiration,
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* A table that stretches the full window width and columns size appropriately to content.
|
||||
* The .monitoringTable class is on the KuiControlledTable instance.
|
||||
* The table within it requires the shrinkToContent flag as well as width set to 100%
|
||||
*/
|
||||
|
||||
.monTableCell__clusterCellExpired,
|
||||
.monTableCell__offline {
|
||||
color: $euiTextColor;
|
||||
}
|
||||
|
||||
.monTableCell__clusterCellLicense {
|
||||
font-size: $euiFontSize;
|
||||
}
|
||||
|
||||
.monTableCell__clusterCellExpiration {
|
||||
color: $euiColorDarkShade;
|
||||
}
|
||||
|
||||
.monTableCell__name,
|
||||
.monTableCell__status {
|
||||
@include euiFontSizeM;
|
||||
}
|
||||
|
||||
.monTableCell__status {
|
||||
overflow-x: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.monTableCell__transportAddress {
|
||||
@include euiFontSizeS;
|
||||
color: $euiColorDarkShade;
|
||||
}
|
||||
|
||||
.monTableCell__number {
|
||||
@include euiFontSizeL;
|
||||
}
|
||||
|
||||
.monTableCell__splitNumber {
|
||||
@include euiFontSizeM;
|
||||
}
|
|
@ -13,7 +13,6 @@ exports[`Ccr that it renders normally 1`] = `
|
|||
</EuiScreenReaderOnly>
|
||||
<EuiPanel>
|
||||
<EuiInMemoryTable
|
||||
className="monitoringElasticsearchCcrListingTable"
|
||||
columns={
|
||||
Array [
|
||||
Object {
|
||||
|
@ -57,6 +56,19 @@ exports[`Ccr that it renders normally 1`] = `
|
|||
},
|
||||
]
|
||||
}
|
||||
css={
|
||||
Object {
|
||||
"map": undefined,
|
||||
"name": "f6xtqm",
|
||||
"next": undefined,
|
||||
"styles": "
|
||||
.euiTableRow-isExpandedRow > .euiTableRowCell > .euiTableCellContent {
|
||||
padding: 0;
|
||||
}
|
||||
",
|
||||
"toString": [Function],
|
||||
}
|
||||
}
|
||||
executeQueryOptions={
|
||||
Object {
|
||||
"defaultFields": Array [
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
import React, { Fragment, useState } from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import {
|
||||
EuiInMemoryTable,
|
||||
EuiLink,
|
||||
|
@ -17,11 +18,22 @@ import {
|
|||
EuiTextColor,
|
||||
EuiScreenReaderOnly,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { getSafeForExternalLink } from '../../../lib/get_safe_for_external_link';
|
||||
import { AlertsStatus } from '../../../alerts/status';
|
||||
import './ccr.scss';
|
||||
|
||||
/**
|
||||
* We want the collapsed table (that shows the shard data) to be inline
|
||||
* with the columns from the main table so we need to remove the padding
|
||||
*/
|
||||
const ccrListingTableStyle = css`
|
||||
.euiTableRow-isExpandedRow > .euiTableRowCell > .euiTableCellContent {
|
||||
padding: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
function toSeconds(ms) {
|
||||
return Math.floor(ms / 1000) + 's';
|
||||
|
@ -194,7 +206,7 @@ export const Ccr = (props) => {
|
|||
|
||||
return (
|
||||
<EuiInMemoryTable
|
||||
className="monitoringElasticsearchCcrListingTable"
|
||||
css={ccrListingTableStyle}
|
||||
columns={[
|
||||
{
|
||||
field: 'index',
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
/**
|
||||
* [1] - We want the collapsed table (that shows the shard data) to be inline
|
||||
* with the columns from the main table so we need to remove the padding
|
||||
*/
|
||||
.monitoringElasticsearchCcrListingTable .euiTableRow-isExpandedRow > .euiTableRowCell > .euiTableCellContent {
|
||||
padding: 0; /* [1] */
|
||||
}
|
|
@ -7,12 +7,7 @@
|
|||
|
||||
import React from 'react';
|
||||
import { capitalize } from 'lodash';
|
||||
import { LARGE_FLOAT, LARGE_BYTES, LARGE_ABBREVIATED } from '../../../../common/formatting';
|
||||
import { formatMetric } from '../../../lib/format_number';
|
||||
import { getSafeForExternalLink } from '../../../lib/get_safe_for_external_link';
|
||||
import { ElasticsearchStatusIcon } from '../status_icon';
|
||||
import { ClusterStatus } from '../cluster_status';
|
||||
import { EuiMonitoringTable } from '../../table';
|
||||
import { css } from '@emotion/react';
|
||||
import {
|
||||
EuiLink,
|
||||
EuiPage,
|
||||
|
@ -22,10 +17,22 @@ import {
|
|||
EuiSpacer,
|
||||
EuiScreenReaderOnly,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
||||
import { AlertsStatus } from '../../../alerts/status';
|
||||
import './indices.scss';
|
||||
import { ClusterStatus } from '../cluster_status';
|
||||
import { ElasticsearchStatusIcon } from '../status_icon';
|
||||
import { EuiMonitoringTable } from '../../table';
|
||||
import { LARGE_FLOAT, LARGE_BYTES, LARGE_ABBREVIATED } from '../../../../common/formatting';
|
||||
import { formatMetric } from '../../../lib/format_number';
|
||||
import { getSafeForExternalLink } from '../../../lib/get_safe_for_external_link';
|
||||
|
||||
const statusStyle = css`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const getColumns = (alerts) => {
|
||||
return [
|
||||
|
@ -70,7 +77,7 @@ const getColumns = (alerts) => {
|
|||
field: 'status',
|
||||
sortable: true,
|
||||
render: (value) => (
|
||||
<div className="monElasticsearchIndicesTable__status" title={`Index status: ${value}`}>
|
||||
<div css={statusStyle} title={`Index status: ${value}`}>
|
||||
<ElasticsearchStatusIcon status={value} />
|
||||
|
||||
{capitalize(value)}
|
||||
|
@ -183,7 +190,7 @@ export const ElasticsearchIndices = ({
|
|||
/>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiMonitoringTable
|
||||
className="elasticsearchIndicesTable"
|
||||
data-test-subj="elasticsearchIndicesTable"
|
||||
rows={indices}
|
||||
columns={getColumns(alerts)}
|
||||
sorting={sorting}
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
.monElasticsearchIndicesTable__status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
|
@ -53,7 +53,7 @@ export const ElasticsearchMLJobs = ({
|
|||
<EuiSpacer size="m" />
|
||||
<EuiPanel>
|
||||
<EuiMonitoringTable
|
||||
className="mlJobsTable"
|
||||
data-test-subj="mlJobsTable"
|
||||
rows={jobs}
|
||||
columns={columns}
|
||||
sorting={{
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Node Listing Metric Cell should format N/A as the metric for an offline node 1`] = `
|
||||
<div
|
||||
class="monTableCell__offline"
|
||||
>
|
||||
<div>
|
||||
N/A
|
||||
</div>
|
||||
`;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import React, { useState } from 'react';
|
||||
import { get } from 'lodash';
|
||||
import { formatMetric } from '../../../lib/format_number';
|
||||
import { css } from '@emotion/react';
|
||||
import {
|
||||
EuiText,
|
||||
EuiPopover,
|
||||
|
@ -17,8 +17,15 @@ import {
|
|||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { formatMetric } from '../../../lib/format_number';
|
||||
|
||||
const offlineStyle = ({ euiTheme }) => css`
|
||||
color: ${euiTheme.colors.textParagraph};
|
||||
`;
|
||||
|
||||
const TRENDING_DOWN = i18n.translate('xpack.monitoring.elasticsearch.node.cells.trendingDownText', {
|
||||
defaultMessage: 'down',
|
||||
});
|
||||
|
@ -27,7 +34,7 @@ const TRENDING_UP = i18n.translate('xpack.monitoring.elasticsearch.node.cells.tr
|
|||
});
|
||||
|
||||
function OfflineCell() {
|
||||
return <div className="monTableCell__offline">N/A</div>;
|
||||
return <div css={offlineStyle}>N/A</div>;
|
||||
}
|
||||
|
||||
const getDirection = (slope) => {
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { Fragment } from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import { get } from 'lodash';
|
||||
import {
|
||||
EuiBadge,
|
||||
EuiBadgeGroup,
|
||||
|
@ -20,11 +23,12 @@ import {
|
|||
EuiSpacer,
|
||||
EuiText,
|
||||
EuiToolTip,
|
||||
euiFontSize,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { get } from 'lodash';
|
||||
import React, { Fragment } from 'react';
|
||||
|
||||
import { ELASTICSEARCH_SYSTEM_ID } from '../../../../common/constants';
|
||||
import { SetupModeFeature } from '../../../../common/enums';
|
||||
import { AlertsStatus } from '../../../alerts/status';
|
||||
|
@ -37,6 +41,15 @@ import { EuiMonitoringSSPTable } from '../../table';
|
|||
import { ClusterStatus } from '../cluster_status';
|
||||
import { MetricCell, OfflineCell } from './cells';
|
||||
|
||||
const tableCellNameStyle = (theme) => css`
|
||||
${euiFontSize(theme, 'm')}
|
||||
`;
|
||||
|
||||
const tableCellTransportAddressStyle = (theme) => css`
|
||||
${euiFontSize(theme, 's')}
|
||||
color: ${theme.euiTheme.colors.darkShade};
|
||||
`;
|
||||
|
||||
const getNodeTooltip = (node) => {
|
||||
const { nodeTypeLabel, nodeTypeClass } = node;
|
||||
|
||||
|
@ -97,15 +110,13 @@ const getColumns = (showCgroupMetricsElasticsearch, setupMode, clusterUuid, aler
|
|||
};
|
||||
|
||||
setupModeStatus = (
|
||||
<div className="monTableCell__setupModeStatus">
|
||||
<SetupModeBadge
|
||||
setupMode={setupMode}
|
||||
status={status}
|
||||
instance={instance}
|
||||
productName={ELASTICSEARCH_SYSTEM_ID}
|
||||
clusterUuid={clusterUuid}
|
||||
/>
|
||||
</div>
|
||||
<SetupModeBadge
|
||||
setupMode={setupMode}
|
||||
status={status}
|
||||
instance={instance}
|
||||
productName={ELASTICSEARCH_SYSTEM_ID}
|
||||
clusterUuid={clusterUuid}
|
||||
/>
|
||||
);
|
||||
if (status.isNetNewUser) {
|
||||
nameLink = value;
|
||||
|
@ -114,13 +125,13 @@ const getColumns = (showCgroupMetricsElasticsearch, setupMode, clusterUuid, aler
|
|||
|
||||
return (
|
||||
<div>
|
||||
<div className="monTableCell__name">
|
||||
<div css={tableCellNameStyle}>
|
||||
<EuiText size="m">
|
||||
{getNodeTooltip(node)}
|
||||
<span data-test-subj="name">{nameLink}</span>
|
||||
</EuiText>
|
||||
</div>
|
||||
<div className="monTableCell__transportAddress">{extractIp(node.transport_address)}</div>
|
||||
<div css={tableCellTransportAddressStyle}>{extractIp(node.transport_address)}</div>
|
||||
{setupModeStatus}
|
||||
</div>
|
||||
);
|
||||
|
@ -502,7 +513,7 @@ export function ElasticsearchNodes({ clusterStatus, showCgroupMetricsElasticsear
|
|||
{setupModeCallout}
|
||||
<EuiPanel>
|
||||
<EuiMonitoringSSPTable
|
||||
className="elasticsearchNodesTable"
|
||||
data-test-subj="elasticsearchNodesTable"
|
||||
rows={nodes}
|
||||
columns={columns}
|
||||
sorting={sorting}
|
||||
|
|
|
@ -139,7 +139,7 @@ export const ShardActivity = (props) => {
|
|||
/>
|
||||
<EuiSpacer />
|
||||
<EuiMonitoringTable
|
||||
className="esShardActivityTable"
|
||||
data-test-subj="esShardActivityTable"
|
||||
rows={rows}
|
||||
columns={columns}
|
||||
message={getNoDataMessage()}
|
||||
|
|
|
@ -5,13 +5,67 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { get, sortBy } from 'lodash';
|
||||
import React from 'react';
|
||||
import { get, sortBy } from 'lodash';
|
||||
import { css } from '@emotion/react';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiLink, euiFontSize, logicalCSS } from '@elastic/eui';
|
||||
|
||||
import { Shard } from './shard';
|
||||
import { calculateClass } from '../lib/calculate_class';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiLink } from '@elastic/eui';
|
||||
import { getSafeForExternalLink } from '../../../../lib/get_safe_for_external_link';
|
||||
|
||||
const assignedChildrenStyle = ({ euiTheme }) => css`
|
||||
${logicalCSS('padding-top', euiTheme.size.l)}
|
||||
`;
|
||||
|
||||
const childTitleStyle = (theme) => css`
|
||||
${logicalCSS('padding', `${theme.euiTheme.size.l} ${theme.euiTheme.size.s}`)}
|
||||
text-align: center;
|
||||
font-size: ${euiFontSize(theme, 'xs').fontSize};
|
||||
color: ${theme.euiTheme.colors.ghost};
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const shardStyle = (theme) => css`
|
||||
align-self: center;
|
||||
${logicalCSS('padding', `${theme.euiTheme.size.xs} ${theme.euiTheme.size.s}`)}
|
||||
font-size: ${euiFontSize(theme, 'xs').fontSize};
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
`;
|
||||
|
||||
const childStyle = (data, shardStats) => (theme) =>
|
||||
css`
|
||||
float: left;
|
||||
align-self: center;
|
||||
background-color: ${theme.euiTheme.colors.lightestShade};
|
||||
margin: ${theme.euiTheme.size.s};
|
||||
border: 1px solid ${theme.euiTheme.colors.mediumShade};
|
||||
border-radius: ${theme.euiTheme.size.xs};
|
||||
${logicalCSS('padding', `calc(${theme.euiTheme.size.xs} / 2) 0`)}
|
||||
|
||||
${data.type === 'index' &&
|
||||
logicalCSS(
|
||||
'border-left',
|
||||
`${theme.euiTheme.size.xs} solid ${theme.euiTheme.colors.borderStrongSuccess}`
|
||||
)}
|
||||
|
||||
${shardStats?.status === 'red' &&
|
||||
logicalCSS(
|
||||
'border-left',
|
||||
`${theme.euiTheme.size.xs} solid ${theme.euiTheme.colors.borderStrongDanger}`
|
||||
)}
|
||||
|
||||
${shardStats?.status === 'yellow' &&
|
||||
logicalCSS(
|
||||
'border-left',
|
||||
`${theme.euiTheme.size.xs} solid ${theme.euiTheme.colors.borderStrongWarning}`
|
||||
)}
|
||||
|
||||
${data.type === 'shard' && shardStyle(theme)}
|
||||
`;
|
||||
|
||||
const generateQueryAndLink = (data) => {
|
||||
let type = 'indices';
|
||||
let ident = data.name;
|
||||
|
@ -46,21 +100,7 @@ export class Assigned extends React.Component {
|
|||
|
||||
createChild = (data) => {
|
||||
const key = data.id;
|
||||
const initialClasses = ['monChild'];
|
||||
if (data.type === 'index') {
|
||||
initialClasses.push('monChild--index');
|
||||
}
|
||||
const shardStats = get(this.props.shardStats.indices, key);
|
||||
if (shardStats) {
|
||||
switch (shardStats.status) {
|
||||
case 'red':
|
||||
initialClasses.push('monChild--danger');
|
||||
break;
|
||||
case 'yellow':
|
||||
initialClasses.push('monChild--warning');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: redesign for shard allocation
|
||||
const name = <EuiLink href={generateQueryAndLink(data)}>{data.name}</EuiLink>;
|
||||
|
@ -71,13 +111,13 @@ export class Assigned extends React.Component {
|
|||
return (
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
className={calculateClass(data, initialClasses.join(' '))}
|
||||
css={childStyle(data, shardStats)}
|
||||
key={key}
|
||||
data-test-subj={`clusterView-Assigned-${key}`}
|
||||
data-status={shardStats && shardStats.status}
|
||||
data-status={shardStats?.status}
|
||||
>
|
||||
<EuiFlexGroup gutterSize="xs">
|
||||
<EuiFlexItem grow={false} className="monChild__title eui-textNoWrap">
|
||||
<EuiFlexItem css={childTitleStyle} grow={false} className="eui-textNoWrap">
|
||||
<EuiFlexGroup gutterSize="xs">
|
||||
<EuiFlexItem grow={false}>{name}</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>{master}</EuiFlexItem>
|
||||
|
@ -93,9 +133,10 @@ export class Assigned extends React.Component {
|
|||
|
||||
render() {
|
||||
const data = sortBy(this.props.data, sortByName).map(this.createChild);
|
||||
|
||||
return (
|
||||
<td className="monAssigned">
|
||||
<EuiFlexGroup wrap className="monAssigned__children">
|
||||
<td>
|
||||
<EuiFlexGroup wrap css={assignedChildrenStyle}>
|
||||
{data}
|
||||
</EuiFlexGroup>
|
||||
</td>
|
||||
|
|
|
@ -6,11 +6,22 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import { get } from 'lodash';
|
||||
import { EuiToolTip, EuiBadge, euiFontSize, logicalCSS } from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { calculateClass } from '../lib/calculate_class';
|
||||
import { vents } from '../lib/vents';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiToolTip, EuiBadge } from '@elastic/eui';
|
||||
|
||||
const shardStyle = (theme) => css`
|
||||
${logicalCSS('padding', `${theme.euiTheme.size.xs} ${theme.euiTheme.size.s}`)}
|
||||
align-self: center;
|
||||
font-size: ${euiFontSize(theme, 'xs').fontSize};
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
`;
|
||||
|
||||
function getColor(classes) {
|
||||
const classList = classes.split(' ');
|
||||
|
@ -117,6 +128,7 @@ export class Shard extends React.Component {
|
|||
<div
|
||||
onMouseEnter={this.toggle}
|
||||
onMouseLeave={this.toggle}
|
||||
css={shard.type === 'shard' && shardStyle}
|
||||
className={classes}
|
||||
data-shard-tooltip={tooltipContent}
|
||||
data-shard-classification={classification}
|
||||
|
|
|
@ -5,18 +5,28 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { sortBy } from 'lodash';
|
||||
import React from 'react';
|
||||
import { Shard } from './shard';
|
||||
import { sortBy } from 'lodash';
|
||||
import { css } from '@emotion/react';
|
||||
import { EuiFlexGroup, logicalCSS } from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiFlexGroup } from '@elastic/eui';
|
||||
|
||||
import { Shard } from './shard';
|
||||
|
||||
export const unassignedStyle = ({ euiTheme }) => css`
|
||||
vertical-align: middle;
|
||||
width: calc(${euiTheme.size.l} * 10);
|
||||
`;
|
||||
|
||||
export const unassignedChildrenStyle = ({ euiTheme }) => css`
|
||||
${logicalCSS('padding-top', euiTheme.size.l)}
|
||||
`;
|
||||
|
||||
export class Unassigned extends React.Component {
|
||||
static displayName = i18n.translate(
|
||||
'xpack.monitoring.elasticsearch.shardAllocation.unassignedDisplayName',
|
||||
{
|
||||
defaultMessage: 'Unassigned',
|
||||
}
|
||||
{ defaultMessage: 'Unassigned' }
|
||||
);
|
||||
|
||||
createShard = (shard) => {
|
||||
|
@ -33,14 +43,16 @@ export class Unassigned extends React.Component {
|
|||
'.' +
|
||||
shard.shard +
|
||||
additionId;
|
||||
|
||||
return <Shard shard={shard} key={key} />;
|
||||
};
|
||||
|
||||
render() {
|
||||
const shards = sortBy(this.props.shards, 'shard').map(this.createShard);
|
||||
|
||||
return (
|
||||
<td className="monUnassigned" data-test-subj="clusterView-Unassigned">
|
||||
<EuiFlexGroup wrap className="monUnassigned__children">
|
||||
<td css={unassignedStyle} data-test-subj="clusterView-Unassigned">
|
||||
<EuiFlexGroup wrap css={unassignedChildrenStyle}>
|
||||
{shards}
|
||||
</EuiFlexGroup>
|
||||
</td>
|
||||
|
|
|
@ -6,12 +6,24 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import { EuiTitle, EuiBadge, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import './shard_allocation.scss';
|
||||
|
||||
import { ClusterView } from './components/cluster_view';
|
||||
|
||||
const clusterStyle = ({ euiTheme }) => css`
|
||||
th {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
td:first-child {
|
||||
width: calc(${euiTheme.base} * 12.5);
|
||||
}
|
||||
`;
|
||||
|
||||
export const ShardAllocation = (props) => {
|
||||
const types = [
|
||||
{
|
||||
|
@ -59,7 +71,7 @@ export const ShardAllocation = (props) => {
|
|||
];
|
||||
|
||||
return (
|
||||
<div className="monCluster">
|
||||
<div css={clusterStyle}>
|
||||
<EuiTitle>
|
||||
<h1>
|
||||
<FormattedMessage
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
.monClusterTitle {
|
||||
font-size: $euiFontSizeL;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
// SASSTODO: This needs a full rewrite / redesign
|
||||
.monCluster {
|
||||
.monUnassigned {
|
||||
vertical-align: middle;
|
||||
width: $euiSize * 10;
|
||||
}
|
||||
|
||||
.monUnassigned__children,
|
||||
.monAssigned__children {
|
||||
padding-top: $euiSizeL;
|
||||
}
|
||||
|
||||
.monChild {
|
||||
float: left;
|
||||
align-self: center;
|
||||
background-color: $euiColorLightestShade;
|
||||
margin: $euiSizeS;
|
||||
border: 1px solid $euiColorMediumShade;
|
||||
border-radius: $euiSizeXS;
|
||||
padding: calc($euiSizeXS / 2) 0;
|
||||
|
||||
&.monChild--index {
|
||||
border-left: $euiSizeXS solid $euiColorSuccess;
|
||||
|
||||
&.monChild--danger {
|
||||
border-left: $euiSizeXS solid $euiColorDanger;
|
||||
}
|
||||
|
||||
&.monChild--warning {
|
||||
border-left: $euiSizeXS solid $euiColorWarning;
|
||||
}
|
||||
}
|
||||
|
||||
.monChild__title {
|
||||
padding: $euiSizeXS $euiSizeS;
|
||||
text-align: center;
|
||||
font-size: $euiFontSizeXS;
|
||||
color: $euiColorGhost;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&.monClusterUnassigned {
|
||||
.title {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
td:first-child {
|
||||
width: $euiSize * 12.5;
|
||||
}
|
||||
|
||||
.monShard {
|
||||
align-self: center;
|
||||
padding: $euiSizeXS $euiSizeS;
|
||||
font-size: $euiFontSizeXS;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
|
@ -5,10 +5,13 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { EuiBadge, EuiLink, EuiStat, EuiToolTip } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { css } from '@emotion/react';
|
||||
import { EuiBadge, EuiLink, EuiStat, euiTextTruncate, EuiToolTip } from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import type { AlertsByName } from '../../../alerts/types';
|
||||
import { ExternalConfigContext } from '../../../application/contexts/external_config_context';
|
||||
import { formatMetric } from '../../../lib/format_number';
|
||||
|
@ -16,6 +19,12 @@ import { getSafeForExternalLink } from '../../../lib/get_safe_for_external_link'
|
|||
import { DefaultStatusIndicator, SummaryStatus } from '../../summary_status';
|
||||
import { KibanaStatusIcon } from '../status_icon';
|
||||
|
||||
const summaryStatusNoWrapStatStyle = css`
|
||||
p {
|
||||
${euiTextTruncate()}
|
||||
}
|
||||
`;
|
||||
|
||||
interface ClusterStatusProps {
|
||||
stats: {
|
||||
concurrent_connections: number;
|
||||
|
@ -159,7 +168,7 @@ function OverviewPageStatusIndicator({ staleMessage }: IndicatorProps) {
|
|||
title={title}
|
||||
titleSize="xxxs"
|
||||
textAlign="left"
|
||||
className="monSummaryStatusNoWrap__stat"
|
||||
css={summaryStatusNoWrapStatStyle}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -187,7 +196,7 @@ function InstancesPageStatusIndicator({ staleMessage }: IndicatorProps) {
|
|||
title={title}
|
||||
titleSize="xxxs"
|
||||
textAlign="left"
|
||||
className="monSummaryStatusNoWrap__stat"
|
||||
css={summaryStatusNoWrapStatStyle}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,17 +5,26 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { EuiBadge, EuiStat, EuiToolTip } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { capitalize } from 'lodash';
|
||||
import { css } from '@emotion/react';
|
||||
import { EuiBadge, EuiStat, EuiToolTip, euiTextTruncate } from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { useUiSetting } from '@kbn/kibana-react-plugin/public';
|
||||
import { capitalize } from 'lodash';
|
||||
import React from 'react';
|
||||
|
||||
import { ExternalConfigContext } from '../../../application/contexts/external_config_context';
|
||||
import { formatMetric } from '../../../lib/format_number';
|
||||
import { DefaultStatusIndicator, SummaryStatus } from '../../summary_status';
|
||||
import { formatLastSeenTimestamp } from '../format_last_seen_timestamp';
|
||||
import { KibanaStatusIcon } from '../status_icon';
|
||||
|
||||
const summaryStatusNoWrapStatStyle = css`
|
||||
p {
|
||||
${euiTextTruncate()}
|
||||
}
|
||||
`;
|
||||
|
||||
export function DetailStatus({ stats }) {
|
||||
const {
|
||||
transport_address: transportAddress,
|
||||
|
@ -77,12 +86,12 @@ export function DetailStatus({ stats }) {
|
|||
|
||||
return (
|
||||
<EuiStat
|
||||
css={summaryStatusNoWrapStatStyle}
|
||||
data-test-subj="status"
|
||||
description={description}
|
||||
textAlign="left"
|
||||
title={title}
|
||||
titleSize="xxxs"
|
||||
textAlign="left"
|
||||
className="monSummaryStatusNoWrap__stat"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { Fragment } from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import { capitalize, get } from 'lodash';
|
||||
import {
|
||||
EuiCallOut,
|
||||
EuiHealth,
|
||||
|
@ -16,12 +19,14 @@ import {
|
|||
EuiScreenReaderOnly,
|
||||
EuiSpacer,
|
||||
EuiToolTip,
|
||||
UseEuiTheme,
|
||||
euiFontSize,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { useUiSetting } from '@kbn/kibana-react-plugin/public';
|
||||
import { capitalize, get } from 'lodash';
|
||||
import React, { Fragment } from 'react';
|
||||
|
||||
import type { TableChange, Sorting, Pagination } from '../../../application/hooks/use_table';
|
||||
import type { AlertsByName } from '../../../alerts/types';
|
||||
import { KIBANA_SYSTEM_ID } from '../../../../common/constants';
|
||||
|
@ -40,6 +45,10 @@ import { ClusterStatus } from '../cluster_status';
|
|||
import { formatLastSeenTimestamp } from '../format_last_seen_timestamp';
|
||||
import type { SetupMode } from '../../setup_mode/types';
|
||||
|
||||
const tableCellSplitNumber = (theme: UseEuiTheme) => css`
|
||||
font-size: ${euiFontSize(theme, 'm').fontSize};
|
||||
`;
|
||||
|
||||
const getColumns = (
|
||||
setupMode: SetupMode,
|
||||
alerts: AlertsByName,
|
||||
|
@ -64,14 +73,12 @@ const getColumns = (
|
|||
};
|
||||
|
||||
setupModeStatus = (
|
||||
<div className="monTableCell__setupModeStatus">
|
||||
<SetupModeBadge
|
||||
setupMode={setupMode}
|
||||
status={status}
|
||||
instance={instance}
|
||||
productName={KIBANA_SYSTEM_ID}
|
||||
/>
|
||||
</div>
|
||||
<SetupModeBadge
|
||||
setupMode={setupMode}
|
||||
status={status}
|
||||
instance={instance}
|
||||
productName={KIBANA_SYSTEM_ID}
|
||||
/>
|
||||
);
|
||||
if (status.isNetNewUser) {
|
||||
return (
|
||||
|
@ -188,10 +195,8 @@ const getColumns = (
|
|||
|
||||
return (
|
||||
<div>
|
||||
<div className="monTableCell__splitNumber">
|
||||
{formatNumber(value, 'int_commas') + ' ms avg'}
|
||||
</div>
|
||||
<div className="monTableCell__splitNumber">
|
||||
<div css={tableCellSplitNumber}>{formatNumber(value, 'int_commas') + ' ms avg'}</div>
|
||||
<div css={tableCellSplitNumber}>
|
||||
{formatNumber(kibana?.response_times?.max, 'int_commas')} ms max
|
||||
</div>
|
||||
</div>
|
||||
|
@ -319,7 +324,7 @@ export const KibanaInstances: React.FC<Props> = (props: Props) => {
|
|||
{setupModeCallOut}
|
||||
<EuiPanel>
|
||||
<EuiMonitoringTable
|
||||
className="kibanaInstancesTable"
|
||||
data-test-subj="kibanaInstancesTable"
|
||||
rows={dataFlattened}
|
||||
columns={getColumns(setupMode, alerts, dateFormat, staleStatusThresholdSeconds)}
|
||||
sorting={sorting}
|
||||
|
|
|
@ -5,11 +5,18 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { EuiFieldSearch, EuiOutsideClickDetector, EuiPanel } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import {
|
||||
EuiFieldSearch,
|
||||
EuiOutsideClickDetector,
|
||||
EuiPanel,
|
||||
logicalCSS,
|
||||
UseEuiTheme,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { QuerySuggestion } from '@kbn/unified-search-plugin/public';
|
||||
import { euiStyled } from '@kbn/kibana-react-plugin/common';
|
||||
import { euiThemeVars } from '@kbn/ui-theme';
|
||||
|
||||
import { composeStateUpdaters } from '../../lib/typed_react';
|
||||
import { SuggestionItem } from './suggestion_item';
|
||||
|
||||
|
@ -59,7 +66,7 @@ export class AutocompleteField extends React.Component<
|
|||
|
||||
return (
|
||||
<EuiOutsideClickDetector onOutsideClick={this.handleBlur}>
|
||||
<AutocompleteContainer>
|
||||
<div css={autocompleteContainerCss}>
|
||||
<EuiFieldSearch
|
||||
fullWidth
|
||||
disabled={disabled}
|
||||
|
@ -76,7 +83,7 @@ export class AutocompleteField extends React.Component<
|
|||
aria-label={ariaLabel}
|
||||
/>
|
||||
{areSuggestionsVisible && !isLoadingSuggestions && suggestions.length > 0 ? (
|
||||
<SuggestionsPanel>
|
||||
<EuiPanel css={suggestionsPanelCss} paddingSize="none" hasShadow>
|
||||
{suggestions.map((suggestion, suggestionIndex) => (
|
||||
<SuggestionItem
|
||||
key={suggestion.text}
|
||||
|
@ -86,9 +93,9 @@ export class AutocompleteField extends React.Component<
|
|||
onClick={this.applySuggestionAt(suggestionIndex)}
|
||||
/>
|
||||
))}
|
||||
</SuggestionsPanel>
|
||||
</EuiPanel>
|
||||
) : null}
|
||||
</AutocompleteContainer>
|
||||
</div>
|
||||
</EuiOutsideClickDetector>
|
||||
);
|
||||
}
|
||||
|
@ -299,19 +306,16 @@ const withUnfocused = (state: AutocompleteFieldState) => ({
|
|||
isFocused: false,
|
||||
});
|
||||
|
||||
const AutocompleteContainer = euiStyled.div`
|
||||
const autocompleteContainerCss = css`
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
const SuggestionsPanel = euiStyled(EuiPanel).attrs(() => ({
|
||||
paddingSize: 'none',
|
||||
hasShadow: true,
|
||||
}))`
|
||||
const suggestionsPanelCss = ({ euiTheme }: UseEuiTheme) => css`
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
margin-top: 2px;
|
||||
${logicalCSS('margin-top', euiTheme.size.xxs)}
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
z-index: ${euiThemeVars.euiZLevel1};
|
||||
z-index: ${euiTheme.levels.maskBelowHeader};
|
||||
max-height: 322px;
|
||||
`;
|
||||
|
|
|
@ -5,11 +5,12 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { EuiIcon } from '@elastic/eui';
|
||||
import { transparentize } from 'polished';
|
||||
import React from 'react';
|
||||
import { EuiIcon, UseEuiTheme, euiFontSize } from '@elastic/eui';
|
||||
import { css } from '@emotion/react';
|
||||
import { transparentize } from 'polished';
|
||||
|
||||
import { QuerySuggestion, QuerySuggestionTypes } from '@kbn/unified-search-plugin/public';
|
||||
import { euiStyled } from '@kbn/kibana-react-plugin/common';
|
||||
|
||||
interface Props {
|
||||
isSelected?: boolean;
|
||||
|
@ -18,69 +19,74 @@ interface Props {
|
|||
suggestion: QuerySuggestion;
|
||||
}
|
||||
|
||||
export const SuggestionItem: React.FC<Props> = (props) => {
|
||||
const { isSelected, onClick, onMouseEnter, suggestion } = props;
|
||||
|
||||
export const SuggestionItem: React.FC<Props> = ({
|
||||
isSelected = false,
|
||||
onClick,
|
||||
onMouseEnter,
|
||||
suggestion,
|
||||
}) => {
|
||||
return (
|
||||
<SuggestionItemContainer isSelected={isSelected} onClick={onClick} onMouseEnter={onMouseEnter}>
|
||||
<SuggestionItemIconField suggestionType={suggestion.type}>
|
||||
// TODO: should be focusable and have relevant key events; try using an existing component from EUI
|
||||
// eslint-disable-next-line jsx-a11y/click-events-have-key-events
|
||||
<div
|
||||
css={suggestionItemContainerStyle(isSelected)}
|
||||
onClick={onClick}
|
||||
onMouseEnter={onMouseEnter}
|
||||
>
|
||||
<div css={suggestionItemIconFieldStyle(suggestion.type)}>
|
||||
<EuiIcon type={getEuiIconType(suggestion.type)} />
|
||||
</SuggestionItemIconField>
|
||||
<SuggestionItemTextField>{suggestion.text}</SuggestionItemTextField>
|
||||
<SuggestionItemDescriptionField>{suggestion.description}</SuggestionItemDescriptionField>
|
||||
</SuggestionItemContainer>
|
||||
</div>
|
||||
<div css={suggestionItemTextFieldStyle}>{suggestion.text}</div>
|
||||
<div css={suggestionItemDescriptionFieldStyle}>{suggestion.description}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
SuggestionItem.defaultProps = {
|
||||
isSelected: false,
|
||||
};
|
||||
const suggestionItemContainerStyle = (isSelected?: boolean) => (theme: UseEuiTheme) =>
|
||||
css`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
font-size: ${euiFontSize(theme, 's').fontSize};
|
||||
height: ${theme.euiTheme.size.xl};
|
||||
white-space: nowrap;
|
||||
background-color: ${isSelected ? theme.euiTheme.colors.lightestShade : 'transparent'};
|
||||
`;
|
||||
|
||||
const SuggestionItemContainer = euiStyled.div<{
|
||||
isSelected?: boolean;
|
||||
}>`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
font-size: ${(props) => props.theme.eui.euiFontSizeS};
|
||||
height: ${(props) => props.theme.eui.euiSizeXL};
|
||||
white-space: nowrap;
|
||||
background-color: ${(props) =>
|
||||
props.isSelected ? props.theme.eui.euiColorLightestShade : 'transparent'};
|
||||
`;
|
||||
|
||||
const SuggestionItemField = euiStyled.div`
|
||||
const suggestionItemFieldStyle = ({ euiTheme }: UseEuiTheme) => css`
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: ${(props) => props.theme.eui.euiSizeXL};
|
||||
padding: ${(props) => props.theme.eui.euiSizeXS};
|
||||
height: ${euiTheme.size.xl};
|
||||
padding: ${euiTheme.size.xs};
|
||||
`;
|
||||
|
||||
const SuggestionItemIconField = euiStyled(SuggestionItemField)<{
|
||||
suggestionType: QuerySuggestionTypes;
|
||||
}>`
|
||||
background-color: ${(props) =>
|
||||
transparentize(0.9, getEuiIconColor(props.theme, props.suggestionType))};
|
||||
color: ${(props) => getEuiIconColor(props.theme, props.suggestionType)};
|
||||
flex: 0 0 auto;
|
||||
justify-content: center;
|
||||
width: ${(props) => props.theme.eui.euiSizeXL};
|
||||
`;
|
||||
const suggestionItemIconFieldStyle =
|
||||
(suggestionType: QuerySuggestionTypes) => (theme: UseEuiTheme) =>
|
||||
css`
|
||||
${suggestionItemFieldStyle(theme)};
|
||||
background-color: ${transparentize(0.9, getEuiIconColor(theme, suggestionType))};
|
||||
color: ${getEuiIconColor(theme, suggestionType)};
|
||||
flex: 0 0 auto;
|
||||
justify-content: center;
|
||||
width: ${theme.euiTheme.size.xl};
|
||||
`;
|
||||
|
||||
const SuggestionItemTextField = euiStyled(SuggestionItemField)`
|
||||
const suggestionItemTextFieldStyle = (theme: UseEuiTheme) => css`
|
||||
${suggestionItemFieldStyle(theme)};
|
||||
flex: 2 0 0;
|
||||
font-family: ${(props) => props.theme.eui.euiCodeFontFamily};
|
||||
font-family: ${theme.euiTheme.font.familyCode};
|
||||
`;
|
||||
|
||||
const SuggestionItemDescriptionField = euiStyled(SuggestionItemField)`
|
||||
const suggestionItemDescriptionFieldStyle = (theme: UseEuiTheme) => css`
|
||||
${suggestionItemFieldStyle(theme)};
|
||||
flex: 3 0 0;
|
||||
|
||||
p {
|
||||
display: inline;
|
||||
|
||||
span {
|
||||
font-family: ${(props) => props.theme.eui.euiCodeFontFamily};
|
||||
font-family: ${theme.euiTheme.font.familyCode};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
@ -102,18 +108,21 @@ const getEuiIconType = (suggestionType: QuerySuggestionTypes) => {
|
|||
}
|
||||
};
|
||||
|
||||
const getEuiIconColor = (theme: any, suggestionType: QuerySuggestionTypes): string => {
|
||||
const getEuiIconColor = (
|
||||
{ euiTheme }: UseEuiTheme,
|
||||
suggestionType: QuerySuggestionTypes
|
||||
): string => {
|
||||
switch (suggestionType) {
|
||||
case QuerySuggestionTypes.Field:
|
||||
return theme?.eui.euiColorVis7;
|
||||
return euiTheme.colors.vis.euiColorVis7;
|
||||
case QuerySuggestionTypes.Value:
|
||||
return theme?.eui.euiColorVis0;
|
||||
return euiTheme.colors.vis.euiColorVis0;
|
||||
case QuerySuggestionTypes.Operator:
|
||||
return theme?.eui.euiColorVis1;
|
||||
return euiTheme.colors.vis.euiColorVis1;
|
||||
case QuerySuggestionTypes.Conjunction:
|
||||
return theme?.eui.euiColorVis2;
|
||||
return euiTheme.colors.vis.euiColorVis2;
|
||||
case QuerySuggestionTypes.RecentSearch:
|
||||
default:
|
||||
return theme?.eui.euiColorMediumShade;
|
||||
return euiTheme.colors.mediumShade;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
exports[`Listing should render with certain data pieces missing 1`] = `
|
||||
<EuiMonitoringTable
|
||||
className="logstashNodesTable"
|
||||
columns={
|
||||
Array [
|
||||
Object {
|
||||
|
@ -55,6 +54,7 @@ exports[`Listing should render with certain data pieces missing 1`] = `
|
|||
},
|
||||
]
|
||||
}
|
||||
data-test-subj="logstashNodesTable"
|
||||
executeQueryOptions={
|
||||
Object {
|
||||
"defaultFields": Array [
|
||||
|
@ -104,7 +104,6 @@ exports[`Listing should render with certain data pieces missing 1`] = `
|
|||
|
||||
exports[`Listing should render with expected props 1`] = `
|
||||
<EuiMonitoringTable
|
||||
className="logstashNodesTable"
|
||||
columns={
|
||||
Array [
|
||||
Object {
|
||||
|
@ -157,6 +156,7 @@ exports[`Listing should render with expected props 1`] = `
|
|||
},
|
||||
]
|
||||
}
|
||||
data-test-subj="logstashNodesTable"
|
||||
executeQueryOptions={
|
||||
Object {
|
||||
"defaultFields": Array [
|
||||
|
|
|
@ -52,14 +52,12 @@ export class Listing extends PureComponent {
|
|||
};
|
||||
|
||||
setupModeStatus = (
|
||||
<div className="monTableCell__setupModeStatus">
|
||||
<SetupModeBadge
|
||||
setupMode={setupMode}
|
||||
status={status}
|
||||
instance={instance}
|
||||
productName={LOGSTASH_SYSTEM_ID}
|
||||
/>
|
||||
</div>
|
||||
<SetupModeBadge
|
||||
setupMode={setupMode}
|
||||
status={status}
|
||||
instance={instance}
|
||||
productName={LOGSTASH_SYSTEM_ID}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -202,7 +200,7 @@ export class Listing extends PureComponent {
|
|||
{setupModeCallOut}
|
||||
<EuiPanel>
|
||||
<EuiMonitoringTable
|
||||
className="logstashNodesTable"
|
||||
data-test-subj="logstashNodesTable"
|
||||
rows={flattenedData}
|
||||
setupMode={setupMode}
|
||||
productName={LOGSTASH_SYSTEM_ID}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import React, { Component } from 'react';
|
||||
import moment from 'moment';
|
||||
import { css } from '@emotion/react';
|
||||
import { partialRight } from 'lodash';
|
||||
import {
|
||||
EuiPage,
|
||||
|
@ -17,15 +18,22 @@ import {
|
|||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiScreenReaderOnly,
|
||||
euiFontSize,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
||||
import { formatMetric } from '../../../lib/format_number';
|
||||
import { ClusterStatus } from '../cluster_status';
|
||||
import { Sparkline } from '../../sparkline';
|
||||
import { EuiMonitoringSSPTable } from '../../table';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { getSafeForExternalLink } from '../../../lib/get_safe_for_external_link';
|
||||
|
||||
const tableCellNumberStyle = (theme) => css`
|
||||
font-size: ${euiFontSize(theme, 'l').fontSize};
|
||||
`;
|
||||
|
||||
export class PipelineListing extends Component {
|
||||
tooltipXValueFormatter(xValue, dateFormat) {
|
||||
return moment(xValue).format(dateFormat);
|
||||
|
@ -76,7 +84,7 @@ export class PipelineListing extends Component {
|
|||
options={{ xaxis: throughput.timeRange }}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem className="monTableCell__number" data-test-subj="eventsEmittedRate">
|
||||
<EuiFlexItem css={tableCellNumberStyle} data-test-subj="eventsEmittedRate">
|
||||
{formatMetric(value, '0.[0]a', throughput.metric.units)}
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
@ -108,7 +116,7 @@ export class PipelineListing extends Component {
|
|||
options={{ xaxis: nodesCount.timeRange }}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem className="monTableCell__number" data-test-subj="nodeCount">
|
||||
<EuiFlexItem css={tableCellNumberStyle} data-test-subj="nodeCount">
|
||||
{formatMetric(value, '0a')}
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
@ -128,8 +136,7 @@ export class PipelineListing extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { data, sorting, pagination, onTableChange, upgradeMessage, className, ...props } =
|
||||
this.props;
|
||||
const { data, sorting, pagination, onTableChange, upgradeMessage, ...props } = this.props;
|
||||
|
||||
const sortingOptions = sorting || { field: 'id', direction: 'asc' };
|
||||
if (sortingOptions.field === 'name') {
|
||||
|
@ -152,7 +159,7 @@ export class PipelineListing extends Component {
|
|||
<EuiSpacer size="m" />
|
||||
<EuiPanel>
|
||||
<EuiMonitoringSSPTable
|
||||
className={className || 'logstashNodesTable'}
|
||||
data-test-subj={this.props['data-test-subj'] || 'logstashNodesTable'}
|
||||
rows={data}
|
||||
columns={columns}
|
||||
sorting={sortingOptions}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
exports[`CollapsibleStatement component renders child components 1`] = `
|
||||
<EuiFlexGroup
|
||||
alignItems="center"
|
||||
className="monPipelineViewer__collapsibleStatement"
|
||||
css={[Function]}
|
||||
gutterSize="none"
|
||||
responsive={false}
|
||||
>
|
||||
|
|
|
@ -13,9 +13,7 @@ exports[`DetailDrawer component If vertices shows basic info and no stats for if
|
|||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiIcon
|
||||
className="lspvDetailDrawerIcon"
|
||||
/>
|
||||
<EuiIcon />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle>
|
||||
|
@ -66,9 +64,7 @@ exports[`DetailDrawer component Plugin vertices Plugin does not have explicit ID
|
|||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiIcon
|
||||
className="lspvDetailDrawerIcon"
|
||||
/>
|
||||
<EuiIcon />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle>
|
||||
|
@ -114,7 +110,17 @@ exports[`DetailDrawer component Plugin vertices Plugin does not have explicit ID
|
|||
</EuiTableRowCell>
|
||||
<EuiTableRowCell>
|
||||
<div
|
||||
className="lspvDetailDrawerSparklineContainer"
|
||||
css={
|
||||
Object {
|
||||
"map": undefined,
|
||||
"name": "b37u90",
|
||||
"next": undefined,
|
||||
"styles": "
|
||||
width: 7vw;
|
||||
",
|
||||
"toString": [Function],
|
||||
}
|
||||
}
|
||||
>
|
||||
<Sparkline
|
||||
options={
|
||||
|
@ -162,7 +168,17 @@ exports[`DetailDrawer component Plugin vertices Plugin does not have explicit ID
|
|||
</EuiTableRowCell>
|
||||
<EuiTableRowCell>
|
||||
<div
|
||||
className="lspvDetailDrawerSparklineContainer"
|
||||
css={
|
||||
Object {
|
||||
"map": undefined,
|
||||
"name": "b37u90",
|
||||
"next": undefined,
|
||||
"styles": "
|
||||
width: 7vw;
|
||||
",
|
||||
"toString": [Function],
|
||||
}
|
||||
}
|
||||
>
|
||||
<Sparkline
|
||||
options={
|
||||
|
@ -210,7 +226,17 @@ exports[`DetailDrawer component Plugin vertices Plugin does not have explicit ID
|
|||
</EuiTableRowCell>
|
||||
<EuiTableRowCell>
|
||||
<div
|
||||
className="lspvDetailDrawerSparklineContainer"
|
||||
css={
|
||||
Object {
|
||||
"map": undefined,
|
||||
"name": "b37u90",
|
||||
"next": undefined,
|
||||
"styles": "
|
||||
width: 7vw;
|
||||
",
|
||||
"toString": [Function],
|
||||
}
|
||||
}
|
||||
>
|
||||
<Sparkline
|
||||
options={
|
||||
|
@ -258,7 +284,17 @@ exports[`DetailDrawer component Plugin vertices Plugin does not have explicit ID
|
|||
</EuiTableRowCell>
|
||||
<EuiTableRowCell>
|
||||
<div
|
||||
className="lspvDetailDrawerSparklineContainer"
|
||||
css={
|
||||
Object {
|
||||
"map": undefined,
|
||||
"name": "b37u90",
|
||||
"next": undefined,
|
||||
"styles": "
|
||||
width: 7vw;
|
||||
",
|
||||
"toString": [Function],
|
||||
}
|
||||
}
|
||||
>
|
||||
<Sparkline
|
||||
options={
|
||||
|
@ -315,9 +351,7 @@ exports[`DetailDrawer component Plugin vertices Plugin has explicit ID shows bas
|
|||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiIcon
|
||||
className="lspvDetailDrawerIcon"
|
||||
/>
|
||||
<EuiIcon />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle>
|
||||
|
@ -357,7 +391,17 @@ exports[`DetailDrawer component Plugin vertices Plugin has explicit ID shows bas
|
|||
</EuiTableRowCell>
|
||||
<EuiTableRowCell>
|
||||
<div
|
||||
className="lspvDetailDrawerSparklineContainer"
|
||||
css={
|
||||
Object {
|
||||
"map": undefined,
|
||||
"name": "b37u90",
|
||||
"next": undefined,
|
||||
"styles": "
|
||||
width: 7vw;
|
||||
",
|
||||
"toString": [Function],
|
||||
}
|
||||
}
|
||||
>
|
||||
<Sparkline
|
||||
options={
|
||||
|
@ -405,7 +449,17 @@ exports[`DetailDrawer component Plugin vertices Plugin has explicit ID shows bas
|
|||
</EuiTableRowCell>
|
||||
<EuiTableRowCell>
|
||||
<div
|
||||
className="lspvDetailDrawerSparklineContainer"
|
||||
css={
|
||||
Object {
|
||||
"map": undefined,
|
||||
"name": "b37u90",
|
||||
"next": undefined,
|
||||
"styles": "
|
||||
width: 7vw;
|
||||
",
|
||||
"toString": [Function],
|
||||
}
|
||||
}
|
||||
>
|
||||
<Sparkline
|
||||
options={
|
||||
|
@ -453,7 +507,17 @@ exports[`DetailDrawer component Plugin vertices Plugin has explicit ID shows bas
|
|||
</EuiTableRowCell>
|
||||
<EuiTableRowCell>
|
||||
<div
|
||||
className="lspvDetailDrawerSparklineContainer"
|
||||
css={
|
||||
Object {
|
||||
"map": undefined,
|
||||
"name": "b37u90",
|
||||
"next": undefined,
|
||||
"styles": "
|
||||
width: 7vw;
|
||||
",
|
||||
"toString": [Function],
|
||||
}
|
||||
}
|
||||
>
|
||||
<Sparkline
|
||||
options={
|
||||
|
@ -501,7 +565,17 @@ exports[`DetailDrawer component Plugin vertices Plugin has explicit ID shows bas
|
|||
</EuiTableRowCell>
|
||||
<EuiTableRowCell>
|
||||
<div
|
||||
className="lspvDetailDrawerSparklineContainer"
|
||||
css={
|
||||
Object {
|
||||
"map": undefined,
|
||||
"name": "b37u90",
|
||||
"next": undefined,
|
||||
"styles": "
|
||||
width: 7vw;
|
||||
",
|
||||
"toString": [Function],
|
||||
}
|
||||
}
|
||||
>
|
||||
<Sparkline
|
||||
options={
|
||||
|
@ -558,9 +632,7 @@ exports[`DetailDrawer component Queue vertices shows basic info and no stats for
|
|||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiIcon
|
||||
className="lspvDetailDrawerIcon"
|
||||
/>
|
||||
<EuiIcon />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle>
|
||||
|
@ -603,9 +675,7 @@ exports[`DetailDrawer component shows vertex title 1`] = `
|
|||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiIcon
|
||||
className="lspvDetailDrawerIcon"
|
||||
/>
|
||||
<EuiIcon />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle>
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
exports[`Metric component does not render warning badge when no warning present 1`] = `
|
||||
<EuiFlexItem
|
||||
className="monPipelineViewer__metricFlexItem"
|
||||
css={[Function]}
|
||||
grow={false}
|
||||
>
|
||||
<EuiText
|
||||
className="monPipelineViewer__metric metricClass"
|
||||
color="subdued"
|
||||
css={[Function]}
|
||||
size="s"
|
||||
>
|
||||
<span>
|
||||
|
@ -19,11 +19,10 @@ exports[`Metric component does not render warning badge when no warning present
|
|||
|
||||
exports[`Metric component renders warning badge 1`] = `
|
||||
<EuiFlexItem
|
||||
className="monPipelineViewer__metricFlexItem"
|
||||
css={[Function]}
|
||||
grow={false}
|
||||
>
|
||||
<EuiBadge
|
||||
className="metricClass"
|
||||
color="warning"
|
||||
>
|
||||
220
|
||||
|
|
|
@ -13,7 +13,7 @@ exports[`PipelineViewer component passes expected props 1`] = `
|
|||
</EuiScreenReaderOnly>
|
||||
<EuiPageSection
|
||||
alignment="center"
|
||||
className="monPipelineViewer"
|
||||
data-test-subj="pipeline-viewer"
|
||||
>
|
||||
<StatementSection
|
||||
elements={
|
||||
|
@ -88,7 +88,7 @@ exports[`PipelineViewer component renders DetailDrawer when selected vertex is n
|
|||
</EuiScreenReaderOnly>
|
||||
<EuiPageSection
|
||||
alignment="center"
|
||||
className="monPipelineViewer"
|
||||
data-test-subj="pipeline-viewer"
|
||||
>
|
||||
<StatementSection
|
||||
elements={
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
exports[`PluginStatement component adds warning highlight for cpu time 1`] = `
|
||||
<EuiFlexGroup
|
||||
alignItems="center"
|
||||
className="monPipelineViewer__pluginStatement"
|
||||
css={[Function]}
|
||||
gutterSize="none"
|
||||
justifyContent="spaceBetween"
|
||||
>
|
||||
|
@ -20,8 +20,8 @@ exports[`PluginStatement component adds warning highlight for cpu time 1`] = `
|
|||
>
|
||||
<EuiButtonEmpty
|
||||
aria-label="mutate"
|
||||
className="monPipelineViewer__plugin"
|
||||
color="primary"
|
||||
css={[Function]}
|
||||
flush="left"
|
||||
iconType="dot"
|
||||
onClick={[Function]}
|
||||
|
@ -51,20 +51,20 @@ exports[`PluginStatement component adds warning highlight for cpu time 1`] = `
|
|||
gutterSize="s"
|
||||
>
|
||||
<Metric
|
||||
className="monPipelineViewer__metric--cpuTime"
|
||||
key="cpuMetric"
|
||||
type="cpuTime"
|
||||
value="25%"
|
||||
warning={true}
|
||||
/>
|
||||
<Metric
|
||||
className="monPipelineViewer__metric--eventMillis"
|
||||
key="eventMillis"
|
||||
type="eventMillis"
|
||||
value="100 ms/e"
|
||||
warning={false}
|
||||
/>
|
||||
<Metric
|
||||
className="monPipelineViewer__metric--events"
|
||||
key="eventsReceived"
|
||||
type="events"
|
||||
value="120 e/s received"
|
||||
/>
|
||||
</EuiFlexGroup>
|
||||
|
@ -75,7 +75,7 @@ exports[`PluginStatement component adds warning highlight for cpu time 1`] = `
|
|||
exports[`PluginStatement component adds warning highlight for event millis 1`] = `
|
||||
<EuiFlexGroup
|
||||
alignItems="center"
|
||||
className="monPipelineViewer__pluginStatement"
|
||||
css={[Function]}
|
||||
gutterSize="none"
|
||||
justifyContent="spaceBetween"
|
||||
>
|
||||
|
@ -92,8 +92,8 @@ exports[`PluginStatement component adds warning highlight for event millis 1`] =
|
|||
>
|
||||
<EuiButtonEmpty
|
||||
aria-label="mutate"
|
||||
className="monPipelineViewer__plugin"
|
||||
color="primary"
|
||||
css={[Function]}
|
||||
flush="left"
|
||||
iconType="dot"
|
||||
onClick={[Function]}
|
||||
|
@ -123,20 +123,20 @@ exports[`PluginStatement component adds warning highlight for event millis 1`] =
|
|||
gutterSize="s"
|
||||
>
|
||||
<Metric
|
||||
className="monPipelineViewer__metric--cpuTime"
|
||||
key="cpuMetric"
|
||||
type="cpuTime"
|
||||
value="25%"
|
||||
warning={false}
|
||||
/>
|
||||
<Metric
|
||||
className="monPipelineViewer__metric--eventMillis"
|
||||
key="eventMillis"
|
||||
type="eventMillis"
|
||||
value="100 ms/e"
|
||||
warning={true}
|
||||
/>
|
||||
<Metric
|
||||
className="monPipelineViewer__metric--events"
|
||||
key="eventsReceived"
|
||||
type="events"
|
||||
value="120 e/s received"
|
||||
/>
|
||||
</EuiFlexGroup>
|
||||
|
@ -147,7 +147,7 @@ exports[`PluginStatement component adds warning highlight for event millis 1`] =
|
|||
exports[`PluginStatement component does not render explicit id field if no id is specified 1`] = `
|
||||
<EuiFlexGroup
|
||||
alignItems="center"
|
||||
className="monPipelineViewer__pluginStatement"
|
||||
css={[Function]}
|
||||
gutterSize="none"
|
||||
justifyContent="spaceBetween"
|
||||
>
|
||||
|
@ -164,8 +164,8 @@ exports[`PluginStatement component does not render explicit id field if no id is
|
|||
>
|
||||
<EuiButtonEmpty
|
||||
aria-label="stdin"
|
||||
className="monPipelineViewer__plugin"
|
||||
color="primary"
|
||||
css={[Function]}
|
||||
flush="left"
|
||||
iconType="dot"
|
||||
onClick={[Function]}
|
||||
|
@ -185,8 +185,8 @@ exports[`PluginStatement component does not render explicit id field if no id is
|
|||
gutterSize="s"
|
||||
>
|
||||
<Metric
|
||||
className="monPipelineViewer__metric--eventsEmitted"
|
||||
key="eventsEmitted"
|
||||
type="eventsEmitted"
|
||||
value="125 e/s emitted"
|
||||
/>
|
||||
</EuiFlexGroup>
|
||||
|
@ -197,7 +197,7 @@ exports[`PluginStatement component does not render explicit id field if no id is
|
|||
exports[`PluginStatement component renders input metrics and explicit id fields 1`] = `
|
||||
<EuiFlexGroup
|
||||
alignItems="center"
|
||||
className="monPipelineViewer__pluginStatement"
|
||||
css={[Function]}
|
||||
gutterSize="none"
|
||||
justifyContent="spaceBetween"
|
||||
>
|
||||
|
@ -214,8 +214,8 @@ exports[`PluginStatement component renders input metrics and explicit id fields
|
|||
>
|
||||
<EuiButtonEmpty
|
||||
aria-label="stdin"
|
||||
className="monPipelineViewer__plugin"
|
||||
color="primary"
|
||||
css={[Function]}
|
||||
flush="left"
|
||||
iconType="dot"
|
||||
onClick={[Function]}
|
||||
|
@ -245,8 +245,8 @@ exports[`PluginStatement component renders input metrics and explicit id fields
|
|||
gutterSize="s"
|
||||
>
|
||||
<Metric
|
||||
className="monPipelineViewer__metric--eventsEmitted"
|
||||
key="eventsEmitted"
|
||||
type="eventsEmitted"
|
||||
value="125 e/s emitted"
|
||||
/>
|
||||
</EuiFlexGroup>
|
||||
|
@ -257,7 +257,7 @@ exports[`PluginStatement component renders input metrics and explicit id fields
|
|||
exports[`PluginStatement component renders processor statement metrics 1`] = `
|
||||
<EuiFlexGroup
|
||||
alignItems="center"
|
||||
className="monPipelineViewer__pluginStatement"
|
||||
css={[Function]}
|
||||
gutterSize="none"
|
||||
justifyContent="spaceBetween"
|
||||
>
|
||||
|
@ -274,8 +274,8 @@ exports[`PluginStatement component renders processor statement metrics 1`] = `
|
|||
>
|
||||
<EuiButtonEmpty
|
||||
aria-label="mutate"
|
||||
className="monPipelineViewer__plugin"
|
||||
color="primary"
|
||||
css={[Function]}
|
||||
flush="left"
|
||||
iconType="dot"
|
||||
onClick={[Function]}
|
||||
|
@ -305,20 +305,20 @@ exports[`PluginStatement component renders processor statement metrics 1`] = `
|
|||
gutterSize="s"
|
||||
>
|
||||
<Metric
|
||||
className="monPipelineViewer__metric--cpuTime"
|
||||
key="cpuMetric"
|
||||
type="cpuTime"
|
||||
value="25%"
|
||||
warning={false}
|
||||
/>
|
||||
<Metric
|
||||
className="monPipelineViewer__metric--eventMillis"
|
||||
key="eventMillis"
|
||||
type="eventMillis"
|
||||
value="100 ms/e"
|
||||
warning={false}
|
||||
/>
|
||||
<Metric
|
||||
className="monPipelineViewer__metric--events"
|
||||
key="eventsReceived"
|
||||
type="events"
|
||||
value="120 e/s received"
|
||||
/>
|
||||
</EuiFlexGroup>
|
||||
|
|
|
@ -10,7 +10,7 @@ exports[`Queue component renders default elements 1`] = `
|
|||
size="s"
|
||||
/>
|
||||
<EuiText
|
||||
className="monPipelineViewer__queueMessage"
|
||||
css={[Function]}
|
||||
>
|
||||
<MemoizedFormattedMessage
|
||||
defaultMessage="Queue metrics not available"
|
||||
|
|
|
@ -5,7 +5,7 @@ exports[`Statement component renders a CollapsibleStatement with else body for n
|
|||
className="monPipelineViewer__listItem"
|
||||
>
|
||||
<div
|
||||
className="monPipelineViewer__spaceContainer"
|
||||
css={[Function]}
|
||||
/>
|
||||
<CollapsibleStatement
|
||||
collapse={[MockFunction]}
|
||||
|
@ -25,7 +25,7 @@ exports[`Statement component renders a CollapsibleStatement with else body for n
|
|||
size="xs"
|
||||
>
|
||||
<span
|
||||
className="monPipelineViewer__conditional"
|
||||
css={[Function]}
|
||||
>
|
||||
else
|
||||
</span>
|
||||
|
@ -40,7 +40,7 @@ exports[`Statement component renders a CollapsibleStatement with if body for bra
|
|||
className="monPipelineViewer__listItem"
|
||||
>
|
||||
<div
|
||||
className="monPipelineViewer__spaceContainer"
|
||||
css={[Function]}
|
||||
/>
|
||||
<CollapsibleStatement
|
||||
collapse={[MockFunction]}
|
||||
|
@ -60,7 +60,7 @@ exports[`Statement component renders a CollapsibleStatement with if body for bra
|
|||
size="xs"
|
||||
>
|
||||
<span
|
||||
className="monPipelineViewer__conditional"
|
||||
css={[Function]}
|
||||
>
|
||||
if
|
||||
</span>
|
||||
|
@ -85,7 +85,7 @@ exports[`Statement component renders a PluginStatement component for plugin mode
|
|||
className="monPipelineViewer__listItem"
|
||||
>
|
||||
<div
|
||||
className="monPipelineViewer__spaceContainer"
|
||||
css={[Function]}
|
||||
/>
|
||||
<PluginStatement
|
||||
onShowVertexDetails={[MockFunction]}
|
||||
|
@ -117,14 +117,14 @@ exports[`Statement component renders spacers for element with depth > 0 1`] = `
|
|||
className="monPipelineViewer__listItem"
|
||||
>
|
||||
<div
|
||||
className="monPipelineViewer__spaceContainer"
|
||||
css={[Function]}
|
||||
>
|
||||
<div
|
||||
className="monPipelineViewer__spacer"
|
||||
css={[Function]}
|
||||
key="spacer_0"
|
||||
/>
|
||||
<div
|
||||
className="monPipelineViewer__spacer"
|
||||
css={[Function]}
|
||||
key="spacer_1"
|
||||
/>
|
||||
</div>
|
||||
|
@ -146,7 +146,7 @@ exports[`Statement component renders spacers for element with depth > 0 1`] = `
|
|||
size="xs"
|
||||
>
|
||||
<span
|
||||
className="monPipelineViewer__conditional"
|
||||
css={[Function]}
|
||||
>
|
||||
else
|
||||
</span>
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
.monPipelineViewer__collapsibleStatement {
|
||||
padding-left: $euiSizeM;
|
||||
}
|
|
@ -6,18 +6,33 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { css } from '@emotion/react';
|
||||
|
||||
import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import './collapsible_statement.scss';
|
||||
import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, logicalCSS, UseEuiTheme } from '@elastic/eui';
|
||||
|
||||
function getToggleIconType(isCollapsed) {
|
||||
const collapsibleStatementStyle = ({ euiTheme }: UseEuiTheme) => css`
|
||||
${logicalCSS('padding-left', euiTheme.size.m)}
|
||||
`;
|
||||
|
||||
function getToggleIconType(isCollapsed: boolean) {
|
||||
return isCollapsed ? 'arrowRight' : 'arrowDown';
|
||||
}
|
||||
|
||||
export function CollapsibleStatement(props) {
|
||||
const { collapse, expand, id, isCollapsed } = props;
|
||||
interface CollapsibleStatementProps {
|
||||
children: React.ReactNode;
|
||||
collapse: (id: string) => void;
|
||||
expand: (id: string) => void;
|
||||
id: string;
|
||||
isCollapsed: boolean;
|
||||
}
|
||||
|
||||
export function CollapsibleStatement({
|
||||
children,
|
||||
collapse,
|
||||
expand,
|
||||
id,
|
||||
isCollapsed,
|
||||
}: CollapsibleStatementProps) {
|
||||
const toggleClicked = () => {
|
||||
if (isCollapsed) {
|
||||
expand(id);
|
||||
|
@ -28,10 +43,10 @@ export function CollapsibleStatement(props) {
|
|||
|
||||
return (
|
||||
<EuiFlexGroup
|
||||
responsive={false}
|
||||
gutterSize="none"
|
||||
alignItems="center"
|
||||
className="monPipelineViewer__collapsibleStatement"
|
||||
css={collapsibleStatementStyle}
|
||||
gutterSize="none"
|
||||
responsive={false}
|
||||
>
|
||||
<EuiFlexItem key={id} grow={false}>
|
||||
<EuiButtonIcon
|
||||
|
@ -42,14 +57,7 @@ export function CollapsibleStatement(props) {
|
|||
size="s"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
{props.children}
|
||||
{children}
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
||||
|
||||
CollapsibleStatement.propTypes = {
|
||||
collapse: PropTypes.func.isRequired,
|
||||
expand: PropTypes.func.isRequired,
|
||||
id: PropTypes.string.isRequired,
|
||||
isCollapsed: PropTypes.bool.isRequired,
|
||||
};
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import React from 'react';
|
||||
import { last } from 'lodash';
|
||||
import { css } from '@emotion/react';
|
||||
import {
|
||||
EuiBadge,
|
||||
EuiCodeBlock,
|
||||
|
@ -24,13 +25,19 @@ import {
|
|||
EuiText,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
||||
import { Sparkline } from '../../../sparkline';
|
||||
import { formatMetric } from '../../../../lib/format_number';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import './detail_drawer.scss';
|
||||
|
||||
// TODO: Why is this width here?
|
||||
const lspvDetailDrawerSparklineContainerStyle = css`
|
||||
width: 7vw;
|
||||
`;
|
||||
|
||||
function renderIcon(vertex) {
|
||||
return <EuiIcon type={vertex.iconType} className="lspvDetailDrawerIcon" />;
|
||||
return <EuiIcon type={vertex.iconType} />;
|
||||
}
|
||||
|
||||
function renderPluginBasicStats(vertex, timeseriesTooltipXValueFormatter) {
|
||||
|
@ -50,7 +57,7 @@ function renderPluginBasicStats(vertex, timeseriesTooltipXValueFormatter) {
|
|||
/>
|
||||
</EuiTableRowCell>
|
||||
<EuiTableRowCell>
|
||||
<div className="lspvDetailDrawerSparklineContainer">
|
||||
<div css={lspvDetailDrawerSparklineContainerStyle}>
|
||||
<Sparkline
|
||||
series={vertex.stats.millis_per_event.data}
|
||||
options={{ xaxis: vertex.stats.millis_per_event.timeRange }}
|
||||
|
@ -76,7 +83,7 @@ function renderPluginBasicStats(vertex, timeseriesTooltipXValueFormatter) {
|
|||
/>
|
||||
</EuiTableRowCell>
|
||||
<EuiTableRowCell>
|
||||
<div className="lspvDetailDrawerSparklineContainer">
|
||||
<div css={lspvDetailDrawerSparklineContainerStyle}>
|
||||
<Sparkline
|
||||
series={vertex.eventsPerSecond.data}
|
||||
options={{ xaxis: vertex.eventsPerSecond.timeRange }}
|
||||
|
@ -108,7 +115,7 @@ function renderPluginBasicStats(vertex, timeseriesTooltipXValueFormatter) {
|
|||
/>
|
||||
</EuiTableRowCell>
|
||||
<EuiTableRowCell>
|
||||
<div className="lspvDetailDrawerSparklineContainer">
|
||||
<div css={lspvDetailDrawerSparklineContainerStyle}>
|
||||
<Sparkline
|
||||
series={vertex.stats.events_in.data}
|
||||
options={{ xaxis: vertex.stats.events_in.timeRange }}
|
||||
|
@ -138,7 +145,7 @@ function renderPluginBasicStats(vertex, timeseriesTooltipXValueFormatter) {
|
|||
/>
|
||||
</EuiTableRowCell>
|
||||
<EuiTableRowCell>
|
||||
<div className="lspvDetailDrawerSparklineContainer">
|
||||
<div css={lspvDetailDrawerSparklineContainerStyle}>
|
||||
<Sparkline
|
||||
series={vertex.stats.events_out.data}
|
||||
options={{ xaxis: vertex.stats.events_out.timeRange }}
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
// SASSTODO: Why is this width here?
|
||||
.lspvDetailDrawerSparklineContainer {
|
||||
width: 7vw;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* 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 PropTypes from 'prop-types';
|
||||
import { EuiFlexItem, EuiBadge, EuiText } from '@elastic/eui';
|
||||
import classNames from 'classnames';
|
||||
import './metric.scss';
|
||||
|
||||
export function Metric({ className, warning, value }) {
|
||||
const classes = classNames('monPipelineViewer__metric', className);
|
||||
|
||||
let stylizedValue;
|
||||
if (warning) {
|
||||
stylizedValue = (
|
||||
<EuiBadge color="warning" className={className}>
|
||||
{value}
|
||||
</EuiBadge>
|
||||
);
|
||||
} else {
|
||||
stylizedValue = (
|
||||
<EuiText size="s" color="subdued" className={classes}>
|
||||
<span>{value}</span>
|
||||
</EuiText>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<EuiFlexItem className="monPipelineViewer__metricFlexItem" grow={false}>
|
||||
{stylizedValue}
|
||||
</EuiFlexItem>
|
||||
);
|
||||
}
|
||||
|
||||
Metric.propTypes = {
|
||||
className: PropTypes.string.isRequired,
|
||||
value: PropTypes.string.isRequired,
|
||||
warning: PropTypes.bool,
|
||||
};
|
|
@ -1,27 +0,0 @@
|
|||
.monPipelineViewer__metric {
|
||||
text-align: right;
|
||||
|
||||
&--cpuTime {
|
||||
width: $euiSizeXXL;
|
||||
}
|
||||
|
||||
&--events,
|
||||
&--eventsEmitted {
|
||||
width: $euiSizeXXL * 4;
|
||||
}
|
||||
|
||||
&--eventMillis {
|
||||
width: $euiSizeXXL * 2;
|
||||
}
|
||||
}
|
||||
|
||||
@include euiBreakpoint('m') {
|
||||
.monPipelineViewer__metricFlexItem {
|
||||
margin-bottom: $euiSizeXS !important; // sass-lint:disable-line no-important
|
||||
}
|
||||
|
||||
.monPipelineViewer__metric {
|
||||
text-align: left;
|
||||
padding-left: $euiSizeXL;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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 { css } from '@emotion/react';
|
||||
import { EuiFlexItem, EuiBadge, EuiText, UseEuiTheme, logicalCSS } from '@elastic/eui';
|
||||
|
||||
type Type = 'cpuTime' | 'events' | 'eventsEmitted' | 'eventMillis';
|
||||
|
||||
const metricStyle =
|
||||
(type: Type) =>
|
||||
({ euiTheme }: UseEuiTheme) => {
|
||||
let width: string;
|
||||
|
||||
switch (type) {
|
||||
case 'cpuTime':
|
||||
width = euiTheme.size.xxl;
|
||||
break;
|
||||
case 'events':
|
||||
case 'eventsEmitted':
|
||||
width = `calc(${euiTheme.size.xxl} * 4)`;
|
||||
break;
|
||||
case 'eventMillis':
|
||||
width = `calc(${euiTheme.size.xxl} * 2)`;
|
||||
break;
|
||||
default:
|
||||
width = 'auto';
|
||||
}
|
||||
|
||||
return css`
|
||||
text-align: right;
|
||||
width: ${width};
|
||||
|
||||
@media (min-width: ${euiTheme.breakpoint.m}) {
|
||||
text-align: left;
|
||||
${logicalCSS('padding-left', euiTheme.size.xl)}
|
||||
}
|
||||
`;
|
||||
};
|
||||
|
||||
const metricFlexItemStyle = ({ euiTheme }: UseEuiTheme) => css`
|
||||
@media (min-width: ${euiTheme.breakpoint.m}) {
|
||||
${logicalCSS('margin-bottom', euiTheme.size.xs)}
|
||||
}
|
||||
`;
|
||||
|
||||
interface MetricProps {
|
||||
type: Type;
|
||||
value: string;
|
||||
warning?: boolean;
|
||||
}
|
||||
|
||||
export function Metric({ type, warning, value }: MetricProps) {
|
||||
let stylizedValue;
|
||||
|
||||
if (warning) {
|
||||
stylizedValue = <EuiBadge color="warning">{value}</EuiBadge>;
|
||||
} else {
|
||||
stylizedValue = (
|
||||
<EuiText css={metricStyle(type)} size="s" color="subdued">
|
||||
<span>{value}</span>
|
||||
</EuiText>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<EuiFlexItem css={metricFlexItemStyle} grow={false}>
|
||||
{stylizedValue}
|
||||
</EuiFlexItem>
|
||||
);
|
||||
}
|
|
@ -52,7 +52,7 @@ export class PipelineViewer extends React.Component {
|
|||
/>
|
||||
</h1>
|
||||
</EuiScreenReaderOnly>
|
||||
<EuiPageSection alignment="center" className="monPipelineViewer">
|
||||
<EuiPageSection data-test-subj="pipeline-viewer" alignment="center">
|
||||
<StatementSection
|
||||
iconType="logstashInput"
|
||||
headingText={i18n.translate('xpack.monitoring.logstash.pipelineViewer.inputsTitle', {
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
.monPipelineViewer__plugin {
|
||||
margin-left: $euiSizeXS;
|
||||
}
|
||||
|
||||
.monPipelineViewer__pluginStatement {
|
||||
padding-left: $euiSizeM;
|
||||
}
|
|
@ -6,31 +6,48 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiBadge } from '@elastic/eui';
|
||||
import { css } from '@emotion/react';
|
||||
import {
|
||||
EuiButtonEmpty,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiBadge,
|
||||
UseEuiTheme,
|
||||
logicalCSS,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { formatMetric } from '../../../../lib/format_number';
|
||||
import { Metric } from './metric';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import './plugin_statement.scss';
|
||||
import { Vertex } from './types';
|
||||
|
||||
function getInputStatementMetrics({ latestEventsPerSecond }) {
|
||||
const pluginStyle = ({ euiTheme }: UseEuiTheme) => css`
|
||||
${logicalCSS('margin-left', euiTheme.size.xs)}
|
||||
`;
|
||||
|
||||
const pluginStatementStyle = ({ euiTheme }: UseEuiTheme) => css`
|
||||
${logicalCSS('padding-left', euiTheme.size.m)}
|
||||
`;
|
||||
|
||||
function getInputStatementMetrics({ latestEventsPerSecond }: Vertex) {
|
||||
return [
|
||||
<Metric
|
||||
key="eventsEmitted"
|
||||
className="monPipelineViewer__metric--eventsEmitted"
|
||||
type="eventsEmitted"
|
||||
value={formatMetric(latestEventsPerSecond, '0.[00]a', 'e/s emitted')}
|
||||
/>,
|
||||
];
|
||||
}
|
||||
|
||||
function getProcessorStatementMetrics(processorVertex) {
|
||||
function getProcessorStatementMetrics(processorVertex: Vertex) {
|
||||
const { latestMillisPerEvent, latestEventsPerSecond, percentOfTotalProcessorTime } =
|
||||
processorVertex;
|
||||
|
||||
return [
|
||||
<Metric
|
||||
key="cpuMetric"
|
||||
className="monPipelineViewer__metric--cpuTime"
|
||||
type="cpuTime"
|
||||
warning={processorVertex.isTimeConsuming()}
|
||||
value={formatMetric(Math.round(percentOfTotalProcessorTime || 0), '0', '%', {
|
||||
prependSpace: false,
|
||||
|
@ -38,29 +55,43 @@ function getProcessorStatementMetrics(processorVertex) {
|
|||
/>,
|
||||
<Metric
|
||||
key="eventMillis"
|
||||
className="monPipelineViewer__metric--eventMillis"
|
||||
type="eventMillis"
|
||||
warning={processorVertex.isSlow()}
|
||||
value={formatMetric(latestMillisPerEvent, '0.[00]a', 'ms/e')}
|
||||
/>,
|
||||
<Metric
|
||||
key="eventsReceived"
|
||||
className="monPipelineViewer__metric--events"
|
||||
type="events"
|
||||
value={formatMetric(latestEventsPerSecond, '0.[00]a', 'e/s received')}
|
||||
/>,
|
||||
];
|
||||
}
|
||||
|
||||
function renderPluginStatementMetrics(pluginType, vertex) {
|
||||
function renderPluginStatementMetrics(pluginType: string, vertex: Vertex) {
|
||||
return pluginType === 'input'
|
||||
? getInputStatementMetrics(vertex)
|
||||
: getProcessorStatementMetrics(vertex);
|
||||
}
|
||||
|
||||
interface Statement {
|
||||
hasExplicitId: boolean;
|
||||
id: string;
|
||||
name: string;
|
||||
pluginType: string;
|
||||
vertex: Vertex;
|
||||
}
|
||||
|
||||
interface PluginStatementProps {
|
||||
onShowVertexDetails: (vertex: Vertex) => void;
|
||||
statement: Statement;
|
||||
}
|
||||
|
||||
export function PluginStatement({
|
||||
statement: { hasExplicitId, id, name, pluginType, vertex },
|
||||
onShowVertexDetails,
|
||||
}) {
|
||||
}: PluginStatementProps) {
|
||||
const statementMetrics = renderPluginStatementMetrics(pluginType, vertex);
|
||||
|
||||
const onNameButtonClick = () => {
|
||||
onShowVertexDetails(vertex);
|
||||
};
|
||||
|
@ -68,7 +99,7 @@ export function PluginStatement({
|
|||
return (
|
||||
<EuiFlexGroup
|
||||
alignItems="center"
|
||||
className="monPipelineViewer__pluginStatement"
|
||||
css={pluginStatementStyle}
|
||||
gutterSize="none"
|
||||
justifyContent="spaceBetween"
|
||||
>
|
||||
|
@ -77,8 +108,8 @@ export function PluginStatement({
|
|||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
aria-label={name}
|
||||
className="monPipelineViewer__plugin"
|
||||
color="primary"
|
||||
css={pluginStyle}
|
||||
flush="left"
|
||||
iconType="dot"
|
||||
onClick={onNameButtonClick}
|
||||
|
@ -93,9 +124,7 @@ export function PluginStatement({
|
|||
onClick={onNameButtonClick}
|
||||
onClickAriaLabel={i18n.translate(
|
||||
'xpack.monitoring.logstash.pipelineStatement.viewDetailsAriaLabel',
|
||||
{
|
||||
defaultMessage: 'View details',
|
||||
}
|
||||
{ defaultMessage: 'View details' }
|
||||
)}
|
||||
>
|
||||
{id}
|
||||
|
@ -112,18 +141,3 @@ export function PluginStatement({
|
|||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
||||
|
||||
PluginStatement.propTypes = {
|
||||
onShowVertexDetails: PropTypes.func.isRequired,
|
||||
statement: PropTypes.shape({
|
||||
hasExplicitId: PropTypes.bool.isRequired,
|
||||
id: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
pluginType: PropTypes.string.isRequired,
|
||||
vertex: PropTypes.shape({
|
||||
latestEventsPerSecond: PropTypes.number.isRequired,
|
||||
latestMillisPerEvent: PropTypes.number,
|
||||
percentOfTotalProcessorTime: PropTypes.number,
|
||||
}).isRequired,
|
||||
}).isRequired,
|
||||
};
|
|
@ -1,4 +0,0 @@
|
|||
.monPipelineViewer__queueMessage {
|
||||
margin-left: $euiSizeL;
|
||||
color: $euiColorDarkShade;
|
||||
}
|
|
@ -6,17 +6,24 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { StatementListHeading } from './statement_list_heading';
|
||||
import { EuiSpacer, EuiText } from '@elastic/eui';
|
||||
import { css } from '@emotion/react';
|
||||
import { EuiSpacer, EuiText, UseEuiTheme, logicalCSS } from '@elastic/eui';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import './queue.scss';
|
||||
|
||||
import { StatementListHeading } from './statement_list_heading';
|
||||
|
||||
const queueMessageStyle = ({ euiTheme }: UseEuiTheme) => css`
|
||||
${logicalCSS('margin-left', euiTheme.size.l)}
|
||||
color: ${euiTheme.colors.darkShade};
|
||||
`;
|
||||
|
||||
export function Queue() {
|
||||
return (
|
||||
<div>
|
||||
<StatementListHeading iconType="logstashQueue" title="Queue" />
|
||||
<EuiSpacer size="s" />
|
||||
<EuiText className="monPipelineViewer__queueMessage">
|
||||
<EuiText css={queueMessageStyle}>
|
||||
<FormattedMessage
|
||||
id="xpack.monitoring.logstash.pipeline.queue.noMetricsDescription"
|
||||
defaultMessage="Queue metrics not available"
|
|
@ -1,113 +0,0 @@
|
|||
/*
|
||||
* 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 PropTypes from 'prop-types';
|
||||
import { EuiButtonEmpty, EuiCodeBlock, EuiFlexItem } from '@elastic/eui';
|
||||
import { PluginStatement as PluginStatementModel } from '../models/pipeline/plugin_statement';
|
||||
import { CollapsibleStatement } from './collapsible_statement';
|
||||
import { IfElement } from '../models/list/if_element';
|
||||
import { PluginStatement } from './plugin_statement';
|
||||
import './statement.scss';
|
||||
|
||||
function renderStatementName(name, onVertexSelected) {
|
||||
return (
|
||||
<EuiFlexItem grow={false} key="statementName">
|
||||
<EuiButtonEmpty
|
||||
aria-label={name}
|
||||
color="text"
|
||||
size="xs"
|
||||
onClick={onVertexSelected}
|
||||
flush="left"
|
||||
>
|
||||
<span className="monPipelineViewer__conditional">{name}</span>
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
);
|
||||
}
|
||||
|
||||
function renderIfStatement({ condition }, onVertexSelected) {
|
||||
return [
|
||||
renderStatementName('if', onVertexSelected),
|
||||
<EuiFlexItem key="ifContent" grow={false}>
|
||||
<EuiCodeBlock fontSize="s" paddingSize="none" transparentBackground={true}>
|
||||
{condition}
|
||||
</EuiCodeBlock>
|
||||
</EuiFlexItem>,
|
||||
];
|
||||
}
|
||||
|
||||
function getStatementBody(isIf, statement, vertex, onShowVertexDetails) {
|
||||
const showVertexDetailsClicked = () => {
|
||||
onShowVertexDetails(vertex);
|
||||
};
|
||||
|
||||
return isIf
|
||||
? renderIfStatement(statement, showVertexDetailsClicked)
|
||||
: renderStatementName('else', showVertexDetailsClicked);
|
||||
}
|
||||
|
||||
function renderNestingSpacers(depth) {
|
||||
const spacers = [];
|
||||
for (let i = 0; i < depth; i += 1) {
|
||||
spacers.push(<div key={`spacer_${i}`} className="monPipelineViewer__spacer" />);
|
||||
}
|
||||
return spacers;
|
||||
}
|
||||
|
||||
function renderStatement({
|
||||
collapse,
|
||||
element,
|
||||
element: {
|
||||
id,
|
||||
statement,
|
||||
statement: { vertex },
|
||||
},
|
||||
expand,
|
||||
isCollapsed,
|
||||
onShowVertexDetails,
|
||||
}) {
|
||||
if (statement instanceof PluginStatementModel) {
|
||||
return <PluginStatement statement={statement} onShowVertexDetails={onShowVertexDetails} />;
|
||||
}
|
||||
|
||||
const statementBody = getStatementBody(
|
||||
element instanceof IfElement,
|
||||
statement,
|
||||
vertex,
|
||||
onShowVertexDetails
|
||||
);
|
||||
|
||||
return (
|
||||
<CollapsibleStatement expand={expand} collapse={collapse} isCollapsed={isCollapsed} id={id}>
|
||||
{statementBody}
|
||||
</CollapsibleStatement>
|
||||
);
|
||||
}
|
||||
|
||||
export function Statement(props) {
|
||||
const { depth } = props.element;
|
||||
|
||||
return (
|
||||
<li className={`monPipelineViewer__listItem`}>
|
||||
<div className="monPipelineViewer__spaceContainer">{renderNestingSpacers(depth)}</div>
|
||||
{renderStatement(props)}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
Statement.propTypes = {
|
||||
collapse: PropTypes.func.isRequired,
|
||||
element: PropTypes.shape({
|
||||
depth: PropTypes.number.isRequired,
|
||||
id: PropTypes.string.isRequired,
|
||||
statement: PropTypes.object.isRequired,
|
||||
}).isRequired,
|
||||
expand: PropTypes.func.isRequired,
|
||||
isCollapsed: PropTypes.bool.isRequired,
|
||||
onShowVertexDetails: PropTypes.func.isRequired,
|
||||
};
|
|
@ -1,47 +0,0 @@
|
|||
.monPipelineViewer__spaceContainer {
|
||||
background-color: $euiColorEmptyShade;
|
||||
align-self: stretch;
|
||||
display: flex;
|
||||
// Separates the left border spaces properly
|
||||
border-bottom: solid 2px $euiColorEmptyShade;
|
||||
}
|
||||
|
||||
.monPipelineViewer__spacer {
|
||||
width: $euiSizeM;
|
||||
align-self: stretch;
|
||||
margin-left: $euiSizeM;
|
||||
border-left: 1px $euiBorderColor dashed;
|
||||
|
||||
// This allows the border to be flush
|
||||
&:last-child {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
// Odd number is because of the single pixel border.
|
||||
margin-left: $euiSizeL - 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.monPipelineViewer__list {
|
||||
.monPipelineViewer__listItem {
|
||||
display: flex;
|
||||
min-height: $euiSizeXL;
|
||||
align-items: center;
|
||||
padding-right: $euiSizeM;
|
||||
|
||||
&:nth-child(2n + 1) {
|
||||
background: tintOrShade($euiColorLightestShade, 2%, 2%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.monPipelineViewer__conditional {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@include euiBreakpoint('m') {
|
||||
.monPipelineViewer__spacer {
|
||||
border: none;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* 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, { MouseEventHandler } from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import { EuiButtonEmpty, EuiCodeBlock, EuiFlexItem, logicalCSS, UseEuiTheme } from '@elastic/eui';
|
||||
|
||||
import { PluginStatement as PluginStatementModel } from '../models/pipeline/plugin_statement';
|
||||
import { CollapsibleStatement } from './collapsible_statement';
|
||||
import { IfElement } from '../models/list/if_element';
|
||||
import { PluginStatement } from './plugin_statement';
|
||||
import { Vertex } from './types';
|
||||
|
||||
const spaceContainerStyle = ({ euiTheme }: UseEuiTheme) => css`
|
||||
background-color: ${euiTheme.colors.backgroundBasePlain};
|
||||
align-self: stretch;
|
||||
display: flex;
|
||||
// Separates the left border spaces properly
|
||||
${logicalCSS('border-bottom', `solid 2px ${euiTheme.colors.emptyShade}`)}
|
||||
`;
|
||||
|
||||
const spacerStyle = ({ euiTheme }: UseEuiTheme) => css`
|
||||
width: ${euiTheme.size.m};
|
||||
align-self: stretch;
|
||||
${logicalCSS('margin-left', euiTheme.size.m)}
|
||||
${logicalCSS('border-left', `1px ${euiTheme.border.color} dashed`)}
|
||||
|
||||
// This allows the border to be flush
|
||||
&:last-child {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
// Odd number is because of the single pixel border
|
||||
${logicalCSS('margin-left', `calc(${euiTheme.size.l}) - 1px)`)}
|
||||
}
|
||||
|
||||
@media (min-width: var(${euiTheme.breakpoint.m})) {
|
||||
border: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const listItemStyle = ({ euiTheme }: UseEuiTheme) => css`
|
||||
display: flex;
|
||||
min-height: ${euiTheme.size.xl};
|
||||
align-items: center;
|
||||
${logicalCSS('padding-right', euiTheme.size.m)}
|
||||
|
||||
&:nth-child(2n + 1) {
|
||||
background: ${euiTheme.colors.lightestShade};
|
||||
}
|
||||
`;
|
||||
|
||||
const conditionalStyle = ({ euiTheme }: UseEuiTheme) => css`
|
||||
font-weight: ${euiTheme.font.weight.bold};
|
||||
`;
|
||||
|
||||
function renderStatementName(name: string, onVertexSelected: MouseEventHandler<HTMLButtonElement>) {
|
||||
return (
|
||||
<EuiFlexItem grow={false} key="statementName">
|
||||
<EuiButtonEmpty
|
||||
aria-label={name}
|
||||
color="text"
|
||||
size="xs"
|
||||
onClick={onVertexSelected}
|
||||
flush="left"
|
||||
>
|
||||
<span css={conditionalStyle}>{name}</span>
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
);
|
||||
}
|
||||
|
||||
function renderIfStatement(
|
||||
{ condition }: { vertex?: Vertex; condition?: string },
|
||||
onVertexSelected: MouseEventHandler<HTMLButtonElement>
|
||||
) {
|
||||
return [
|
||||
renderStatementName('if', onVertexSelected),
|
||||
<EuiFlexItem key="ifContent" grow={false}>
|
||||
<EuiCodeBlock fontSize="s" paddingSize="none" transparentBackground={true}>
|
||||
{condition}
|
||||
</EuiCodeBlock>
|
||||
</EuiFlexItem>,
|
||||
];
|
||||
}
|
||||
|
||||
function getStatementBody(
|
||||
isIf: boolean,
|
||||
statement: { vertex?: Vertex; condition?: string },
|
||||
vertex: Vertex,
|
||||
onShowVertexDetails: (vertex: Vertex) => void
|
||||
) {
|
||||
const showVertexDetailsClicked = () => {
|
||||
onShowVertexDetails(vertex);
|
||||
};
|
||||
|
||||
return isIf
|
||||
? renderIfStatement(statement, showVertexDetailsClicked)
|
||||
: renderStatementName('else', showVertexDetailsClicked);
|
||||
}
|
||||
|
||||
function renderNestingSpacers(depth: number) {
|
||||
const spacers = [];
|
||||
|
||||
for (let i = 0; i < depth; i += 1) {
|
||||
spacers.push(<div key={`spacer_${i}`} css={spacerStyle} />);
|
||||
}
|
||||
|
||||
return spacers;
|
||||
}
|
||||
|
||||
interface StatementProps {
|
||||
collapse: () => void;
|
||||
element: {
|
||||
depth: number;
|
||||
id: string;
|
||||
statement: {
|
||||
vertex: Vertex;
|
||||
};
|
||||
};
|
||||
expand: () => void;
|
||||
isCollapsed: boolean;
|
||||
onShowVertexDetails: (vertex: Vertex) => void;
|
||||
}
|
||||
|
||||
function renderStatement({
|
||||
collapse,
|
||||
element,
|
||||
element: {
|
||||
id,
|
||||
statement,
|
||||
statement: { vertex },
|
||||
},
|
||||
expand,
|
||||
isCollapsed,
|
||||
onShowVertexDetails,
|
||||
}: StatementProps) {
|
||||
if (statement instanceof PluginStatementModel) {
|
||||
return <PluginStatement statement={statement} onShowVertexDetails={onShowVertexDetails} />;
|
||||
}
|
||||
|
||||
const statementBody = getStatementBody(
|
||||
element instanceof IfElement,
|
||||
statement,
|
||||
vertex,
|
||||
onShowVertexDetails
|
||||
);
|
||||
|
||||
return (
|
||||
<CollapsibleStatement expand={expand} collapse={collapse} isCollapsed={isCollapsed} id={id}>
|
||||
{statementBody}
|
||||
</CollapsibleStatement>
|
||||
);
|
||||
}
|
||||
|
||||
export function Statement(props: StatementProps) {
|
||||
const { depth } = props.element;
|
||||
|
||||
return (
|
||||
<li className={`monPipelineViewer__listItem`} css={listItemStyle}>
|
||||
<div css={spaceContainerStyle}>{renderNestingSpacers(depth)}</div>
|
||||
{renderStatement(props)}
|
||||
</li>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export interface Vertex {
|
||||
latestEventsPerSecond: number;
|
||||
latestMillisPerEvent?: number;
|
||||
percentOfTotalProcessorTime?: number;
|
||||
isTimeConsuming: () => boolean;
|
||||
isSlow: () => boolean;
|
||||
}
|
|
@ -3,7 +3,11 @@
|
|||
exports[`Sparkline component does not show tooltip initially 1`] = `
|
||||
<div>
|
||||
<div
|
||||
className="monSparkline"
|
||||
css={
|
||||
Object {
|
||||
"height": "2em",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
@ -11,7 +15,11 @@ exports[`Sparkline component does not show tooltip initially 1`] = `
|
|||
exports[`Sparkline component shows tooltip on hover 1`] = `
|
||||
<div>
|
||||
<div
|
||||
className="monSparkline"
|
||||
css={
|
||||
Object {
|
||||
"height": "2em",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<div
|
||||
className="monSparklineTooltip__container"
|
||||
|
@ -23,7 +31,7 @@ exports[`Sparkline component shows tooltip on hover 1`] = `
|
|||
}
|
||||
>
|
||||
<i
|
||||
className="fa fa-caret-left monSparklineTooltip__caret"
|
||||
className="fa fa-caret-left"
|
||||
style={
|
||||
Object {
|
||||
"display": "block",
|
||||
|
@ -32,7 +40,7 @@ exports[`Sparkline component shows tooltip on hover 1`] = `
|
|||
}
|
||||
/>
|
||||
<div
|
||||
className="monSparklineTooltip"
|
||||
css={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"height": 56,
|
||||
|
@ -41,18 +49,18 @@ exports[`Sparkline component shows tooltip on hover 1`] = `
|
|||
}
|
||||
>
|
||||
<div
|
||||
className="monSparklineTooltip__yValue"
|
||||
css={[Function]}
|
||||
>
|
||||
1513814914
|
||||
</div>
|
||||
<div
|
||||
className="monSparklineTooltip__xValue"
|
||||
css={[Function]}
|
||||
>
|
||||
25
|
||||
</div>
|
||||
</div>
|
||||
<i
|
||||
className="fa fa-caret-right monSparklineTooltip__caret"
|
||||
className="fa fa-caret-right"
|
||||
style={
|
||||
Object {
|
||||
"width": 6,
|
||||
|
|
|
@ -5,11 +5,47 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { isEqual } from 'lodash';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import { isEqual } from 'lodash';
|
||||
import { transparentize } from 'polished';
|
||||
import { euiFontSize } from '@elastic/eui';
|
||||
|
||||
import { SparklineFlotChart } from './sparkline_flot_chart';
|
||||
import './sparkline.scss';
|
||||
|
||||
// TODO: Replace with EUI tooltip
|
||||
const sparklineTooltipStyle = (theme) => css`
|
||||
font-weight: ${theme.euiTheme.font.weight.regular};
|
||||
background: ${transparentize(0.3, theme.euiTheme.colors.darkestShade)};
|
||||
font-size: ${euiFontSize(theme, 'xs').fontSize};
|
||||
padding: ${theme.euiTheme.size.xs};
|
||||
border-radius: ${theme.euiTheme.border.radius.medium};
|
||||
pointer-events: none;
|
||||
`;
|
||||
|
||||
const tooltipXValueStyle = ({ euiTheme }) => css`
|
||||
color: ${transparentize(0.3, euiTheme.colors.ghost)};
|
||||
`;
|
||||
|
||||
const tooltipYValueStyle = ({ euiTheme }) => css`
|
||||
color: ${euiTheme.colors.ghost};
|
||||
`;
|
||||
|
||||
const tooltipContainerStyle = ({ euiTheme }) => css`
|
||||
position: fixed;
|
||||
z-index: ${euiTheme.levels.menu};
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const tooltipCaretStyle = (theme) => css`
|
||||
font-size: ${euiFontSize(theme, 'l').fontSize};
|
||||
color: ${transparentize(0.3, theme.euiTheme.colors.darkestShade)};
|
||||
display: none;
|
||||
`;
|
||||
|
||||
export class Sparkline extends React.Component {
|
||||
constructor(props) {
|
||||
|
@ -97,17 +133,21 @@ export class Sparkline extends React.Component {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="monSparklineTooltip__container" style={styles.tooltipContainer}>
|
||||
<i className="fa fa-caret-left monSparklineTooltip__caret" style={styles.leftCaret} />
|
||||
<div className="monSparklineTooltip" style={styles.tooltip}>
|
||||
<div className="monSparklineTooltip__yValue">
|
||||
<div
|
||||
className="monSparklineTooltip__container"
|
||||
css={tooltipContainerStyle}
|
||||
style={styles.tooltipContainer}
|
||||
>
|
||||
<i className="fa fa-caret-left" css={tooltipCaretStyle} style={styles.leftCaret} />
|
||||
<div css={sparklineTooltipStyle} style={styles.tooltip}>
|
||||
<div css={tooltipYValueStyle}>
|
||||
{this.props.tooltip.yValueFormatter(this.state.tooltip.yValue)}
|
||||
</div>
|
||||
<div className="monSparklineTooltip__xValue">
|
||||
<div css={tooltipXValueStyle}>
|
||||
{this.props.tooltip.xValueFormatter(this.state.tooltip.xValue)}
|
||||
</div>
|
||||
</div>
|
||||
<i className="fa fa-caret-right monSparklineTooltip__caret" style={styles.rightCaret} />
|
||||
<i className="fa fa-caret-right" css={tooltipCaretStyle} style={styles.rightCaret} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -124,7 +164,7 @@ export class Sparkline extends React.Component {
|
|||
render() {
|
||||
return (
|
||||
<div>
|
||||
<div className="monSparkline" ref={this.handleSparklineRef} />
|
||||
<div css={{ height: '2em' }} ref={this.handleSparklineRef} />
|
||||
{this.renderTooltip()}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
.monSparkline {
|
||||
height: 2em;
|
||||
}
|
||||
|
||||
// SASSTODO: Replace with EUI tooltip
|
||||
.monSparklineTooltip {
|
||||
font-weight: normal;
|
||||
background: transparentize($euiColorDarkestShade, .3);
|
||||
font-size: $euiFontSizeXS;
|
||||
padding: $euiSizeXS;
|
||||
border-radius: $euiBorderRadius;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.monSparklineTooltip__xValue {
|
||||
color: transparentize($euiColorGhost, .3);
|
||||
}
|
||||
|
||||
.monSparklineTooltip__yValue {
|
||||
color: $euiColorGhost;
|
||||
}
|
||||
|
||||
.monSparklineTooltip__caret {
|
||||
font-size: $euiFontSizeL;
|
||||
color: transparentize($euiColorDarkestShade, .3);
|
||||
display: none;
|
||||
}
|
||||
|
||||
.monSparklineTooltip__container {
|
||||
position: fixed;
|
||||
z-index: $euiZContentMenu;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
.monStatusIcon {
|
||||
display: inline-block;
|
||||
margin-left: $euiSizeXS;
|
||||
padding: calc($euiSizeXS / 2) $euiSizeS;
|
||||
border-radius: $euiBorderRadius;
|
||||
color: $euiColorGhost;
|
||||
min-width: 1.9em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.monStatusIcon--green {
|
||||
background-color: $euiColorSuccess;
|
||||
}
|
||||
|
||||
.monStatusIcon--red {
|
||||
background-color: $euiColorDanger;
|
||||
}
|
||||
|
||||
.monStatusIcon--yellow {
|
||||
background-color: $euiColorWarning;
|
||||
}
|
||||
|
||||
.monStatusIcon--gray {
|
||||
background-color: $euiTextColor;
|
||||
}
|
|
@ -26,6 +26,7 @@ export interface StatusIconProps {
|
|||
type: keyof typeof STATUS_ICON_TYPES;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export const StatusIcon: React.FunctionComponent<StatusIconProps> = ({ type, label }) => {
|
||||
const icon = typeToIconMap[type];
|
||||
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Summary Status Component should allow label to be optional 1`] = `
|
||||
<div
|
||||
class="monSummaryStatusNoWrap"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class="euiFlexGroup emotion-euiFlexGroup-responsive-m-spaceBetween-center-row"
|
||||
>
|
||||
|
@ -12,7 +10,7 @@ exports[`Summary Status Component should allow label to be optional 1`] = `
|
|||
style="max-width:200px"
|
||||
>
|
||||
<div
|
||||
class="euiStat monSummaryStatusNoWrap__stat emotion-euiStat-left"
|
||||
class="euiStat emotion-EuiStat"
|
||||
data-test-subj="status"
|
||||
>
|
||||
<div
|
||||
|
@ -42,7 +40,7 @@ exports[`Summary Status Component should allow label to be optional 1`] = `
|
|||
style="max-width:200px"
|
||||
>
|
||||
<div
|
||||
class="euiStat monSummaryStatusNoWrap__stat emotion-euiStat-left"
|
||||
class="euiStat emotion-EuiStat"
|
||||
>
|
||||
<div
|
||||
class="euiText euiStat__description emotion-euiText-s"
|
||||
|
@ -62,7 +60,7 @@ exports[`Summary Status Component should allow label to be optional 1`] = `
|
|||
style="max-width:200px"
|
||||
>
|
||||
<div
|
||||
class="euiStat monSummaryStatusNoWrap__stat emotion-euiStat-left"
|
||||
class="euiStat emotion-EuiStat"
|
||||
>
|
||||
<div
|
||||
class="euiText euiStat__description emotion-euiText-s"
|
||||
|
@ -83,9 +81,7 @@ exports[`Summary Status Component should allow label to be optional 1`] = `
|
|||
`;
|
||||
|
||||
exports[`Summary Status Component should allow status to be optional 1`] = `
|
||||
<div
|
||||
class="monSummaryStatusNoWrap"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class="euiFlexGroup emotion-euiFlexGroup-responsive-m-spaceBetween-center-row"
|
||||
>
|
||||
|
@ -99,7 +95,7 @@ exports[`Summary Status Component should allow status to be optional 1`] = `
|
|||
style="max-width:200px"
|
||||
>
|
||||
<div
|
||||
class="euiStat monSummaryStatusNoWrap__stat emotion-euiStat-left"
|
||||
class="euiStat emotion-EuiStat"
|
||||
>
|
||||
<div
|
||||
class="euiText euiStat__description emotion-euiText-s"
|
||||
|
@ -121,7 +117,7 @@ exports[`Summary Status Component should allow status to be optional 1`] = `
|
|||
style="max-width:200px"
|
||||
>
|
||||
<div
|
||||
class="euiStat monSummaryStatusNoWrap__stat emotion-euiStat-left"
|
||||
class="euiStat emotion-EuiStat"
|
||||
>
|
||||
<div
|
||||
class="euiText euiStat__description emotion-euiText-s"
|
||||
|
@ -142,9 +138,7 @@ exports[`Summary Status Component should allow status to be optional 1`] = `
|
|||
`;
|
||||
|
||||
exports[`Summary Status Component should render metrics in a summary bar 1`] = `
|
||||
<div
|
||||
class="monSummaryStatusNoWrap"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class="euiFlexGroup emotion-euiFlexGroup-responsive-m-spaceBetween-center-row"
|
||||
>
|
||||
|
@ -153,7 +147,7 @@ exports[`Summary Status Component should render metrics in a summary bar 1`] = `
|
|||
style="max-width:200px"
|
||||
>
|
||||
<div
|
||||
class="euiStat monSummaryStatusNoWrap__stat emotion-euiStat-left"
|
||||
class="euiStat emotion-EuiStat"
|
||||
data-test-subj="status"
|
||||
>
|
||||
<div
|
||||
|
@ -183,7 +177,7 @@ exports[`Summary Status Component should render metrics in a summary bar 1`] = `
|
|||
style="max-width:200px"
|
||||
>
|
||||
<div
|
||||
class="euiStat monSummaryStatusNoWrap__stat emotion-euiStat-left"
|
||||
class="euiStat emotion-EuiStat"
|
||||
>
|
||||
<div
|
||||
class="euiText euiStat__description emotion-euiText-s"
|
||||
|
@ -205,7 +199,7 @@ exports[`Summary Status Component should render metrics in a summary bar 1`] = `
|
|||
style="max-width:200px"
|
||||
>
|
||||
<div
|
||||
class="euiStat monSummaryStatusNoWrap__stat emotion-euiStat-left"
|
||||
class="euiStat emotion-EuiStat"
|
||||
>
|
||||
<div
|
||||
class="euiText euiStat__description emotion-euiText-s"
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
.monSummaryStatusNoWrap {
|
||||
margin-left: $euiSizeM;
|
||||
margin-right: $euiSizeM;
|
||||
|
||||
.monSummaryStatusNoWrap__stat {
|
||||
p {
|
||||
@include euiTextTruncate;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,14 +6,34 @@
|
|||
*/
|
||||
|
||||
import React, { Fragment } from 'react';
|
||||
import {
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiStat,
|
||||
UseEuiTheme,
|
||||
euiTextTruncate,
|
||||
logicalCSS,
|
||||
} from '@elastic/eui';
|
||||
import { capitalize } from 'lodash';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiStat } from '@elastic/eui';
|
||||
import { css } from '@emotion/react';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
||||
import { StatusIcon, StatusIconProps } from '../status_icon';
|
||||
import { AlertsStatus } from '../../alerts/status';
|
||||
import type { AlertsByName } from '../../alerts/types';
|
||||
import './summary_status.scss';
|
||||
|
||||
const summaryStatusNoWrapStyle = ({ euiTheme }: UseEuiTheme) => css`
|
||||
${logicalCSS('margin-left', euiTheme.size.m)}
|
||||
${logicalCSS('margin-right', euiTheme.size.m)}
|
||||
`;
|
||||
|
||||
const summaryStatusNoWrapStatStyle = css`
|
||||
p {
|
||||
${euiTextTruncate()}
|
||||
}
|
||||
`;
|
||||
|
||||
interface Metrics {
|
||||
label: string;
|
||||
|
@ -46,7 +66,7 @@ const wrapChild = ({ label, value, ...props }: Metrics, index: number) => (
|
|||
>
|
||||
<EuiStat
|
||||
title={value}
|
||||
className="monSummaryStatusNoWrap__stat"
|
||||
css={summaryStatusNoWrapStatStyle}
|
||||
titleSize="xxxs"
|
||||
textAlign="left"
|
||||
description={label ? `${label}` : ''}
|
||||
|
@ -102,7 +122,7 @@ export const DefaultStatusIndicator = ({
|
|||
}
|
||||
titleSize="xxxs"
|
||||
textAlign="left"
|
||||
className="monSummaryStatusNoWrap__stat"
|
||||
css={summaryStatusNoWrapStatStyle}
|
||||
description={i18n.translate('xpack.monitoring.summaryStatus.statusDescription', {
|
||||
defaultMessage: 'Status',
|
||||
})}
|
||||
|
@ -120,7 +140,7 @@ export function SummaryStatus({
|
|||
...props
|
||||
}: SummaryProps) {
|
||||
return (
|
||||
<div {...props} className="monSummaryStatusNoWrap">
|
||||
<div {...props} css={summaryStatusNoWrapStyle}>
|
||||
<EuiFlexGroup gutterSize="m" alignItems="center" justifyContent="spaceBetween">
|
||||
<EuiFlexItem
|
||||
className="eui-textTruncate"
|
||||
|
@ -136,7 +156,7 @@ export function SummaryStatus({
|
|||
title={<AlertsStatus showOnlyCount={true} alerts={alerts} />}
|
||||
titleSize="xxxs"
|
||||
textAlign="left"
|
||||
className="monSummaryStatusNoWrap__stat"
|
||||
css={summaryStatusNoWrapStatStyle}
|
||||
description={i18n.translate('xpack.monitoring.summaryStatus.alertsDescription', {
|
||||
defaultMessage: 'Alerts',
|
||||
})}
|
||||
|
|
|
@ -67,15 +67,15 @@ export const EuiMonitoringTable: FunctionComponent<Record<any, any>> = ({
|
|||
}
|
||||
|
||||
return (
|
||||
<div data-test-subj={`${props.className}Container`}>
|
||||
<div data-test-subj={`${props['data-test-subj']}Container`}>
|
||||
<EuiInMemoryTable
|
||||
data-test-subj={
|
||||
items.length && hasItems === true ? 'monitoringTableHasData' : 'monitoringTableNoData'
|
||||
}
|
||||
items={items}
|
||||
search={search}
|
||||
columns={columns}
|
||||
{...props}
|
||||
data-test-subj={
|
||||
items.length && hasItems ? 'monitoringTableHasData' : 'monitoringTableNoData'
|
||||
}
|
||||
/>
|
||||
{footerContent}
|
||||
</div>
|
||||
|
|
|
@ -100,7 +100,7 @@ export function EuiMonitoringSSPTable({
|
|||
};
|
||||
|
||||
return (
|
||||
<div data-test-subj={`${props.className}Container`}>
|
||||
<div data-test-subj={`${props['data-test-subj']}Container`}>
|
||||
<EuiSearchBar {...search} onChange={onQueryChange} />
|
||||
<EuiSpacer size="l" />
|
||||
<EuiBasicTable
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
// Monitoring plugin styles
|
||||
|
||||
// Prefix all styles with "mon" to avoid conflicts.
|
||||
// Examples
|
||||
// monChart
|
||||
// monChart__legend
|
||||
// monChart__legend--small
|
||||
// monChart__legend-isLoading
|
|
@ -1,9 +1,15 @@
|
|||
{
|
||||
"extends": "../../../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "target/types",
|
||||
"outDir": "target/types"
|
||||
},
|
||||
"include": ["common/**/*", "public/**/*", "server/**/*", "server/**/*.json"],
|
||||
"include": [
|
||||
"common/**/*",
|
||||
"public/**/*",
|
||||
"server/**/*",
|
||||
"server/**/*.json",
|
||||
"../../../../../typings/emotion.d.ts"
|
||||
],
|
||||
"kbn_references": [
|
||||
"@kbn/core",
|
||||
"@kbn/data-plugin",
|
||||
|
@ -43,12 +49,9 @@
|
|||
"@kbn/react-kibana-mount",
|
||||
"@kbn/react-kibana-context-render",
|
||||
"@kbn/flot-charts",
|
||||
"@kbn/ui-theme",
|
||||
"@kbn/core-elasticsearch-server",
|
||||
"@kbn/share-plugin",
|
||||
"@kbn/analytics",
|
||||
"@kbn/analytics"
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
]
|
||||
"exclude": ["target/**/*"]
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ export function MonitoringLogstashPipelineViewerProvider({ getService }) {
|
|||
const retry = getService('retry');
|
||||
const find = getService('find');
|
||||
|
||||
const PIPELINE_VIEWER_SELECTOR = '.monPipelineViewer';
|
||||
const PIPELINE_VIEWER_SELECTOR = '[data-test-subj*="pipeline-viewer"]';
|
||||
const SUBJ_PIPELINE_SECTION_PREFIX = 'pipelineViewerSection_';
|
||||
const PIPELINE_SECTION_ITEM_CLS = 'monPipelineViewer__listItem';
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue