### Summary (#28056)

Moved "Add data" and the theme switcher from the footer to a settings gear / style cleanup

### Details
* Moved the "Add data" button and the theme switcher from the page footer to a settings gear popover in the header
**Before:**
![03-add-data-before](https://user-images.githubusercontent.com/4459398/50673779-d0ddf500-0f9d-11e9-9ff7-d83aba360c9f.png)
**After:**
![02-settings-dark-theme](https://user-images.githubusercontent.com/4459398/50673593-2addbb00-0f9c-11e9-9274-1850c8a2f7f5.gif)

* Fixed broken theming after a merge from `master` in commit `06be9aba69` brought in angular code that is not theme
-friendly https://github.com/elastic/ingest-dev/issues/186
**This was fixed:**
![01-broken-dark-theme](https://user-images.githubusercontent.com/4459398/50673918-eacc0780-0f9e-11e9-81d4-f5ca8ac72a50.gif)

* Removed whitespace above navigation
**Before:**
![05-left-header-before](https://user-images.githubusercontent.com/4459398/50673620-5eb8e080-0f9c-11e9-99b0-0773fd86f991.png)
**After:**
![06-left-header-after](https://user-images.githubusercontent.com/4459398/50673626-67a9b200-0f9c-11e9-9bc2-0908a7a19cec.png)

* Removed some global CSS overrides of EUI styles via usage of the className API https://github.com/elastic/ingest-dev/issues/178

* Fixed incorrect text wrapping of the "empty data providers" message https://github.com/elastic/ingest-dev/issues/158
* Fixed alignment of "drop anything" text https://github.com/elastic/ingest-dev/issues/180
**Before:**
![07-no-data-before](https://user-images.githubusercontent.com/4459398/50673642-8a3bcb00-0f9c-11e9-84ea-08b289496006.gif)
**After:**
![08-no-data-after](https://user-images.githubusercontent.com/4459398/50673645-90ca4280-0f9c-11e9-9d41-39e1be90435c.gif)
This commit is contained in:
Andrew Goldstein 2019-01-04 09:33:06 -07:00 committed by GitHub
parent be1f8fd876
commit bc8013e81a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 215 additions and 58 deletions

View file

@ -0,0 +1,40 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { mount } from 'enzyme';
import { noop } from 'lodash/fp';
import * as React from 'react';
import { AppSettingsPopover } from './app_settings_popover';
describe('AppSettingsPopover', () => {
describe('rendering', () => {
test('it renders a settings gear icon', () => {
const wrapper = mount(
<AppSettingsPopover onClick={noop} onClose={noop} showPopover={false} />
);
expect(wrapper.find('[data-test-subj="gear"]').exists()).toEqual(true);
});
});
describe('onClick', () => {
test('it invokes onClick when clicked', () => {
const onClick = jest.fn();
const wrapper = mount(
<AppSettingsPopover onClick={onClick} onClose={noop} showPopover={false} />
);
wrapper
.find('[data-test-subj="gear"]')
.first()
.simulate('click');
expect(onClick).toHaveBeenCalled();
});
});
});

View file

@ -0,0 +1,59 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiIcon, EuiPopover, EuiTitle } from '@elastic/eui';
import * as React from 'react';
import { pure } from 'recompose';
import styled from 'styled-components';
import { ThemeSwitcher } from '../theme_switcher';
interface Props {
showPopover: boolean;
onClick: () => void;
onClose: () => void;
}
const SettingsPopover = styled(EuiPopover)`
cursor: pointer;
`;
const Title = styled(EuiTitle)`
margin-bottom: 5px;
`;
const TitleText = styled.h1`
text-align: center;
`;
export const AppSettingsPopover = pure<Props>(({ showPopover, onClick, onClose }) => (
<SettingsPopover
anchorPosition="downRight"
button={<EuiIcon data-test-subj="gear" type="gear" size="l" onClick={onClick} />}
closePopover={onClose}
data-test-subj="app-settings-popover"
id="timelineSettingsPopover"
isOpen={showPopover}
>
<EuiFlexGroup direction="column" alignItems="center">
<EuiFlexItem grow={false}>
<EuiButton
data-test-subj="add-data"
href="kibana#home/tutorial_directory/security"
target="_blank"
>
Add data
</EuiButton>
</EuiFlexItem>
<EuiFlexItem>
<Title size="xs">
<TitleText>Theme</TitleText>
</Title>
<ThemeSwitcher />
</EuiFlexItem>
</EuiFlexGroup>
</SettingsPopover>
));

View file

@ -0,0 +1,41 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import * as React from 'react';
import { AppSettingsPopover } from './app_settings_popover';
export interface State {
showPopover: boolean;
}
export class AppSettings extends React.PureComponent<{}, State> {
public readonly state = {
showPopover: false,
};
public render() {
return (
<AppSettingsPopover
onClick={this.onClick}
onClose={this.onClose}
showPopover={this.state.showPopover}
/>
);
}
private onClick = () => {
this.setState({
showPopover: !this.state.showPopover,
});
};
private onClose = () => {
this.setState({
showPopover: false,
});
};
}

View file

@ -21,25 +21,22 @@ interface FlyoutPaneProps {
width: number;
}
/** SIDE EFFECT: This container has selectors that override EUI flyout styles */
const EuiFlyoutContainer = styled.div<{ headerHeight: number; width: number }>`
& > span > div {
.euiFlyout {
min-width: 150px !important;
width: ${({ width }) => `${width}px !important`};
}
.euiFlyoutHeader {
align-items: center !important;
display: flex !important;
flex-direction: row !important;
height: ${({ headerHeight }) => `${headerHeight}px !important`};
max-height: ${({ headerHeight }) => `${headerHeight}px !important`};
overflow: hidden;
}
.euiFlyoutBody {
overflow-y: hidden !important;
padding: 10px 24px 24px 24px !important;
}
.timeline-flyout {
min-width: 150px;
width: ${({ width }) => `${width}px`};
}
.timeline-flyout-header {
align-items: center;
display: flex;
flex-direction: row;
height: ${({ headerHeight }) => `${headerHeight}px`};
max-height: ${({ headerHeight }) => `${headerHeight}px`};
overflow: hidden;
}
.timeline-flyout-body {
overflow-y: hidden;
padding: 10px 24px 24px 24px;
}
`;
@ -63,6 +60,7 @@ export const FlyoutPane = pure<FlyoutPaneProps>(
width={width}
>
<EuiFlyout
className="timeline-flyout"
size="l"
maxWidth="95%"
onClose={onClose}
@ -71,7 +69,7 @@ export const FlyoutPane = pure<FlyoutPaneProps>(
hideCloseButton={true}
>
<ResizeHandle height={flyoutHeight} timelineId={timelineId} />
<EuiFlyoutHeader hasBorder>
<EuiFlyoutHeader hasBorder className="timeline-flyout-header">
<FlyoutHeaderContainer>
<WrappedCloseButton>
<EuiToolTip content="Close">
@ -85,7 +83,9 @@ export const FlyoutPane = pure<FlyoutPaneProps>(
<FlyoutHeader timelineId={timelineId} />
</FlyoutHeaderContainer>
</EuiFlyoutHeader>
<EuiFlyoutBody data-test-subj="flyoutChildren">{children}</EuiFlyoutBody>
<EuiFlyoutBody data-test-subj="flyoutChildren" className="timeline-flyout-body">
{children}
</EuiFlyoutBody>
</EuiFlyout>
</EuiFlyoutContainer>
)

View file

@ -5,7 +5,6 @@
*/
import {
EuiButton,
EuiFlexGroup,
EuiFlexItem,
// @ts-ignore
@ -17,7 +16,6 @@ import { pure } from 'recompose';
import { FooterContainer } from '.';
import { WhoAmI } from '../../containers/who_am_i';
import { ThemeSwitcher } from '../theme_switcher';
export const Footer = pure(() => (
<FooterContainer data-test-subj="footer">
@ -27,18 +25,6 @@ export const Footer = pure(() => (
{({ appName }) => <EuiHealth color="success">Live {appName} data</EuiHealth>}
</WhoAmI>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFlexGroup alignItems="center">
<EuiFlexItem>
<ThemeSwitcher />
</EuiFlexItem>
<EuiFlexItem>
<EuiButton href="kibana#home/tutorial_directory/security" target="_blank">
Add data
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
</FooterContainer>
));

View file

@ -6,6 +6,19 @@
import { EuiPage } from '@elastic/eui';
import styled from 'styled-components';
import { injectGlobal } from 'styled-components';
// SIDE EFFECT: the following `injectGlobal` overrides default styling in angular code that was not theme-friendly
// tslint:disable-next-line:no-unused-expression
injectGlobal`
div.app-wrapper {
background-color: rgba(0,0,0,0);
}
div.application {
background-color: rgba(0,0,0,0);
}
`;
export const PageContainer = styled.div`
display: flex;

View file

@ -9,50 +9,58 @@ import * as React from 'react';
import { pure } from 'recompose';
import styled from 'styled-components';
const Text = styled.span`
const Text = styled.div`
color: #999999;
overflow: hidden;
padding: 3px;
white-space: nowrap;
`;
const BadgeHighlighted = styled(EuiBadge)`
height: 20px;
margin: 0 5px 0 12px;
margin: 0 5px 0 5px;
max-width: 70px;
min-width: 70px;
`;
const BadgeOr = styled(EuiBadge)`
height: 20px;
margin: 0 5px 0 12px;
margin: 0 5px 0 5px;
max-width: 20px;
min-width: 20px;
`;
const Hint = styled.div`
display: flex;
justify-content: center;
`;
const Flex = styled.div`
const EmptyContainer = styled.div`
align-items: center;
display: flex;
flex-direction: column;
min-height: 100px;
padding: 10px;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
min-height: 100px;
user-select: none;
`;
const NoWrap = styled.div`
align-items: center;
display: flex;
flex-direction: row;
flex-wrap: no-wrap;
`;
/**
* Prompts the user to drop anything with a facet count into the data providers section.
*/
export const Empty = pure(() => (
<Flex data-test-subj="empty">
<Hint>
<EmptyContainer data-test-subj="empty">
<NoWrap>
<Text>Drop anything</Text>
<BadgeHighlighted color="#d9d9d9">highlighted</BadgeHighlighted>
</NoWrap>
<NoWrap>
<Text>here to build an</Text>
<BadgeOr color="#d9d9d9">OR</BadgeOr>
<Text>query</Text>
</Hint>
</Flex>
</NoWrap>
</EmptyContainer>
));

View file

@ -22,6 +22,7 @@ import { Dispatch } from 'redux';
import styled, { ThemeProvider } from 'styled-components';
import chrome from 'ui/chrome';
import { AppSettings } from '../../components/app_settings';
import { AutoSizer } from '../../components/auto_sizer';
import { DragDropContextWrapper } from '../../components/drag_and_drop/drag_drop_context_wrapper';
import { Flyout, flyoutHeaderHeight } from '../../components/flyout';
@ -105,13 +106,22 @@ const HomePageComponent = pure<Props>(({ theme }) => (
headers={headers}
/>
</Flyout>
<MyEuiFlexGroup justifyContent="flexEnd" alignItems="center">
<EuiFlexItem grow={false} data-test-subj="datePickerContainer">
<RangeDatePicker id="global" />
</EuiFlexItem>
</MyEuiFlexGroup>
<PageHeader data-test-subj="pageHeader">
<Navigation data-test-subj="navigation" />
<HeaderFlexGroup justifyContent="spaceBetween" alignItems="center">
<EuiFlexItem grow={false} data-test-subj="datePickerContainer">
<Navigation data-test-subj="navigation" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFlexGroup alignItems="center" wrap={false}>
<EuiFlexItem grow={false} data-test-subj="datePickerContainer">
<RangeDatePicker id="global" />
</EuiFlexItem>
<EuiFlexItem grow={false} data-test-subj="appSettingsContainer">
<AppSettings />
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</HeaderFlexGroup>
</PageHeader>
<PageContent data-test-subj="pageContent">
<Pane data-test-subj="pane">
@ -145,6 +155,6 @@ const mapStateToProps = (state: State) => ({
export const HomePage = connect(mapStateToProps)(HomePageComponent);
const MyEuiFlexGroup = styled(EuiFlexGroup)`
margin: 2px 0px;
const HeaderFlexGroup = styled(EuiFlexGroup)`
margin-bottom: 2px;
`;