[6.x] Management: EUI Navigation sidebar (#25905) (#29490)

* Management: EUI Navigation sidebar (#25905)

* partial work - sidebar works, need to address rendering issues

* rendering fixes

* refactor sidenav into its own file

* refactor sidenav into its own file

* remove unneeded changes

* remove unneeded formatting changes

* remove unneeded formatting changes

* remove unneeded formatting changes

* remove unneeded formatting changes

* remove more unneeded EuiPage

* remove more unneeded EuiPage

* snap snap

* remove unused dependencies

* functional tests

* sidebar tweaks, beats-cm

* lint

* properly sharing UI code

* fix eui export

* type fixes

* add test

* add test

* testy test

* partial progress

* attmpt to fix functional test

* from merge

* snap snap

* clean up management for side nav changes

* functional test fix

* snap, blank landing

* snap snap

* change management item order

* test fix

* disable tslint line

* ts fix

* functional test fix

* functional test fixes

* fix functional test

* minor cleanup

* simplify management registry callback

* remove comment

* react island with kibana version

* merge

* fix scss reference

* fix types

* remove mistaken commit

* remove k7 switch

* snapshot update

* fix sidebar nav headers

* landing page copy

* remove dummy text

* merge

* i18n and revert unneeded change

* Update edit_role_page.tsx

* i18n

* i18n

* snap snap

* better text

* snap snap

* mergi

* pop open nav on mobile

* add management section tests

* NOTICE

* fix subhead text, add padding to bottom of management nav

* Update sidebar_nav.tsx

* merge merge

* fix sass lint

* .

* snap snap

* snap snap
This commit is contained in:
Matthew Kime 2019-01-31 14:31:18 -06:00 committed by GitHub
parent 7925589df9
commit ad92f4b451
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
93 changed files with 2987 additions and 2880 deletions

View file

@ -2502,17 +2502,17 @@ main {
* 1. Make seamless transition from ToolBar to Table header and contained Menu.
* 1. Make seamless transition from Table to ToolBarFooter header.
*/
.kuiControlledTable .kuiTable {
border-top: none;
/* 1 */ }
.kuiControlledTable .kuiToolBarFooter {
border-top: none;
/* 2 */ }
.kuiControlledTable .kuiMenu--contained {
border-top: none;
/* 1 */ }
.kuiControlledTable {
background: #FFF; }
.kuiControlledTable .kuiTable {
border-top: none;
/* 1 */ }
.kuiControlledTable .kuiToolBarFooter {
border-top: none;
/* 2 */ }
.kuiControlledTable .kuiMenu--contained {
border-top: none;
/* 1 */ }
/**
* 1. Prevent cells from expanding based on content size. This substitutes for table-layout: fixed.

View file

@ -3,6 +3,7 @@
* 1. Make seamless transition from Table to ToolBarFooter header.
*/
.kuiControlledTable {
background: $tableBackgroundColor;
.kuiTable {
border-top: none; /* 1 */
}

View file

@ -4,7 +4,6 @@
padding: 10px;
height: 40px;
background-color: #ffffff;
border: $kuiBorderThin;
}
.kuiToolBarFooterSection {

View file

@ -11,14 +11,14 @@ kbn-management-objects-view {
}
// SASSTODO: Remove when Kibana has a proper background color
.tab-account, .tab-management {
background-color: $euiColorEmptyShade;
kbn-management-objects, kbn-management-app, .tab-management {
background: $euiColorLightestShade;
flex-grow: 1;
}
// SASSTODO: Remove when Kibana has a proper background color
kbn-management-objects, kbn-management-app {
background: $euiColorLightestShade;
min-height: 100vh;
#management-landing {
display: flex;
flex-grow: 1;
}
.kbn-management-tab:first-letter {

View file

@ -1,42 +1,4 @@
<div class="app-container">
<!-- Local nav. -->
<kbn-top-nav name="management-subnav" data-test-subj="managementNav">
<!-- Transcluded elements. -->
<div data-transclude-slots>
<!-- Breadcrumbs. -->
<bread-crumbs
data-transclude-slot="topLeftCorner"
omit-current-page="true"
use-links="true"
omit-pages="omitPages"
page-title="pageTitle"
></bread-crumbs>
<!-- Tabs. -->
<div data-transclude-slot="bottomRow" class="kuiLocalTabs" role="tablist" ng-show="!sectionName || section.visibleItems.length > 0">
<h2 class="kuiLocalTab" ng-if="!sectionName" id="tabHeader" tabindex="0" role="tab">
{{::section.display}}
</h2>
<a
role="tab"
ng-if="sectionName"
ng-repeat="item in section.visibleItems"
class="kuiLocalTab"
ng-class="{ 'kuiLocalTab-isSelected': item.active, 'kuiLocalTab-isDisabled': !item.active && (item.disabled || !item.url) }"
kbn-href="{{::item.disabled ? '' : item.url}}"
data-test-subj="{{::item.name}}"
tooltip="{{::item.tooltip}}"
tooltip-placement="bottom"
tooltip-popup-delay="400"
tooltip-append-to-body="1"
aria-selected="{{!!item.active}}"
aria-disabled="{{!!item.disabled}}"
>
{{::item.display}}
</a>
</div>
</div>
</kbn-top-nav>
<main class="management-container" ng-transclude></main>
</div>
<div class="app-container euiPage">
<div id="management-sidenav" class="euiPageSideBar" style="position: static;"></div>
<main class="management-container euiPageBody euiPageBody--restrictWidth-default" ng-transclude></main>
</div>

View file

@ -17,6 +17,10 @@
* under the License.
*/
import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { I18nProvider, FormattedMessage } from '@kbn/i18n/react';
import './sections';
import 'ui/filters/start_from';
import 'ui/field_editor';
@ -24,11 +28,15 @@ import uiRoutes from 'ui/routes';
import { uiModules } from 'ui/modules';
import appTemplate from './app.html';
import landingTemplate from './landing.html';
import { management, MANAGEMENT_BREADCRUMB } from 'ui/management';
import { management, SidebarNav, MANAGEMENT_BREADCRUMB } from 'ui/management';
import { FeatureCatalogueRegistryProvider, FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
import { timefilter } from 'ui/timefilter';
import { EuiPageContent, EuiTitle, EuiText, EuiSpacer, EuiIcon, EuiHorizontalRule } from '@elastic/eui';
import 'ui/kbn_top_nav';
const SIDENAV_ID = 'management-sidenav';
const LANDING_ID = 'management-landing';
uiRoutes
.when('/management', {
template: landingTemplate,
@ -46,6 +54,78 @@ require('ui/index_patterns/route_setup/load_default')({
whenMissingRedirectTo: '/management/kibana/index'
});
export function updateLandingPage(version) {
const node = document.getElementById(LANDING_ID);
if (!node) {
return;
}
render(
<EuiPageContent verticalPosition="center" horizontalPosition="center">
<I18nProvider>
<div>
<div className="eui-textCenter">
<EuiIcon type="managementApp" size="xxl" />
<EuiSpacer />
<EuiTitle>
<h1>
<FormattedMessage
id="kbn.management.landing.header"
defaultMessage="Kibana {version} management"
values={{ version }}
/>
</h1>
</EuiTitle>
<EuiText>
<FormattedMessage
id="kbn.management.landing.subhead"
defaultMessage="Manage your indices, index patterns, saved objects, Kibana settings, and more."
/>
</EuiText>
</div>
<EuiHorizontalRule />
<EuiText color="subdued" size="s" textAlign="center">
<p>
<FormattedMessage
id="kbn.management.landing.text"
defaultMessage="A full list of tools can be found in the left menu"
/>
</p>
</EuiText>
</div>
</I18nProvider>
</EuiPageContent>,
node,
);
}
export function updateSidebar(
items, id
) {
const node = document.getElementById(SIDENAV_ID);
if (!node) {
return;
}
render(
<I18nProvider>
<SidebarNav
sections={items}
selectedId={id}
style={{ width: 192 }}
/>
</I18nProvider>,
node,
);
}
export const destroyReact = id => {
const node = document.getElementById(id);
node && unmountComponentAtNode(node);
};
uiModules
.get('apps/management')
.directive('kbnManagementApp', function (Private, $location) {
@ -70,6 +150,13 @@ uiModules
item.active = `#${$location.path()}`.indexOf(item.url) > -1;
});
}
updateSidebar($scope.sections, $scope.section.id);
$scope.$on('$destroy', () => destroyReact(SIDENAV_ID));
management.addListener(() => updateSidebar(management.items.inOrder, $scope.section.id));
updateLandingPage($scope.$root.chrome.getKibanaVersion());
$scope.$on('$destroy', () => destroyReact(LANDING_ID));
}
};
});

View file

@ -1,50 +1,3 @@
<kbn-management-app>
<kbn-management-landing>
<!-- General info -->
<div class="page-row">
<div class="page-row-text">Version: {{::kbnVersion}}</div>
</div>
<!-- Management sections for the ES stack -->
<div
ng-if="section.visibleItems.length > 0"
ng-repeat="section in sections"
class="page-row"
>
<div class="kuiPanel mgtPanel" role="group">
<div class="kuiPanelHeader">
<div class="kuiPanelHeaderSection">
<icon type="'{{::section.icon}}'" size="'l'"></icon>
<h3 class="kuiPanelHeader__title">
{{::section.display}}
</h3>
</div>
</div>
<div class="kuiPanelBody mgtPanel__body">
<div class="row">
<ul class="list-unstyled">
<li
class="col-xs-4 col-md-3 mgtPanel__item"
ng-repeat="item in section.visibleItems"
>
<a
data-test-subj="{{::item.id}}"
class="euiLink euiLink--primary mgtPanel__link"
ng-class="{ 'mgtPanel__link--disabled': item.disabled || !item.url }"
kbn-href="{{::item.disabled ? '' : item.url}}"
tooltip="{{::item.tooltip}}"
tooltip-placement="bottom"
tooltip-popup-delay="400"
tooltip-append-to-body="1"
>
{{::item.display}}
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</kbn-management-landing>
<div id="management-landing"></div>
</kbn-management-app>

View file

@ -1,4 +1,4 @@
<kbn-management-app section="kibana">
<kbn-management-app section="kibana/indices">
<kbn-management-indices>
<div id="createIndexPatternReact"></div>
</kbn-management-indices>

View file

@ -1,131 +1,75 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`EmptyState should render normally 1`] = `
<EuiPanel
grow={true}
hasShadow={false}
paddingSize="l"
>
<EuiFlexGroup
alignItems="center"
component="div"
direction="row"
gutterSize="l"
justifyContent="center"
responsive={true}
wrap={false}
<div>
<EuiCallOut
color="warning"
size="m"
title={
<FormattedMessage
defaultMessage="Couldn't find any Elasticsearch data"
id="kbn.management.createIndexPattern.emptyStateHeader"
values={Object {}}
/>
}
>
<EuiFlexItem
component="div"
grow={false}
<p>
<FormattedMessage
defaultMessage="{needToIndex} {learnHowLink} or {getStartedLink}"
id="kbn.management.createIndexPattern.emptyStateLabel.emptyStateDetail"
values={
Object {
"getStartedLink": <EuiLink
color="primary"
href="#/home/tutorial_directory/sampleData"
type="button"
>
<FormattedMessage
defaultMessage="get started with some sample data sets."
id="kbn.management.createIndexPattern.emptyStateLabel.getStartedLink"
values={Object {}}
/>
</EuiLink>,
"learnHowLink": <EuiLink
color="primary"
href="#/home/tutorial_directory"
type="button"
>
<FormattedMessage
defaultMessage="Learn how"
id="kbn.management.createIndexPattern.emptyStateLabel.learnHowLink"
values={Object {}}
/>
</EuiLink>,
"needToIndex": <EuiTextColor
color="subdued"
component="span"
>
<FormattedMessage
defaultMessage="You'll need to index some data into Elasticsearch before you can create an index pattern."
id="kbn.management.createIndexPattern.emptyStateLabel.needToIndexLabel"
values={Object {}}
/>
</EuiTextColor>,
}
}
/>
</p>
<EuiButton
color="warning"
data-test-subj="refreshIndicesButton"
fill={false}
iconSide="left"
iconType="refresh"
onClick={[Function]}
type="button"
>
<EuiTitle
size="m"
textTransform="none"
>
<EuiTextColor
color="subdued"
component="span"
>
<h2
style={
Object {
"textAlign": "center",
}
}
>
<FormattedMessage
defaultMessage="Couldn't find any Elasticsearch data"
id="kbn.management.createIndexPattern.emptyStateHeader"
values={Object {}}
/>
</h2>
</EuiTextColor>
</EuiTitle>
<EuiSpacer
size="s"
<FormattedMessage
defaultMessage="Check for new data"
id="kbn.management.createIndexPattern.emptyState.checkDataButton"
values={Object {}}
/>
<EuiText
grow={true}
size="m"
>
<p>
<FormattedMessage
defaultMessage="{needToIndex} {learnHowLink} or {getStartedLink}"
id="kbn.management.createIndexPattern.emptyStateLabel.emptyStateDetail"
values={
Object {
"getStartedLink": <EuiLink
color="primary"
href="#/home/tutorial_directory/sampleData"
type="button"
>
<FormattedMessage
defaultMessage="get started with some sample data sets."
id="kbn.management.createIndexPattern.emptyStateLabel.getStartedLink"
values={Object {}}
/>
</EuiLink>,
"learnHowLink": <EuiLink
color="primary"
href="#/home/tutorial_directory"
type="button"
>
<FormattedMessage
defaultMessage="Learn how"
id="kbn.management.createIndexPattern.emptyStateLabel.learnHowLink"
values={Object {}}
/>
</EuiLink>,
"needToIndex": <EuiTextColor
color="subdued"
component="span"
>
<FormattedMessage
defaultMessage="You'll need to index some data into Elasticsearch before you can create an index pattern."
id="kbn.management.createIndexPattern.emptyStateLabel.needToIndexLabel"
values={Object {}}
/>
</EuiTextColor>,
}
}
/>
</p>
</EuiText>
<EuiSpacer
size="m"
/>
<EuiFlexGroup
alignItems="center"
component="div"
direction="row"
gutterSize="l"
justifyContent="center"
responsive={true}
wrap={false}
>
<EuiFlexItem
component="div"
grow={false}
>
<EuiButton
color="primary"
data-test-subj="refreshIndicesButton"
fill={false}
iconSide="left"
iconType="refresh"
onClick={[Function]}
type="button"
>
<FormattedMessage
defaultMessage="Check for new data"
id="kbn.management.createIndexPattern.emptyState.checkDataButton"
values={Object {}}
/>
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
</EuiButton>
</EuiCallOut>
</div>
`;

View file

@ -21,13 +21,8 @@ import React from 'react';
import PropTypes from 'prop-types';
import {
EuiPanel,
EuiFlexGroup,
EuiFlexItem,
EuiTitle,
EuiText,
EuiCallOut,
EuiTextColor,
EuiSpacer,
EuiLink,
EuiButton,
} from '@elastic/eui';
@ -37,74 +32,63 @@ import { FormattedMessage } from '@kbn/i18n/react';
export const EmptyState = ({
onRefresh,
}) => (
<EuiPanel paddingSize="l">
<EuiFlexGroup justifyContent="center" alignItems="center">
<EuiFlexItem grow={false}>
<EuiTitle>
<EuiTextColor color="subdued">
<h2 style={{ textAlign: 'center' }}>
<FormattedMessage
id="kbn.management.createIndexPattern.emptyStateHeader"
defaultMessage="Couldn't find any Elasticsearch data"
/>
</h2>
</EuiTextColor>
</EuiTitle>
<EuiSpacer size="s"/>
<EuiText>
<p>
<FormattedMessage
id="kbn.management.createIndexPattern.emptyStateLabel.emptyStateDetail"
defaultMessage="{needToIndex} {learnHowLink} or {getStartedLink}"
values={{
needToIndex: (
<EuiTextColor color="subdued">
<FormattedMessage
id="kbn.management.createIndexPattern.emptyStateLabel.needToIndexLabel"
defaultMessage="You'll need to index some data into Elasticsearch before you can create an index pattern."
/>
</EuiTextColor>
),
learnHowLink: (
<EuiLink href="#/home/tutorial_directory">
<FormattedMessage
id="kbn.management.createIndexPattern.emptyStateLabel.learnHowLink"
defaultMessage="Learn how"
/>
</EuiLink>
),
getStartedLink: (
<EuiLink href="#/home/tutorial_directory/sampleData">
<FormattedMessage
id="kbn.management.createIndexPattern.emptyStateLabel.getStartedLink"
defaultMessage="get started with some sample data sets."
/>
</EuiLink>
)
}}
/>
</p>
</EuiText>
<div>
<EuiCallOut
color="warning"
title={
<FormattedMessage
id="kbn.management.createIndexPattern.emptyStateHeader"
defaultMessage="Couldn't find any Elasticsearch data"
/>
}
>
<p>
<FormattedMessage
id="kbn.management.createIndexPattern.emptyStateLabel.emptyStateDetail"
defaultMessage="{needToIndex} {learnHowLink} or {getStartedLink}"
values={{
needToIndex: (
<EuiTextColor color="subdued">
<FormattedMessage
id="kbn.management.createIndexPattern.emptyStateLabel.needToIndexLabel"
defaultMessage="You'll need to index some data into Elasticsearch before you can create an index pattern."
/>
</EuiTextColor>
),
learnHowLink: (
<EuiLink href="#/home/tutorial_directory">
<FormattedMessage
id="kbn.management.createIndexPattern.emptyStateLabel.learnHowLink"
defaultMessage="Learn how"
/>
</EuiLink>
),
getStartedLink: (
<EuiLink href="#/home/tutorial_directory/sampleData">
<FormattedMessage
id="kbn.management.createIndexPattern.emptyStateLabel.getStartedLink"
defaultMessage="get started with some sample data sets."
/>
</EuiLink>
)
}}
/>
</p>
<EuiSpacer size="m"/>
<EuiButton
iconType="refresh"
onClick={onRefresh}
data-test-subj="refreshIndicesButton"
color="warning"
>
<FormattedMessage
id="kbn.management.createIndexPattern.emptyState.checkDataButton"
defaultMessage="Check for new data"
/>
</EuiButton>
</EuiCallOut>
<EuiFlexGroup justifyContent="center" alignItems="center">
<EuiFlexItem grow={false}>
<EuiButton
iconType="refresh"
onClick={onRefresh}
data-test-subj="refreshIndicesButton"
>
<FormattedMessage
id="kbn.management.createIndexPattern.emptyState.checkDataButton"
defaultMessage="Check for new data"
/>
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
</div>
);
EmptyState.propTypes = {

View file

@ -1,56 +1,45 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`LoadingState should render normally 1`] = `
<EuiPanel
grow={true}
hasShadow={false}
paddingSize="l"
<EuiFlexGroup
alignItems="center"
component="div"
direction="column"
gutterSize="s"
justifyContent="center"
responsive={true}
wrap={false}
>
<EuiFlexGroup
alignItems="center"
<EuiFlexItem
component="div"
direction="column"
gutterSize="s"
justifyContent="center"
responsive={true}
wrap={false}
grow={false}
>
<EuiFlexItem
component="div"
grow={false}
<EuiTitle
size="s"
textTransform="none"
>
<EuiTitle
size="s"
textTransform="none"
<h2
style={
Object {
"textAlign": "center",
}
}
>
<EuiTextColor
color="subdued"
component="span"
>
<h2
style={
Object {
"textAlign": "center",
}
}
>
<FormattedMessage
defaultMessage="Checking for Elasticsearch data"
id="kbn.management.createIndexPattern.loadingState.checkingLabel"
values={Object {}}
/>
</h2>
</EuiTextColor>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem
component="div"
grow={false}
>
<EuiLoadingSpinner
size="l"
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
<FormattedMessage
defaultMessage="Checking for Elasticsearch data"
id="kbn.management.createIndexPattern.loadingState.checkingLabel"
values={Object {}}
/>
</h2>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem
component="div"
grow={false}
>
<EuiLoadingSpinner
size="l"
/>
</EuiFlexItem>
</EuiFlexGroup>
`;

View file

@ -23,32 +23,26 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiLoadingSpinner,
EuiPanel,
EuiTextColor,
EuiTitle,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
export const LoadingState = () => (
<EuiPanel paddingSize="l">
<EuiFlexGroup justifyContent="center" alignItems="center" direction="column" gutterSize="s">
<EuiFlexItem grow={false}>
<EuiTitle size="s">
<EuiTextColor color="subdued">
<h2 style={{ textAlign: 'center' }}>
<FormattedMessage
id="kbn.management.createIndexPattern.loadingState.checkingLabel"
defaultMessage="Checking for Elasticsearch data"
/>
</h2>
</EuiTextColor>
</EuiTitle>
</EuiFlexItem>
<EuiFlexGroup justifyContent="center" alignItems="center" direction="column" gutterSize="s">
<EuiFlexItem grow={false}>
<EuiTitle size="s">
<h2 style={{ textAlign: 'center' }}>
<FormattedMessage
id="kbn.management.createIndexPattern.loadingState.checkingLabel"
defaultMessage="Checking for Elasticsearch data"
/>
</h2>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiLoadingSpinner size="l"/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
<EuiFlexItem grow={false}>
<EuiLoadingSpinner size="l"/>
</EuiFlexItem>
</EuiFlexGroup>
);

View file

@ -1,4 +1,4 @@
<kbn-management-app section="kibana">
<kbn-management-app section="kibana/indices">
<kbn-management-indices>
<div class="kuiViewContent">
<kbn-management-index-header

View file

@ -1,4 +1,4 @@
<kbn-management-app section="kibana" omit-breadcrumb-pages="['indices']">
<kbn-management-app section="kibana/indices" omit-breadcrumb-pages="['indices']">
<kbn-management-indices>
<div
ng-controller="managementIndicesEdit"
@ -14,32 +14,49 @@
delete="removePattern()"
></kbn-management-index-header>
<p class="kuiText kuiVerticalRhythm" ng-if="::(indexPattern.timeFieldName || (indexPattern.tags && indexPattern.tags.length))">
<div class="euiSpacer euiSpacer--s"></div>
<p ng-if="::(indexPattern.timeFieldName || (indexPattern.tags && indexPattern.tags.length))">
<span ng-if="::indexPattern.timeFieldName">
<span class="label label-success">
<span class="kuiIcon fa-clock-o"></span>
<span i18n-id="kbn.management.editIndexPattern.timeFilterHeader"
<span class="euiBadge euiBadge--warning">
<span class="euiBadge__content">
<span class="euiBadge__text">
<span
i18n-id="kbn.management.editIndexPattern.timeFilterHeader"
i18n-default-message="Time Filter field name: {timeFieldName}"
i18n-values="{ timeFieldName: indexPattern.timeFieldName }"></span>
i18n-values="{ timeFieldName: indexPattern.timeFieldName }">
</span>
</span>
</span>
</span>
&nbsp;
</span>
<span ng-repeat="tag in indexPattern.tags">
<span class="label label-info">{{tag.name}}</span>
<span class="euiBadge euiBadge--hollow">
<span class="euiBadge__content">
<span class="euiBadge__text">
{{tag.name}}
</span>
</span>
</span>
</span>
</p>
<div class="euiSpacer euiSpacer--m"></div>
<p class="kuiText kuiVerticalRhythm">
<span i18n-id="kbn.management.editIndexPattern.timeFilterLabel.timeFilterDetail"
i18n-default-message="This page lists every field in the {indexPatternTitle} index and the field's associated core type as recorded by Elasticsearch. To change a field type, use the Elasticsearch"
i18n-values="{ html_indexPatternTitle: '<strong>' + indexPattern.title + '</strong>' }"></span>
<a target="_window" class="euiLink euiLink--primary" href="http://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html">
<span i18n-id="kbn.management.editIndexPattern.timeFilterLabel.mappingAPILink"
i18n-default-message="Mapping API"></span>
<i aria-hidden="true" class="fa-link fa"></i>
</a>
</p>
<div class="euiText">
<p>
<span i18n-id="kbn.management.editIndexPattern.timeFilterLabel.timeFilterDetail"
i18n-default-message="This page lists every field in the {indexPatternTitle} index and the field's associated core type as recorded by Elasticsearch. To change a field type, use the Elasticsearch"
i18n-values="{ html_indexPatternTitle: '<strong>' + indexPattern.title + '</strong>' }"></span>
<a target="_window" class="euiLink euiLink--primary" href="http://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html">
<span i18n-id="kbn.management.editIndexPattern.timeFilterLabel.mappingAPILink"
i18n-default-message="Mapping API"></span>
<i aria-hidden="true" class="fa-link fa"></i>
</a>
</p>
</div>
<div class="euiSpacer euiSpacer--m"></div>
<!-- Alerts -->
<div

View file

@ -2,7 +2,7 @@
<div class="kuiBarSection">
<!-- Index pattern name -->
<h1
class="kuiTitle kuiVerticalRhythm"
class="euiTitle euiTitle--medium"
data-test-subj="indexPatternTitle"
>
<span

View file

@ -1,13 +1,11 @@
<div class="euiPage">
<div class="col-md-2 sidebar-container" role="region" aria-label="{{::'kbn.management.editIndexPatternAria' | i18n: { defaultMessage: 'Index patterns' } }}">
<div class="sidebar-list">
<div id="indexPatternListReact" role="region" aria-label="{{'kbn.management.editIndexPatternLiveRegionAriaLabel' | i18n: { defaultMessage: 'Index patterns' } }}"></div>
</div>
</div>
<div class="col-md-10">
<div class="euiPanel euiPanel--paddingLarge">
<div ng-transclude></div>
</div>
<div class="col-md-2 sidebar-container" role="region" aria-label="{{::'kbn.management.editIndexPatternAria' | i18n: { defaultMessage: 'Index patterns' } }}">
<div class="sidebar-list">
<div id="indexPatternListReact" role="region" aria-label="{{'kbn.management.editIndexPatternLiveRegionAriaLabel' | i18n: { defaultMessage: 'Index patterns' } }}"></div>
</div>
</div>
<div class="col-md-10">
<div class="euiPanel euiPanel--paddingLarge">
<div ng-transclude></div>
</div>
</div>

View file

@ -24,7 +24,7 @@ import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
import {
EuiButtonEmpty,
EuiBadge,
EuiCallOut,
EuiText,
EuiSpacer,
} from '@elastic/eui';
@ -105,17 +105,14 @@ class ListUi extends Component {
const { defaultIndex } = this.props;
return !defaultIndex ? (
<div className="indexPatternList__headerWrapper">
<EuiCallOut
color="warning"
size="s"
iconType="alert"
title={(
<EuiText size="xs" color="subdued">
<p>
<FormattedMessage
id="kbn.management.indexPatternList.noDefaultIndexPatternTitle"
defaultMessage="No default index pattern. You must select or create one to continue."
/>
)}
/>
</p>
</EuiText>
</div>
) : null;
}

View file

@ -1,4 +1,4 @@
<kbn-management-app section="kibana" class="kuiView">
<kbn-management-app section="kibana/objects">
<kbn-management-objects>
<div id="reactSavedObjectsTable"></div>
</kbn-management-objects>

View file

@ -1,4 +1,4 @@
<kbn-management-app section="kibana" class="kuiView">
<kbn-management-app section="kibana/objects" class="kuiView">
<kbn-management-objects-view class="kuiViewContent kuiViewContent--constrainedWidth">
<!-- Header -->
<div class="kuiViewContentItem kuiBar kuiVerticalRhythm">

View file

@ -172,106 +172,96 @@ exports[`ObjectsTable relationships should show the flyout 1`] = `
`;
exports[`ObjectsTable should render normally 1`] = `
<EuiPage
restrictWidth={false}
<EuiPageContent
horizontalPosition="center"
panelPaddingSize="l"
style={
Object {
"maxWidth": 1000,
}
}
verticalPosition="center"
>
<EuiPageBody
restrictWidth={false}
>
<EuiPageContent
horizontalPosition="center"
panelPaddingSize="l"
style={
<Header
filteredCount={4}
onExportAll={[Function]}
onImport={[Function]}
onRefresh={[Function]}
/>
<EuiSpacer
size="xs"
/>
<InjectIntl(TableUI)
filterOptions={
Array [
Object {
"marginBottom": 16,
"marginTop": 16,
"maxWidth": 1000,
}
"name": "index-pattern",
"value": "index-pattern",
"view": "index-pattern (0)",
},
Object {
"name": "visualization",
"value": "visualization",
"view": "visualization (0)",
},
Object {
"name": "dashboard",
"value": "dashboard",
"view": "dashboard (0)",
},
Object {
"name": "search",
"value": "search",
"view": "search (0)",
},
]
}
getEditUrl={[Function]}
goInApp={[Function]}
isSearching={false}
itemId="id"
items={
Array [
Object {
"icon": "indexPatternApp",
"id": "1",
"title": "MyIndexPattern*",
"type": "index-pattern",
},
Object {
"icon": "search",
"id": "2",
"title": "MySearch",
"type": "search",
},
Object {
"icon": "dashboardApp",
"id": "3",
"title": "MyDashboard",
"type": "dashboard",
},
Object {
"icon": "visualizeApp",
"id": "4",
"title": "MyViz",
"type": "visualization",
},
]
}
onDelete={[Function]}
onExport={[Function]}
onQueryChange={[Function]}
onShowRelationships={[Function]}
onTableChange={[Function]}
pageIndex={0}
pageSize={15}
selectedSavedObjects={Array []}
selectionConfig={
Object {
"onSelectionChange": [Function],
}
verticalPosition="center"
>
<Header
filteredCount={4}
onExportAll={[Function]}
onImport={[Function]}
onRefresh={[Function]}
/>
<EuiSpacer
size="xs"
/>
<InjectIntl(TableUI)
filterOptions={
Array [
Object {
"name": "index-pattern",
"value": "index-pattern",
"view": "index-pattern (0)",
},
Object {
"name": "visualization",
"value": "visualization",
"view": "visualization (0)",
},
Object {
"name": "dashboard",
"value": "dashboard",
"view": "dashboard (0)",
},
Object {
"name": "search",
"value": "search",
"view": "search (0)",
},
]
}
getEditUrl={[Function]}
goInApp={[Function]}
isSearching={false}
itemId="id"
items={
Array [
Object {
"icon": "indexPatternApp",
"id": "1",
"title": "MyIndexPattern*",
"type": "index-pattern",
},
Object {
"icon": "search",
"id": "2",
"title": "MySearch",
"type": "search",
},
Object {
"icon": "dashboardApp",
"id": "3",
"title": "MyDashboard",
"type": "dashboard",
},
Object {
"icon": "visualizeApp",
"id": "4",
"title": "MyViz",
"type": "visualization",
},
]
}
onDelete={[Function]}
onExport={[Function]}
onQueryChange={[Function]}
onShowRelationships={[Function]}
onTableChange={[Function]}
pageIndex={0}
pageSize={15}
selectedSavedObjects={Array []}
selectionConfig={
Object {
"onSelectionChange": [Function],
}
}
totalItemCount={4}
/>
</EuiPageContent>
</EuiPageBody>
</EuiPage>
}
totalItemCount={4}
/>
</EuiPageContent>
`;

View file

@ -37,9 +37,7 @@ import {
EUI_MODAL_CONFIRM_BUTTON,
EuiCheckboxGroup,
EuiToolTip,
EuiPage,
EuiPageContent,
EuiPageBody,
} from '@elastic/eui';
import {
retrieveAndExportDocs,
@ -593,47 +591,43 @@ class ObjectsTableUI extends Component {
}));
return (
<EuiPage>
<EuiPageBody>
<EuiPageContent
verticalPosition="center"
horizontalPosition="center"
style={{ maxWidth: 1000, marginTop: 16, marginBottom: 16 }}
>
{this.renderFlyout()}
{this.renderRelationships()}
{this.renderDeleteConfirmModal()}
{this.renderExportAllOptionsModal()}
<Header
onExportAll={() =>
this.setState({ isShowingExportAllOptionsModal: true })
}
onImport={this.showImportFlyout}
onRefresh={this.refreshData}
filteredCount={filteredItemCount}
/>
<EuiSpacer size="xs" />
<Table
itemId={'id'}
selectionConfig={selectionConfig}
selectedSavedObjects={selectedSavedObjects}
onQueryChange={this.onQueryChange}
onTableChange={this.onTableChange}
filterOptions={filterOptions}
onExport={this.onExport}
onDelete={this.onDelete}
getEditUrl={this.props.getEditUrl}
goInApp={this.props.goInApp}
pageIndex={page}
pageSize={perPage}
items={savedObjects}
totalItemCount={filteredItemCount}
isSearching={isSearching}
onShowRelationships={this.onShowRelationships}
/>
</EuiPageContent>
</EuiPageBody>
</EuiPage>
<EuiPageContent
verticalPosition="center"
horizontalPosition="center"
style={{ maxWidth: 1000 }}
>
{this.renderFlyout()}
{this.renderRelationships()}
{this.renderDeleteConfirmModal()}
{this.renderExportAllOptionsModal()}
<Header
onExportAll={() =>
this.setState({ isShowingExportAllOptionsModal: true })
}
onImport={this.showImportFlyout}
onRefresh={this.refreshData}
filteredCount={filteredItemCount}
/>
<EuiSpacer size="xs" />
<Table
itemId={'id'}
selectionConfig={selectionConfig}
selectedSavedObjects={selectedSavedObjects}
onQueryChange={this.onQueryChange}
onTableChange={this.onTableChange}
filterOptions={filterOptions}
onExport={this.onExport}
onDelete={this.onDelete}
getEditUrl={this.props.getEditUrl}
goInApp={this.props.goInApp}
pageIndex={page}
pageSize={perPage}
items={savedObjects}
totalItemCount={filteredItemCount}
isSearching={isSearching}
onShowRelationships={this.onShowRelationships}
/>
</EuiPageContent>
);
}
}

View file

@ -2,512 +2,500 @@
exports[`AdvancedSettings should render normally 1`] = `
<I18nProvider>
<EuiPage
restrictWidth={true}
>
<div
className="mgtAdvancedSettings"
<div>
<EuiFlexGroup
alignItems="stretch"
component="div"
direction="row"
gutterSize="none"
justifyContent="flexStart"
responsive={true}
wrap={false}
>
<EuiFlexGroup
alignItems="stretch"
<EuiFlexItem
component="div"
direction="row"
gutterSize="none"
justifyContent="flexStart"
responsive={true}
wrap={false}
grow={true}
>
<EuiFlexItem
component="div"
grow={true}
>
<advanced_settings_page_title />
</EuiFlexItem>
<EuiFlexItem
component="div"
grow={true}
>
<Search
categories={
Array [
"general",
"elasticsearch",
]
}
onQueryChange={[Function]}
query={
Query {
"ast": _AST {
"_clauses": Array [],
"_indexedClauses": Object {
"field": Object {},
"is": Object {},
"term": Array [],
},
},
"syntax": Object {
"parse": [Function],
"print": [Function],
},
"text": "",
}
}
/>
</EuiFlexItem>
</EuiFlexGroup>
<advanced_settings_page_subtitle />
<EuiSpacer
size="m"
/>
<CallOuts />
<EuiSpacer
size="m"
/>
<InjectIntl(FormUI)
categories={
Array [
"general",
"elasticsearch",
]
}
categoryCounts={
Object {
"elasticsearch": 2,
"general": 11,
<advanced_settings_page_title />
</EuiFlexItem>
<EuiFlexItem
component="div"
grow={true}
>
<Search
categories={
Array [
"general",
"elasticsearch",
]
}
onQueryChange={[Function]}
query={
Query {
"ast": _AST {
"_clauses": Array [],
"_indexedClauses": Object {
"field": Object {},
"is": Object {},
"term": Array [],
},
},
"syntax": Object {
"parse": [Function],
"print": [Function],
},
"text": "",
}
}
/>
</EuiFlexItem>
</EuiFlexGroup>
<advanced_settings_page_subtitle />
<EuiSpacer
size="m"
/>
<CallOuts />
<EuiSpacer
size="m"
/>
<InjectIntl(FormUI)
categories={
Array [
"general",
"elasticsearch",
]
}
categoryCounts={
Object {
"elasticsearch": 2,
"general": 11,
}
clear={[Function]}
clearQuery={[Function]}
save={[Function]}
settings={
Object {
"elasticsearch": Array [
Object {
"ariaName": "Test array setting",
"category": Array [
"elasticsearch",
],
"defVal": Array [
"default_value",
],
"description": "Description for Test array setting",
"displayName": "Test array setting",
"isCustom": undefined,
"isOverridden": false,
"name": "test:array:setting",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "array",
"value": undefined,
},
Object {
"ariaName": "Test boolean setting",
"category": Array [
"elasticsearch",
],
"defVal": true,
"description": "Description for Test boolean setting",
"displayName": "Test boolean setting",
"isCustom": undefined,
"isOverridden": false,
"name": "test:boolean:setting",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "boolean",
"value": undefined,
},
],
"general": Array [
Object {
"ariaName": "Test custom string setting",
"category": Array [
"general",
],
"defVal": null,
"description": "Description for Test custom string setting",
"displayName": "Test custom string setting",
"isCustom": undefined,
"isOverridden": false,
"name": "test:customstring:setting",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "string",
"value": undefined,
},
Object {
"ariaName": "Test image setting",
"category": Array [
"general",
],
"defVal": null,
"description": "Description for Test image setting",
"displayName": "Test image setting",
"isCustom": undefined,
"isOverridden": false,
"name": "test:image:setting",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "image",
"value": undefined,
},
Object {
"ariaName": "An overridden json",
"category": Array [
"general",
],
"defVal": "{
}
clear={[Function]}
clearQuery={[Function]}
save={[Function]}
settings={
Object {
"elasticsearch": Array [
Object {
"ariaName": "Test array setting",
"category": Array [
"elasticsearch",
],
"defVal": Array [
"default_value",
],
"description": "Description for Test array setting",
"displayName": "Test array setting",
"isCustom": undefined,
"isOverridden": false,
"name": "test:array:setting",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "array",
"value": undefined,
},
Object {
"ariaName": "Test boolean setting",
"category": Array [
"elasticsearch",
],
"defVal": true,
"description": "Description for Test boolean setting",
"displayName": "Test boolean setting",
"isCustom": undefined,
"isOverridden": false,
"name": "test:boolean:setting",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "boolean",
"value": undefined,
},
],
"general": Array [
Object {
"ariaName": "Test custom string setting",
"category": Array [
"general",
],
"defVal": null,
"description": "Description for Test custom string setting",
"displayName": "Test custom string setting",
"isCustom": undefined,
"isOverridden": false,
"name": "test:customstring:setting",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "string",
"value": undefined,
},
Object {
"ariaName": "Test image setting",
"category": Array [
"general",
],
"defVal": null,
"description": "Description for Test image setting",
"displayName": "Test image setting",
"isCustom": undefined,
"isOverridden": false,
"name": "test:image:setting",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "image",
"value": undefined,
},
Object {
"ariaName": "An overridden json",
"category": Array [
"general",
],
"defVal": "{
\\"foo\\": \\"bar\\"
}",
"description": "Description for overridden json",
"displayName": "An overridden json",
"isCustom": undefined,
"isOverridden": true,
"name": "test:isOverridden:json",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "json",
"value": undefined,
},
Object {
"ariaName": "An overridden number",
"category": Array [
"general",
],
"defVal": 1234,
"description": "Description for overridden number",
"displayName": "An overridden number",
"isCustom": undefined,
"isOverridden": true,
"name": "test:isOverridden:number",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "number",
"value": undefined,
},
Object {
"ariaName": "Test overridden select setting",
"category": Array [
"general",
],
"defVal": "orange",
"description": "Description for overridden select setting",
"displayName": "Test overridden select setting",
"isCustom": undefined,
"isOverridden": true,
"name": "test:isOverridden:select",
"optionLabels": undefined,
"options": Array [
"apple",
"orange",
"banana",
],
"readonly": false,
"type": "select",
"value": undefined,
},
Object {
"ariaName": "An overridden string",
"category": Array [
"general",
],
"defVal": "foo",
"description": "Description for overridden string",
"displayName": "An overridden string",
"isCustom": undefined,
"isOverridden": true,
"name": "test:isOverridden:string",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "string",
"value": undefined,
},
Object {
"ariaName": "Test json setting",
"category": Array [
"general",
],
"defVal": "{\\"foo\\": \\"bar\\"}",
"description": "Description for Test json setting",
"displayName": "Test json setting",
"isCustom": undefined,
"isOverridden": false,
"name": "test:json:setting",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "json",
"value": undefined,
},
Object {
"ariaName": "Test markdown setting",
"category": Array [
"general",
],
"defVal": "",
"description": "Description for Test markdown setting",
"displayName": "Test markdown setting",
"isCustom": undefined,
"isOverridden": false,
"name": "test:markdown:setting",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "markdown",
"value": undefined,
},
Object {
"ariaName": "Test number setting",
"category": Array [
"general",
],
"defVal": 5,
"description": "Description for Test number setting",
"displayName": "Test number setting",
"isCustom": undefined,
"isOverridden": false,
"name": "test:number:setting",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "number",
"value": undefined,
},
Object {
"ariaName": "Test select setting",
"category": Array [
"general",
],
"defVal": "orange",
"description": "Description for Test select setting",
"displayName": "Test select setting",
"isCustom": undefined,
"isOverridden": false,
"name": "test:select:setting",
"optionLabels": undefined,
"options": Array [
"apple",
"orange",
"banana",
],
"readonly": false,
"type": "select",
"value": undefined,
},
Object {
"ariaName": "Test string setting",
"category": Array [
"general",
],
"defVal": null,
"description": "Description for Test string setting",
"displayName": "Test string setting",
"isCustom": undefined,
"isOverridden": false,
"name": "test:string:setting",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "string",
"value": undefined,
},
],
}
}
showNoResultsMessage={true}
/>
<advanced_settings_page_footer
onQueryMatchChange={[Function]}
query={
Query {
"ast": _AST {
"_clauses": Array [],
"_indexedClauses": Object {
"field": Object {},
"is": Object {},
"term": Array [],
},
"description": "Description for overridden json",
"displayName": "An overridden json",
"isCustom": undefined,
"isOverridden": true,
"name": "test:isOverridden:json",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "json",
"value": undefined,
},
"syntax": Object {
"parse": [Function],
"print": [Function],
Object {
"ariaName": "An overridden number",
"category": Array [
"general",
],
"defVal": 1234,
"description": "Description for overridden number",
"displayName": "An overridden number",
"isCustom": undefined,
"isOverridden": true,
"name": "test:isOverridden:number",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "number",
"value": undefined,
},
"text": "",
}
Object {
"ariaName": "Test overridden select setting",
"category": Array [
"general",
],
"defVal": "orange",
"description": "Description for overridden select setting",
"displayName": "Test overridden select setting",
"isCustom": undefined,
"isOverridden": true,
"name": "test:isOverridden:select",
"optionLabels": undefined,
"options": Array [
"apple",
"orange",
"banana",
],
"readonly": false,
"type": "select",
"value": undefined,
},
Object {
"ariaName": "An overridden string",
"category": Array [
"general",
],
"defVal": "foo",
"description": "Description for overridden string",
"displayName": "An overridden string",
"isCustom": undefined,
"isOverridden": true,
"name": "test:isOverridden:string",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "string",
"value": undefined,
},
Object {
"ariaName": "Test json setting",
"category": Array [
"general",
],
"defVal": "{\\"foo\\": \\"bar\\"}",
"description": "Description for Test json setting",
"displayName": "Test json setting",
"isCustom": undefined,
"isOverridden": false,
"name": "test:json:setting",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "json",
"value": undefined,
},
Object {
"ariaName": "Test markdown setting",
"category": Array [
"general",
],
"defVal": "",
"description": "Description for Test markdown setting",
"displayName": "Test markdown setting",
"isCustom": undefined,
"isOverridden": false,
"name": "test:markdown:setting",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "markdown",
"value": undefined,
},
Object {
"ariaName": "Test number setting",
"category": Array [
"general",
],
"defVal": 5,
"description": "Description for Test number setting",
"displayName": "Test number setting",
"isCustom": undefined,
"isOverridden": false,
"name": "test:number:setting",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "number",
"value": undefined,
},
Object {
"ariaName": "Test select setting",
"category": Array [
"general",
],
"defVal": "orange",
"description": "Description for Test select setting",
"displayName": "Test select setting",
"isCustom": undefined,
"isOverridden": false,
"name": "test:select:setting",
"optionLabels": undefined,
"options": Array [
"apple",
"orange",
"banana",
],
"readonly": false,
"type": "select",
"value": undefined,
},
Object {
"ariaName": "Test string setting",
"category": Array [
"general",
],
"defVal": null,
"description": "Description for Test string setting",
"displayName": "Test string setting",
"isCustom": undefined,
"isOverridden": false,
"name": "test:string:setting",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "string",
"value": undefined,
},
],
}
/>
</div>
</EuiPage>
}
showNoResultsMessage={true}
/>
<advanced_settings_page_footer
onQueryMatchChange={[Function]}
query={
Query {
"ast": _AST {
"_clauses": Array [],
"_indexedClauses": Object {
"field": Object {},
"is": Object {},
"term": Array [],
},
},
"syntax": Object {
"parse": [Function],
"print": [Function],
},
"text": "",
}
}
/>
</div>
</I18nProvider>
`;
exports[`AdvancedSettings should render specific setting if given setting key 1`] = `
<I18nProvider>
<EuiPage
restrictWidth={true}
>
<div
className="mgtAdvancedSettings"
<div>
<EuiFlexGroup
alignItems="stretch"
component="div"
direction="row"
gutterSize="none"
justifyContent="flexStart"
responsive={true}
wrap={false}
>
<EuiFlexGroup
alignItems="stretch"
<EuiFlexItem
component="div"
direction="row"
gutterSize="none"
justifyContent="flexStart"
responsive={true}
wrap={false}
grow={true}
>
<EuiFlexItem
component="div"
grow={true}
>
<advanced_settings_page_title />
</EuiFlexItem>
<EuiFlexItem
component="div"
grow={true}
>
<Search
categories={
Array [
"general",
"elasticsearch",
]
}
onQueryChange={[Function]}
query={
Query {
"ast": _AST {
"_clauses": Array [
Object {
"field": "ariaName",
"match": "must",
"operator": "eq",
"type": "field",
"value": "test string setting",
},
],
"_indexedClauses": Object {
"field": Object {
"ariaName": Array [
Object {
"field": "ariaName",
"match": "must",
"operator": "eq",
"type": "field",
"value": "test string setting",
},
],
},
"is": Object {},
"term": Array [],
},
},
"syntax": Object {
"parse": [Function],
"print": [Function],
},
"text": "ariaName:\\"test string setting\\"",
}
}
/>
</EuiFlexItem>
</EuiFlexGroup>
<advanced_settings_page_subtitle />
<EuiSpacer
size="m"
/>
<CallOuts />
<EuiSpacer
size="m"
/>
<InjectIntl(FormUI)
categories={
Array [
"general",
"elasticsearch",
]
}
categoryCounts={
Object {
"elasticsearch": 2,
"general": 11,
<advanced_settings_page_title />
</EuiFlexItem>
<EuiFlexItem
component="div"
grow={true}
>
<Search
categories={
Array [
"general",
"elasticsearch",
]
}
}
clear={[Function]}
clearQuery={[Function]}
save={[Function]}
settings={
Object {
"general": Array [
Object {
"ariaName": "Test string setting",
"category": Array [
"general",
onQueryChange={[Function]}
query={
Query {
"ast": _AST {
"_clauses": Array [
Object {
"field": "ariaName",
"match": "must",
"operator": "eq",
"type": "field",
"value": "test string setting",
},
],
"defVal": null,
"description": "Description for Test string setting",
"displayName": "Test string setting",
"isCustom": undefined,
"isOverridden": false,
"name": "test:string:setting",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "string",
"value": undefined,
"_indexedClauses": Object {
"field": Object {
"ariaName": Array [
Object {
"field": "ariaName",
"match": "must",
"operator": "eq",
"type": "field",
"value": "test string setting",
},
],
},
"is": Object {},
"term": Array [],
},
},
"syntax": Object {
"parse": [Function],
"print": [Function],
},
"text": "ariaName:\\"test string setting\\"",
}
}
/>
</EuiFlexItem>
</EuiFlexGroup>
<advanced_settings_page_subtitle />
<EuiSpacer
size="m"
/>
<CallOuts />
<EuiSpacer
size="m"
/>
<InjectIntl(FormUI)
categories={
Array [
"general",
"elasticsearch",
]
}
categoryCounts={
Object {
"elasticsearch": 2,
"general": 11,
}
}
clear={[Function]}
clearQuery={[Function]}
save={[Function]}
settings={
Object {
"general": Array [
Object {
"ariaName": "Test string setting",
"category": Array [
"general",
],
"defVal": null,
"description": "Description for Test string setting",
"displayName": "Test string setting",
"isCustom": undefined,
"isOverridden": false,
"name": "test:string:setting",
"optionLabels": undefined,
"options": undefined,
"readonly": false,
"type": "string",
"value": undefined,
},
],
}
}
showNoResultsMessage={true}
/>
<advanced_settings_page_footer
onQueryMatchChange={[Function]}
query={
Query {
"ast": _AST {
"_clauses": Array [
Object {
"field": "ariaName",
"match": "must",
"operator": "eq",
"type": "field",
"value": "test string setting",
},
],
}
}
showNoResultsMessage={true}
/>
<advanced_settings_page_footer
onQueryMatchChange={[Function]}
query={
Query {
"ast": _AST {
"_clauses": Array [
Object {
"field": "ariaName",
"match": "must",
"operator": "eq",
"type": "field",
"value": "test string setting",
},
],
"_indexedClauses": Object {
"field": Object {
"ariaName": Array [
Object {
"field": "ariaName",
"match": "must",
"operator": "eq",
"type": "field",
"value": "test string setting",
},
],
},
"is": Object {},
"term": Array [],
"_indexedClauses": Object {
"field": Object {
"ariaName": Array [
Object {
"field": "ariaName",
"match": "must",
"operator": "eq",
"type": "field",
"value": "test string setting",
},
],
},
"is": Object {},
"term": Array [],
},
"syntax": Object {
"parse": [Function],
"print": [Function],
},
"text": "ariaName:\\"test string setting\\"",
}
},
"syntax": Object {
"parse": [Function],
"print": [Function],
},
"text": "ariaName:\\"test string setting\\"",
}
/>
</div>
</EuiPage>
}
/>
</div>
</I18nProvider>
`;

View file

@ -25,7 +25,6 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiSpacer,
EuiPage,
Query,
} from '@elastic/eui';
@ -157,36 +156,34 @@ export class AdvancedSettings extends Component {
return (
<I18nProvider>
<EuiPage restrictWidth>
<div className="mgtAdvancedSettings">
<EuiFlexGroup gutterSize="none">
<EuiFlexItem>
<PageTitle />
</EuiFlexItem>
<EuiFlexItem>
<Search
query={query}
categories={this.categories}
onQueryChange={this.onQueryChange}
/>
</EuiFlexItem>
</EuiFlexGroup>
<PageSubtitle />
<EuiSpacer size="m" />
<CallOuts />
<EuiSpacer size="m" />
<Form
settings={filteredSettings}
categories={this.categories}
categoryCounts={this.categoryCounts}
clearQuery={this.clearQuery}
save={this.saveConfig}
clear={this.clearConfig}
showNoResultsMessage={!footerQueryMatched}
/>
<PageFooter query={query} onQueryMatchChange={this.onFooterQueryMatchChange} />
</div>
</EuiPage>
<div>
<EuiFlexGroup gutterSize="none">
<EuiFlexItem>
<PageTitle />
</EuiFlexItem>
<EuiFlexItem>
<Search
query={query}
categories={this.categories}
onQueryChange={this.onQueryChange}
/>
</EuiFlexItem>
</EuiFlexGroup>
<PageSubtitle />
<EuiSpacer size="m" />
<CallOuts />
<EuiSpacer size="m" />
<Form
settings={filteredSettings}
categories={this.categories}
categoryCounts={this.categoryCounts}
clearQuery={this.clearQuery}
save={this.saveConfig}
clear={this.clearConfig}
showNoResultsMessage={!footerQueryMatched}
/>
<PageFooter query={query} onQueryMatchChange={this.onFooterQueryMatchChange} />
</div>
</I18nProvider>
);
}

