Skip to content

Commit

Permalink
[Infra UI] Table View for Home Page (elastic#29192)
Browse files Browse the repository at this point in the history
* Addding initial table implimentation

* Moving waffle map to seperate component; adding contextual menu to nodes; adding filter to groups; adding pagination; adding sorting

* Fixing EUI types for EuiInMemoryTable to work for EVERYONE

* Adding server plugin for tslint for VIM; Fixing tests

* Adding the view switcher

* removing dependency

* updating yarn.lock

* Change padding to use EUI rules

* Rename waffle/index to nodes_overview; move table to nodes_overview

* Adding missed files in last commit

* Adding textOnly to the columns that need special truncation because they are buttons

* Fixed an error in the merge

* Fixing merge issues
  • Loading branch information
simianhacker committed Jan 31, 2019
1 parent bb7a67a commit e58f4dd
Show file tree
Hide file tree
Showing 24 changed files with 622 additions and 233 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -427,4 +427,4 @@
"node": "10.14.1",
"yarn": "^1.10.1"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,29 @@ import React from 'react';
import styled from 'styled-components';

import {
isWaffleMapGroupWithGroups,
isWaffleMapGroupWithNodes,
} from '../../containers/waffle/type_guards';
import { InfraMetricType, InfraNodeType, InfraTimerangeInput } from '../../graphql/types';
import {
InfraFormatterType,
InfraWaffleData,
InfraWaffleMapBounds,
InfraWaffleMapGroup,
InfraWaffleMapOptions,
} from '../../lib/lib';
InfraMetricType,
InfraNode,
InfraNodeType,
InfraTimerangeInput,
} from '../../graphql/types';
import { InfraFormatterType, InfraWaffleMapBounds, InfraWaffleMapOptions } from '../../lib/lib';
import { KueryFilterQuery } from '../../store/local/waffle_filter';
import { createFormatter } from '../../utils/formatters';
import { AutoSizer } from '../auto_sizer';
import { InfraLoadingPanel } from '../loading';
import { GroupOfGroups } from './group_of_groups';
import { GroupOfNodes } from './group_of_nodes';
import { Legend } from './legend';
import { applyWaffleMapLayout } from './lib/apply_wafflemap_layout';
import { Map } from '../waffle/map';
import { ViewSwitcher } from '../waffle/view_switcher';
import { TableView } from './table';

interface Props {
options: InfraWaffleMapOptions;
nodeType: InfraNodeType;
map: InfraWaffleData;
nodes: InfraNode[];
loading: boolean;
reload: () => void;
onDrilldown: (filter: KueryFilterQuery) => void;
timeRange: InfraTimerangeInput;
onViewChange: (view: string) => void;
view: string;
intl: InjectedIntl;
}

Expand Down Expand Up @@ -71,36 +66,20 @@ const METRIC_FORMATTERS: MetricFormatters = {
},
};

const extractValuesFromMap = (groups: InfraWaffleMapGroup[], values: number[] = []): number[] => {
return groups.reduce((acc: number[], group: InfraWaffleMapGroup) => {
if (isWaffleMapGroupWithGroups(group)) {
return acc.concat(extractValuesFromMap(group.groups, values));
}
if (isWaffleMapGroupWithNodes(group)) {
return acc.concat(
group.nodes.map(node => {
return node.metric.value || 0;
})
);
}
return acc;
}, values);
};

