[ML] Transforms: Converts management pages to new layout (#102648)

* [ML] Transforms: Converts management pages to new layout

* [ML] Fix vertical centering of error state in app

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Pete Harverson 2021-06-24 11:31:30 +01:00 committed by GitHub
parent 9a1f5a4a7a
commit fa71c6d7ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 287 additions and 228 deletions

View file

@ -10,7 +10,7 @@ import { render, unmountComponentAtNode } from 'react-dom';
import { Router, Route, Switch } from 'react-router-dom';
import { ScopedHistory } from 'kibana/public';
import { EuiErrorBoundary } from '@elastic/eui';
import { EuiErrorBoundary, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
@ -35,7 +35,7 @@ export const App: FC<{ history: ScopedHistory }> = ({ history }) => {
title={
<FormattedMessage
id="xpack.transform.app.checkingPrivilegesErrorMessage"
defaultMessage="Error fetching user privileges from the server."
defaultMessage="Error fetching user privileges from the server"
/>
}
error={apiError}
@ -44,21 +44,23 @@ export const App: FC<{ history: ScopedHistory }> = ({ history }) => {
}
return (
<div data-test-subj="transformApp">
<Router history={history}>
<Switch>
<Route
path={`/${SECTION_SLUG.CLONE_TRANSFORM}/:transformId`}
component={CloneTransformSection}
/>
<Route
path={`/${SECTION_SLUG.CREATE_TRANSFORM}/:savedObjectId`}
component={CreateTransformSection}
/>
<Route path={`/`} component={TransformManagementSection} />
</Switch>
</Router>
</div>
<EuiFlexGroup justifyContent="spaceAround" data-test-subj="transformApp">
<EuiFlexItem grow={true}>
<Router history={history}>
<Switch>
<Route
path={`/${SECTION_SLUG.CLONE_TRANSFORM}/:transformId`}
component={CloneTransformSection}
/>
<Route
path={`/${SECTION_SLUG.CREATE_TRANSFORM}/:savedObjectId`}
component={CreateTransformSection}
/>
<Route path={`/`} component={TransformManagementSection} />
</Switch>
</Router>
</EuiFlexItem>
</EuiFlexGroup>
);
};

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { EuiCallOut } from '@elastic/eui';
import { EuiEmptyPrompt, EuiPageContent } from '@elastic/eui';
import React from 'react';
interface Props {
@ -23,9 +23,17 @@ export const SectionError: React.FunctionComponent<Props> = ({
const errorMessage = error?.message ?? JSON.stringify(error, null, 2);
return (
<EuiCallOut title={title} color="danger" iconType="alert" {...rest}>
<pre>{errorMessage}</pre>
{actions ? actions : null}
</EuiCallOut>
<EuiPageContent verticalPosition="center" horizontalPosition="center" color="danger">
<EuiEmptyPrompt
iconType="alert"
title={<h2>{title}</h2>}
body={
<p>
<pre>{errorMessage}</pre>
{actions ? actions : null}
</p>
}
/>
</EuiPageContent>
);
};

View file

@ -7,7 +7,7 @@
import React, { useContext, FC } from 'react';
import { EuiPageContent } from '@elastic/eui';
import { EuiFlexItem, EuiFlexGroup, EuiPageContent } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
@ -74,27 +74,31 @@ const MissingClusterPrivileges: FC<MissingClusterPrivilegesProps> = ({
missingPrivileges,
privilegesCount,
}) => (
<EuiPageContent>
<NotAuthorizedSection
title={
<FormattedMessage
id="xpack.transform.app.deniedPrivilegeTitle"
defaultMessage="You're missing cluster privileges"
/>
}
message={
<FormattedMessage
id="xpack.transform.app.deniedPrivilegeDescription"
defaultMessage="To use this section of Transforms, you must have {privilegesCount,
<EuiFlexGroup justifyContent="spaceAround">
<EuiFlexItem grow={false}>
<EuiPageContent verticalPosition="center" horizontalPosition="center" color="danger">
<NotAuthorizedSection
title={
<FormattedMessage
id="xpack.transform.app.deniedPrivilegeTitle"
defaultMessage="You're missing cluster privileges"
/>
}
message={
<FormattedMessage
id="xpack.transform.app.deniedPrivilegeDescription"
defaultMessage="To use this section of Transforms, you must have {privilegesCount,
plural, one {this cluster privilege} other {these cluster privileges}}: {missingPrivileges}."
values={{
missingPrivileges,
privilegesCount,
}}
values={{
missingPrivileges,
privilegesCount,
}}
/>
}
/>
}
/>
</EuiPageContent>
</EuiPageContent>
</EuiFlexItem>
</EuiFlexGroup>
);
export const PrivilegesWrapper: FC<{ privileges: string | string[] }> = ({

View file

@ -15,12 +15,9 @@ import { i18n } from '@kbn/i18n';
import {
EuiButtonEmpty,
EuiCallOut,
EuiFlexGroup,
EuiFlexItem,
EuiPageContent,
EuiPageContentBody,
EuiPageHeader,
EuiSpacer,
EuiTitle,
} from '@elastic/eui';
import { APP_CREATE_TRANSFORM_CLUSTER_PRIVILEGES } from '../../../../common/constants';
@ -105,37 +102,38 @@ export const CloneTransformSection: FC<Props> = ({ match, location }) => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const docsLink = (
<EuiButtonEmpty
href={esTransform}
target="_blank"
iconType="help"
data-test-subj="documentationLink"
>
<FormattedMessage
id="xpack.transform.transformsWizard.transformDocsLinkText"
defaultMessage="Transform docs"
/>
</EuiButtonEmpty>
);
return (
<PrivilegesWrapper privileges={APP_CREATE_TRANSFORM_CLUSTER_PRIVILEGES}>
<EuiPageContent data-test-subj="transformPageCloneTransform">
<EuiTitle size="l">
<EuiFlexGroup alignItems="center">
<EuiFlexItem grow={true}>
<h1>
<FormattedMessage
id="xpack.transform.transformsWizard.cloneTransformTitle"
defaultMessage="Clone transform"
/>
</h1>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonEmpty
href={esTransform}
target="_blank"
iconType="help"
data-test-subj="documentationLink"
>
<FormattedMessage
id="xpack.transform.transformsWizard.transformDocsLinkText"
defaultMessage="Transform docs"
/>
</EuiButtonEmpty>
</EuiFlexItem>
</EuiFlexGroup>
</EuiTitle>
<EuiPageContentBody>
<EuiSpacer size="l" />
{typeof errorMessage !== 'undefined' && (
<EuiPageHeader
pageTitle={
<FormattedMessage
id="xpack.transform.transformsWizard.cloneTransformTitle"
defaultMessage="Clone transform"
/>
}
rightSideItems={[docsLink]}
bottomBorder
/>
<EuiSpacer size="l" />
<EuiPageContentBody data-test-subj="transformPageCloneTransform">
{typeof errorMessage !== 'undefined' && (
<>
<EuiCallOut
title={i18n.translate('xpack.transform.clone.errorPromptTitle', {
defaultMessage: 'An error occurred getting the transform configuration.',
@ -145,12 +143,13 @@ export const CloneTransformSection: FC<Props> = ({ match, location }) => {
>
<pre>{JSON.stringify(errorMessage)}</pre>
</EuiCallOut>
)}
{searchItems !== undefined && isInitialized === true && transformConfig !== undefined && (
<Wizard cloneConfig={transformConfig} searchItems={searchItems} />
)}
</EuiPageContentBody>
</EuiPageContent>
<EuiSpacer size="l" />
</>
)}
{searchItems !== undefined && isInitialized === true && transformConfig !== undefined && (
<Wizard cloneConfig={transformConfig} searchItems={searchItems} />
)}
</EuiPageContentBody>
</PrivilegesWrapper>
);
};

View file

@ -13,12 +13,9 @@ import { FormattedMessage } from '@kbn/i18n/react';
import {
EuiButtonEmpty,
EuiCallOut,
EuiFlexGroup,
EuiFlexItem,
EuiPageContent,
EuiPageContentBody,
EuiPageHeader,
EuiSpacer,
EuiTitle,
} from '@elastic/eui';
import { APP_CREATE_TRANSFORM_CLUSTER_PRIVILEGES } from '../../../../common/constants';
@ -42,42 +39,44 @@ export const CreateTransformSection: FC<Props> = ({ match }) => {
const { error: searchItemsError, searchItems } = useSearchItems(match.params.savedObjectId);
const docsLink = (
<EuiButtonEmpty
href={esTransform}
target="_blank"
iconType="help"
data-test-subj="documentationLink"
>
<FormattedMessage
id="xpack.transform.transformsWizard.transformDocsLinkText"
defaultMessage="Transform docs"
/>
</EuiButtonEmpty>
);
return (
<PrivilegesWrapper privileges={APP_CREATE_TRANSFORM_CLUSTER_PRIVILEGES}>
<EuiPageContent data-test-subj="transformPageCreateTransform">
<EuiTitle size="l">
<EuiFlexGroup alignItems="center">
<EuiFlexItem grow={true}>
<h1>
<FormattedMessage
id="xpack.transform.transformsWizard.createTransformTitle"
defaultMessage="Create transform"
/>
</h1>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonEmpty
href={esTransform}
target="_blank"
iconType="help"
data-test-subj="documentationLink"
>
<FormattedMessage
id="xpack.transform.transformsWizard.transformDocsLinkText"
defaultMessage="Transform docs"
/>
</EuiButtonEmpty>
</EuiFlexItem>
</EuiFlexGroup>
</EuiTitle>
<EuiPageContentBody>
<EuiSpacer size="l" />
{searchItemsError !== undefined && (
<EuiPageHeader
pageTitle={
<FormattedMessage
id="xpack.transform.transformsWizard.createTransformTitle"
defaultMessage="Create transform"
/>
}
rightSideItems={[docsLink]}
bottomBorder
/>
<EuiSpacer size="l" />
<EuiPageContentBody data-test-subj="transformPageCreateTransform">
{searchItemsError !== undefined && (
<>
<EuiCallOut title={searchItemsError} color="danger" iconType="alert" />
)}
{searchItems !== undefined && <Wizard searchItems={searchItems} />}
</EuiPageContentBody>
</EuiPageContent>
<EuiSpacer size="l" />
</>
)}
{searchItems !== undefined && <Wizard searchItems={searchItems} />}
</EuiPageContentBody>
</PrivilegesWrapper>
);
};

View file

@ -1,23 +1,42 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Transform: Transform List <TransformList /> Minimal initialization 1`] = `
<EuiEmptyPrompt
actions={
Array [
<EuiButtonEmpty
data-test-subj="transformCreateFirstButton"
isDisabled={true}
onClick={[MockFunction]}
>
Create your first transform
</EuiButtonEmpty>,
]
}
data-test-subj="transformNoTransformsFound"
title={
<h2>
No transforms found
</h2>
}
/>
<EuiFlexGroup
justifyContent="spaceAround"
>
<EuiFlexItem
grow={false}
>
<EuiSpacer
size="l"
/>
<EuiPageContent
color="subdued"
horizontalPosition="center"
verticalPosition="center"
>
<EuiEmptyPrompt
actions={
Array [
<EuiButton
color="primary"
data-test-subj="transformCreateFirstButton"
fill={true}
isDisabled={true}
onClick={[MockFunction]}
>
Create your first transform
</EuiButton>,
]
}
data-test-subj="transformNoTransformsFound"
title={
<h2>
No transforms found
</h2>
}
/>
</EuiPageContent>
</EuiFlexItem>
</EuiFlexGroup>
`;

View file

@ -10,12 +10,15 @@ import React, { MouseEventHandler, FC, useContext, useState } from 'react';
import { i18n } from '@kbn/i18n';
import {
EuiButton,
EuiButtonEmpty,
EuiButtonIcon,
EuiEmptyPrompt,
EuiFlexGroup,
EuiFlexItem,
EuiPageContent,
EuiPopover,
EuiSpacer,
EuiTitle,
EuiInMemoryTable,
EuiSearchBarProps,
@ -135,27 +138,36 @@ export const TransformList: FC<TransformListProps> = ({
if (transforms.length === 0) {
return (
<EuiEmptyPrompt
title={
<h2>
{i18n.translate('xpack.transform.list.emptyPromptTitle', {
defaultMessage: 'No transforms found',
})}
</h2>
}
actions={[
<EuiButtonEmpty
onClick={onCreateTransform}
isDisabled={disabled}
data-test-subj="transformCreateFirstButton"
>
{i18n.translate('xpack.transform.list.emptyPromptButtonText', {
defaultMessage: 'Create your first transform',
})}
</EuiButtonEmpty>,
]}
data-test-subj="transformNoTransformsFound"
/>
<EuiFlexGroup justifyContent="spaceAround">
<EuiFlexItem grow={false}>
<EuiSpacer size="l" />
<EuiPageContent verticalPosition="center" horizontalPosition="center" color="subdued">
<EuiEmptyPrompt
title={
<h2>
{i18n.translate('xpack.transform.list.emptyPromptTitle', {
defaultMessage: 'No transforms found',
})}
</h2>
}
actions={[
<EuiButton
color="primary"
fill
onClick={onCreateTransform}
isDisabled={disabled}
data-test-subj="transformCreateFirstButton"
>
{i18n.translate('xpack.transform.list.emptyPromptButtonText', {
defaultMessage: 'Create your first transform',
})}
</EuiButton>,
]}
data-test-subj="transformNoTransformsFound"
/>
</EuiPageContent>
</EuiFlexItem>
</EuiFlexGroup>
);
}

View file

@ -5,23 +5,21 @@
* 2.0.
*/
import React, { FC, Fragment, useEffect, useState } from 'react';
import React, { FC, useEffect, useState } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import {
EuiButtonEmpty,
EuiCallOut,
EuiEmptyPrompt,
EuiFlexGroup,
EuiFlexItem,
EuiLoadingContent,
EuiModal,
EuiPageContent,
EuiPageContentBody,
EuiPageHeader,
EuiSpacer,
EuiText,
EuiTitle,
} from '@elastic/eui';
import { APP_GET_TRANSFORM_CLUSTER_PRIVILEGES } from '../../../../common/constants';
@ -77,73 +75,91 @@ export const TransformManagement: FC = () => {
setSavedObjectId(id);
};
const docsLink = (
<EuiButtonEmpty
href={esTransform}
target="_blank"
iconType="help"
data-test-subj="documentationLink"
>
<FormattedMessage
id="xpack.transform.transformList.transformDocsLinkText"
defaultMessage="Transform docs"
/>
</EuiButtonEmpty>
);
return (
<Fragment>
<EuiPageContent data-test-subj="transformPageTransformList">
<EuiTitle size="l">
<EuiFlexGroup alignItems="center">
<EuiFlexItem grow={true}>
<h1 data-test-subj="transformAppTitle">
<FormattedMessage
id="xpack.transform.transformList.transformTitle"
defaultMessage="Transforms"
/>
</h1>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonEmpty
href={esTransform}
target="_blank"
iconType="help"
data-test-subj="documentationLink"
>
<FormattedMessage
id="xpack.transform.transformList.transformDocsLinkText"
defaultMessage="Transform docs"
/>
</EuiButtonEmpty>
</EuiFlexItem>
</EuiFlexGroup>
</EuiTitle>
<EuiSpacer size="s" />
<EuiTitle size="s">
<EuiText color="subdued">
<>
<EuiPageHeader
pageTitle={
<span data-test-subj="transformAppTitle">
<FormattedMessage
id="xpack.transform.transformList.transformDescription"
defaultMessage="Use transforms to pivot existing Elasticsearch indices into summarized entity-centric indices or to create an indexed view of the latest documents for fast access."
id="xpack.transform.transformList.transformTitle"
defaultMessage="Transforms"
/>
</EuiText>
</EuiTitle>
<EuiPageContentBody>
<EuiSpacer size="l" />
{!isInitialized && <EuiLoadingContent lines={2} />}
{isInitialized && (
<>
<TransformStatsBar transformNodes={transformNodes} transformsList={transforms} />
<EuiSpacer size="s" />
{typeof errorMessage !== 'undefined' && (
<EuiCallOut
title={i18n.translate('xpack.transform.list.errorPromptTitle', {
defaultMessage: 'An error occurred getting the transform list.',
})}
color="danger"
iconType="alert"
>
<pre>{JSON.stringify(errorMessage)}</pre>
</EuiCallOut>
)}
{typeof errorMessage === 'undefined' && (
<TransformList
onCreateTransform={onOpenModal}
transformNodes={transformNodes}
transforms={transforms}
transformsLoading={transformsLoading}
/>
)}
</>
)}
</EuiPageContentBody>
</EuiPageContent>
</span>
}
description={
<FormattedMessage
id="xpack.transform.transformList.transformDescription"
defaultMessage="Use transforms to pivot existing Elasticsearch indices into summarized entity-centric indices or to create an indexed view of the latest documents for fast access."
/>
}
rightSideItems={[docsLink]}
bottomBorder
/>
<EuiSpacer size="l" />
<EuiPageContentBody data-test-subj="transformPageTransformList">
{!isInitialized && <EuiLoadingContent lines={2} />}
{isInitialized && (
<>
<TransformStatsBar transformNodes={transformNodes} transformsList={transforms} />
<EuiSpacer size="s" />
{typeof errorMessage !== 'undefined' && (
<EuiFlexGroup justifyContent="spaceAround">
<EuiFlexItem grow={false}>
<EuiSpacer size="l" />
<EuiPageContent
verticalPosition="center"
horizontalPosition="center"
color="danger"
>
<EuiEmptyPrompt
iconType="alert"
title={
<h2>
<FormattedMessage
id="xpack.transform.list.errorPromptTitle"
defaultMessage="An error occurred getting the transform list"
/>
</h2>
}
body={
<p>
<pre>{JSON.stringify(errorMessage)}</pre>
</p>
}
actions={[]}
/>
</EuiPageContent>
</EuiFlexItem>
</EuiFlexGroup>
)}
{typeof errorMessage === 'undefined' && (
<TransformList
onCreateTransform={onOpenModal}
transformNodes={transformNodes}
transforms={transforms}
transformsLoading={transformsLoading}
/>
)}
</>
)}
</EuiPageContentBody>
{isSearchSelectionVisible && (
<EuiModal
onClose={onCloseModal}
@ -153,7 +169,7 @@ export const TransformManagement: FC = () => {
<SearchSelection onSearchSelected={onSearchSelected} />
</EuiModal>
)}
</Fragment>
</>
);
};