View file

@ -1,19 +1,13 @@
.mgtAdvancedSettings {
padding: $euiSizeL;
background: $euiColorLightestShade;
min-height: calc(100vh - 70px);
.mgtAdvancedSettings__field {
+ * {
margin-top: $euiSize;
}
.mgtAdvancedSettings__field {
+ * {
margin-top: $euiSize;
}
&Wrapper {
width: 640px;
}
&Wrapper {
width: 640px;
}
&Actions {
padding-top: $euiSizeM;
}
&Actions {
padding-top: $euiSizeM;
}
}

View file

@ -1,4 +1,4 @@
<kbn-management-app section="kibana">
<kbn-management-app section="kibana/settings">
<kbn-management-advanced>
<div id="reactAdvancedSettings"></div>
</kbn-management-advanced>

View file

@ -101,6 +101,15 @@ describe('ManagementSection', () => {
expect(threwException).to.be(true);
});
it('calls listener when item added', () => {
let listerCalled = false;
const listenerFn = () => { listerCalled = true; };
section.addListener(listenerFn);
section.register('about');
expect(listerCalled).to.be(true);
});
});
describe('deregister', () => {
@ -122,6 +131,14 @@ describe('ManagementSection', () => {
expect(section.items).to.have.length(0);
});
it('calls listener when item added', () => {
let listerCalled = false;
const listenerFn = () => { listerCalled = true; };
section.addListener(listenerFn);
section.deregister('about');
expect(listerCalled).to.be(true);
});
});
describe('getSection', () => {

View file

@ -0,0 +1,24 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Management filters and filters and maps section objects into SidebarNav items 1`] = `
Array [
Object {
"data-test-subj": "activeSection",
"href": undefined,
"icon": null,
"id": "activeSection",
"isSelected": false,
"items": Array [
Object {
"data-test-subj": "item",
"href": undefined,
"icon": null,
"id": "item",
"isSelected": false,
"name": "item",
},
],
"name": "activeSection",
},
]
`;

View file

@ -0,0 +1,20 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
export { SidebarNav } from './sidebar_nav';

View file

@ -0,0 +1,82 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { IndexedArray } from '../../indexed_array';
import { sideNavItems } from '../components/sidebar_nav';
const toIndexedArray = (initialSet: any[]) =>
new IndexedArray({
index: ['id'],
order: ['order'],
initialSet,
});
const activeProps = { visible: true, disabled: false };
const disabledProps = { visible: true, disabled: true };
const notVisibleProps = { visible: false, disabled: false };
const visibleItem = { display: 'item', id: 'item', ...activeProps };
const notVisibleSection = {
display: 'Not visible',
id: 'not-visible',
items: toIndexedArray([visibleItem]),
...notVisibleProps,
};
const disabledSection = {
display: 'Disabled',
id: 'disabled',
items: toIndexedArray([visibleItem]),
...disabledProps,
};
const noItemsSection = {
display: 'No items',
id: 'no-items',
items: toIndexedArray([]),
...activeProps,
};
const noActiveItemsSection = {
display: 'No active items',
id: 'no-active-items',
items: toIndexedArray([
{ display: 'disabled', id: 'disabled', ...disabledProps },
{ display: 'notVisible', id: 'notVisible', ...notVisibleProps },
]),
...activeProps,
};
const activeSection = {
display: 'activeSection',
id: 'activeSection',
items: toIndexedArray([visibleItem]),
...activeProps,
};
const managementSections = [
notVisibleSection,
disabledSection,
noItemsSection,
noActiveItemsSection,
activeSection,
];
describe('Management', () => {
it('filters and filters and maps section objects into SidebarNav items', () => {
expect(sideNavItems(managementSections, 'active-item-id')).toMatchSnapshot();
});
});

View file

@ -0,0 +1,94 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { EuiIcon, EuiSideNav, IconType } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import React from 'react';
import { IndexedArray } from 'ui/indexed_array';
interface Subsection {
disabled: boolean;
visible: boolean;
id: string;
display: string;
url?: string;
icon?: IconType;
}
interface Section extends Subsection {
items: IndexedArray<Subsection>;
}
const sectionVisible = (section: Subsection) => !section.disabled && section.visible;
const sectionToNav = (selectedId: string) => ({ display, id, url, icon }: Subsection) => ({
id,
name: display,
icon: icon ? <EuiIcon type={icon} /> : null,
isSelected: selectedId === id,
href: url,
'data-test-subj': id,
});
export const sideNavItems = (sections: Section[], selectedId: string) =>
sections
.filter(sectionVisible)
.filter(section => section.items.filter(sectionVisible).length)
.map(section => ({
items: section.items.inOrder.filter(sectionVisible).map(sectionToNav(selectedId)),
...sectionToNav(selectedId)(section),
}));
interface SidebarNavProps {
sections: Section[];
selectedId: string;
}
interface SidebarNavState {
isSideNavOpenOnMobile: boolean;
}
export class SidebarNav extends React.Component<SidebarNavProps, SidebarNavState> {
constructor(props: SidebarNavProps) {
super(props);
this.state = {
isSideNavOpenOnMobile: false,
};
}
public render() {
return (
<EuiSideNav
mobileTitle={this.renderMobileTitle()}
isOpenOnMobile={this.state.isSideNavOpenOnMobile}
toggleOpenOnMobile={this.toggleOpenOnMobile}
items={sideNavItems(this.props.sections, this.props.selectedId)}
style={{ width: 192, paddingBottom: '16px' }}
/>
);
}
private renderMobileTitle() {
return <FormattedMessage id="common.ui.management.nav.menu" defaultMessage="Management menu" />;
}
private toggleOpenOnMobile = () => {
this.setState({
isSideNavOpenOnMobile: !this.state.isSideNavOpenOnMobile,
});
};
}

31
src/ui/public/management/index.d.ts vendored Normal file
View file

@ -0,0 +1,31 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
declare module 'ui/management' {
export const PAGE_TITLE_COMPONENT: string;
export const PAGE_SUBTITLE_COMPONENT: string;
export const PAGE_FOOTER_COMPONENT: string;
export const SidebarNav: React.SFC<any>;
export function registerSettingsComponent(
id: string,
component: string | React.SFC<any>,
allowOverride: boolean
): void;
export const management: any; // TODO - properly provide types
}

View file

@ -27,4 +27,5 @@ export {
} from '../../../legacy/core_plugins/kibana/public/management/sections/settings/components/component_registry';
export { Field } from '../../../legacy/core_plugins/kibana/public/management/sections/settings/components/field/field';
export { management } from './sections_register';
export { SidebarNav } from './components';
export { MANAGEMENT_BREADCRUMB } from './breadcrumbs';

View file

@ -20,8 +20,9 @@
import { assign } from 'lodash';
import { IndexedArray } from '../indexed_array';
export class ManagementSection {
const listeners = [];
export class ManagementSection {
/**
* @param {string} id
* @param {object} options
@ -55,6 +56,16 @@ export class ManagementSection {
return this.items.inOrder.filter(item => item.visible);
}
/**
* Registers a callback that will be executed when management sections are updated
* Globally bound to solve for sidebar nav needs
*
* @param {function} fn
*/
addListener(fn) {
listeners.push(fn);
}
/**
* Registers a sub-section
*
@ -71,6 +82,7 @@ export class ManagementSection {
}
this.items.push(item);
listeners.forEach(fn => fn());
return item;
}
@ -82,6 +94,7 @@ export class ManagementSection {
*/
deregister(id) {
this.items.remove(item => item.id === id);
listeners.forEach(fn => fn(this.items));
}
/**

View file

@ -38,19 +38,18 @@ export function SettingsPageProvider({ getService, getPageObjects }) {
await find.clickByDisplayedLinkText(text);
}
async clickKibanaSettings() {
await find.clickByDisplayedLinkText('Advanced Settings');
await testSubjects.click('settings');
await PageObjects.header.waitUntilLoadingHasFinished();
// Verify navigation is successful.
await testSubjects.existOrFail('managementSettingsTitle');
}
async clickKibanaSavedObjects() {
await find.clickByDisplayedLinkText('Saved Objects');
await testSubjects.click('objects');
}
async clickKibanaIndices() {
log.debug('clickKibanaIndices link');
await find.clickByDisplayedLinkText('Index Patterns');
await testSubjects.click('indices');
}
async getAdvancedSettings(propertyName) {

View file

@ -23,4 +23,5 @@ declare module '@elastic/eui' {
export const EuiWrappingPopover: React.SFC<any>;
export const EuiCopy: React.SFC<any>;
export const EuiOutsideClickDetector: React.SFC<any>;
export const EuiSideNav: React.SFC<any>;
}

View file

@ -143,6 +143,7 @@ export class KibanaFrameworkAdapter implements FrameworkAdapter {
toController === 'self'
? `<${this.PLUGIN_ID}><div id="${this.PLUGIN_ID}ReactRoot"></div></${this.PLUGIN_ID}>`
: `<kbn-management-app section="${this.PLUGIN_ID.replace('_', '-')}">
<div id="management-sidenav" class="euiPageSideBar" style="position: static;"></div>
<div id="${this.PLUGIN_ID}ReactRoot" />
</kbn-management-app>`,
// tslint:disable-next-line: max-classes-per-file

View file

@ -9,8 +9,8 @@
.indTable__horizontalScrollContainer {
overflow-x: auto;
max-width: 100%;
height: 100vh;
}
.indTable__horizontalScroll {
min-width: 800px;
width: 100%;

View file

@ -12,7 +12,7 @@ const esSection = management.getSection('elasticsearch');
esSection.register('index_management', {
visible: true,
display: i18n.translate('xpack.idxMgmt.appTitle', { defaultMessage: 'Index Management' }),
order: 1,
order: 2,
url: `#${BASE_PATH}indices`
});

