mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[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:
parent
fa16b2b849
commit
ce6029b9b0
10 changed files with 56 additions and 259 deletions
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
@ -88,7 +88,6 @@
|
|||
/x-pack/test/functional/services/ml.ts @elastic/ml-ui
|
||||
# ML team owns the transform plugin, ES team added here for visibility
|
||||
# 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/test/functional/apps/transform/ @elastic/ml-ui
|
||||
/x-pack/test/functional/services/transform_ui/ @elastic/ml-ui
|
||||
|
|
|
@ -31,7 +31,6 @@ import { crossClusterReplication } from './legacy/plugins/cross_cluster_replicat
|
|||
import { upgradeAssistant } from './legacy/plugins/upgrade_assistant';
|
||||
import { uptime } from './legacy/plugins/uptime';
|
||||
import { encryptedSavedObjects } from './legacy/plugins/encrypted_saved_objects';
|
||||
import { transform } from './legacy/plugins/transform';
|
||||
import { actions } from './legacy/plugins/actions';
|
||||
import { alerting } from './legacy/plugins/alerting';
|
||||
import { lens } from './legacy/plugins/lens';
|
||||
|
@ -61,7 +60,6 @@ module.exports = function(kibana) {
|
|||
infra(kibana),
|
||||
taskManager(kibana),
|
||||
rollup(kibana),
|
||||
transform(kibana),
|
||||
siem(kibana),
|
||||
remoteClusters(kibana),
|
||||
crossClusterReplication(kibana),
|
||||
|
|
|
@ -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',
|
||||
});
|
||||
}
|
|
@ -15,4 +15,3 @@
|
|||
@import 'sections/create_transform/components/wizard/index';
|
||||
@import 'sections/transform_management/components/create_transform_button/index';
|
||||
@import 'sections/transform_management/components/stats_bar/index';
|
||||
@import 'sections/transform_management/components/transform_list/index';
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
@import 'transform_table';
|
|
@ -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;
|
||||
}
|
|
@ -9,6 +9,9 @@ import { i18n } from '@kbn/i18n';
|
|||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import {
|
||||
EuiBadge,
|
||||
EuiTableActionsColumnType,
|
||||
EuiTableComputedColumnType,
|
||||
EuiTableFieldDataColumnType,
|
||||
EuiButtonIcon,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
|
@ -21,13 +24,6 @@ import {
|
|||
|
||||
import { TransformId, TRANSFORM_STATE } from '../../../../../../common';
|
||||
|
||||
import {
|
||||
ActionsColumnType,
|
||||
ComputedColumnType,
|
||||
ExpanderColumnType,
|
||||
FieldDataColumnType,
|
||||
} from '../../../../../shared_imports';
|
||||
|
||||
import {
|
||||
getTransformProgress,
|
||||
TransformListRow,
|
||||
|
@ -89,15 +85,15 @@ export const getColumns = (
|
|||
}
|
||||
|
||||
const columns: [
|
||||
ExpanderColumnType<TransformListRow>,
|
||||
FieldDataColumnType<TransformListRow>,
|
||||
FieldDataColumnType<TransformListRow>,
|
||||
FieldDataColumnType<TransformListRow>,
|
||||
FieldDataColumnType<TransformListRow>,
|
||||
ComputedColumnType<TransformListRow>,
|
||||
ComputedColumnType<TransformListRow>,
|
||||
ComputedColumnType<TransformListRow>,
|
||||
ActionsColumnType<TransformListRow>
|
||||
EuiTableComputedColumnType<TransformListRow>,
|
||||
EuiTableFieldDataColumnType<TransformListRow>,
|
||||
EuiTableFieldDataColumnType<TransformListRow>,
|
||||
EuiTableFieldDataColumnType<TransformListRow>,
|
||||
EuiTableFieldDataColumnType<TransformListRow>,
|
||||
EuiTableComputedColumnType<TransformListRow>,
|
||||
EuiTableComputedColumnType<TransformListRow>,
|
||||
EuiTableComputedColumnType<TransformListRow>,
|
||||
EuiTableActionsColumnType<TransformListRow>
|
||||
] = [
|
||||
{
|
||||
name: (
|
||||
|
|
|
@ -4,11 +4,12 @@
|
|||
* 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 {
|
||||
Direction,
|
||||
EuiBadge,
|
||||
EuiButtonEmpty,
|
||||
EuiButtonIcon,
|
||||
|
@ -16,15 +17,13 @@ import {
|
|||
EuiEmptyPrompt,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiInMemoryTable,
|
||||
EuiPopover,
|
||||
EuiTitle,
|
||||
Direction,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { TransformId, TRANSFORM_STATE } from '../../../../../../common';
|
||||
|
||||
import { OnTableChangeArg, SortDirection, SORT_DIRECTION } from '../../../../../shared_imports';
|
||||
|
||||
import {
|
||||
useRefreshTransformList,
|
||||
TransformListRow,
|
||||
|
@ -43,7 +42,6 @@ import { StopAction } from './action_stop';
|
|||
import { ItemIdToExpandedRowMap, Query, Clause } from './common';
|
||||
import { getColumns } from './columns';
|
||||
import { ExpandedRow } from './expanded_row';
|
||||
import { ProgressBar, transformTableFactory } from './transform_table';
|
||||
|
||||
function getItemIdToExpandedRowMap(
|
||||
itemIds: TransformId[],
|
||||
|
@ -74,8 +72,6 @@ interface Props {
|
|||
transformsLoading: boolean;
|
||||
}
|
||||
|
||||
const TransformTable = transformTableFactory<TransformListRow>();
|
||||
|
||||
export const TransformList: FC<Props> = ({
|
||||
errorMessage,
|
||||
isInitialized,
|
||||
|
@ -100,7 +96,7 @@ export const TransformList: FC<Props> = ({
|
|||
const [pageSize, setPageSize] = useState(10);
|
||||
|
||||
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 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.
|
||||
// Otherwise a user would see 'No transforms found' during the initial loading.
|
||||
if (!isInitialized) {
|
||||
return <ProgressBar isLoading={isLoading || transformsLoading} />;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (typeof errorMessage !== 'undefined') {
|
||||
return (
|
||||
<Fragment>
|
||||
<ProgressBar isLoading={isLoading || transformsLoading} />
|
||||
<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>
|
||||
</Fragment>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
if (transforms.length === 0) {
|
||||
return (
|
||||
<Fragment>
|
||||
<ProgressBar isLoading={isLoading || transformsLoading} />
|
||||
<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"
|
||||
/>
|
||||
</Fragment>
|
||||
<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"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -362,15 +352,15 @@ export const TransformList: FC<Props> = ({
|
|||
|
||||
const onTableChange = ({
|
||||
page = { index: 0, size: 10 },
|
||||
sort = { field: TRANSFORM_LIST_COLUMN.ID, direction: SORT_DIRECTION.ASC },
|
||||
}: OnTableChangeArg) => {
|
||||
sort = { field: TRANSFORM_LIST_COLUMN.ID as string, direction: 'asc' },
|
||||
}) => {
|
||||
const { index, size } = page;
|
||||
setPageIndex(index);
|
||||
setPageSize(size);
|
||||
|
||||
const { field, direction } = sort;
|
||||
setSortField(field);
|
||||
setSortDirection(direction);
|
||||
setSortField(field as string);
|
||||
setSortDirection(direction as Direction);
|
||||
};
|
||||
|
||||
const selection = {
|
||||
|
@ -379,8 +369,7 @@ export const TransformList: FC<Props> = ({
|
|||
|
||||
return (
|
||||
<div data-test-subj="transformListTableContainer">
|
||||
<ProgressBar isLoading={isLoading || transformsLoading} />
|
||||
<TransformTable
|
||||
<EuiInMemoryTable
|
||||
allowNeutralSort={false}
|
||||
className="transform__TransformTable"
|
||||
columns={columns}
|
||||
|
@ -391,6 +380,7 @@ export const TransformList: FC<Props> = ({
|
|||
items={filterActive ? filteredTransforms : transforms}
|
||||
itemId={TRANSFORM_LIST_COLUMN.ID}
|
||||
itemIdToExpandedRowMap={itemIdToExpandedRowMap}
|
||||
loading={isLoading || transformsLoading}
|
||||
onTableChange={onTableChange}
|
||||
pagination={pagination}
|
||||
rowProps={item => ({
|
||||
|
@ -399,11 +389,9 @@ export const TransformList: FC<Props> = ({
|
|||
selection={selection}
|
||||
sorting={sorting}
|
||||
search={search}
|
||||
data-test-subj={
|
||||
isLoading || transformsLoading
|
||||
? 'transformListTable loading'
|
||||
: 'transformListTable loaded'
|
||||
}
|
||||
data-test-subj={`transformListTable ${
|
||||
isLoading || transformsLoading ? 'loading' : 'loaded'
|
||||
}`}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -24,21 +24,6 @@ export {
|
|||
DAY,
|
||||
} 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.
|
||||
export { setDependencyCache } from '../../../legacy/plugins/ml/public/application/util/dependency_cache';
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue