Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Observability] Landing page for Observability #67467

Merged
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
fe63501
creating overview page and menu
cauemarcondes May 27, 2020
fe9d636
styling the home page
cauemarcondes May 28, 2020
377a3f3
adjusting breadcrumb
cauemarcondes May 28, 2020
df6410b
renaming isnt working
cauemarcondes May 28, 2020
5b55b84
renaming isnt working
cauemarcondes May 28, 2020
e790500
renaming isnt working
cauemarcondes May 28, 2020
3035d48
fixing import
cauemarcondes May 29, 2020
1aaeb79
fixing scroll when resize window
cauemarcondes May 29, 2020
f60716d
fixing eslint errors
cauemarcondes May 29, 2020
bae11f4
prepending links
cauemarcondes May 29, 2020
47170f2
adding target option
cauemarcondes May 29, 2020
69d4e3d
refactoring
cauemarcondes Jun 1, 2020
405491a
adding dark mode support
cauemarcondes Jun 2, 2020
69ca82e
Merge branch 'master' of github.com:elastic/kibana into observability…
cauemarcondes Jun 2, 2020
d382091
fixing prettier format
cauemarcondes Jun 2, 2020
0636b5f
fixing i18n
cauemarcondes Jun 2, 2020
d9d1d6a
reverting some unnecessary changes
cauemarcondes Jun 2, 2020
9111811
addressing PR comments
cauemarcondes Jun 3, 2020
0d5b98d
fixing functional tests
cauemarcondes Jun 3, 2020
94bf0fc
ordering observability menu
cauemarcondes Jun 3, 2020
1067fad
fixing tests
cauemarcondes Jun 3, 2020
3ce844f
addressing PR comments
cauemarcondes Jun 4, 2020
f3b8cd8
fixing test
cauemarcondes Jun 4, 2020
6f59f71
fixing scroll
cauemarcondes Jun 4, 2020
e302e33
Merge branch 'master' into observability-landing-page
elasticmachine Jun 4, 2020
f2443fe
addressing pr comments
cauemarcondes Jun 5, 2020
be5e21c
addressing pr comments
cauemarcondes Jun 5, 2020
f1676a9
Merge branch 'master' into observability-landing-page
elasticmachine Jun 6, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion x-pack/.i18nrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
"xpack.triggersActionsUI": "plugins/triggers_actions_ui",
"xpack.upgradeAssistant": "plugins/upgrade_assistant",
"xpack.uptime": ["plugins/uptime"],
"xpack.watcher": "plugins/watcher"
"xpack.watcher": "plugins/watcher",
"xpack.observability": "plugins/observability"
},
"translations": [
"plugins/translations/translations/zh-CN.json",
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/apm/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export class ApmPlugin implements Plugin<ApmPluginSetup, ApmPluginStart> {
core.application.register({
id: 'apm',
title: 'APM',
order: 8100,
order: 8300,
euiIconType: 'apmApp',
appRoute: '/app/apm',
icon: 'plugins/apm/public/icon.svg',
Expand Down
4 changes: 2 additions & 2 deletions x-pack/plugins/infra/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export class Plugin
defaultMessage: 'Logs',
}),
euiIconType: 'logsApp',
order: 8000,
order: 8100,
appRoute: '/app/logs',
category: DEFAULT_APP_CATEGORIES.observability,
mount: async (params: AppMountParameters) => {
Expand All @@ -89,7 +89,7 @@ export class Plugin
defaultMessage: 'Metrics',
}),
euiIconType: 'metricsApp',
order: 8001,
order: 8200,
appRoute: '/app/metrics',
category: DEFAULT_APP_CATEGORIES.observability,
mount: async (params: AppMountParameters) => {
Expand Down
29 changes: 29 additions & 0 deletions x-pack/plugins/observability/public/application/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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 React from 'react';
import ReactDOM from 'react-dom';
import { EuiThemeProvider } from '../../../../legacy/common/eui_styled_components';
import { AppMountParameters, CoreStart } from '../../../../../src/core/public';
import { Home } from '../pages/home';
import { PluginContext } from '../context/plugin_context';

export const renderApp = (core: CoreStart, { element }: AppMountParameters) => {
const i18nCore = core.i18n;
const isDarkMode = core.uiSettings.get('theme:darkMode');
ReactDOM.render(
<PluginContext.Provider value={{ core }}>
<EuiThemeProvider darkMode={isDarkMode}>
<i18nCore.Context>
<Home />
</i18nCore.Context>
</EuiThemeProvider>
</PluginContext.Provider>,
element
);
return () => {
ReactDOM.unmountComponentAtNode(element);
};
};
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions x-pack/plugins/observability/public/context/plugin_context.tsx
Original file line number Diff line number Diff line change
@@ -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;
* you may not use this file except in compliance with the Elastic License.
*/

import { createContext } from 'react';
import { AppMountContext } from 'kibana/public';

export interface PluginContextValue {
core: AppMountContext['core'];
}

export const PluginContext = createContext({} as PluginContextValue);
12 changes: 12 additions & 0 deletions x-pack/plugins/observability/public/hooks/use_plugin_context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* 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 { useContext } from 'react';
import { PluginContext } from '../context/plugin_context';

export function usePluginContext() {
return useContext(PluginContext);
}
205 changes: 205 additions & 0 deletions x-pack/plugins/observability/public/pages/home/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
/*
* 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,
EuiCard,
EuiFlexGrid,
EuiFlexGroup,
EuiFlexItem,
EuiHorizontalRule,
EuiIcon,
EuiImage,
EuiSpacer,
EuiText,
EuiTitle,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React, { useEffect } from 'react';
import styled from 'styled-components';
import { usePluginContext } from '../../hooks/use_plugin_context';
import { appsSection, tryItOutItemsSection } from './section';

const Container = styled.div`
min-height: calc(100vh - 48px);
background: ${(props) => props.theme.eui.euiColorEmptyShade};
cauemarcondes marked this conversation as resolved.
Show resolved Hide resolved
`;

const Title = styled.div`
background-color: ${(props) => props.theme.eui.euiPageBackgroundColor};
border-bottom: ${(props) => props.theme.eui.euiBorderThin};
`;

const Page = styled.div`
width: 100%;
max-width: 1200px;
margin: 0 auto;
overflow: hidden;
}
`;

const EuiCardWithoutPadding = styled(EuiCard)`
padding: 0;
`;

export const Home = () => {
const { core } = usePluginContext();

useEffect(() => {
core.chrome.setBreadcrumbs([
{
text: i18n.translate('xpack.observability.home.breadcrumb.observability', {
defaultMessage: 'Observability',
}),
},
{
text: i18n.translate('xpack.observability.home.breadcrumb.gettingStarted', {
defaultMessage: 'Getting started',
}),
},
]);
}, [core]);

return (
<Container>
<Title>
<Page>
<EuiSpacer size="xxl" />
<EuiFlexGroup>
<EuiFlexItem grow={false}>
<EuiIcon type="logoObservability" size="xxl" />
</EuiFlexItem>
<EuiFlexItem>
<EuiTitle size="m">
<h1>
{i18n.translate('xpack.observability.home.title', {
defaultMessage: 'Observability',
})}
</h1>
</EuiTitle>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="xxl" />
</Page>
</Title>
<Page>
<EuiSpacer size="xxl" />
<EuiFlexGroup direction="column">
{/* title and description */}
<EuiFlexItem style={{ maxWidth: '50%' }}>
<EuiTitle size="s">
<h2>
{i18n.translate('xpack.observability.home.sectionTitle', {
defaultMessage: 'Observability built on the Elastic Stack',
})}
</h2>
</EuiTitle>
<EuiSpacer size="m" />
<EuiText size="s" color="subdued">
{i18n.translate('xpack.observability.home.sectionsubtitle', {
defaultMessage:
'Bring your logs, metrics, and APM traces together at scale in a single stack so you can monitor and react to events happening anywhere in your environment.',
})}
</EuiText>
</EuiFlexItem>

{/* Apps sections */}
Copy link
Member

Choose a reason for hiding this comment

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

Is there a reason the EuiCard doesn't work for the App sections? Otherwise this all looks good.

Copy link
Contributor

Choose a reason for hiding this comment

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

We might need to add an option in EUI to render EuiCard without the panel (border & shadow) display. But I'd certainly switch to using the EuiCard, and I can work on getting this display style into EUI

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought about that too, but since we talked in one of the comments above that we shouldn't overwrite the Eui styles I thought I shouldn't do it.

But I also agree that replacing it by EuiCard is way better.

Since both of you are fine with that, I go with the EuiCard here too.

Copy link
Member

Choose a reason for hiding this comment

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

@cauemarcondes thanks for considering that! In most cases, we want to do a flow like this (@sqren please correct me if I'm off here for APM):

  1. Use an existing EUI component as-is or with its documented props/options
  2. Use an existing EUI component, and ping the EUI team about a special need we have (we may need to hack around it for a release or so but with the idea we will use the EUI recommended way eventually)
  3. In rare cases, use our own styles to override EUI styles because what we want can't be accommodated by EUI

I think we ran into a case of (2) here, and the EUI team is the BEST at helping us out with those situations. Thanks for being flexible!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the clarification @jasonrhodes .

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@cchaos I just noticed there's a property called display available on EuiCard which has the options plain or panel when choosing plain it removes the border and shadow.

Screenshot 2020-06-05 at 10 43 46

Copy link
Contributor

Choose a reason for hiding this comment

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

Gah, hahaha, You're right. We just never added an example in our docs specifically for that. Glad you found it!

<EuiFlexItem>
<EuiSpacer size="s" />
<EuiFlexGroup>
<EuiFlexItem>
<EuiFlexGrid columns={2}>
{appsSection.map((app) => (
<EuiFlexItem>
<EuiCardWithoutPadding
display="plain"
layout="horizontal"
icon={<EuiIcon size="l" type={app.icon} />}
title={
<EuiTitle size="xs" className="title">
<h3>{app.title}</h3>
</EuiTitle>
}
description={app.description}
/>
</EuiFlexItem>
))}
</EuiFlexGrid>
</EuiFlexItem>
<EuiFlexItem>
<EuiImage
size="xl"
alt="observability overview image"
url={core.http.basePath.prepend(
'/plugins/observability/assets/observability_overview.png'
)}
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>

{/* Get started button */}
<EuiFlexItem>
<EuiFlexGroup justifyContent="center" gutterSize="none">
<EuiFlexItem grow={false}>
<EuiButton
fill
iconType="sortRight"
iconSide="right"
href={core.http.basePath.prepend('/app/home#/tutorial_directory/logging')}
>
{i18n.translate('xpack.observability.home.getStatedButton', {
defaultMessage: 'Get started',
})}
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>

<EuiHorizontalRule margin="xl" />

{/* Try it out */}
<EuiFlexItem>
<EuiFlexGroup justifyContent="center">
<EuiFlexItem grow={false}>
<EuiTitle size="s">
<h3>
{i18n.translate('xpack.observability.home.tryItOut', {
defaultMessage: 'Try it out',
})}
</h3>
</EuiTitle>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>

{/* Try it out sections */}
<EuiFlexItem>
<EuiFlexGroup justifyContent="center">
{tryItOutItemsSection.map((item) => (
<EuiFlexItem grow={false} key={item.id} style={{ width: '260px' }}>
<EuiCard
layout="horizontal"
icon={<EuiIcon size="l" type={item.icon} />}
title={
<EuiTitle size="xs" className="title">
<h3>{item.title}</h3>
</EuiTitle>
}
description={item.description}
target={item.target}
href={item.href}
/>
</EuiFlexItem>
))}
</EuiFlexGroup>
<EuiSpacer />
</EuiFlexItem>
</EuiFlexGroup>
</Page>
</Container>
);
};
84 changes: 84 additions & 0 deletions x-pack/plugins/observability/public/pages/home/section.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* 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 { i18n } from '@kbn/i18n';