View file

@ -22,7 +22,6 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiLoadingSpinner,
EuiPage,
EuiSpacer,
EuiSearchBar,
EuiSwitch,
@ -37,7 +36,6 @@ import {
EuiTableRowCellCheckbox,
EuiTitle,
EuiText,
EuiPageBody,
EuiPageContent,
} from '@elastic/eui';
@ -357,136 +355,132 @@ export class IndexTableUi extends Component {
const { selectedIndicesMap } = this.state;
const atLeastOneItemSelected = Object.keys(selectedIndicesMap).length > 0;
return (
<EuiPage>
<EuiPageBody>
<EuiPageContent>
<EuiFlexGroup justifyContent="spaceBetween" alignItems="flexEnd">
<EuiFlexItem grow={false}>
<EuiTitle size="l">
<h1>
<FormattedMessage
id="xpack.idxMgmt.indexTable.sectionHeading"
defaultMessage="Index management"
/>
</h1>
</EuiTitle>
<EuiSpacer size="s" />
<EuiText>
<p>
<FormattedMessage
id="xpack.idxMgmt.indexTable.sectionDescription"
defaultMessage="Update your Elasticsearch indices individually or in bulk."
/>
</p>
</EuiText>
</EuiFlexItem>
<EuiFlexItem grow={false}>
{indicesLoading && allIndices.length === 0 ? null : (
<EuiFlexGroup>
{getToggleExtensions().map(toggle => {
return this.renderToggleControl(toggle);
})}
<EuiFlexItem grow={false}>
<EuiSwitch
id="checkboxShowSystemIndices"
checked={showSystemIndices}
onChange={event => showSystemIndicesChanged(event.target.checked)}
label={
<FormattedMessage
id="xpack.idxMgmt.indexTable.systemIndicesSwitchLabel"
defaultMessage="Include system indices"
/>
}
/>
</EuiFlexItem>
</EuiFlexGroup>
)}
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer />
{this.renderBanners()}
<EuiFlexGroup gutterSize="l" alignItems="center">
{atLeastOneItemSelected ? (
<EuiPageContent>
<EuiFlexGroup justifyContent="spaceBetween" alignItems="flexEnd">
<EuiFlexItem grow={false}>
<EuiTitle size="m">
<h1>
<FormattedMessage
id="xpack.idxMgmt.indexTable.sectionHeading"
defaultMessage="Index management"
/>
</h1>
</EuiTitle>
<EuiSpacer size="s" />
<EuiText>
<p>
<FormattedMessage
id="xpack.idxMgmt.indexTable.sectionDescription"
defaultMessage="Update your Elasticsearch indices individually or in bulk."
/>
</p>
</EuiText>
</EuiFlexItem>
<EuiFlexItem grow={false}>
{indicesLoading && allIndices.length === 0 ? null : (
<EuiFlexGroup>
{getToggleExtensions().map(toggle => {
return this.renderToggleControl(toggle);
})}
<EuiFlexItem grow={false}>
<Route
key="menu"
render={() => (
<IndexActionsContextMenu
indexNames={Object.keys(selectedIndicesMap)}
resetSelection={() => {
this.setState({ selectedIndicesMap: {} });
}}
<EuiSwitch
id="checkboxShowSystemIndices"
checked={showSystemIndices}
onChange={event => showSystemIndicesChanged(event.target.checked)}
label={
<FormattedMessage
id="xpack.idxMgmt.indexTable.systemIndicesSwitchLabel"
defaultMessage="Include system indices"
/>
)}
}
/>
</EuiFlexItem>
) : null}
{indicesLoading && allIndices.length === 0 ? null : (
<Fragment>
<EuiFlexItem>
<EuiSearchBar
filters={this.getFilters()}
defaultQuery={filter}
query={filter}
box={{
incremental: true,
placeholder: intl.formatMessage({
id: 'xpack.idxMgmt.indexTable.systemIndicesSearchInputPlaceholder',
defaultMessage: 'Search',
}),
}}
aria-label={intl.formatMessage({
id: 'xpack.idxMgmt.indexTable.systemIndicesSearchIndicesAriaLabel',
defaultMessage: 'Search indices',
})}
data-test-subj="indexTableFilterInput"
onChange={this.onFilterChanged}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton
isLoading={indicesLoading}
color="secondary"
onClick={() => {
loadIndices();
}}
iconType="refresh"
>
<FormattedMessage
id="xpack.idxMgmt.indexTable.reloadIndicesButton"
defaultMessage="Reload indices"
/>
</EuiButton>
</EuiFlexItem>
</Fragment>
)}
</EuiFlexGroup>
{this.renderFilterError()}
<EuiSpacer size="m" />
{indices.length > 0 ? (
<EuiTable>
<EuiTableHeader>
<EuiTableHeaderCellCheckbox>
<EuiCheckbox
id="selectAllIndexes"
checked={this.areAllItemsSelected()}
onChange={this.toggleAll}
type="inList"
/>
</EuiTableHeaderCellCheckbox>
{this.buildHeader()}
</EuiTableHeader>
<EuiTableBody>{this.buildRows()}</EuiTableBody>
</EuiTable>
) : (
emptyState
</EuiFlexGroup>
)}
<EuiSpacer size="m" />
{indices.length > 0 ? this.renderPager() : null}
</EuiPageContent>
</EuiPageBody>
</EuiPage>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer />
{this.renderBanners()}
<EuiFlexGroup gutterSize="l" alignItems="center">
{atLeastOneItemSelected ? (
<EuiFlexItem grow={false}>
<Route
key="menu"
render={() => (
<IndexActionsContextMenu
indexNames={Object.keys(selectedIndicesMap)}
resetSelection={() => {
this.setState({ selectedIndicesMap: {} });
}}
/>
)}
/>
</EuiFlexItem>
) : null}
{indicesLoading && allIndices.length === 0 ? null : (
<Fragment>
<EuiFlexItem>
<EuiSearchBar
filters={this.getFilters()}
defaultQuery={filter}
query={filter}
box={{
incremental: true,
placeholder: intl.formatMessage({
id: 'xpack.idxMgmt.indexTable.systemIndicesSearchInputPlaceholder',
defaultMessage: 'Search',
}),
}}
aria-label={intl.formatMessage({
id: 'xpack.idxMgmt.indexTable.systemIndicesSearchIndicesAriaLabel',
defaultMessage: 'Search indices',
})}
data-test-subj="indexTableFilterInput"
onChange={this.onFilterChanged}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton
isLoading={indicesLoading}
color="secondary"
onClick={() => {
loadIndices();
}}
iconType="refresh"
>
<FormattedMessage
id="xpack.idxMgmt.indexTable.reloadIndicesButton"
defaultMessage="Reload indices"
/>
</EuiButton>
</EuiFlexItem>
</Fragment>
)}
</EuiFlexGroup>
{this.renderFilterError()}
<EuiSpacer size="m" />
{indices.length > 0 ? (
<EuiTable>
<EuiTableHeader>
<EuiTableHeaderCellCheckbox>
<EuiCheckbox
id="selectAllIndexes"
checked={this.areAllItemsSelected()}
onChange={this.toggleAll}
type="inList"
/>
</EuiTableHeaderCellCheckbox>
{this.buildHeader()}
</EuiTableHeader>
<EuiTableBody>{this.buildRows()}</EuiTableBody>
</EuiTable>
) : (
emptyState
)}
<EuiSpacer size="m" />
{indices.length > 0 ? this.renderPager() : null}
</EuiPageContent>
);
}
}

View file

@ -1,5 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`LicenseStatus component should display display warning is expired 1`] = `"<div><div class=\\"euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--justifyContentSpaceAround euiFlexGroup--directionRow euiFlexGroup--responsive\\"><div class=\\"euiFlexItem euiFlexItem--flexGrowZero\\"><div class=\\"euiFlexGroup euiFlexGroup--gutterSmall euiFlexGroup--alignItemsCenter euiFlexGroup--directionRow euiFlexGroup--responsive\\"><div class=\\"euiFlexItem euiFlexItem--flexGrowZero\\"><svg class=\\"euiIcon euiIcon--medium euiIcon--danger\\" focusable=\\"false\\" xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"16\\" height=\\"16\\" viewBox=\\"0 0 16 16\\"><path fill-rule=\\"evenodd\\" d=\\"M8.378 1.496l6.695 10.984A1 1 0 0 1 14.22 14H1.667a1 1 0 0 1-.883-1.47L6.642 1.545a1 1 0 0 1 1.736-.05zm-.853.52L1.667 13h12.552L7.525 2.016zM7.14 10.06L6.9 5.18h1.3l-.25 4.878h-.81zm.394 1.901a.61.61 0 0 1-.448-.186.606.606 0 0 1-.186-.444c0-.174.062-.323.186-.446a.614.614 0 0 1 .448-.184c.169 0 .315.06.44.182.124.122.186.27.186.448a.6.6 0 0 1-.189.446.607.607 0 0 1-.437.184z\\"></path></svg></div><div class=\\"euiFlexItem euiFlexItem--flexGrowZero\\"><h2 data-test-subj=\\"licenseText\\" class=\\"euiTitle euiTitle--large\\">Your Platinum license has expired</h2></div></div></div></div><div class=\\"euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--justifyContentSpaceAround euiFlexGroup--directionRow euiFlexGroup--responsive\\"><div class=\\"euiFlexItem euiFlexItem--flexGrowZero\\"><span data-test-subj=\\"licenseSubText\\"><div class=\\"euiText euiText--medium\\"><div class=\\"euiTextColor euiTextColor--subdued\\">Your license expired on <strong></strong></div></div></span></div></div><div class=\\"euiSpacer euiSpacer--l\\"></div></div>"`;
exports[`LicenseStatus component should display display warning is expired 1`] = `"<div><div class=\\"euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--justifyContentSpaceAround euiFlexGroup--directionRow euiFlexGroup--responsive\\"><div class=\\"euiFlexItem euiFlexItem--flexGrowZero\\"><div class=\\"euiFlexGroup euiFlexGroup--gutterSmall euiFlexGroup--alignItemsCenter euiFlexGroup--directionRow euiFlexGroup--responsive\\"><div class=\\"euiFlexItem euiFlexItem--flexGrowZero\\"><svg class=\\"euiIcon euiIcon--medium euiIcon--danger\\" focusable=\\"false\\" xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"16\\" height=\\"16\\" viewBox=\\"0 0 16 16\\"><path fill-rule=\\"evenodd\\" d=\\"M8.378 1.496l6.695 10.984A1 1 0 0 1 14.22 14H1.667a1 1 0 0 1-.883-1.47L6.642 1.545a1 1 0 0 1 1.736-.05zm-.853.52L1.667 13h12.552L7.525 2.016zM7.14 10.06L6.9 5.18h1.3l-.25 4.878h-.81zm.394 1.901a.61.61 0 0 1-.448-.186.606.606 0 0 1-.186-.444c0-.174.062-.323.186-.446a.614.614 0 0 1 .448-.184c.169 0 .315.06.44.182.124.122.186.27.186.448a.6.6 0 0 1-.189.446.607.607 0 0 1-.437.184z\\"></path></svg></div><div class=\\"euiFlexItem euiFlexItem--flexGrowZero\\"><h2 data-test-subj=\\"licenseText\\" class=\\"euiTitle euiTitle--medium\\">Your Platinum license has expired</h2></div></div></div></div><div class=\\"euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--justifyContentSpaceAround euiFlexGroup--directionRow euiFlexGroup--responsive\\"><div class=\\"euiFlexItem euiFlexItem--flexGrowZero\\"><span data-test-subj=\\"licenseSubText\\"><div class=\\"euiText euiText--medium\\"><div class=\\"euiTextColor euiTextColor--subdued\\">Your license expired on <strong></strong></div></div></span></div></div><div class=\\"euiSpacer euiSpacer--l\\"></div></div>"`;
exports[`LicenseStatus component should display normally when license is active 1`] = `"<div><div class=\\"euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--justifyContentSpaceAround euiFlexGroup--directionRow euiFlexGroup--responsive\\"><div class=\\"euiFlexItem euiFlexItem--flexGrowZero\\"><div class=\\"euiFlexGroup euiFlexGroup--gutterSmall euiFlexGroup--alignItemsCenter euiFlexGroup--directionRow euiFlexGroup--responsive\\"><div class=\\"euiFlexItem euiFlexItem--flexGrowZero\\"><svg class=\\"euiIcon euiIcon--medium euiIcon--success\\" focusable=\\"false\\" xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"16\\" height=\\"16\\" viewBox=\\"0 0 16 16\\"><path fill-rule=\\"evenodd\\" d=\\"M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm3.65-10.857L6.91 9.8 4.35 7.286a.5.5 0 0 0-.7.714l2.909 2.857a.5.5 0 0 0 .7 0l5.091-5a.5.5 0 1 0-.7-.714z\\"></path></svg></div><div class=\\"euiFlexItem euiFlexItem--flexGrowZero\\"><h2 data-test-subj=\\"licenseText\\" class=\\"euiTitle euiTitle--large\\">Your Gold license is active</h2></div></div></div></div><div class=\\"euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--justifyContentSpaceAround euiFlexGroup--directionRow euiFlexGroup--responsive\\"><div class=\\"euiFlexItem euiFlexItem--flexGrowZero\\"><span data-test-subj=\\"licenseSubText\\"><div class=\\"euiText euiText--medium\\"><div class=\\"euiTextColor euiTextColor--subdued\\">Your license will expire on <strong>October 12, 2099 7:00 PM EST</strong></div></div></span></div></div><div class=\\"euiSpacer euiSpacer--l\\"></div></div>"`;
exports[`LicenseStatus component should display normally when license is active 1`] = `"<div><div class=\\"euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--justifyContentSpaceAround euiFlexGroup--directionRow euiFlexGroup--responsive\\"><div class=\\"euiFlexItem euiFlexItem--flexGrowZero\\"><div class=\\"euiFlexGroup euiFlexGroup--gutterSmall euiFlexGroup--alignItemsCenter euiFlexGroup--directionRow euiFlexGroup--responsive\\"><div class=\\"euiFlexItem euiFlexItem--flexGrowZero\\"><svg class=\\"euiIcon euiIcon--medium euiIcon--success\\" focusable=\\"false\\" xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"16\\" height=\\"16\\" viewBox=\\"0 0 16 16\\"><path fill-rule=\\"evenodd\\" d=\\"M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16zm3.65-10.857L6.91 9.8 4.35 7.286a.5.5 0 0 0-.7.714l2.909 2.857a.5.5 0 0 0 .7 0l5.091-5a.5.5 0 1 0-.7-.714z\\"></path></svg></div><div class=\\"euiFlexItem euiFlexItem--flexGrowZero\\"><h2 data-test-subj=\\"licenseText\\" class=\\"euiTitle euiTitle--medium\\">Your Gold license is active</h2></div></div></div></div><div class=\\"euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--justifyContentSpaceAround euiFlexGroup--directionRow euiFlexGroup--responsive\\"><div class=\\"euiFlexItem euiFlexItem--flexGrowZero\\"><span data-test-subj=\\"licenseSubText\\"><div class=\\"euiText euiText--medium\\"><div class=\\"euiTextColor euiTextColor--subdued\\">Your license will expire on <strong>October 12, 2099 7:00 PM EST</strong></div></div></span></div></div><div class=\\"euiSpacer euiSpacer--l\\"></div></div>"`;