const calculateBoundsFromMap = (map: InfraWaffleData): InfraWaffleMapBounds => {
const values = extractValuesFromMap(map);
const calculateBoundsFromNodes = (nodes: InfraNode[]): InfraWaffleMapBounds => {
const values = nodes.map(node => node.metric.value);
// if there is only one value then we need to set the bottom range to zero
if (values.length === 1) {
values.unshift(0);
}
return { min: min(values) || 0, max: max(values) || 0 };
};

export const Waffle = injectI18n(
export const NodesOverview = injectI18n(
class extends React.Component<Props, {}> {
public static displayName = 'Waffle';
public render() {
const { loading, map, reload, timeRange, intl } = this.props;
const { loading, nodes, nodeType, reload, intl, view, options, timeRange } = this.props;
if (loading) {
return (
<InfraLoadingPanel
Expand All @@ -112,7 +91,7 @@ export const Waffle = injectI18n(
})}
/>
);
} else if (!loading && map && map.length === 0) {
} else if (!loading && nodes && nodes.length === 0) {
return (
<CenteredEmptyPrompt
title={
Expand Down Expand Up @@ -157,31 +136,42 @@ export const Waffle = injectI18n(
metric.type,
METRIC_FORMATTERS[InfraMetricType.count]
);
const bounds = (metricFormatter && metricFormatter.bounds) || calculateBoundsFromMap(map);
const bounds = (metricFormatter && metricFormatter.bounds) || calculateBoundsFromNodes(nodes);
return (
<AutoSizer content>
{({ measureRef, content: { width = 0, height = 0 } }) => {
const groupsWithLayout = applyWaffleMapLayout(map, width, height);
return (
<WaffleMapOuterContiner
innerRef={(el: any) => measureRef(el)}
data-test-subj="waffleMap"
>
<WaffleMapInnerContainer>
{groupsWithLayout.map(this.renderGroup(bounds, timeRange))}
</WaffleMapInnerContainer>
<Legend
formatter={this.formatter}
bounds={bounds}
legend={this.props.options.legend}
/>
</WaffleMapOuterContiner>
);
}}
</AutoSizer>
<MainContainer>
<ViewSwitcherContainer>
<ViewSwitcher view={view} onChange={this.handleViewChange} />
</ViewSwitcherContainer>
{view === 'table' ? (
<TableContainer>
<TableView
nodeType={nodeType}
nodes={nodes}
options={options}
formatter={this.formatter}
timeRange={timeRange}
onFilter={this.handleDrilldown}
/>
</TableContainer>
) : (
<MapContainer>
<Map
nodeType={nodeType}
nodes={nodes}
options={options}
formatter={this.formatter}
timeRange={timeRange}
onFilter={this.handleDrilldown}
bounds={bounds}
/>
</MapContainer>
)}
</MainContainer>
);
}

private handleViewChange = (view: string) => this.props.onViewChange(view);

// TODO: Change this to a real implimentation using the tickFormatter from the prototype as an example.
private formatter = (val: string | number) => {
const { metric } = this.props.options;
Expand All @@ -204,61 +194,31 @@ export const Waffle = injectI18n(
});
return;
};

private renderGroup = (bounds: InfraWaffleMapBounds, timeRange: InfraTimerangeInput) => (
group: InfraWaffleMapGroup
) => {
if (isWaffleMapGroupWithGroups(group)) {
return (
<GroupOfGroups
onDrilldown={this.handleDrilldown}
key={group.id}
options={this.props.options}
group={group}
formatter={this.formatter}
bounds={bounds}
nodeType={this.props.nodeType}
timeRange={timeRange}
/>
);
}
if (isWaffleMapGroupWithNodes(group)) {
return (
<GroupOfNodes
key={group.id}
options={this.props.options}
group={group}
onDrilldown={this.handleDrilldown}
formatter={this.formatter}
isChild={false}
bounds={bounds}
nodeType={this.props.nodeType}
timeRange={timeRange}
/>
);
}
};
}
);

const WaffleMapOuterContiner = styled.div`
flex: 1 0 0%;
display: flex;
justify-content: center;
flex-direction: column;
overflow-x: hidden;
overflow-y: auto;
const CenteredEmptyPrompt = styled(EuiEmptyPrompt)`
align-self: center;
`;

const WaffleMapInnerContainer = styled.div`
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
align-content: flex-start;
padding: 10px;
const MainContainer = styled.div`
position: relative;
flex: 1 1 auto;
`;

const CenteredEmptyPrompt = styled(EuiEmptyPrompt)`
align-self: center;
const TableContainer = styled.div`
padding: ${props => props.theme.eui.paddingSizes.l};
`;

const ViewSwitcherContainer = styled.div`
padding: ${props => props.theme.eui.paddingSizes.l};
`;

const MapContainer = styled.div`
position: absolute;
display: flex;
top: 0;
right: 0;
bottom: 0;
left: 0;
`;
Loading

0 comments on commit e58f4dd

Please sign in to comment.