interface ISection {
id: string;
title: string;
icon: string;
description: string;
href?: string;
target?: '_blank';
}

export const appsSection: ISection[] = [
{
id: 'logs',
title: i18n.translate('xpack.observability.section.apps.logs.title', {
defaultMessage: 'Logs',
}),
icon: 'logoLogging',
description: i18n.translate('xpack.observability.section.apps.logs.description', {
defaultMessage:
'The Elastic Stack (sometimes known as the ELK Stack) is the most popular open source logging platform.',
}),
},
{
id: 'apm',
title: i18n.translate('xpack.observability.section.apps.apm.title', {
defaultMessage: 'APM',
}),
icon: 'logoAPM',
description: i18n.translate('xpack.observability.section.apps.apm.description', {
defaultMessage:
'See exactly where your application is spending time so you can quickly fix issues and feel good about the code you push.',
}),
},
{
id: 'metrics',
title: i18n.translate('xpack.observability.section.apps.metrics.title', {
defaultMessage: 'Metrics',
}),
icon: 'logoMetrics',
description: i18n.translate('xpack.observability.section.apps.metrics.description', {
defaultMessage:
'Already using the Elastic Stack for logs? Add metrics in just a few steps and correlate metrics and logs in one place.',
}),
},
{
id: 'uptime',
title: i18n.translate('xpack.observability.section.apps.uptime.title', {
defaultMessage: 'Uptime',
}),
icon: 'logoUptime',
description: i18n.translate('xpack.observability.section.apps.uptime.description', {
defaultMessage:
'React to availability issues across your apps and services before they affect users.',
}),
},
];

export const tryItOutItemsSection: ISection[] = [
{
id: 'demo',
title: i18n.translate('xpack.observability.section.tryItOut.demo.title', {
defaultMessage: 'Demo Playground',
}),
icon: 'play',
description: '',
href: 'https://demo.elastic.co/',
target: '_blank',
},
{
id: 'sampleData',
title: i18n.translate('xpack.observability.section.tryItOut.sampleData.title', {
defaultMessage: 'Add sample data',
}),
icon: 'documents',
description: '',
href: '/app/home#/tutorial_directory/sampleData',
},
];
Loading