View file

@ -105,24 +105,29 @@ exports[`TelemetryOptIn should display when telemetry not opted in 1`] = `
}
}
>
<EuiText
grow={true}
size="m"
<EuiSpacer
size="s"
>
<div
className="euiText euiText--medium"
className="euiSpacer euiSpacer--s"
/>
</EuiSpacer>
<EuiTitle
size="s"
textTransform="none"
>
<h4
className="euiTitle euiTitle--small"
>
<p>
<FormattedMessage
defaultMessage="Gold and platinum customers: help support give you better service."
id="xpack.licenseMgmt.telemetryOptIn.customersHelpSupportDescription"
values={Object {}}
>
Gold and platinum customers: help support give you better service.
</FormattedMessage>
</p>
</div>
</EuiText>
<FormattedMessage
defaultMessage="Help Elastic support provide better service"
id="xpack.licenseMgmt.telemetryOptIn.customersHelpSupportDescription"
values={Object {}}
>
Help Elastic support provide better service
</FormattedMessage>
</h4>
</EuiTitle>
<EuiSpacer
size="s"
>

View file

@ -133,30 +133,6 @@ exports[`UploadLicense should display a modal when license requires acknowledgem
uploadLicense={[Function]}
uploadLicenseStatus={[Function]}
>
<EuiTitle
className="eui-textCenter"
size="l"
textTransform="none"
>
<h1
className="euiTitle euiTitle--large eui-textCenter"
>
<FormattedMessage
defaultMessage="Upload your license"
id="xpack.licenseMgmt.uploadLicense.uploadLicenseTitle"
values={Object {}}
>
Upload your license
</FormattedMessage>
</h1>
</EuiTitle>
<EuiSpacer
size="l"
>
<div
className="euiSpacer euiSpacer--l"
/>
</EuiSpacer>
<EuiPageContent
horizontalPosition="center"
panelPaddingSize="l"
@ -175,6 +151,29 @@ exports[`UploadLicense should display a modal when license requires acknowledgem
<div
className="euiPageContentBody"
>
<EuiTitle
size="m"
textTransform="none"
>
<h1
className="euiTitle euiTitle--medium"
>
<FormattedMessage
defaultMessage="Upload your license"
id="xpack.licenseMgmt.uploadLicense.uploadLicenseTitle"
values={Object {}}
>
Upload your license
</FormattedMessage>
</h1>
</EuiTitle>
<EuiSpacer
size="l"
>
<div
className="euiSpacer euiSpacer--l"
/>
</EuiSpacer>
<EuiOverlayMask>
<Portal
containerInfo={
@ -902,30 +901,6 @@ exports[`UploadLicense should display an error when ES says license is expired 1
uploadLicense={[Function]}
uploadLicenseStatus={[Function]}
>
<EuiTitle
className="eui-textCenter"
size="l"
textTransform="none"
>
<h1
className="euiTitle euiTitle--large eui-textCenter"
>
<FormattedMessage
defaultMessage="Upload your license"
id="xpack.licenseMgmt.uploadLicense.uploadLicenseTitle"
values={Object {}}
>
Upload your license
</FormattedMessage>
</h1>
</EuiTitle>
<EuiSpacer
size="l"
>
<div
className="euiSpacer euiSpacer--l"
/>
</EuiSpacer>
<EuiPageContent
horizontalPosition="center"
panelPaddingSize="l"
@ -944,6 +919,29 @@ exports[`UploadLicense should display an error when ES says license is expired 1
<div
className="euiPageContentBody"
>
<EuiTitle
size="m"
textTransform="none"
>
<h1
className="euiTitle euiTitle--medium"
>
<FormattedMessage
defaultMessage="Upload your license"
id="xpack.licenseMgmt.uploadLicense.uploadLicenseTitle"
values={Object {}}
>
Upload your license
</FormattedMessage>
</h1>
</EuiTitle>
<EuiSpacer
size="l"
>
<div
className="euiSpacer euiSpacer--l"
/>
</EuiSpacer>
<EuiText
grow={true}
size="m"
@ -1389,30 +1387,6 @@ exports[`UploadLicense should display an error when ES says license is invalid 1
uploadLicense={[Function]}
uploadLicenseStatus={[Function]}
>
<EuiTitle
className="eui-textCenter"
size="l"
textTransform="none"
>
<h1
className="euiTitle euiTitle--large eui-textCenter"
>
<FormattedMessage
defaultMessage="Upload your license"
id="xpack.licenseMgmt.uploadLicense.uploadLicenseTitle"
values={Object {}}
>
Upload your license
</FormattedMessage>
</h1>
</EuiTitle>
<EuiSpacer
size="l"
>
<div
className="euiSpacer euiSpacer--l"
/>
</EuiSpacer>
<EuiPageContent
horizontalPosition="center"
panelPaddingSize="l"
@ -1431,6 +1405,29 @@ exports[`UploadLicense should display an error when ES says license is invalid 1
<div
className="euiPageContentBody"
>
<EuiTitle
size="m"
textTransform="none"
>
<h1
className="euiTitle euiTitle--medium"
>
<FormattedMessage
defaultMessage="Upload your license"
id="xpack.licenseMgmt.uploadLicense.uploadLicenseTitle"
values={Object {}}
>
Upload your license
</FormattedMessage>
</h1>
</EuiTitle>
<EuiSpacer
size="l"
>
<div
className="euiSpacer euiSpacer--l"
/>
</EuiSpacer>
<EuiText
grow={true}
size="m"
@ -1876,30 +1873,6 @@ exports[`UploadLicense should display an error when submitting invalid JSON 1`]
uploadLicense={[Function]}
uploadLicenseStatus={[Function]}
>
<EuiTitle
className="eui-textCenter"
size="l"
textTransform="none"
>
<h1
className="euiTitle euiTitle--large eui-textCenter"
>
<FormattedMessage
defaultMessage="Upload your license"
id="xpack.licenseMgmt.uploadLicense.uploadLicenseTitle"
values={Object {}}
>
Upload your license
</FormattedMessage>
</h1>
</EuiTitle>
<EuiSpacer
size="l"
>
<div
className="euiSpacer euiSpacer--l"
/>
</EuiSpacer>
<EuiPageContent
horizontalPosition="center"
panelPaddingSize="l"
@ -1918,6 +1891,29 @@ exports[`UploadLicense should display an error when submitting invalid JSON 1`]
<div
className="euiPageContentBody"
>
<EuiTitle
size="m"
textTransform="none"
>
<h1
className="euiTitle euiTitle--medium"
>
<FormattedMessage
defaultMessage="Upload your license"
id="xpack.licenseMgmt.uploadLicense.uploadLicenseTitle"
values={Object {}}
>
Upload your license
</FormattedMessage>
</h1>
</EuiTitle>
<EuiSpacer
size="l"
>
<div
className="euiSpacer euiSpacer--l"
/>
</EuiSpacer>
<EuiText
grow={true}
size="m"
@ -2363,30 +2359,6 @@ exports[`UploadLicense should display error when ES returns error 1`] = `
uploadLicense={[Function]}
uploadLicenseStatus={[Function]}
>
<EuiTitle
className="eui-textCenter"
size="l"
textTransform="none"
>
<h1
className="euiTitle euiTitle--large eui-textCenter"
>
<FormattedMessage
defaultMessage="Upload your license"
id="xpack.licenseMgmt.uploadLicense.uploadLicenseTitle"
values={Object {}}
>
Upload your license
</FormattedMessage>
</h1>
</EuiTitle>
<EuiSpacer
size="l"
>
<div
className="euiSpacer euiSpacer--l"
/>
</EuiSpacer>
<EuiPageContent
horizontalPosition="center"
panelPaddingSize="l"
@ -2405,6 +2377,29 @@ exports[`UploadLicense should display error when ES returns error 1`] = `
<div
className="euiPageContentBody"
>
<EuiTitle
size="m"
textTransform="none"
>
<h1
className="euiTitle euiTitle--medium"
>
<FormattedMessage
defaultMessage="Upload your license"
id="xpack.licenseMgmt.uploadLicense.uploadLicenseTitle"
values={Object {}}
>
Upload your license
</FormattedMessage>
</h1>
</EuiTitle>
<EuiSpacer
size="l"
>
<div
className="euiSpacer euiSpacer--l"
/>
</EuiSpacer>
<EuiText
grow={true}
size="m"

View file

@ -1,12 +1,5 @@
.licFeature {
flex-grow: 1;
background: $euiColorLightestShade;
min-height: 100vh;
}
.licManagement__pageBody {
padding-top: $euiSizeL;
min-height: auto;
}
// EUITODO: Fix modal width/max-width
@ -19,5 +12,5 @@
}
.licManagement__ieFlex {
flex-shrink: 0;
flex-shrink: 0;
}

View file

@ -8,18 +8,13 @@ import React from 'react';
import { LicenseDashboard, UploadLicense } from './sections/';
import { Switch, Route } from 'react-router-dom';
import { BASE_PATH } from '../common/constants';
import {
EuiPage,
EuiPageBody,
} from '@elastic/eui';
import { EuiPageBody } from '@elastic/eui';
export default () => (
<EuiPage restrictWidth>
<EuiPageBody className="licManagement__pageBody">
<Switch>
<Route path={`${BASE_PATH}upload_license`} component={UploadLicense}/>
<Route path={`${BASE_PATH}`} component={LicenseDashboard}/>
</Switch>
</EuiPageBody>
</EuiPage>
);
<EuiPageBody>
<Switch>
<Route path={`${BASE_PATH}upload_license`} component={UploadLicense} />
<Route path={`${BASE_PATH}`} component={LicenseDashboard} />
</Switch>
</EuiPageBody>
);

View file

@ -10,6 +10,7 @@ import {
EuiCheckbox,
EuiSpacer,
EuiText,
EuiTitle,
EuiPopover
} from '@elastic/eui';
import { showTelemetryOptIn, getTelemetryFetcher, PRIVACY_STATEMENT_URL, OptInExampleFlyout } from '../../lib/telemetry';
@ -60,14 +61,15 @@ export class TelemetryOptIn extends React.Component {
if (!isStartTrial) {
toCurrentCustomers = (
<Fragment>
<EuiText>
<p>
<EuiSpacer size="s"/>
<EuiTitle size="s">
<h4>
<FormattedMessage
id="xpack.licenseMgmt.telemetryOptIn.customersHelpSupportDescription"
defaultMessage="Gold and platinum customers: help support give you better service."
defaultMessage="Help Elastic support provide better service"
/>
</p>
</EuiText>
</h4>
</EuiTitle>
<EuiSpacer size="s"/>
</Fragment>
);

View file

@ -13,7 +13,7 @@ management.getSection('elasticsearch').register('license_management', {
display: i18n.translate('xpack.licenseMgmt.managementSectionDisplayName', {
defaultMessage: 'License Management',
}),
order: 4,
order: 1,
url: `#${BASE_PATH}home`
});

View file

@ -20,10 +20,8 @@ import {
export const LicenseDashboard = () => {
return (
<div className="licManagement__contain">
<EuiFlexGroup justifyContent="spaceAround">
<LicenseStatus />
</EuiFlexGroup>
<div>
<LicenseStatus />
<EuiSpacer size="l" />
<EuiFlexGroup justifyContent="spaceAround">
<EuiFlexItem>

View file

@ -87,7 +87,7 @@ export class LicenseStatus extends React.PureComponent {
<EuiFlexGroup alignItems="center" gutterSize="s">
<EuiFlexItem grow={false}>{icon}</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiTitle size="l">
<EuiTitle size="m">
<h2 data-test-subj="licenseText">{title}</h2>
</EuiTitle>
</EuiFlexItem>

View file

@ -112,19 +112,19 @@ export class UploadLicense extends React.PureComponent {
const { currentLicenseType, applying } = this.props;
return (
<Fragment>
<EuiTitle className="eui-textCenter" size="l">
<h1>
<FormattedMessage
id="xpack.licenseMgmt.uploadLicense.uploadLicenseTitle"
defaultMessage="Upload your license"
/>
</h1>
</EuiTitle>
<EuiSpacer />
<EuiPageContent horizontalPosition="center" verticalPosition="center">
<EuiPageContentBody>
<EuiTitle size="m">
<h1>
<FormattedMessage
id="xpack.licenseMgmt.uploadLicense.uploadLicenseTitle"
defaultMessage="Upload your license"
/>
</h1>
</EuiTitle>
<EuiSpacer />
{this.acknowledgeModal()}
<EuiText>

View file

@ -1,9 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`PipelineEditor component includes required error message for falsy pipeline id 1`] = `
<EuiPage
<div
data-test-subj="pipelineEdit pipelineEdit-"
restrictWidth={false}
>
<EuiPageContent
horizontalPosition="center"
@ -341,13 +340,12 @@ Default value: 1024"
</EuiFlexItem>
</EuiFlexGroup>
</EuiPageContent>
</EuiPage>
</div>
`;
exports[`PipelineEditor component invalidates form for invalid pipeline id input 1`] = `
<EuiPage
<div
data-test-subj="pipelineEdit pipelineEdit-$invalid-pipeline-name"
restrictWidth={false}
>
<EuiPageContent
horizontalPosition="center"
@ -684,13 +682,12 @@ Default value: 1024"
</EuiFlexItem>
</EuiFlexGroup>
</EuiPageContent>
</EuiPage>
</div>
`;
exports[`PipelineEditor component invalidates form for pipeline id with spaces 1`] = `
<EuiPage
<div
data-test-subj="pipelineEdit pipelineEdit-pipeline id with spaces"
restrictWidth={false}
>
<EuiPageContent
horizontalPosition="center"
@ -1027,13 +1024,12 @@ Default value: 1024"
</EuiFlexItem>
</EuiFlexGroup>
</EuiPageContent>
</EuiPage>
</div>
`;
exports[`PipelineEditor component matches snapshot for clone pipeline 1`] = `
<EuiPage
<div
data-test-subj="pipelineEdit pipelineEdit-pipelineId"
restrictWidth={false}
>
<EuiPageContent
horizontalPosition="center"
@ -1360,13 +1356,12 @@ Default value: 1024"
</EuiFlexItem>
</EuiFlexGroup>
</EuiPageContent>
</EuiPage>
</div>
`;
exports[`PipelineEditor component matches snapshot for create pipeline 1`] = `
<EuiPage
<div
data-test-subj="pipelineEdit pipelineEdit-pipelineId"
restrictWidth={false}
>
<EuiPageContent
horizontalPosition="center"
@ -1699,13 +1694,12 @@ Default value: 1024"
</EuiFlexItem>
</EuiFlexGroup>
</EuiPageContent>
</EuiPage>
</div>
`;
exports[`PipelineEditor component matches snapshot for edit pipeline 1`] = `
<EuiPage
<div
data-test-subj="pipelineEdit pipelineEdit-pipelineId"
restrictWidth={false}
>
<EuiPageContent
horizontalPosition="center"
@ -2032,5 +2026,5 @@ Default value: 1024"
</EuiFlexItem>
</EuiFlexGroup>
</EuiPageContent>
</EuiPage>
</div>
`;

View file

@ -23,7 +23,6 @@ import {
EuiFieldText,
EuiForm,
EuiFormRow,
EuiPage,
EuiPageContent,
EuiSelect,
EuiSpacer,
@ -256,7 +255,7 @@ class PipelineEditorUi extends React.Component {
const { intl } = this.props;
return (
<EuiPage data-test-subj={`pipelineEdit pipelineEdit-${this.state.pipeline.id}`}>
<div data-test-subj={`pipelineEdit pipelineEdit-${this.state.pipeline.id}`}>
<EuiPageContent
style={{
width: 1100,
@ -467,7 +466,7 @@ class PipelineEditorUi extends React.Component {
confirmDeletePipeline={this.deletePipeline}
/>
)}
</EuiPage>
</div>
);
}
}

View file

@ -11,8 +11,10 @@ import {
EuiCallOut,
EuiEmptyPrompt,
EuiLoadingSpinner,
EuiPage,
EuiPageContent,
EuiTitle,
EuiText,
EuiSpacer,
} from '@elastic/eui';
import { InfoAlerts } from './info_alerts';
@ -267,8 +269,20 @@ class PipelineListUi extends React.Component {
const { clonePipeline, createPipeline, isReadOnly, openPipeline } = this.props;
const { isSelectable, message, pipelines, selection, showConfirmDeleteModal } = this.state;
return (
<EuiPage data-test-subj="pipelineList">
<div data-test-subj="pipelineList">
<EuiPageContent horizontalPosition="center">
<EuiTitle size="m">
<h1><FormattedMessage id="xpack.logstash.pipelineList.head" defaultMessage="Pipelines" /></h1>
</EuiTitle>
<EuiText color="subdued">
<p>
<FormattedMessage
id="xpack.logstash.pipelineList.subhead"
defaultMessage="Manage logstash event processing and see the result visually"
/>
</p>
</EuiText>
<EuiSpacer />
{this.renderNoPermissionCallOut()}
<PipelinesTable
clonePipeline={clonePipeline}
@ -293,7 +307,7 @@ class PipelineListUi extends React.Component {
showAddRoleAlert={this.state.showAddRoleAlert}
showEnableMonitoringAlert={this.state.showEnableMonitoringAlert}
/>
</EuiPage>
</div>
);
}
}

View file

@ -5,7 +5,7 @@
*/
import React from 'react';
import { EuiEmptyPrompt, EuiPage, EuiPageContent } from '@elastic/eui';
import { EuiEmptyPrompt, EuiPageContent } from '@elastic/eui';
import { UpgradeFailureTitle } from './upgrade_failure_title';
import { UpgradeFailureActions } from './upgrade_failure_actions';
import { UPGRADE_FAILURE } from './constants';
@ -24,7 +24,7 @@ export function UpgradeFailure({ isNewPipeline, isManualUpgrade, onClose, onRetr
: UPGRADE_FAILURE.UPGRADE_BUTTON_TEXT.NOT_MANUAL_UPGRADE;
return (
<EuiPage data-test-subj="pipelineEdit upgradeFailure" style={{ minHeight: '100vh' }}>
<div data-test-subj="pipelineEdit upgradeFailure" style={{ minHeight: '100vh' }}>
<EuiPageContent>
<EuiEmptyPrompt
actions={
@ -38,6 +38,6 @@ export function UpgradeFailure({ isNewPipeline, isManualUpgrade, onClose, onRetr
body={<p style={{ textAlign: 'left' }}>{messageText}</p>}
/>
</EuiPageContent>
</EuiPage>
</div>
);
}

View file

@ -1,4 +1,4 @@
<kbn-management-app section="logstash/pipelines/pipeline" omit-breadcrumb-pages="['pipeline']">
<kbn-management-app section="logstash/pipelines" omit-breadcrumb-pages="['pipeline']">
<pipeline-edit ng-if="pipelineEditRoute.isUpgraded" pipeline="pipelineEditRoute.pipeline"></pipeline-edit>
<upgrade-failure ng-if="!pipelineEditRoute.isUpgraded" pipeline="pipelineEditRoute.pipeline"></upgrade-failure>

View file

@ -1,3 +1,3 @@
<kbn-management-app section="logstash">
<kbn-management-app section="logstash/pipelines">
<pipeline-list></pipeline-list>
</kbn-management-app>

View file

@ -54,7 +54,7 @@ export function License(props) {
const { status, type, isExpired, expiryDate } = props;
return (
<EuiPage className="licenseManagement">
<EuiPageBody className="licManagement__pageBody">
<EuiPageBody>
<div className="licManagement__contain">
<LicenseStatus
isExpired={isExpired}

View file

@ -1,9 +1,3 @@
// SASSTODO: Hack for lack of body background
monitoring-main[page="pipeline"] {
background: $euiColorLightestShade;
min-height: 100vh;
}
.monPipelineViewer {
max-width: 1000px;
}

View file

@ -25,9 +25,8 @@ import { ReportInfoButton } from './report_info_button';
import {
EuiBasicTable,
EuiButtonIcon,
EuiPage,
EuiPageBody,
EuiPageContent,
EuiSpacer,
EuiText,
EuiTextColor,
EuiTitle,
@ -118,21 +117,23 @@ class ReportListingUi extends Component<Props, State> {
public render() {
return (
<EuiPage>
<EuiPageBody restrictWidth>
<EuiPageContent horizontalPosition="center">
<EuiTitle>
<h1>
<FormattedMessage
id="xpack.reporting.listing.reportsTitle"
defaultMessage="Reports"
/>
</h1>
</EuiTitle>
{this.renderTable()}
</EuiPageContent>
</EuiPageBody>
</EuiPage>
<EuiPageContent horizontalPosition="center" className="euiPageBody--restrictWidth-default">
<EuiTitle>
<h1>
<FormattedMessage id="xpack.reporting.listing.reportstitle" defaultMessage="Reports" />
</h1>
</EuiTitle>
<EuiText color="subdued">
<p>
<FormattedMessage
id="xpack.reporting.listing.reports.subtitle"
defaultMessage="Find reports generated in Kibana applications here"
/>
</p>
</EuiText>
<EuiSpacer />
{this.renderTable()}
</EuiPageContent>
);
}

View file

@ -1,3 +1,3 @@
<kbn-management-app section="kibana">
<div id="reportListingAnchor"></div>
</kbn-management-app>
<kbn-management-app section="kibana/reporting">
<div id="reportListingAnchor" class="euiPageBody--restrictWidth-default"></div>
</kbn-management-app>

View file

@ -4,3 +4,10 @@
.rollupJobWizardStepActions {
align-items: flex-end;
}
// Needed because this sits in between some EuiPage elements that require it
// sass-lint:disable no-ids
#rollupJobsReactRoot {
display: flex;
flex-grow: 1;
}

View file

@ -40,13 +40,11 @@ export class App extends Component {
render() {
return (
<div>
<Switch>
<Redirect exact from={`${CRUD_APP_BASE_PATH}`} to={`${CRUD_APP_BASE_PATH}/job_list`} />
<Route exact path={`${CRUD_APP_BASE_PATH}/job_list`} component={JobList} />
<Route exact path={`${CRUD_APP_BASE_PATH}/create`} component={JobCreate} />
</Switch>
</div>
<Switch>
<Redirect exact from={`${CRUD_APP_BASE_PATH}`} to={`${CRUD_APP_BASE_PATH}/job_list`} />
<Route exact path={`${CRUD_APP_BASE_PATH}/job_list`} component={JobList} />
<Route exact path={`${CRUD_APP_BASE_PATH}/create`} component={JobCreate} />
</Switch>
);
}
}

View file

@ -17,8 +17,6 @@ import {
EuiCallOut,
EuiLoadingKibana,
EuiOverlayMask,
EuiPage,
EuiPageBody,
EuiPageContent,
EuiPageContentHeader,
EuiSpacer,
@ -467,7 +465,7 @@ export class JobCreateUi extends Component {
if (isSaving) {
savingFeedback = (
<EuiOverlayMask>
<EuiLoadingKibana size="xl"/>
<EuiLoadingKibana size="xl" />
</EuiOverlayMask>
);
}
@ -510,40 +508,41 @@ export class JobCreateUi extends Component {
return (
<Fragment>
<EuiPage>
<EuiPageBody restrictWidth>
<EuiPageContent
horizontalPosition="center"
>
<EuiBreadcrumbs breadcrumbs={breadcrumbs} responsive={false} />
<EuiSpacer size="xs" />
<EuiPageContent
horizontalPosition="center"
>
<EuiBreadcrumbs breadcrumbs={breadcrumbs} responsive={false} />
<EuiSpacer size="xs" />
<EuiPageContentHeader>
<EuiTitle size="m">
<h1>
<FormattedMessage
id="xpack.rollupJobs.createTitle"
defaultMessage="Create rollup job"
/>
</h1>
</EuiTitle>
</EuiPageContentHeader>
<EuiPageContentHeader>
<EuiTitle size="l">
<h1>
<FormattedMessage
id="xpack.rollupJobs.createTitle"
defaultMessage="Create rollup job"
/>
</h1>
</EuiTitle>
</EuiPageContentHeader>
{saveErrorFeedback}
{saveErrorFeedback}
<EuiStepsHorizontal steps={this.getSteps()} />
<EuiStepsHorizontal steps={this.getSteps()} />
<EuiSpacer />
<EuiSpacer />
{this.renderCurrentStep()}
{this.renderCurrentStep()}
<EuiSpacer size="l" />
<EuiSpacer size="l" />
{this.renderNavigation()}
<EuiSpacer />
{this.renderNavigation()}
</EuiPageContent>
</EuiPageBody>
</EuiPage>
{this.renderCurrentStep()}
<EuiSpacer size="l" />
{this.renderNavigation()}
</EuiPageContent>
{savingFeedback}
</Fragment>
);

View file

@ -14,8 +14,6 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiLoadingSpinner,
EuiPage,
EuiPageBody,
EuiPageContent,
EuiPageContentHeader,
EuiPageContentHeaderSection,
@ -266,13 +264,12 @@ export class JobListUi extends Component {
}
return (
<EuiPage>
<EuiPageBody>
<EuiPageContent>
{content}
</EuiPageContent>
</EuiPageBody>
</EuiPage>
<EuiPageContent
horizontalPosition="center"
verticalPosition="center"
>
{content}
</EuiPageContent>
);
}
}

View file

@ -19,9 +19,7 @@ import {
EuiIcon,
EuiText,
EuiFieldText,
EuiPage,
EuiComboBox,
EuiPageBody,
EuiPageContent,
EuiPageContentHeader,
EuiPageContentHeaderSection,
@ -386,262 +384,260 @@ class EditUserUI extends Component {
}
return (
<EuiPage className="mgtUsersEditPage">
<EuiPageBody>
<EuiPageContent className="mgtUsersEditPage__content">
<EuiPageContentHeader>
<EuiPageContentHeaderSection>
<EuiTitle>
<h2>
{isNewUser ?
<FormattedMessage
id="xpack.security.management.users.editUser.newUserTitle"
defaultMessage="New user"
/>
:
<FormattedMessage
id="xpack.security.management.users.editUser.editUserTitle"
defaultMessage="Edit {userName} user"
values={{ userName: user.username }}
/>
}
</h2>
</EuiTitle>
</EuiPageContentHeaderSection>
{reserved && (
<EuiPageContentHeaderSection>
<EuiIcon type="lock" size="l" color="subdued" />
</EuiPageContentHeaderSection>
)}
</EuiPageContentHeader>
<EuiPageContentBody>
{reserved && (
<EuiText size="s" color="subdued">
<p>
<div className="mgtUsersEditPage">
<EuiPageContent className="mgtUsersEditPage__content">
<EuiPageContentHeader>
<EuiPageContentHeaderSection>
<EuiTitle>
<h2>
{isNewUser ?
<FormattedMessage
id="xpack.security.management.users.editUser.modifyingReservedUsersDescription"
defaultMessage="Reserved users are built-in and cannot be removed or modified. Only the password
may be changed."
id="xpack.security.management.users.editUser.newUserTitle"
defaultMessage="New user"
/>
</p>
</EuiText>
)}
:
<FormattedMessage
id="xpack.security.management.users.editUser.editUserTitle"
defaultMessage="Edit {userName} user"
values={{ userName: user.username }}
/>
}
</h2>
</EuiTitle>
</EuiPageContentHeaderSection>
{reserved && (
<EuiPageContentHeaderSection>
<EuiIcon type="lock" size="l" color="subdued" />
</EuiPageContentHeaderSection>
)}
</EuiPageContentHeader>
<EuiPageContentBody>
{reserved && (
<EuiText size="s" color="subdued">
<p>
<FormattedMessage
id="xpack.security.management.users.editUser.modifyingReservedUsersDescription"
defaultMessage="Reserved users are built-in and cannot be removed or modified. Only the password
may be changed."
/>
</p>
</EuiText>
)}
{showDeleteConfirmation ? (
<ConfirmDelete
onCancel={this.onCancelDelete}
apiClient={apiClient}
usersToDelete={[user.username]}
callback={this.handleDelete}
/>
) : null}
{showDeleteConfirmation ? (
<ConfirmDelete
onCancel={this.onCancelDelete}
apiClient={apiClient}
usersToDelete={[user.username]}
callback={this.handleDelete}
/>
) : null}
<form
onSubmit={event => {
event.preventDefault();
}}
>
<EuiForm>
<EuiFormRow
isInvalid={!!this.usernameError()}
error={this.usernameError()}
helpText={
!isNewUser && !reserved
? intl.formatMessage({
id: "xpack.security.management.users.editUser.changingUserNameAfterCreationDescription",
defaultMessage: "Username's cannot be changed after creation."
})
: null
<form
onSubmit={event => {
event.preventDefault();
}}
>
<EuiForm>
<EuiFormRow
isInvalid={!!this.usernameError()}
error={this.usernameError()}
helpText={
!isNewUser && !reserved
? intl.formatMessage({
id: "xpack.security.management.users.editUser.changingUserNameAfterCreationDescription",
defaultMessage: "Username's cannot be changed after creation."
})
: null
}
label={intl.formatMessage({
id: "xpack.security.management.users.editUser.usernameFormRowLabel",
defaultMessage: "Username"
})}
>
<EuiFieldText
onBlur={event =>
this.setState({
user: {
...this.state.user,
username: event.target.value || '',
},
})
}
label={intl.formatMessage({
id: "xpack.security.management.users.editUser.usernameFormRowLabel",
defaultMessage: "Username"
})}
>
<EuiFieldText
onBlur={event =>
this.setState({
user: {
...this.state.user,
username: event.target.value || '',
},
})
}
value={user.username || ''}
name="username"
data-test-subj="userFormUserNameInput"
disabled={!isNewUser}
onChange={event => {
this.setState({
user: { ...this.state.user, username: event.target.value },
});
}}
/>
</EuiFormRow>
{isNewUser ? this.passwordFields() : null}
{reserved ? null : (
<Fragment>
<EuiFormRow
label={intl.formatMessage({
id: "xpack.security.management.users.editUser.fullNameFormRowLabel",
defaultMessage: "Full name"
})}
>
<EuiFieldText
onBlur={event =>
this.setState({
user: {
...this.state.user,
full_name: event.target.value || '',
},
})
}
data-test-subj="userFormFullNameInput"
name="full_name"
value={user.full_name || ''}
onChange={event => {
this.setState({
user: {
...this.state.user,
full_name: event.target.value,
},
});
}}
/>
</EuiFormRow>
<EuiFormRow
isInvalid={!!this.emailError()}
error={this.emailError()}
label={intl.formatMessage({
id: "xpack.security.management.users.editUser.emailAddressFormRowLabel",
defaultMessage: "Email address"
})}
>
<EuiFieldText
onBlur={event =>
this.setState({
user: {
...this.state.user,
email: event.target.value || '',
},
})
}
data-test-subj="userFormEmailInput"
name="email"
value={user.email || ''}
onChange={event => {
this.setState({
user: {
...this.state.user,
email: event.target.value,
},
});
}}
/>
</EuiFormRow>
</Fragment>
)}
<EuiFormRow
label={intl.formatMessage({
id: "xpack.security.management.users.editUser.rolesFormRowLabel",
defaultMessage: "Roles"
})}
>
<EuiComboBox
data-test-subj="userFormRolesDropdown"
placeholder={intl.formatMessage({
id: "xpack.security.management.users.editUser.addRolesPlaceholder",
defaultMessage: "Add roles"
value={user.username || ''}
name="username"
data-test-subj="userFormUserNameInput"
disabled={!isNewUser}
onChange={event => {
this.setState({
user: { ...this.state.user, username: event.target.value },
});
}}
/>
</EuiFormRow>
{isNewUser ? this.passwordFields() : null}
{reserved ? null : (
<Fragment>
<EuiFormRow
label={intl.formatMessage({
id: "xpack.security.management.users.editUser.fullNameFormRowLabel",
defaultMessage: "Full name"
})}
onChange={this.onRolesChange}
isDisabled={reserved}
name="roles"
options={roles.map(role => {
return { 'data-test-subj': `roleOption-${role.name}`, label: role.name };
})}
selectedOptions={selectedRoles}
/>
</EuiFormRow>
{isNewUser || showChangePasswordForm ? null : (
<EuiFormRow label="Password">
<EuiLink onClick={this.toggleChangePasswordForm}>
<FormattedMessage
id="xpack.security.management.users.editUser.changePasswordButtonLabel"
defaultMessage="Change password"
/>
</EuiLink>
</EuiFormRow>
)}
{this.changePasswordForm()}
<EuiHorizontalRule />
{reserved && (
<EuiButton onClick={() => changeUrl(USERS_PATH)}>
<FormattedMessage
id="xpack.security.management.users.editUser.returnToUserListButtonLabel"
defaultMessage="Return to user list"
>
<EuiFieldText
onBlur={event =>
this.setState({
user: {
...this.state.user,
full_name: event.target.value || '',
},
})
}
data-test-subj="userFormFullNameInput"
name="full_name"
value={user.full_name || ''}
onChange={event => {
this.setState({
user: {
...this.state.user,
full_name: event.target.value,
},
});
}}
/>
</EuiButton>
)}
{reserved ? null : (
<EuiFlexGroup responsive={false}>
<EuiFlexItem grow={false}>
<EuiButton
disabled={this.cannotSaveUser()}
fill
data-test-subj="userFormSaveButton"
onClick={() => this.saveUser()}
>
{isNewUser ?
<FormattedMessage
id="xpack.security.management.users.editUser.createUserButtonLabel"
defaultMessage="Create user"
/>
:
<FormattedMessage
id="xpack.security.management.users.editUser.updateUserButtonLabel"
defaultMessage="Update user"
/>}
</EuiButton>
</EuiFlexItem>
</EuiFormRow>
<EuiFormRow
isInvalid={!!this.emailError()}
error={this.emailError()}
label={intl.formatMessage({
id: "xpack.security.management.users.editUser.emailAddressFormRowLabel",
defaultMessage: "Email address"
})}
>
<EuiFieldText
onBlur={event =>
this.setState({
user: {
...this.state.user,
email: event.target.value || '',
},
})
}
data-test-subj="userFormEmailInput"
name="email"
value={user.email || ''}
onChange={event => {
this.setState({
user: {
...this.state.user,
email: event.target.value,
},
});
}}
/>
</EuiFormRow>
</Fragment>
)}
<EuiFormRow
label={intl.formatMessage({
id: "xpack.security.management.users.editUser.rolesFormRowLabel",
defaultMessage: "Roles"
})}
>
<EuiComboBox
data-test-subj="userFormRolesDropdown"
placeholder={intl.formatMessage({
id: "xpack.security.management.users.editUser.addRolesPlaceholder",
defaultMessage: "Add roles"
})}
onChange={this.onRolesChange}
isDisabled={reserved}
name="roles"
options={roles.map(role => {
return { 'data-test-subj': `roleOption-${role.name}`, label: role.name };
})}
selectedOptions={selectedRoles}
/>
</EuiFormRow>
{isNewUser || showChangePasswordForm ? null : (
<EuiFormRow label="Password">
<EuiLink onClick={this.toggleChangePasswordForm}>
<FormattedMessage
id="xpack.security.management.users.editUser.changePasswordButtonLabel"
defaultMessage="Change password"
/>
</EuiLink>
</EuiFormRow>
)}
{this.changePasswordForm()}
<EuiHorizontalRule />
{reserved && (
<EuiButton onClick={() => changeUrl(USERS_PATH)}>
<FormattedMessage
id="xpack.security.management.users.editUser.returnToUserListButtonLabel"
defaultMessage="Return to user list"
/>
</EuiButton>
)}
{reserved ? null : (
<EuiFlexGroup responsive={false}>
<EuiFlexItem grow={false}>
<EuiButton
disabled={this.cannotSaveUser()}
fill
data-test-subj="userFormSaveButton"
onClick={() => this.saveUser()}
>
{isNewUser ?
<FormattedMessage
id="xpack.security.management.users.editUser.createUserButtonLabel"
defaultMessage="Create user"
/>
:
<FormattedMessage
id="xpack.security.management.users.editUser.updateUserButtonLabel"
defaultMessage="Update user"
/>}
</EuiButton>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonEmpty
data-test-subj="userFormCancelButton"
onClick={() => changeUrl(USERS_PATH)}
>
<FormattedMessage
id="xpack.security.management.users.editUser.cancelButtonLabel"
defaultMessage="Cancel"
/>
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={true} />
{isNewUser || reserved ? null : (
<EuiFlexItem grow={false}>
<EuiButtonEmpty
data-test-subj="userFormCancelButton"
onClick={() => changeUrl(USERS_PATH)}
onClick={() => {
this.setState({ showDeleteConfirmation: true });
}}
data-test-subj="userFormDeleteButton"
color="danger"
>
<FormattedMessage
id="xpack.security.management.users.editUser.cancelButtonLabel"
defaultMessage="Cancel"
id="xpack.security.management.users.editUser.deleteUserButtonLabel"
defaultMessage="Delete user"
/>
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={true} />
{isNewUser || reserved ? null : (
<EuiFlexItem grow={false}>
<EuiButtonEmpty
onClick={() => {
this.setState({ showDeleteConfirmation: true });
}}
data-test-subj="userFormDeleteButton"
color="danger"
>
<FormattedMessage
id="xpack.security.management.users.editUser.deleteUserButtonLabel"
defaultMessage="Delete user"
/>
</EuiButtonEmpty>
</EuiFlexItem>
)}
</EuiFlexGroup>
)}
</EuiForm>
</form>
</EuiPageContentBody>
</EuiPageContent>
</EuiPageBody>
</EuiPage>
)}
</EuiFlexGroup>
)}
</EuiForm>
</form>
</EuiPageContentBody>
</EuiPageContent>
</div>
);
}
}

View file

@ -10,8 +10,6 @@ import {
EuiIcon,
EuiLink,
EuiInMemoryTable,
EuiPage,
EuiPageBody,
EuiPageContent,
EuiTitle,
EuiPageContentHeader,
@ -93,30 +91,28 @@ class UsersUI extends Component {
const { apiClient, intl } = this.props;
if (permissionDenied) {
return (
<EuiPage className="mgtUsersListingPage">
<EuiPageBody>
<EuiPageContent horizontalPosition="center">
<EuiEmptyPrompt
iconType="securityApp"
iconColor={null}
title={
<h2>
<FormattedMessage
id="xpack.security.management.users.deniedPermissionTitle"
defaultMessage="Permission denied"
/>
</h2>}
body={
<p data-test-subj="permissionDeniedMessage">
<FormattedMessage
id="xpack.security.management.users.permissionDeniedToManageUsersDescription"
defaultMessage="You do not have permission to manage users."
/>
</p>}
/>
</EuiPageContent>
</EuiPageBody>
</EuiPage>
<div className="mgtUsersListingPage">
<EuiPageContent horizontalPosition="center">
<EuiEmptyPrompt
iconType="securityApp"
iconColor={null}
title={
<h2>
<FormattedMessage
id="xpack.security.management.users.deniedPermissionTitle"
defaultMessage="Permission denied"
/>
</h2>}
body={
<p data-test-subj="permissionDeniedMessage">
<FormattedMessage
id="xpack.security.management.users.permissionDeniedToManageUsersDescription"
defaultMessage="You do not have permission to manage users."
/>
</p>}
/>
</EuiPageContent>
</div>
);
}
const path = '#/management/security/';
@ -222,60 +218,58 @@ class UsersUI extends Component {
return normalized.indexOf(normalizedQuery) !== -1;
}) : users;
return (
<EuiPage className="mgtUsersListingPage">
<EuiPageBody>
<EuiPageContent className="mgtUsersListingPage__content">
<EuiPageContentHeader>
<EuiPageContentHeaderSection>
<EuiTitle>
<h2>
<FormattedMessage
id="xpack.security.management.users.usersTitle"
defaultMessage="Users"
/>
</h2>
</EuiTitle>
</EuiPageContentHeaderSection>
<EuiPageContentHeaderSection>
<EuiButton
data-test-subj="createUserButton"
href="#/management/security/users/edit"
>
<div className="mgtUsersListingPage">
<EuiPageContent className="mgtUsersListingPage__content">
<EuiPageContentHeader>
<EuiPageContentHeaderSection>
<EuiTitle>
<h2>
<FormattedMessage
id="xpack.security.management.users.createNewUserButtonLabel"
defaultMessage="Create new user"
id="xpack.security.management.users.usersTitle"
defaultMessage="Users"
/>
</EuiButton>
</EuiPageContentHeaderSection>
</EuiPageContentHeader>
<EuiPageContentBody>
{showDeleteConfirmation ? (
<ConfirmDelete
onCancel={this.onCancelDelete}
apiClient={apiClient}
usersToDelete={selection.map((user) => user.username)}
callback={this.handleDelete}
</h2>
</EuiTitle>
</EuiPageContentHeaderSection>
<EuiPageContentHeaderSection>
<EuiButton
data-test-subj="createUserButton"
href="#/management/security/users/edit"
>
<FormattedMessage
id="xpack.security.management.users.createNewUserButtonLabel"
defaultMessage="Create new user"
/>
) : null}
</EuiButton>
</EuiPageContentHeaderSection>
</EuiPageContentHeader>
<EuiPageContentBody>
<EuiInMemoryTable
itemId="username"
columns={columns}
selection={selectionConfig}
pagination={pagination}
items={usersToShow}
loading={users.length === 0}
search={search}
sorting={sorting}
rowProps={rowProps}
isSelectable
{showDeleteConfirmation ? (
<ConfirmDelete
onCancel={this.onCancelDelete}
apiClient={apiClient}
usersToDelete={selection.map((user) => user.username)}
callback={this.handleDelete}
/>
) : null}
</EuiPageContentBody>
</EuiPageContent>
</EuiPageBody>
</EuiPage>
<EuiInMemoryTable
itemId="username"
columns={columns}
selection={selectionConfig}
pagination={pagination}
items={usersToShow}
loading={users.length === 0}
search={search}
sorting={sorting}
rowProps={rowProps}
isSelectable
/>
</EuiPageContentBody>
</EuiPageContent>
</div>
);
}
}

View file

@ -13,8 +13,6 @@ import {
// @ts-ignore
EuiForm,
EuiFormRow,
EuiPage,
EuiPageBody,
EuiPanel,
EuiSpacer,
EuiText,
@ -83,43 +81,41 @@ class EditRolePageUI extends Component<Props, State> {
);
return (
<EuiPage className="editRolePage" restrictWidth>
<EuiPageBody>
<EuiForm {...this.state.formError}>
{this.getFormTitle()}
<div className="editRolePage">
<EuiForm {...this.state.formError}>
{this.getFormTitle()}
<EuiSpacer />
<EuiSpacer />
<EuiText size="s">{description}</EuiText>
<EuiText size="s">{description}</EuiText>
{isReservedRole(this.props.role) && (
<Fragment>
<EuiSpacer size="s" />
<EuiText size="s" color="subdued">
<p id="reservedRoleDescription" tabIndex={0}>
<FormattedMessage
id="xpack.security.management.editRole.modifyingReversedRolesDescription"
defaultMessage="Reserved roles are built-in and cannot be removed or modified."
/>
</p>
</EuiText>
</Fragment>
)}
{isReservedRole(this.props.role) && (
<Fragment>
<EuiSpacer size="s" />
<EuiText size="s" color="subdued">
<p id="reservedRoleDescription" tabIndex={0}>
<FormattedMessage
id="xpack.security.management.editRole.modifyingReversedRolesDescription"
defaultMessage="Reserved roles are built-in and cannot be removed or modified."
/>
</p>
</EuiText>
</Fragment>
)}
<EuiSpacer />
<EuiSpacer />
{this.getRoleName()}
{this.getRoleName()}
{this.getElasticsearchPrivileges()}
{this.getElasticsearchPrivileges()}
{this.getKibanaPrivileges()}
{this.getKibanaPrivileges()}
<EuiSpacer />
<EuiSpacer />
{this.getFormButtons()}
</EuiForm>
</EuiPageBody>
</EuiPage>
{this.getFormButtons()}
</EuiForm>
</div>
);
}

View file

@ -1,3 +1,3 @@
<kbn-management-app section="security" omit-breadcrumb-pages="['edit']">
<kbn-management-app section="security/roles" omit-breadcrumb-pages="['edit']">
<div id="editRoleReactRoot" />
</kbn-management-app>

View file

@ -1,4 +0,0 @@
#editRoleReactRoot {
background: #F5F7FA;
min-height: ~"calc(100vh - 70px)";
}

View file

@ -1,5 +0,0 @@
//sass-lint:disable-block no-ids
#editRoleReactRoot {
background: $euiColorLightestShade;
min-height: calc(100vh - 70px);
}

View file

@ -1,3 +1,3 @@
<kbn-management-app section="security" omit-breadcrumb-pages="['edit']">
<kbn-management-app section="security/users" omit-breadcrumb-pages="['edit']">
<div id="editUserReactRoot" />
</kbn-management-app>

View file

@ -1,8 +1,6 @@
// Edit role styles
@import './edit_role/components/privileges/kibana/impacted_spaces_flyout';
@import './edit_role/components/collapsible_panel';
@import './edit_role/edit_role';
$securityFormWidth: 460px;
@ -29,11 +27,6 @@ $securityFormWidth: 460px;
}
}
.mgtUsersEditPage,
.mgtUsersListingPage {
min-height: calc(100vh - 70px);
}
.mgtUsersListingPage__content {
flex-grow: 0;
}

View file

@ -35,7 +35,7 @@ routes.defaults(/\/management/, {
'xpack.security.management.securityTitle', {
defaultMessage: 'Security',
}),
order: 10,
order: 100,
icon: 'securityApp',
});
const getSecurity = () => management.getSection('security');
@ -69,16 +69,17 @@ routes.defaults(/\/management/, {
}
}
deregisterSecurity();
if (!showSecurityLinks) return;
// getCurrent will reject if there is no authenticated user, so we prevent them from seeing the security
// management screens
//
// $promise is used here because the result is an ngResource, not a promise itself
return ShieldUser.getCurrent().$promise
.then(ensureSecurityRegistered)
.catch(deregisterSecurity);
if (!showSecurityLinks) {
deregisterSecurity();
} else {
// getCurrent will reject if there is no authenticated user, so we prevent them from seeing the security
// management screens
//
// $promise is used here because the result is an ngResource, not a promise itself
return ShieldUser.getCurrent().$promise
.then(ensureSecurityRegistered)
.catch(deregisterSecurity);
}
}
}
});

View file

@ -1,5 +1,13 @@
<kbn-management-app section="security">
<div class="kuiViewContent kuiViewContent--constrainedWidth kuiViewContentItem">
<kbn-management-app section="security/roles">
<div class="euiPanel euiPanel--paddingLarge euiPageContent" style="flex-grow: 0">
<h1 class="euiTitle euiTitle--medium"
i18n-id="xpack.security.management.roles.title"
i18n-default-message="Roles"></h1>
<div class="euiText euiTextColor--subdued">
<p i18n-id="xpack.security.management.roles.subtitle"
i18n-default-message="Apply roles to groups of users and manage permissions across the stack"></p>
</div>
<div class="euiSpacer euiSpacer--l"></div>
<div class="kuiInfoPanel kuiInfoPanel--error" ng-if="forbidden">
<div class="kuiInfoPanelHeader">
<span class="kuiInfoPanelHeader__icon kuiIcon kuiIcon--error fa-warning"></span>

View file

@ -1,3 +1,3 @@
<kbn-management-app section="security">
<kbn-management-app section="security/users">
<div id="usersReactRoot" />
</kbn-management-app>

View file

@ -3,11 +3,6 @@
flex-grow: 1;
}
.spcManagePage,
.spcGridPage {
min-height: calc(100vh - 70px);
}
.spcManagePage__content {
max-width: 640px;
margin-left: auto;

View file

@ -33,9 +33,9 @@ exports[`AdvancedSettingsTitle renders as expected 1`] = `
}
}
>
<EuiText
grow={true}
<EuiTitle
size="m"
textTransform="none"
>
<h1
data-test-subj="managementSettingsTitle"
@ -46,7 +46,7 @@ exports[`AdvancedSettingsTitle renders as expected 1`] = `
values={Object {}}
/>
</h1>
</EuiText>
</EuiTitle>
</EuiFlexItem>
</EuiFlexGroup>
`;

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import React from 'react';
import { Space } from '../../../../../common/model/space';
@ -20,14 +20,14 @@ export const AdvancedSettingsTitle = (props: Props) => (
<SpaceAvatar space={props.space} />
</EuiFlexItem>
<EuiFlexItem style={{ marginLeft: '10px' }}>
<EuiText>
<EuiTitle size="m">
<h1 data-test-subj="managementSettingsTitle">
<FormattedMessage
id="xpack.spaces.management.advancedSettingsTitle.settingsTitle"
defaultMessage="Settings"
/>
</h1>
</EuiText>
</EuiTitle>
</EuiFlexItem>
</EuiFlexGroup>
);

View file

@ -14,8 +14,6 @@ import {
EuiFormRow,
EuiHorizontalRule,
EuiLoadingSpinner,
EuiPage,
EuiPageBody,
EuiPageContent,
EuiPageContentBody,
EuiSpacer,
@ -109,14 +107,12 @@ class ManageSpacePageUI extends Component<Props, State> {
const content = this.state.isLoading ? this.getLoadingIndicator() : this.getForm();
return (
<EuiPage className="spcManagePage">
<EuiPageBody>
<EuiPageContent className="spcManagePage__content">
<EuiPageContentBody>{content}</EuiPageContentBody>
</EuiPageContent>
{this.maybeGetSecureSpacesMessage()}
</EuiPageBody>
</EuiPage>
<div className="spcManagePage">
<EuiPageContent className="spcManagePage__content">
<EuiPageContentBody>{content}</EuiPageContentBody>
</EuiPageContent>
{this.maybeGetSecureSpacesMessage()}
</div>
);
}
@ -231,7 +227,7 @@ class ManageSpacePageUI extends Component<Props, State> {
public getFormHeading = () => {
return (
<EuiTitle size="l">
<EuiTitle size="m">
<h1>
{this.getTitle()} <ReservedSpaceBadge space={this.state.space as Space} />
</h1>

View file

@ -1,140 +1,144 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`SpacesGridPage renders as expected 1`] = `
<EuiPage
className="spcGridPage"
restrictWidth={true}
<div
className="spcGridPage euiPage--restrictWidth-default"
>
<EuiPageBody
restrictWidth={false}
<EuiPageContent
horizontalPosition="center"
panelPaddingSize="l"
>
<EuiPageContent
horizontalPosition="center"
panelPaddingSize="l"
<EuiFlexGroup
alignItems="stretch"
component="div"
direction="row"
gutterSize="l"
justifyContent="spaceBetween"
responsive={true}
wrap={false}
>
<EuiFlexGroup
alignItems="stretch"
<EuiFlexItem
component="div"
direction="row"
gutterSize="l"
justifyContent="spaceBetween"
responsive={true}
wrap={false}
grow={false}
>
<EuiFlexItem
component="div"
grow={false}
<EuiTitle
size="m"
textTransform="none"
>
<EuiText
grow={true}
size="m"
>
<h1>
<FormattedMessage
defaultMessage="Spaces"
id="xpack.spaces.management.spacesGridPage.spacesTitle"
values={Object {}}
/>
</h1>
</EuiText>
</EuiFlexItem>
<EuiFlexItem
component="div"
grow={false}
>
<EuiButton
color="primary"
fill={true}
iconSide="left"
onClick={[Function]}
type="button"
>
<h1>
<FormattedMessage
defaultMessage="Create a space"
id="xpack.spaces.management.spacesGridPage.createSpaceButtonLabel"
defaultMessage="Spaces"
id="xpack.spaces.management.spacesGridPage.spacesTitle"
values={Object {}}
/>
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer
size="xl"
/>
<EuiInMemoryTable
columns={
Array [
Object {
"field": "name",
"name": "",
"render": [Function],
"sortable": true,
"width": "50px",
},
Object {
"field": "name",
"name": "Space",
"render": [Function],
"sortable": true,
},
Object {
"field": "id",
"name": "Identifier",
"sortable": true,
},
Object {
"field": "description",
"name": "Description",
"sortable": true,
},
Object {
"actions": Array [
Object {
"render": [Function],
},
Object {
"available": [Function],
"render": [Function],
},
],
"name": "Actions",
},
]
}
executeQueryOptions={Object {}}
hasActions={true}
itemId="id"
items={Array []}
loading={true}
message={
</h1>
</EuiTitle>
<EuiText
color="subdued"
grow={true}
size="m"
>
<p>
Organize your dashboards and other saved objects into meaningful categories.
</p>
</EuiText>
</EuiFlexItem>
<EuiFlexItem
component="div"
grow={false}
>
<EuiButton
color="primary"
fill={true}
iconSide="left"
onClick={[Function]}
type="button"
>
<FormattedMessage
defaultMessage="loading…"
id="xpack.spaces.management.spacesGridPage.loadingTitle"
defaultMessage="Create a space"
id="xpack.spaces.management.spacesGridPage.createSpaceButtonLabel"
values={Object {}}
/>
}
pagination={true}
responsive={true}
search={
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer
size="l"
/>
<EuiInMemoryTable
columns={
Array [
Object {
"box": Object {
"placeholder": "Search",
},
}
}
sorting={false}
/>
</EuiPageContent>
<Component
userProfile={
UserProfileClass {
"capabilities": Object {
"manageSpaces": true,
"field": "name",
"name": "",
"render": [Function],
"sortable": true,
"width": "50px",
},
Object {
"field": "name",
"name": "Space",
"render": [Function],
"sortable": true,
},
Object {
"field": "id",
"name": "Identifier",
"sortable": true,
},
Object {
"field": "description",
"name": "Description",
"sortable": true,
},
Object {
"actions": Array [
Object {
"render": [Function],
},
Object {
"available": [Function],
"render": [Function],
},
],
"name": "Actions",
},
]
}
executeQueryOptions={Object {}}
hasActions={true}
itemId="id"
items={Array []}
loading={true}
message={
<FormattedMessage
defaultMessage="loading…"
id="xpack.spaces.management.spacesGridPage.loadingTitle"
values={Object {}}
/>
}
pagination={true}
responsive={true}
search={
Object {
"box": Object {
"placeholder": "Search",
},
}
}
sorting={false}
/>
</EuiPageBody>
</EuiPage>
</EuiPageContent>
<Component
userProfile={
UserProfileClass {
"capabilities": Object {
"manageSpaces": true,
},
}
}
/>
</div>
`;
exports[`SpacesGridPage renders the list of spaces 1`] = `

View file

@ -14,11 +14,10 @@ import {
// @ts-ignore
EuiInMemoryTable,
EuiLink,
EuiPage,
EuiPageBody,
EuiPageContent,
EuiSpacer,
EuiText,
EuiTitle,
} from '@elastic/eui';
import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react';
// @ts-ignore
@ -29,6 +28,7 @@ import { UserProfile } from '../../../../../xpack_main/public/services/user_prof
import { isReservedSpace } from '../../../../common';
import { Space } from '../../../../common/model/space';
import { SpaceAvatar } from '../../../components';
import { getSpacesFeatureDescription } from '../../../lib/constants';
import { SpacesManager } from '../../../lib/spaces_manager';
import { ConfirmDeleteModal } from '../components/confirm_delete_modal';
import { SecureSpaceMessage } from '../components/secure_space_message';
@ -67,13 +67,11 @@ class SpacesGridPageUI extends Component<Props, State> {
public render() {
return (
<EuiPage restrictWidth className="spcGridPage">
<EuiPageBody>
<EuiPageContent horizontalPosition="center">{this.getPageContent()}</EuiPageContent>
<SecureSpaceMessage userProfile={this.props.userProfile} />
</EuiPageBody>
<div className="spcGridPage euiPage--restrictWidth-default">
<EuiPageContent horizontalPosition="center">{this.getPageContent()}</EuiPageContent>
<SecureSpaceMessage userProfile={this.props.userProfile} />
{this.getConfirmDeleteModal()}
</EuiPage>
</div>
);
}
@ -87,18 +85,21 @@ class SpacesGridPageUI extends Component<Props, State> {
<Fragment>
<EuiFlexGroup justifyContent={'spaceBetween'}>
<EuiFlexItem grow={false}>
<EuiText>
<EuiTitle size="m">
<h1>
<FormattedMessage
id="xpack.spaces.management.spacesGridPage.spacesTitle"
defaultMessage="Spaces"
/>
</h1>
</EuiTitle>
<EuiText color="subdued">
<p>{getSpacesFeatureDescription()}</p>
</EuiText>
</EuiFlexItem>
<EuiFlexItem grow={false}>{this.getPrimaryActionButton()}</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size={'xl'} />
<EuiSpacer size="l" />
<EuiInMemoryTable
itemId={'id'}

View file

@ -1,3 +1,3 @@
<kbn-management-app section="kibana" omit-breadcrumb-pages="['edit']">
<kbn-management-app section="kibana/manage_spaces" omit-breadcrumb-pages="['edit']">
<div id="manageSpacesReactRoot" />
</kbn-management-app>

View file

@ -0,0 +1,4 @@
.mgtWatcher__list {
display: flex;
flex-grow: 1;
}

View file

@ -25,4 +25,4 @@
@import 'sections/watch_edit/components/threshold_watch_edit/index';
@import 'sections/watch_edit/components/watch_edit_detail/index';
@import 'sections/watch_edit/components/watch_edit_execute_detail/index';
@import 'sections/watch_edit/components/watch_edit_title_panel/index';
@import 'sections/watch_edit/components/watch_edit_title_panel/index';

View file

@ -2,10 +2,6 @@ threshold-watch-edit {
flex: 1 0 auto;
background-color: $euiColorLightestShade;
.thresholdWatchEditContent {
padding: $euiSizeL;
}
.thresholdWatchEditButtons {
flex-direction:row-reverse;
}

View file

@ -4,105 +4,102 @@
omit-breadcrumb-pages="{{ thresholdWatchEdit.omitBreadcrumbPages }}"
page-title="thresholdWatchEdit.breadcrumb"
>
<div class="thresholdWatchEditContent">
<div class="euiPanel euiPanel--paddingLarge kuiVerticalRhythm">
<watch-edit-title-panel
fields="thresholdWatchEdit.fields"
xpack-watch="thresholdWatchEdit.watch"
on-change="thresholdWatchEdit.onChange"
on-valid="thresholdWatchEdit.onTitlePanelValid"
on-invalid="thresholdWatchEdit.onTitlePanelInvalid"
></watch-edit-title-panel>
</div>
<div class="euiPanel euiPanel--paddingLarge kuiVerticalRhythm">
<watch-edit-title-panel
<div
class="kuiPanel kuiVerticalRhythm euiPanel euiPanel--paddingLarge"
ng-show="thresholdWatchEdit.titlePanelValid"
>
<section class="kuiVerticalRhythm">
<header>
<h2
class="kuiSubTitle"
i18n-id="xpack.watcher.sections.watchEdit.threshold.matchingFollowingConditionTitle"
i18n-default-message="Matching the following condition"
></h2>
</header>
</section>
<div class="kuiVerticalRhythm" style="margin-bottom:30px;">
<threshold-watch-expression
threshold-watch="thresholdWatchEdit.watch"
fields="thresholdWatchEdit.fields"
xpack-watch="thresholdWatchEdit.watch"
on-change="thresholdWatchEdit.onChange"
on-valid="thresholdWatchEdit.onTitlePanelValid"
on-invalid="thresholdWatchEdit.onTitlePanelInvalid"
></watch-edit-title-panel>
on-valid="thresholdWatchEdit.onConditionPanelValid"
on-invalid="thresholdWatchEdit.onConditionPanelInvalid"
></threshold-watch-expression>
</div>
<div
class="kuiPanel kuiVerticalRhythm euiPanel euiPanel--paddingLarge"
ng-show="thresholdWatchEdit.titlePanelValid"
>
<section class="kuiVerticalRhythm">
<header>
<h2
class="kuiSubTitle"
i18n-id="xpack.watcher.sections.watchEdit.threshold.matchingFollowingConditionTitle"
i18n-default-message="Matching the following condition"
></h2>
</header>
</section>
<div class="kuiVerticalRhythm" style="margin-bottom:30px;">
<threshold-watch-expression
threshold-watch="thresholdWatchEdit.watch"
fields="thresholdWatchEdit.fields"
on-change="thresholdWatchEdit.onChange"
on-valid="thresholdWatchEdit.onConditionPanelValid"
on-invalid="thresholdWatchEdit.onConditionPanelInvalid"
></threshold-watch-expression>
<div class="kuiPanel kuiVerticalRhythm">
<div
class="kuiPanelHeader"
ng-show="thresholdWatchEdit.visualizeDataPageCount > 1"
>
<div class="kuiPanelHeaderSection">
<div class="kuiPanelHeader__title">
{{ thresholdWatchEdit.visualizeDataTitle }}
</div>
</div>
</div>
<div class="kuiPanel kuiVerticalRhythm">
<div class="kuiPanelBody">
<div
class="kuiPanelHeader"
ng-show="thresholdWatchEdit.visualizeDataPageCount > 1"
>
<div class="kuiPanelHeaderSection">
<div class="kuiPanelHeader__title">
{{ thresholdWatchEdit.visualizeDataTitle }}
</div>
</div>
class="kuiVerticalRhythm kuiWatchVisualization"
ng-class="{ kuiWatchVisualizationMulti: thresholdWatchEdit.visualizeDataPageCount > 1 }">
<threshold-preview-chart
series="thresholdWatchEdit.chartSeries"
threshold-value="thresholdWatchEdit.watch.threshold"
start-date="thresholdWatchEdit.visualizeTimeWindowFrom"
end-date="thresholdWatchEdit.visualizeTimeWindowTo"
></threshold-preview-chart>
</div>
<div class="kuiPanelBody">
<div
class="kuiVerticalRhythm kuiWatchVisualization"
ng-class="{ kuiWatchVisualizationMulti: thresholdWatchEdit.visualizeDataPageCount > 1 }">
<threshold-preview-chart
series="thresholdWatchEdit.chartSeries"
threshold-value="thresholdWatchEdit.watch.threshold"
start-date="thresholdWatchEdit.visualizeTimeWindowFrom"
end-date="thresholdWatchEdit.visualizeTimeWindowTo"
></threshold-preview-chart>
</div>
</div>
<panel-pager
on-next-page="thresholdWatchEdit.onVisualizationNextPage"
on-previous-page="thresholdWatchEdit.onVisualizationPreviousPage"
ng-show="thresholdWatchEdit.visualizeDataPageCount > 1"
></panel-pager>
</div>
<panel-pager
on-next-page="thresholdWatchEdit.onVisualizationNextPage"
on-previous-page="thresholdWatchEdit.onVisualizationPreviousPage"
ng-show="thresholdWatchEdit.visualizeDataPageCount > 1"
></panel-pager>
</div>
</div>
<div
class="kuiPanel kuiVerticalRhythm euiPanel euiPanel--paddingLarge"
ng-show="thresholdWatchEdit.titlePanelValid && thresholdWatchEdit.conditionPanelValid"
>
<watch-actions
actions="thresholdWatchEdit.watch.actions"
on-action-add="thresholdWatchEdit.onActionAdd"
on-action-change="thresholdWatchEdit.onActionChange"
on-action-simulate="thresholdWatchEdit.onActionSimulate"
on-action-delete="thresholdWatchEdit.onActionDelete"
on-valid="thresholdWatchEdit.onActionsValid"
on-invalid="thresholdWatchEdit.onActionsInvalid"
></watch-actions>
</div>
<div
class="kuiPanel kuiVerticalRhythm euiPanel euiPanel--paddingLarge"
ng-show="thresholdWatchEdit.titlePanelValid && thresholdWatchEdit.conditionPanelValid"
>
<watch-actions
actions="thresholdWatchEdit.watch.actions"
on-action-add="thresholdWatchEdit.onActionAdd"
on-action-change="thresholdWatchEdit.onActionChange"
on-action-simulate="thresholdWatchEdit.onActionSimulate"
on-action-delete="thresholdWatchEdit.onActionDelete"
on-valid="thresholdWatchEdit.onActionsValid"
on-invalid="thresholdWatchEdit.onActionsInvalid"
></watch-actions>
</div>
<div class="kuiButtonGroup kuiVerticalRhythm euiPanel euiPanel--paddingLarge thresholdWatchEditButtons">
<div class="kuiButtonGroup kuiVerticalRhythm euiPanel euiPanel--paddingLarge thresholdWatchEditButtons">
<button
class="kuiButton kuiButton--primary"
ng-disabled="thresholdWatchEdit.saveDisabled"
ng-click="thresholdWatchEdit.onWatchSave()">
<span class="kuiButton__inner">
<span
i18n-id="xpack.watcher.sections.watchEdit.threshold.saveButtonLabel"
i18n-default-message="Save"
></span>
</span>
</button>
</div>
<button
class="kuiButton kuiButton--primary"
ng-disabled="thresholdWatchEdit.saveDisabled"
ng-click="thresholdWatchEdit.onWatchSave()">
<span class="kuiButton__inner">
<span
i18n-id="xpack.watcher.sections.watchEdit.threshold.saveButtonLabel"
i18n-default-message="Save"
></span>
</span>
</button>
</div>
</kbn-management-app>

View file

@ -1,11 +1,11 @@
<section>
<header>
<h1 class="kuiTitle">
<h1 class="euiTitle euiTitle--medium">
{{watchEditTitlePanel.title}}
</h1>
<h2 class="kuiSubText kuiSubduedText">
{{watchEditTitlePanel.description}}
</h2>
<div class="euiText euiTextColor--subdued">
<p>{{watchEditTitlePanel.description}}</p>
</div>
</header>
<form name="watchEditTitlePanel.form" novalidate>
<div class="kuiFieldGroup kuiFieldGroup--alignTop watchEditTitlePanelContent">

View file

@ -1,14 +1,25 @@
<kbn-management-app section="elasticsearch/watcher">
<div class="kuiViewContent">
<div class="euiPanel euiPanel--paddingLarge euiPageContent" style="flex-grow: 0">
<forbidden-message ng-if="watchList.forbidden">
{{ 'xpack.watcher.sections.watchList.noPermissionToManageWatchesText' | i18n: { defaultMessage: 'You do not have permission to manage watches.' } }}
</forbidden-message>
<div
ng-if="!watchList.forbidden"
class="kuiViewContentItem kuiVerticalRhythm"
>
<div class="kuiVerticalRhythm">
<h1 class="euiTitle euiTitle--medium"
i18n-id="xpack.watcher.sections.watchList.header"
i18n-default-message="Create threshold alert"
>
Watcher
</h1>
<div class="euiText euiTextColor--subdued">
<p
i18n-id="xpack.watcher.sections.watchList.subhead"
i18n-default-message="Send out emails, slack messages and log events when specific parameters are hit"></p>
</div>
<div class="euiSpacer euiSpacer--l"></div>
<div>
<button
class="kuiButton kuiButton--primary"
ng-click="watchList.onClickCreateThresholdAlert()"
@ -28,6 +39,8 @@
></button>
</div>
<div class="euiSpacer euiSpacer--l"></div>
<div class="kuiControlledTable kuiVerticalRhythm">
<div class="kuiToolBar">
<div class="kuiToolBarSearch">

View file

@ -1 +1 @@
<watch-list watches="watchListRoute.watches"></watch-list>
<watch-list watches="watchListRoute.watches" class="mgtWatcher__list"></watch-list>

View file

@ -54,7 +54,7 @@ export default function ({ getService, getPageObjects }) {
describe('Dashboard viewer', () => {
before('Create logstash data role', async () => {
await PageObjects.settings.navigateTo();
await PageObjects.settings.clickLinkText('Roles');
await testSubjects.click('roles');
await PageObjects.security.clickCreateNewRole();
await testSubjects.setValue('roleFormNameInput', 'logstash-data');

View file

@ -29,7 +29,7 @@ export default function ({ getService, getPageObjects }) {
await PageObjects.settings.navigateTo();
// Create logstash-readonly role
await PageObjects.settings.clickLinkText('Roles');
await testSubjects.click('roles');
await PageObjects.security.clickCreateNewRole();
await testSubjects.setValue('roleFormNameInput', 'logstash-readonly');
await PageObjects.security.addIndexToRole('logstash-*');
@ -83,7 +83,7 @@ export default function ({ getService, getPageObjects }) {
});
it('Can navigate to roles section', async () => {
await PageObjects.settings.clickLinkText('Roles');
await PageObjects.security.clickElasticsearchRoles();
const currentUrl = await browser.getCurrentUrl();
expect(currentUrl).to.contain(ROLES_PATH);
});
@ -139,7 +139,7 @@ export default function ({ getService, getPageObjects }) {
await PageObjects.security.clickSaveEditUser();
await PageObjects.settings.navigateTo();
await PageObjects.settings.clickLinkText('Users');
await testSubjects.click('users');
await PageObjects.settings.clickLinkText('kibana_dashboard_only_user');
const currentUrl = await browser.getCurrentUrl();
expect(currentUrl).to.contain(EDIT_ROLES_PATH);

View file

@ -20,7 +20,7 @@ export default function ({ getService, getPageObjects }) {
before('initialize tests', async () => {
await browser.setWindowSize(1600, 1000);
await PageObjects.common.navigateToApp('settings');
await PageObjects.settings.clickLinkText('Watcher');
await testSubjects.click('watcher');
await PageObjects.watcher.clearAllWatches();
});

View file

@ -101,11 +101,11 @@ export function SecurityPageProvider({ getService, getPageObjects }) {
}
async clickRolesSection() {
await PageObjects.settings.clickLinkText('Roles');
await testSubjects.click('roles');
}
async clickUsersSection() {
await PageObjects.settings.clickLinkText('Users');
await testSubjects.click('users');
}
async clickCreateNewUser() {
@ -174,12 +174,12 @@ export function SecurityPageProvider({ getService, getPageObjects }) {
async clickElasticsearchUsers() {
await this.navigateTo();
await find.clickByDisplayedLinkText('Users');
await this.clickUsersSection();
}
async clickElasticsearchRoles() {
await this.navigateTo();
await find.clickByDisplayedLinkText('Roles');
await this.clickRolesSection();
}