diff --git a/x-pack/plugins/ml/public/application/components/ml_in_memory_table/index.ts b/x-pack/plugins/ml/public/application/components/ml_in_memory_table/index.ts deleted file mode 100644 index bbd793696e005..0000000000000 --- a/x-pack/plugins/ml/public/application/components/ml_in_memory_table/index.ts +++ /dev/null @@ -1,8 +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 { ProgressBar, mlInMemoryTableFactory } from './ml_in_memory_table'; -export * from './types'; diff --git a/x-pack/plugins/ml/public/application/components/ml_in_memory_table/ml_in_memory_table.tsx b/x-pack/plugins/ml/public/application/components/ml_in_memory_table/ml_in_memory_table.tsx deleted file mode 100644 index 7caaadf65d6da..0000000000000 --- a/x-pack/plugins/ml/public/application/components/ml_in_memory_table/ml_in_memory_table.tsx +++ /dev/null @@ -1,108 +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'; - -// 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 ( - - {isLoading && } - {!isLoading && ( - - )} - - ); -}; - -// 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, - }; -}; - -import { mlInMemoryTableBasicFactory } from './types'; - -export function mlInMemoryTableFactory() { - const MlInMemoryTableBasic = mlInMemoryTableBasicFactory(); - - return class MlInMemoryTable 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; - } - }; -} diff --git a/x-pack/plugins/ml/public/application/components/ml_in_memory_table/types.ts b/x-pack/plugins/ml/public/application/components/ml_in_memory_table/types.ts deleted file mode 100644 index 05b941f2544b4..0000000000000 --- a/x-pack/plugins/ml/public/application/components/ml_in_memory_table/types.ts +++ /dev/null @@ -1,202 +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. - */ - -import { Component, HTMLAttributes, ReactElement, ReactNode } from 'react'; - -import { Direction, CommonProps, EuiInMemoryTable } from '@elastic/eui'; - -// Not using an enum here because the original HorizontalAlignment is also a union type of string. -type HorizontalAlignment = 'left' | 'center' | 'right'; - -type SortableFunc = (item: T) => any; -type Sortable = boolean | SortableFunc; -type DATA_TYPES = any; -type FooterFunc = (payload: { items: T[]; pagination: any }) => ReactNode; -type RenderFunc = (value: any, record?: any) => ReactNode; -export interface FieldDataColumnType { - field: string; - name: ReactNode; - description?: string; - dataType?: DATA_TYPES; - width?: string; - sortable?: Sortable; - align?: HorizontalAlignment; - truncateText?: boolean; - render?: RenderFunc; - footer?: string | ReactElement | FooterFunc; - textOnly?: boolean; - scope?: 'col' | 'row' | 'colgroup' | 'rowgroup'; - 'data-test-subj'?: string; -} - -export interface ComputedColumnType { - render: RenderFunc; - name?: ReactNode; - description?: string; - sortable?: (item: T) => any; - width?: string; - truncateText?: boolean; - 'data-test-subj'?: string; -} - -type ICON_TYPES = any; -type IconTypesFunc = (item: T) => ICON_TYPES; // (item) => oneOf(ICON_TYPES) -type BUTTON_ICON_COLORS = any; -type ButtonIconColorsFunc = (item: T) => BUTTON_ICON_COLORS; // (item) => oneOf(ICON_BUTTON_COLORS) -interface DefaultItemActionType { - type?: 'icon' | 'button'; - name: ReactNode; - description: string; - onClick?(item: T): void; - href?: string; - target?: string; - available?(item: T): boolean; - enabled?(item: T): boolean; - isPrimary?: boolean; - icon?: ICON_TYPES | IconTypesFunc; // required when type is 'icon' - color?: BUTTON_ICON_COLORS | ButtonIconColorsFunc; -} - -interface CustomItemActionType { - render(item: T, enabled: boolean): ReactNode; - available?(item: T): boolean; - enabled?(item: T): boolean; - isPrimary?: boolean; -} - -export interface ExpanderColumnType extends ComputedColumnType { - align?: HorizontalAlignment; - isExpander: true; -} - -type SupportedItemActionType = DefaultItemActionType | CustomItemActionType; - -export interface ActionsColumnType { - actions: Array>; - name?: ReactNode; - description?: string; - width?: string; -} - -export type ColumnType = - | ActionsColumnType - | ComputedColumnType - | ExpanderColumnType - | FieldDataColumnType; - -type QueryType = any; - -interface Schema { - strict?: boolean; - fields?: Record; - flags?: string[]; -} - -interface SearchBoxConfigPropTypes { - placeholder?: string; - incremental?: boolean; - schema?: Schema; -} - -interface Box { - placeholder?: string; - incremental?: boolean; - // here we enable the user to just assign 'true' to the schema, in which case - // we will auto-generate it out of the columns configuration - schema?: boolean | SearchBoxConfigPropTypes['schema']; -} - -type SearchFiltersFiltersType = any; - -interface ExecuteQueryOptions { - defaultFields: string[]; - isClauseMatcher: () => void; - explain: boolean; -} - -type SearchType = - | boolean - | { - toolsLeft?: ReactNode; - toolsRight?: ReactNode; - defaultQuery?: QueryType; - box?: Box; - filters?: SearchFiltersFiltersType; - onChange?: (arg: any) => void; - executeQueryOptions?: ExecuteQueryOptions; - }; - -interface PageSizeOptions { - pageSizeOptions: number[]; -} -interface InitialPageOptions extends PageSizeOptions { - initialPageIndex: number; - initialPageSize: number; -} -type PaginationProp = boolean | PageSizeOptions | InitialPageOptions; - -export enum SORT_DIRECTION { - ASC = 'asc', - DESC = 'desc', -} -export type SortDirection = SORT_DIRECTION.ASC | SORT_DIRECTION.DESC | 'asc' | 'desc'; -interface SortFields { - field: string; - direction: SortDirection | Direction; -} -export interface Sorting { - sort?: SortFields; -} -export type SortingPropType = - | boolean - | { - sort: SortFields; - }; - -type SelectionType = any; - -export interface OnTableChangeArg extends Sorting { - page?: { index: number; size: number }; -} - -type ItemIdTypeFunc = (item: T) => string; -type ItemIdType = - | string // the name of the item id property - | ItemIdTypeFunc; - -export type EuiInMemoryTableProps = CommonProps & { - columns: Array>; - hasActions?: boolean; - isExpandable?: boolean; - isSelectable?: boolean; - items?: T[]; - loading?: boolean; - message?: HTMLAttributes; - error?: string; - compressed?: boolean; - search?: SearchType; - pagination?: PaginationProp; - sorting?: SortingPropType; - // Set `allowNeutralSort` to false to force column sorting. Defaults to true. - allowNeutralSort?: boolean; - responsive?: boolean; - selection?: SelectionType; - itemId?: ItemIdType; - itemIdToExpandedRowMap?: Record; - rowProps?: (item: T) => void | Record; - cellProps?: () => void | Record; - onTableChange?: (arg: OnTableChangeArg) => void; -}; - -type EuiInMemoryTableType = typeof EuiInMemoryTable; - -interface ComponentWithConstructor extends EuiInMemoryTableType { - new (): Component; -} - -export function mlInMemoryTableBasicFactory() { - return EuiInMemoryTable as ComponentWithConstructor>; -} diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/_analytics_table.scss b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/_analytics_table.scss index 4472e6dbf64f3..f8071c9210f9c 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/_analytics_table.scss +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/_analytics_table.scss @@ -17,9 +17,6 @@ animation: none !important; } } -.mlAnalyticsProgressBar { - margin-bottom: $euiSizeM; -} .mlTaskStateBadge, .mlTaskModeBadge { max-width: 100px; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/analytics_list.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/analytics_list.tsx index e2298108ddc4b..7b5c714c236b3 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/analytics_list.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/analytics_list.tsx @@ -9,17 +9,18 @@ import React, { FC, useState, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import { + Direction, EuiButtonEmpty, EuiCallOut, EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, + EuiInMemoryTable, + EuiSearchBarProps, EuiSpacer, - EuiSearchBar, } from '@elastic/eui'; import { - getAnalysisType, DataFrameAnalyticsId, useRefreshAnalyticsList, ANALYSIS_CONFIG_TYPE, @@ -31,22 +32,10 @@ import { DataFrameAnalyticsListRow, ItemIdToExpandedRowMap, DATA_FRAME_TASK_STATE, - Query, - Clause, - TermClause, - FieldClause, } from './common'; import { getAnalyticsFactory } from '../../services/analytics_service'; import { getTaskStateBadge, getJobTypeBadge, useColumns } from './use_columns'; import { ExpandedRow } from './expanded_row'; -import { stringMatch } from '../../../../../util/string_utils'; -import { - ProgressBar, - mlInMemoryTableFactory, - OnTableChangeArg, - SortDirection, - SORT_DIRECTION, -} from '../../../../../components/ml_in_memory_table'; import { AnalyticStatsBarStats, StatsBar } from '../../../../../components/stats_bar'; import { CreateAnalyticsButton } from '../create_analytics_button'; import { getSelectedJobIdFromUrl } from '../../../../../jobs/jobs_list/components/utils'; @@ -65,8 +54,6 @@ function getItemIdToExpandedRowMap( }, {} as ItemIdToExpandedRowMap); } -const MlInMemoryTable = mlInMemoryTableFactory(); - interface Props { isManagementTable?: boolean; isMlEnabledInSpace?: boolean; @@ -80,15 +67,13 @@ export const DataFrameAnalyticsList: FC = ({ const [isInitialized, setIsInitialized] = useState(false); const [isSourceIndexModalVisible, setIsSourceIndexModalVisible] = useState(false); const [isLoading, setIsLoading] = useState(false); - const [filterActive, setFilterActive] = useState(false); - const [queryText, setQueryText] = useState(''); + const [searchQueryText, setSearchQueryText] = useState(''); const [analytics, setAnalytics] = useState([]); const [analyticsStats, setAnalyticsStats] = useState( undefined ); - const [filteredAnalytics, setFilteredAnalytics] = useState([]); const [expandedRowItemIds, setExpandedRowItemIds] = useState([]); const [errorMessage, setErrorMessage] = useState(undefined); @@ -98,9 +83,8 @@ export const DataFrameAnalyticsList: FC = ({ const [pageSize, setPageSize] = useState(10); const [sortField, setSortField] = useState(DataFrameAnalyticsListColumn.id); - const [sortDirection, setSortDirection] = useState(SORT_DIRECTION.ASC); + const [sortDirection, setSortDirection] = useState('asc'); - const [jobIdSelected, setJobIdSelected] = useState(false); const disabled = !checkPermission('canCreateDataFrameAnalytics') || !checkPermission('canStartStopDataFrameAnalytics'); @@ -114,18 +98,17 @@ export const DataFrameAnalyticsList: FC = ({ ); // Query text/job_id based on url but only after getAnalytics is done first - // jobIdSelected makes sure the query is only run once since analytics is being refreshed constantly - const selectedId = getSelectedJobIdFromUrl(window.location.href); + // selectedJobIdFromUrlInitialized makes sure the query is only run once since analytics is being refreshed constantly + const [selectedJobIdFromUrlInitialized, setSelectedJobIdFromUrlInitialized] = useState(false); useEffect(() => { - if (jobIdSelected === false && analytics.length > 0) { - if (selectedId !== undefined) { - setJobIdSelected(true); - setQueryText(selectedId); - const selectedIdQuery: Query = EuiSearchBar.Query.parse(selectedId); - onQueryChange({ query: selectedIdQuery, error: undefined }); + if (selectedJobIdFromUrlInitialized === false && analytics.length > 0) { + const selectedJobIdFromUrl = getSelectedJobIdFromUrl(window.location.href); + if (selectedJobIdFromUrl !== undefined) { + setSelectedJobIdFromUrlInitialized(true); + setSearchQueryText(selectedJobIdFromUrl); } } - }, [jobIdSelected, analytics]); + }, [selectedJobIdFromUrlInitialized, analytics]); // Subscribe to the refresh observable to trigger reloading the analytics list. useRefreshAnalyticsList({ @@ -133,94 +116,6 @@ export const DataFrameAnalyticsList: FC = ({ onRefresh: () => getAnalytics(true), }); - const onQueryChange = ({ query, error }: { query: Query; error: any }) => { - if (error) { - setSearchError(error.message); - } else { - let clauses: Clause[] = []; - if (query && query.ast !== undefined && query.ast.clauses !== undefined) { - clauses = query.ast.clauses; - } - if (clauses.length > 0) { - setQueryText(query.text); - setFilterActive(true); - filterAnalytics(clauses as Array); - } else { - setFilterActive(false); - } - setSearchError(undefined); - } - }; - - const filterAnalytics = (clauses: Array) => { - setIsLoading(true); - // keep count of the number of matches we make as we're looping over the clauses - // we only want to return analytics which match all clauses, i.e. each search term is ANDed - // { analytics-one: { analytics: { id: analytics-one, config: {}, state: {}, ... }, count: 0 }, analytics-two: {...} } - const matches: Record = analytics.reduce((p: Record, c) => { - p[c.id] = { - analytics: c, - count: 0, - }; - return p; - }, {}); - - clauses.forEach((c) => { - // the search term could be negated with a minus, e.g. -bananas - const bool = c.match === 'must'; - let ts: DataFrameAnalyticsListRow[]; - - if (c.type === 'term') { - // filter term based clauses, e.g. bananas - // match on id and description - // if the term has been negated, AND the matches - if (bool === true) { - ts = analytics.filter( - (d) => stringMatch(d.id, c.value) === bool // || - // stringMatch(d.config.description, c.value) === bool - ); - } else { - ts = analytics.filter( - (d) => stringMatch(d.id, c.value) === bool // && - // stringMatch(d.config.description, c.value) === bool - ); - } - } else { - // filter other clauses, i.e. the mode and status filters - if (Array.isArray(c.value)) { - if (c.field === 'job_type') { - ts = analytics.filter((d) => - (c.value as string).includes(getAnalysisType(d.config.analysis)) - ); - } else { - // the status value is an array of string(s) e.g. ['failed', 'stopped'] - ts = analytics.filter((d) => (c.value as string).includes(d.stats.state)); - } - } else { - ts = analytics.filter((d) => d.mode === c.value); - } - } - - ts.forEach((t) => matches[t.id].count++); - }); - - // loop through the matches and return only analytics which have match all the clauses - const filtered = Object.values(matches) - .filter((m) => (m && m.count) >= clauses.length) - .map((m) => m.analytics); - - let pageStart = pageIndex * pageSize; - if (pageStart >= filtered.length && filtered.length !== 0) { - // if the page start is larger than the number of items due to - // filters being applied, calculate a new page start - pageStart = Math.floor((filtered.length - 1) / pageSize) * pageSize; - setPageIndex(pageStart / pageSize); - } - - setFilteredAnalytics(filtered); - setIsLoading(false); - }; - const { columns, modals } = useColumns( expandedRowItemIds, setExpandedRowItemIds, @@ -231,30 +126,26 @@ export const DataFrameAnalyticsList: FC = ({ // Before the analytics have been loaded for the first time, display the loading indicator only. // Otherwise a user would see 'No data frame analytics found' during the initial loading. if (!isInitialized) { - return ; + return null; } if (typeof errorMessage !== 'undefined') { return ( - <> - - - {JSON.stringify(errorMessage)} - - > + + {JSON.stringify(errorMessage)} + ); } if (analytics.length === 0) { return ( <> - @@ -304,9 +195,20 @@ export const DataFrameAnalyticsList: FC = ({ hidePerPageOptions: false, }; - const search = { - query: queryText, - onChange: onQueryChange, + const handleSearchOnChange: EuiSearchBarProps['onChange'] = (search) => { + if (search.error !== null) { + setSearchError(search.error.message); + return false; + } + + setSearchError(undefined); + setSearchQueryText(search.queryText); + return true; + }; + + const search: EuiSearchBarProps = { + query: searchQueryText, + onChange: handleSearchOnChange, box: { incremental: true, }, @@ -326,7 +228,7 @@ export const DataFrameAnalyticsList: FC = ({ }, { type: 'field_value_selection', - field: 'state.state', + field: 'state', name: i18n.translate('xpack.ml.dataframe.analyticsList.statusFilter', { defaultMessage: 'Status', }), @@ -340,10 +242,10 @@ export const DataFrameAnalyticsList: FC = ({ ], }; - const onTableChange = ({ + const onTableChange: EuiInMemoryTable['onTableChange'] = ({ page = { index: 0, size: 10 }, - sort = { field: DataFrameAnalyticsListColumn.id, direction: SORT_DIRECTION.ASC }, - }: OnTableChangeArg) => { + sort = { field: DataFrameAnalyticsListColumn.id, direction: 'asc' }, + }) => { const { index, size } = page; setPageIndex(index); setPageSize(size); @@ -379,7 +281,7 @@ export const DataFrameAnalyticsList: FC = ({ - = ({ hasActions={false} isExpandable={true} isSelectable={false} - items={filterActive ? filteredAnalytics : analytics} + items={analytics} itemId={DataFrameAnalyticsListColumn.id} itemIdToExpandedRowMap={itemIdToExpandedRowMap} + loading={isLoading} onTableChange={onTableChange} pagination={pagination} sorting={sorting} diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/common.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/common.ts index 5998c62eeacea..e2d9ecccf0626 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/common.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/common.ts @@ -9,7 +9,11 @@ import { Query, Ast } from '@elastic/eui'; import { DATA_FRAME_TASK_STATE } from './data_frame_task_state'; export { DATA_FRAME_TASK_STATE }; -import { DataFrameAnalyticsId, DataFrameAnalyticsConfig } from '../../../../common'; +import { + DataFrameAnalyticsId, + DataFrameAnalyticsConfig, + ANALYSIS_CONFIG_TYPE, +} from '../../../../common'; export enum DATA_FRAME_MODE { BATCH = 'batch', @@ -98,10 +102,15 @@ export function getDataFrameAnalyticsProgressPhase( } export interface DataFrameAnalyticsListRow { - id: DataFrameAnalyticsId; checkpointing: object; config: DataFrameAnalyticsConfig; + id: DataFrameAnalyticsId; + job_type: + | ANALYSIS_CONFIG_TYPE.CLASSIFICATION + | ANALYSIS_CONFIG_TYPE.OUTLIER_DETECTION + | ANALYSIS_CONFIG_TYPE.REGRESSION; mode: string; + state: DataFrameAnalyticsStats['state']; stats: DataFrameAnalyticsStats; } diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/services/analytics_service/get_analytics.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/services/analytics_service/get_analytics.ts index 964e8e4062b38..41f3bab8113f0 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/services/analytics_service/get_analytics.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/services/analytics_service/get_analytics.ts @@ -10,7 +10,11 @@ import { GetDataFrameAnalyticsStatsResponseError, GetDataFrameAnalyticsStatsResponseOk, } from '../../../../../services/ml_api_service/data_frame_analytics'; -import { REFRESH_ANALYTICS_LIST_STATE, refreshAnalyticsList$ } from '../../../../common'; +import { + ANALYSIS_CONFIG_TYPE, + REFRESH_ANALYTICS_LIST_STATE, + refreshAnalyticsList$, +} from '../../../../common'; import { DATA_FRAME_MODE, @@ -136,10 +140,12 @@ export const getAnalyticsFactory = ( // Table with expandable rows requires `id` on the outer most level reducedtableRows.push({ + checkpointing: {}, config, id: config.id, - checkpointing: {}, + job_type: Object.keys(config.analysis)[0] as ANALYSIS_CONFIG_TYPE, mode: DATA_FRAME_MODE.BATCH, + state: stats.state, stats, }); return reducedtableRows; diff --git a/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/_analytics_table.scss b/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/_analytics_table.scss index 1151599a526e4..f134c467e11b2 100644 --- a/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/_analytics_table.scss +++ b/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/_analytics_table.scss @@ -19,10 +19,6 @@ } } -.mlAnalyticsProgressBar { - margin-bottom: $euiSizeM; -} - .mlTaskStateBadge { max-width: 100px; } diff --git a/x-pack/plugins/ml/public/application/overview/components/analytics_panel/table.tsx b/x-pack/plugins/ml/public/application/overview/components/analytics_panel/table.tsx index 1eeff6287867d..b28729dcf157f 100644 --- a/x-pack/plugins/ml/public/application/overview/components/analytics_panel/table.tsx +++ b/x-pack/plugins/ml/public/application/overview/components/analytics_panel/table.tsx @@ -5,15 +5,15 @@ */ import React, { FC, useState } from 'react'; -import { EuiBadge } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; import { - mlInMemoryTableFactory, - SortDirection, - SORT_DIRECTION, - OnTableChangeArg, - ColumnType, -} from '../../../components/ml_in_memory_table'; + Direction, + EuiBadge, + EuiInMemoryTable, + EuiTableActionsColumnType, + EuiTableComputedColumnType, + EuiTableFieldDataColumnType, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { getAnalysisType } from '../../../data_frame_analytics/common/analytics'; import { DataFrameAnalyticsListColumn, @@ -26,7 +26,14 @@ import { import { getViewAction } from '../../../data_frame_analytics/pages/analytics_management/components/action_view'; import { formatHumanReadableDateTimeSeconds } from '../../../util/date_utils'; -const MlInMemoryTable = mlInMemoryTableFactory(); +type DataFrameAnalyticsTableColumns = [ + EuiTableFieldDataColumnType, + EuiTableComputedColumnType, + EuiTableComputedColumnType, + EuiTableComputedColumnType, + EuiTableFieldDataColumnType, + EuiTableActionsColumnType +]; interface Props { items: DataFrameAnalyticsListRow[]; @@ -36,10 +43,10 @@ export const AnalyticsTable: FC = ({ items }) => { const [pageSize, setPageSize] = useState(10); const [sortField, setSortField] = useState(DataFrameAnalyticsListColumn.id); - const [sortDirection, setSortDirection] = useState(SORT_DIRECTION.ASC); + const [sortDirection, setSortDirection] = useState('asc'); // id, type, status, progress, created time, view icon - const columns: Array> = [ + const columns: DataFrameAnalyticsTableColumns = [ { field: DataFrameAnalyticsListColumn.id, name: i18n.translate('xpack.ml.overview.analyticsList.id', { defaultMessage: 'ID' }), @@ -87,10 +94,10 @@ export const AnalyticsTable: FC = ({ items }) => { }, ]; - const onTableChange = ({ + const onTableChange: EuiInMemoryTable['onTableChange'] = ({ page = { index: 0, size: 10 }, - sort = { field: DataFrameAnalyticsListColumn.id, direction: SORT_DIRECTION.ASC }, - }: OnTableChangeArg) => { + sort = { field: DataFrameAnalyticsListColumn.id, direction: 'asc' }, + }) => { const { index, size } = page; setPageIndex(index); setPageSize(size); @@ -116,7 +123,7 @@ export const AnalyticsTable: FC = ({ items }) => { }; return ( - (); - // Used to pass on attribute names to table columns export enum AnomalyDetectionListColumns { id = 'id', @@ -46,6 +41,15 @@ export enum AnomalyDetectionListColumns { jobsInGroup = 'jobs_in_group', } +type AnomalyDetectionTableColumns = [ + EuiTableFieldDataColumnType, + EuiTableFieldDataColumnType, + EuiTableFieldDataColumnType, + EuiTableFieldDataColumnType, + EuiTableFieldDataColumnType, + EuiTableComputedColumnType +]; + interface Props { items: GroupsDictionary; statsBarData: JobStatsBarStats; @@ -58,10 +62,10 @@ export const AnomalyDetectionTable: FC = ({ items, jobsList, statsBarData const [pageSize, setPageSize] = useState(10); const [sortField, setSortField] = useState(AnomalyDetectionListColumns.id); - const [sortDirection, setSortDirection] = useState(SORT_DIRECTION.ASC); + const [sortDirection, setSortDirection] = useState('asc'); // columns: group, max anomaly, jobs in group, latest timestamp, docs processed, action to explorer - const columns: Array> = [ + const columns: AnomalyDetectionTableColumns = [ { field: AnomalyDetectionListColumns.id, name: i18n.translate('xpack.ml.overview.anomalyDetection.tableId', { @@ -169,17 +173,17 @@ export const AnomalyDetectionTable: FC = ({ items, jobsList, statsBarData }, ]; - const onTableChange = ({ + const onTableChange: EuiInMemoryTable['onTableChange'] = ({ page = { index: 0, size: 10 }, - sort = { field: AnomalyDetectionListColumns.id, direction: SORT_DIRECTION.ASC }, - }: OnTableChangeArg) => { + sort = { field: AnomalyDetectionListColumns.id, 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 pagination = { @@ -214,7 +218,7 @@ export const AnomalyDetectionTable: FC = ({ items, jobsList, statsBarData -
{JSON.stringify(errorMessage)}