[ML] Transforms: Use EuiInMemoryTable instead of custom typed table. (#59782)

Before EuiInMemoryTable had TypeScript support we used our own typings and some state & CSS fixes. This is now all solved by the original EUI component.
- Use EuiInMemoryTable instead of custom typed table.
- Deletes some legacy leftover files.
This commit is contained in:
Walter Rafelsberger 2020-03-11 09:37:03 +01:00 committed by GitHub
parent fa16b2b849
commit ce6029b9b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 56 additions and 259 deletions

1
.github/CODEOWNERS vendored
View file

@ -88,7 +88,6 @@
/x-pack/test/functional/services/ml.ts @elastic/ml-ui /x-pack/test/functional/services/ml.ts @elastic/ml-ui
# ML team owns the transform plugin, ES team added here for visibility # ML team owns the transform plugin, ES team added here for visibility
# because the plugin lives in Kibana's Elasticsearch management section. # because the plugin lives in Kibana's Elasticsearch management section.
/x-pack/legacy/plugins/transform/ @elastic/ml-ui @elastic/es-ui
/x-pack/plugins/transform/ @elastic/ml-ui @elastic/es-ui /x-pack/plugins/transform/ @elastic/ml-ui @elastic/es-ui
/x-pack/test/functional/apps/transform/ @elastic/ml-ui /x-pack/test/functional/apps/transform/ @elastic/ml-ui
/x-pack/test/functional/services/transform_ui/ @elastic/ml-ui /x-pack/test/functional/services/transform_ui/ @elastic/ml-ui

View file

@ -31,7 +31,6 @@ import { crossClusterReplication } from './legacy/plugins/cross_cluster_replicat
import { upgradeAssistant } from './legacy/plugins/upgrade_assistant'; import { upgradeAssistant } from './legacy/plugins/upgrade_assistant';
import { uptime } from './legacy/plugins/uptime'; import { uptime } from './legacy/plugins/uptime';
import { encryptedSavedObjects } from './legacy/plugins/encrypted_saved_objects'; import { encryptedSavedObjects } from './legacy/plugins/encrypted_saved_objects';
import { transform } from './legacy/plugins/transform';
import { actions } from './legacy/plugins/actions'; import { actions } from './legacy/plugins/actions';
import { alerting } from './legacy/plugins/alerting'; import { alerting } from './legacy/plugins/alerting';
import { lens } from './legacy/plugins/lens'; import { lens } from './legacy/plugins/lens';
@ -61,7 +60,6 @@ module.exports = function(kibana) {
infra(kibana), infra(kibana),
taskManager(kibana), taskManager(kibana),
rollup(kibana), rollup(kibana),
transform(kibana),
siem(kibana), siem(kibana),
remoteClusters(kibana), remoteClusters(kibana),
crossClusterReplication(kibana), crossClusterReplication(kibana),

View file

@ -1,12 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
export function transform(kibana: any) {
return new kibana.Plugin({
id: 'transform',
configPrefix: 'xpack.transform',
});
}

View file

@ -15,4 +15,3 @@
@import 'sections/create_transform/components/wizard/index'; @import 'sections/create_transform/components/wizard/index';
@import 'sections/transform_management/components/create_transform_button/index'; @import 'sections/transform_management/components/create_transform_button/index';
@import 'sections/transform_management/components/stats_bar/index'; @import 'sections/transform_management/components/stats_bar/index';
@import 'sections/transform_management/components/transform_list/index';

View file

@ -1,48 +0,0 @@
.transform__TransformTable {
// Using an override as a last resort because we cannot set custom classes on
// nested upstream components. The opening animation limits the height
// of the expanded row to 1000px which turned out to be not predictable.
// The animation could also result in flickering with expanded rows
// where the inner content would result in the DOM changing the height.
.euiTableRow-isExpandedRow .euiTableCellContent {
animation: none !important;
.euiTableCellContent__text {
width: 100%;
}
}
// Another override: Because an update to the table replaces the DOM, the same
// icon would still again fade in with an animation. If the table refreshes with
// e.g. 1s this would result in a blinking icon effect.
.euiIcon-isLoaded {
animation: none !important;
}
}
.transform__BulkActionItem {
display: block;
padding: $euiSizeS;
width: 100%;
text-align: left;
}
.transform__BulkActionsBorder {
height: 20px;
border-right: $euiBorderThin;
width: 1px;
display: inline-block;
vertical-align: middle;
height: 35px;
margin: 0px 5px;
margin-top: -5px;
}
.transform__ProgressBar {
margin-bottom: $euiSizeM;
}
.transform__TaskStateBadge, .transform__TaskModeBadge {
max-width: 100px;
}
.transform__TransformTable__messagesPaneTable .euiTableCellContent__text {
text-align: left;
}

View file

@ -9,6 +9,9 @@ import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react'; import { FormattedMessage } from '@kbn/i18n/react';
import { import {
EuiBadge, EuiBadge,
EuiTableActionsColumnType,
EuiTableComputedColumnType,
EuiTableFieldDataColumnType,
EuiButtonIcon, EuiButtonIcon,
EuiFlexGroup, EuiFlexGroup,
EuiFlexItem, EuiFlexItem,
@ -21,13 +24,6 @@ import {
import { TransformId, TRANSFORM_STATE } from '../../../../../../common'; import { TransformId, TRANSFORM_STATE } from '../../../../../../common';
import {
ActionsColumnType,
ComputedColumnType,
ExpanderColumnType,
FieldDataColumnType,
} from '../../../../../shared_imports';
import { import {
getTransformProgress, getTransformProgress,
TransformListRow, TransformListRow,
@ -89,15 +85,15 @@ export const getColumns = (
} }
const columns: [ const columns: [
ExpanderColumnType<TransformListRow>, EuiTableComputedColumnType<TransformListRow>,
FieldDataColumnType<TransformListRow>, EuiTableFieldDataColumnType<TransformListRow>,
FieldDataColumnType<TransformListRow>, EuiTableFieldDataColumnType<TransformListRow>,
FieldDataColumnType<TransformListRow>, EuiTableFieldDataColumnType<TransformListRow>,
FieldDataColumnType<TransformListRow>, EuiTableFieldDataColumnType<TransformListRow>,
ComputedColumnType<TransformListRow>, EuiTableComputedColumnType<TransformListRow>,
ComputedColumnType<TransformListRow>, EuiTableComputedColumnType<TransformListRow>,
ComputedColumnType<TransformListRow>, EuiTableComputedColumnType<TransformListRow>,
ActionsColumnType<TransformListRow> EuiTableActionsColumnType<TransformListRow>
] = [ ] = [
{ {
name: ( name: (

View file

@ -4,11 +4,12 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
import React, { Fragment, MouseEventHandler, FC, useContext, useState } from 'react'; import React, { MouseEventHandler, FC, useContext, useState } from 'react';
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
import { import {
Direction,
EuiBadge, EuiBadge,
EuiButtonEmpty, EuiButtonEmpty,
EuiButtonIcon, EuiButtonIcon,
@ -16,15 +17,13 @@ import {
EuiEmptyPrompt, EuiEmptyPrompt,
EuiFlexGroup, EuiFlexGroup,
EuiFlexItem, EuiFlexItem,
EuiInMemoryTable,
EuiPopover, EuiPopover,
EuiTitle, EuiTitle,
Direction,
} from '@elastic/eui'; } from '@elastic/eui';
import { TransformId, TRANSFORM_STATE } from '../../../../../../common'; import { TransformId, TRANSFORM_STATE } from '../../../../../../common';
import { OnTableChangeArg, SortDirection, SORT_DIRECTION } from '../../../../../shared_imports';
import { import {
useRefreshTransformList, useRefreshTransformList,
TransformListRow, TransformListRow,
@ -43,7 +42,6 @@ import { StopAction } from './action_stop';
import { ItemIdToExpandedRowMap, Query, Clause } from './common'; import { ItemIdToExpandedRowMap, Query, Clause } from './common';
import { getColumns } from './columns'; import { getColumns } from './columns';
import { ExpandedRow } from './expanded_row'; import { ExpandedRow } from './expanded_row';
import { ProgressBar, transformTableFactory } from './transform_table';
function getItemIdToExpandedRowMap( function getItemIdToExpandedRowMap(
itemIds: TransformId[], itemIds: TransformId[],
@ -74,8 +72,6 @@ interface Props {
transformsLoading: boolean; transformsLoading: boolean;
} }
const TransformTable = transformTableFactory<TransformListRow>();
export const TransformList: FC<Props> = ({ export const TransformList: FC<Props> = ({
errorMessage, errorMessage,
isInitialized, isInitialized,
@ -100,7 +96,7 @@ export const TransformList: FC<Props> = ({
const [pageSize, setPageSize] = useState(10); const [pageSize, setPageSize] = useState(10);
const [sortField, setSortField] = useState<string>(TRANSFORM_LIST_COLUMN.ID); const [sortField, setSortField] = useState<string>(TRANSFORM_LIST_COLUMN.ID);
const [sortDirection, setSortDirection] = useState<SortDirection | Direction>(SORT_DIRECTION.ASC); const [sortDirection, setSortDirection] = useState<Direction>('asc');
const { capabilities } = useContext(AuthorizationContext); const { capabilities } = useContext(AuthorizationContext);
const disabled = const disabled =
@ -186,52 +182,46 @@ export const TransformList: FC<Props> = ({
// Before the transforms have been loaded for the first time, display the loading indicator only. // Before the transforms have been loaded for the first time, display the loading indicator only.
// Otherwise a user would see 'No transforms found' during the initial loading. // Otherwise a user would see 'No transforms found' during the initial loading.
if (!isInitialized) { if (!isInitialized) {
return <ProgressBar isLoading={isLoading || transformsLoading} />; return null;
} }
if (typeof errorMessage !== 'undefined') { if (typeof errorMessage !== 'undefined') {
return ( return (
<Fragment> <EuiCallOut
<ProgressBar isLoading={isLoading || transformsLoading} /> title={i18n.translate('xpack.transform.list.errorPromptTitle', {
<EuiCallOut defaultMessage: 'An error occurred getting the transform list.',
title={i18n.translate('xpack.transform.list.errorPromptTitle', { })}
defaultMessage: 'An error occurred getting the transform list.', color="danger"
})} iconType="alert"
color="danger" >
iconType="alert" <pre>{JSON.stringify(errorMessage)}</pre>
> </EuiCallOut>
<pre>{JSON.stringify(errorMessage)}</pre>
</EuiCallOut>
</Fragment>
); );
} }
if (transforms.length === 0) { if (transforms.length === 0) {
return ( return (
<Fragment> <EuiEmptyPrompt
<ProgressBar isLoading={isLoading || transformsLoading} /> title={
<EuiEmptyPrompt <h2>
title={ {i18n.translate('xpack.transform.list.emptyPromptTitle', {
<h2> defaultMessage: 'No transforms found',
{i18n.translate('xpack.transform.list.emptyPromptTitle', { })}
defaultMessage: 'No transforms found', </h2>
})} }
</h2> actions={[
} <EuiButtonEmpty
actions={[ onClick={onCreateTransform}
<EuiButtonEmpty isDisabled={disabled}
onClick={onCreateTransform} data-test-subj="transformCreateFirstButton"
isDisabled={disabled} >
data-test-subj="transformCreateFirstButton" {i18n.translate('xpack.transform.list.emptyPromptButtonText', {
> defaultMessage: 'Create your first transform',
{i18n.translate('xpack.transform.list.emptyPromptButtonText', { })}
defaultMessage: 'Create your first transform', </EuiButtonEmpty>,
})} ]}
</EuiButtonEmpty>, data-test-subj="transformNoTransformsFound"
]} />
data-test-subj="transformNoTransformsFound"
/>
</Fragment>
); );
} }
@ -362,15 +352,15 @@ export const TransformList: FC<Props> = ({
const onTableChange = ({ const onTableChange = ({
page = { index: 0, size: 10 }, page = { index: 0, size: 10 },
sort = { field: TRANSFORM_LIST_COLUMN.ID, direction: SORT_DIRECTION.ASC }, sort = { field: TRANSFORM_LIST_COLUMN.ID as string, direction: 'asc' },
}: OnTableChangeArg) => { }) => {
const { index, size } = page; const { index, size } = page;
setPageIndex(index); setPageIndex(index);
setPageSize(size); setPageSize(size);
const { field, direction } = sort; const { field, direction } = sort;
setSortField(field); setSortField(field as string);
setSortDirection(direction); setSortDirection(direction as Direction);
}; };
const selection = { const selection = {
@ -379,8 +369,7 @@ export const TransformList: FC<Props> = ({
return ( return (
<div data-test-subj="transformListTableContainer"> <div data-test-subj="transformListTableContainer">
<ProgressBar isLoading={isLoading || transformsLoading} /> <EuiInMemoryTable
<TransformTable
allowNeutralSort={false} allowNeutralSort={false}
className="transform__TransformTable" className="transform__TransformTable"
columns={columns} columns={columns}
@ -391,6 +380,7 @@ export const TransformList: FC<Props> = ({
items={filterActive ? filteredTransforms : transforms} items={filterActive ? filteredTransforms : transforms}
itemId={TRANSFORM_LIST_COLUMN.ID} itemId={TRANSFORM_LIST_COLUMN.ID}
itemIdToExpandedRowMap={itemIdToExpandedRowMap} itemIdToExpandedRowMap={itemIdToExpandedRowMap}
loading={isLoading || transformsLoading}
onTableChange={onTableChange} onTableChange={onTableChange}
pagination={pagination} pagination={pagination}
rowProps={item => ({ rowProps={item => ({
@ -399,11 +389,9 @@ export const TransformList: FC<Props> = ({
selection={selection} selection={selection}
sorting={sorting} sorting={sorting}
search={search} search={search}
data-test-subj={ data-test-subj={`transformListTable ${
isLoading || transformsLoading isLoading || transformsLoading ? 'loading' : 'loaded'
? 'transformListTable loading' }`}
: 'transformListTable loaded'
}
/> />
</div> </div>
); );

View file

@ -1,107 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
// This component extends EuiInMemoryTable with some
// fixes and TS specs until the changes become available upstream.
import React, { Fragment } from 'react';
import { EuiProgress } from '@elastic/eui';
import { mlInMemoryTableBasicFactory } from '../../../../../shared_imports';
// The built in loading progress bar of EuiInMemoryTable causes a full DOM replacement
// of the table and doesn't play well with auto-refreshing. That's why we're displaying
// our own progress bar on top of the table. `EuiProgress` after `isLoading` displays
// the loading indicator. The variation after `!isLoading` displays an empty progress
// bar fixed to 0%. Without it, the display would vertically jump when showing/hiding
// the progress bar.
export const ProgressBar = ({ isLoading = false }) => {
return (
<Fragment>
{isLoading && <EuiProgress className="transform__ProgressBar" size="xs" color="primary" />}
{!isLoading && (
<EuiProgress className="transform__ProgressBar" value={0} max={100} size="xs" />
)}
</Fragment>
);
};
// copied from EUI to be available to the extended getDerivedStateFromProps()
function findColumnByProp(columns: any, prop: any, value: any) {
for (let i = 0; i < columns.length; i++) {
const column = columns[i];
if (column[prop] === value) {
return column;
}
}
}
// copied from EUI to be available to the extended getDerivedStateFromProps()
const getInitialSorting = (columns: any, sorting: any) => {
if (!sorting || !sorting.sort) {
return {
sortName: undefined,
sortDirection: undefined,
};
}
const { field: sortable, direction: sortDirection } = sorting.sort;
// sortable could be a column's `field` or its `name`
// for backwards compatibility `field` must be checked first
let sortColumn = findColumnByProp(columns, 'field', sortable);
if (sortColumn == null) {
sortColumn = findColumnByProp(columns, 'name', sortable);
}
if (sortColumn == null) {
return {
sortName: undefined,
sortDirection: undefined,
};
}
const sortName = sortColumn.name;
return {
sortName,
sortDirection,
};
};
export function transformTableFactory<T>() {
const MlInMemoryTableBasic = mlInMemoryTableBasicFactory<T>();
return class TransformTable extends MlInMemoryTableBasic {
static getDerivedStateFromProps(nextProps: any, prevState: any) {
const derivedState = {
...prevState.prevProps,
pageIndex: nextProps.pagination.initialPageIndex,
pageSize: nextProps.pagination.initialPageSize,
};
if (nextProps.items !== prevState.prevProps.items) {
Object.assign(derivedState, {
prevProps: {
items: nextProps.items,
},
});
}
const { sortName, sortDirection } = getInitialSorting(nextProps.columns, nextProps.sorting);
if (
sortName !== prevState.prevProps.sortName ||
sortDirection !== prevState.prevProps.sortDirection
) {
Object.assign(derivedState, {
sortName,
sortDirection,
});
}
return derivedState;
}
};
}

View file

@ -24,21 +24,6 @@ export {
DAY, DAY,
} from '../../../../src/plugins/es_ui_shared/public/components/cron_editor'; } from '../../../../src/plugins/es_ui_shared/public/components/cron_editor';
// Custom version of EuiInMemoryTable with TypeScript
// support and a fix for updating sorting props.
export {
ActionsColumnType,
ComputedColumnType,
ExpanderColumnType,
FieldDataColumnType,
ColumnType,
mlInMemoryTableBasicFactory,
OnTableChangeArg,
SortingPropType,
SortDirection,
SORT_DIRECTION,
} from '../../../legacy/plugins/ml/public/application/components/ml_in_memory_table';
// Needs to be imported because we're reusing KqlFilterBar which depends on it. // Needs to be imported because we're reusing KqlFilterBar which depends on it.
export { setDependencyCache } from '../../../legacy/plugins/ml/public/application/util/dependency_cache'; export { setDependencyCache } from '../../../legacy/plugins/ml/public/application/util/dependency_cache';