diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index bea2f4e74297e..439adbae83fd6 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -35,6 +35,7 @@ /x-pack/test/functional/apps/machine_learning/ @elastic/ml-ui /x-pack/test/functional/services/machine_learning/ @elastic/ml-ui /x-pack/test/functional/services/ml.ts @elastic/ml-ui +/x-pack/legacy/plugins/transform/ @elastic/ml-ui # Operations /renovate.json5 @elastic/kibana-operations diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index db8e618ff1134..1eb5bd752baee 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -36,6 +36,7 @@ "xpack.server": "legacy/server", "xpack.snapshotRestore": "legacy/plugins/snapshot_restore", "xpack.spaces": "legacy/plugins/spaces", + "xpack.transform": "legacy/plugins/transform", "xpack.upgradeAssistant": "legacy/plugins/upgrade_assistant", "xpack.uptime": "legacy/plugins/uptime", "xpack.watcher": "legacy/plugins/watcher" diff --git a/x-pack/index.js b/x-pack/index.js index 10f969a21b68b..f2e602ec05586 100644 --- a/x-pack/index.js +++ b/x-pack/index.js @@ -41,6 +41,7 @@ import { fileUpload } from './legacy/plugins/file_upload'; import { telemetry } from './legacy/plugins/telemetry'; import { encryptedSavedObjects } from './legacy/plugins/encrypted_saved_objects'; import { snapshotRestore } from './legacy/plugins/snapshot_restore'; +import { transform } from './legacy/plugins/transform'; import { actions } from './legacy/plugins/actions'; import { alerting } from './legacy/plugins/alerting'; import { lens } from './legacy/plugins/lens'; @@ -75,6 +76,7 @@ module.exports = function (kibana) { infra(kibana), taskManager(kibana), rollup(kibana), + transform(kibana), siem(kibana), remoteClusters(kibana), crossClusterReplication(kibana), diff --git a/x-pack/legacy/plugins/ml/common/types/audit_message.ts b/x-pack/legacy/plugins/ml/common/types/audit_message.ts index c34abd6690762..58e77495b9093 100644 --- a/x-pack/legacy/plugins/ml/common/types/audit_message.ts +++ b/x-pack/legacy/plugins/ml/common/types/audit_message.ts @@ -16,10 +16,6 @@ export interface AnalyticsMessage extends AuditMessageBase { analytics_id: string; } -export interface TransformMessage extends AuditMessageBase { - transform_id: string; -} - export interface JobMessage extends AuditMessageBase { job_id: string; } diff --git a/x-pack/legacy/plugins/ml/common/types/privileges.ts b/x-pack/legacy/plugins/ml/common/types/privileges.ts index 83890012c4e2b..d9089c751b81b 100644 --- a/x-pack/legacy/plugins/ml/common/types/privileges.ts +++ b/x-pack/legacy/plugins/ml/common/types/privileges.ts @@ -28,12 +28,6 @@ export interface Privileges { canDeleteFilter: boolean; // File Data Visualizer canFindFileStructure: boolean; - // Data Frame Transforms - canGetDataFrame: boolean; - canDeleteDataFrame: boolean; - canPreviewDataFrame: boolean; - canCreateDataFrame: boolean; - canStartStopDataFrame: boolean; // Data Frame Analytics canGetDataFrameAnalytics: boolean; canDeleteDataFrameAnalytics: boolean; @@ -65,12 +59,6 @@ export function getDefaultPrivileges(): Privileges { canDeleteFilter: false, // File Data Visualizer canFindFileStructure: false, - // Data Frame Transforms - canGetDataFrame: false, - canDeleteDataFrame: false, - canPreviewDataFrame: false, - canCreateDataFrame: false, - canStartStopDataFrame: false, // Data Frame Analytics canGetDataFrameAnalytics: false, canDeleteDataFrameAnalytics: false, diff --git a/x-pack/legacy/plugins/ml/common/util/job_utils.js b/x-pack/legacy/plugins/ml/common/util/job_utils.js index dae60b12b0d59..990dba6e31f15 100644 --- a/x-pack/legacy/plugins/ml/common/util/job_utils.js +++ b/x-pack/legacy/plugins/ml/common/util/job_utils.js @@ -224,7 +224,7 @@ export function mlFunctionToESAggregation(functionName) { // Job name must contain lowercase alphanumeric (a-z and 0-9), hyphens or underscores; // it must also start and end with an alphanumeric character' export function isJobIdValid(jobId) { - return (jobId.match(/^[a-z0-9\-\_]+$/g) && !jobId.match(/^([_-].*)?(.*[_-])?$/g)) ? true : false; + return /^[a-z0-9\-\_]+$/g.test(jobId) && !/^([_-].*)?(.*[_-])?$/g.test(jobId); } // To get median data for jobs and charts we need to use Elasticsearch's diff --git a/x-pack/legacy/plugins/ml/public/app.js b/x-pack/legacy/plugins/ml/public/app.js index 6f96a756f0b67..eb7c9d944ac93 100644 --- a/x-pack/legacy/plugins/ml/public/app.js +++ b/x-pack/legacy/plugins/ml/public/app.js @@ -20,7 +20,6 @@ import 'plugins/ml/jobs'; import 'plugins/ml/overview'; import 'plugins/ml/services/calendar_service'; import 'plugins/ml/components/messagebar'; -import 'plugins/ml/data_frame'; import 'plugins/ml/data_frame_analytics'; import 'plugins/ml/datavisualizer'; import 'plugins/ml/explorer'; diff --git a/x-pack/legacy/plugins/ml/public/components/job_message_icon/job_message_icon.tsx b/x-pack/legacy/plugins/ml/public/components/job_message_icon/job_message_icon.tsx index 0ea1678f6a1e3..59e71974d0aed 100644 --- a/x-pack/legacy/plugins/ml/public/components/job_message_icon/job_message_icon.tsx +++ b/x-pack/legacy/plugins/ml/public/components/job_message_icon/job_message_icon.tsx @@ -17,28 +17,28 @@ interface Props { const [INFO, WARNING, ERROR] = ['info', 'warning', 'error']; export const JobIcon: FC = ({ message, showTooltip = false }) => { - if (message !== undefined) { - let color = 'primary'; - const icon = 'alert'; - - if (message.level === INFO) { - color = 'primary'; - } else if (message.level === WARNING) { - color = 'warning'; - } else if (message.level === ERROR) { - color = 'danger'; - } - - if (showTooltip) { - return ( - - - - ); - } else { - return ; - } - } else { + if (message === undefined) { return ; } + + let color = 'primary'; + const icon = 'alert'; + + if (message.level === INFO) { + color = 'primary'; + } else if (message.level === WARNING) { + color = 'warning'; + } else if (message.level === ERROR) { + color = 'danger'; + } + + if (showTooltip) { + return ( + + + + ); + } else { + return ; + } }; diff --git a/x-pack/legacy/plugins/ml/public/components/navigation_menu/main_tabs.tsx b/x-pack/legacy/plugins/ml/public/components/navigation_menu/main_tabs.tsx index 0ba38abb454e2..cff174eb5627f 100644 --- a/x-pack/legacy/plugins/ml/public/components/navigation_menu/main_tabs.tsx +++ b/x-pack/legacy/plugins/ml/public/components/navigation_menu/main_tabs.tsx @@ -37,13 +37,6 @@ function getTabs(disableLinks: boolean): Tab[] { }), disabled: disableLinks, }, - { - id: 'data_frames', - name: i18n.translate('xpack.ml.navMenu.dataFrameTabLinkText', { - defaultMessage: 'Transforms', - }), - disabled: false, - }, { id: 'data_frame_analytics', name: i18n.translate('xpack.ml.navMenu.dataFrameAnalyticsTabLinkText', { @@ -68,7 +61,6 @@ interface TabData { const TAB_DATA: Record = { overview: { testSubject: 'mlMainTab overview', pathId: 'overview' }, anomaly_detection: { testSubject: 'mlMainTab anomalyDetection', pathId: 'jobs' }, - data_frames: { testSubject: 'mlMainTab dataFrames' }, data_frame_analytics: { testSubject: 'mlMainTab dataFrameAnalytics' }, datavisualizer: { testSubject: 'mlMainTab dataVisualizer' }, }; diff --git a/x-pack/legacy/plugins/ml/public/components/navigation_menu/navigation_menu.tsx b/x-pack/legacy/plugins/ml/public/components/navigation_menu/navigation_menu.tsx index 5961bd5e71873..3a266105ada40 100644 --- a/x-pack/legacy/plugins/ml/public/components/navigation_menu/navigation_menu.tsx +++ b/x-pack/legacy/plugins/ml/public/components/navigation_menu/navigation_menu.tsx @@ -21,7 +21,6 @@ const tabSupport: TabSupport = { overview: null, jobs: 'anomaly_detection', settings: 'anomaly_detection', - data_frames: null, data_frame_analytics: null, datavisualizer: null, filedatavisualizer: null, diff --git a/x-pack/legacy/plugins/ml/public/components/navigation_menu/tabs.tsx b/x-pack/legacy/plugins/ml/public/components/navigation_menu/tabs.tsx index 89ada7453c7c5..7014164ad9756 100644 --- a/x-pack/legacy/plugins/ml/public/components/navigation_menu/tabs.tsx +++ b/x-pack/legacy/plugins/ml/public/components/navigation_menu/tabs.tsx @@ -21,7 +21,6 @@ export function getTabs(tabId: TabId, disableLinks: boolean): Tab[] { const TAB_MAP: Partial> = { overview: [], datavisualizer: [], - data_frames: [], data_frame_analytics: [], anomaly_detection: [ { diff --git a/x-pack/legacy/plugins/ml/public/components/stats_bar/_stat.scss b/x-pack/legacy/plugins/ml/public/components/stats_bar/_stat.scss index d05c1f7195587..ea570c24f0d7b 100644 --- a/x-pack/legacy/plugins/ml/public/components/stats_bar/_stat.scss +++ b/x-pack/legacy/plugins/ml/public/components/stats_bar/_stat.scss @@ -1,7 +1,3 @@ .stat { margin-right: $euiSizeS; - - .stat-value { - font-weight: bold - } } diff --git a/x-pack/legacy/plugins/ml/public/components/stats_bar/index.ts b/x-pack/legacy/plugins/ml/public/components/stats_bar/index.ts index 003378cfc14a5..597975d0b150b 100644 --- a/x-pack/legacy/plugins/ml/public/components/stats_bar/index.ts +++ b/x-pack/legacy/plugins/ml/public/components/stats_bar/index.ts @@ -4,9 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { - StatsBar, - TransformStatsBarStats, - AnalyticStatsBarStats, - JobStatsBarStats, -} from './stats_bar'; +export { StatsBar, AnalyticStatsBarStats, JobStatsBarStats } from './stats_bar'; diff --git a/x-pack/legacy/plugins/ml/public/components/stats_bar/stat.tsx b/x-pack/legacy/plugins/ml/public/components/stats_bar/stat.tsx index 55fa902fe41ed..9de287d54a720 100644 --- a/x-pack/legacy/plugins/ml/public/components/stats_bar/stat.tsx +++ b/x-pack/legacy/plugins/ml/public/components/stats_bar/stat.tsx @@ -18,7 +18,7 @@ interface StatProps { export const Stat: FC = ({ stat }) => { return ( - {stat.label}: {stat.value} + {stat.label}: {stat.value} ); }; diff --git a/x-pack/legacy/plugins/ml/public/components/stats_bar/stats_bar.tsx b/x-pack/legacy/plugins/ml/public/components/stats_bar/stats_bar.tsx index 0ebc4647e030f..df87fb0b05c37 100644 --- a/x-pack/legacy/plugins/ml/public/components/stats_bar/stats_bar.tsx +++ b/x-pack/legacy/plugins/ml/public/components/stats_bar/stats_bar.tsx @@ -18,18 +18,12 @@ export interface JobStatsBarStats extends Stats { activeDatafeeds: StatsBarStat; } -export interface TransformStatsBarStats extends Stats { - batch: StatsBarStat; - continuous: StatsBarStat; - started: StatsBarStat; -} - export interface AnalyticStatsBarStats extends Stats { started: StatsBarStat; stopped: StatsBarStat; } -type StatsBarStats = TransformStatsBarStats | JobStatsBarStats | AnalyticStatsBarStats; +type StatsBarStats = JobStatsBarStats | AnalyticStatsBarStats; type StatsKey = keyof StatsBarStats; interface StatsBarProps { diff --git a/x-pack/legacy/plugins/ml/public/data_frame/_index.scss b/x-pack/legacy/plugins/ml/public/data_frame/_index.scss deleted file mode 100644 index 5b7b8be9128cd..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/_index.scss +++ /dev/null @@ -1,3 +0,0 @@ -@import 'pages/data_frame_new_pivot/components/aggregation_list/index'; -@import 'pages/data_frame_new_pivot/components/group_by_list/index'; -@import 'pages/transform_management/components/transform_list/index'; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/breadcrumbs.ts b/x-pack/legacy/plugins/ml/public/data_frame/breadcrumbs.ts deleted file mode 100644 index c5f7af492ee95..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/breadcrumbs.ts +++ /dev/null @@ -1,61 +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 { i18n } from '@kbn/i18n'; - -// @ts-ignore -import { ML_BREADCRUMB } from '../breadcrumbs'; - -export function getJobManagementBreadcrumbs() { - // Whilst top level nav menu with tabs remains, - // use root ML breadcrumb. - return [ML_BREADCRUMB]; -} - -export function getDataFrameBreadcrumbs() { - return [ - ML_BREADCRUMB, - { - text: i18n.translate('xpack.ml.dataFrameBreadcrumbs.dataFrameLabel', { - defaultMessage: 'Transforms', - }), - href: '', - }, - ]; -} - -const DATA_FRAME_HOME = { - text: i18n.translate('xpack.ml.dataFrameBreadcrumbs.dataFrameLabel', { - defaultMessage: 'Transforms', - }), - href: '#/data_frames', -}; - -export function getDataFrameCreateBreadcrumbs() { - return [ - ML_BREADCRUMB, - DATA_FRAME_HOME, - { - text: i18n.translate('xpack.ml.dataFrameBreadcrumbs.dataFrameCreateLabel', { - defaultMessage: 'Create transform', - }), - href: '', - }, - ]; -} - -export function getDataFrameIndexOrSearchBreadcrumbs() { - return [ - ML_BREADCRUMB, - DATA_FRAME_HOME, - { - text: i18n.translate('xpack.ml.dataFrameBreadcrumbs.selectIndexOrSearchLabel', { - defaultMessage: 'Select index or search', - }), - href: '', - }, - ]; -} diff --git a/x-pack/legacy/plugins/ml/public/data_frame/index.ts b/x-pack/legacy/plugins/ml/public/data_frame/index.ts deleted file mode 100644 index feba0b412b8ed..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/index.ts +++ /dev/null @@ -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. - */ - -import './pages/access_denied/directive'; -import './pages/access_denied/route'; -import './pages/transform_management/directive'; -import './pages/transform_management/route'; -import './pages/data_frame_new_pivot/directive'; -import './pages/data_frame_new_pivot/route'; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/access_denied/directive.tsx b/x-pack/legacy/plugins/ml/public/data_frame/pages/access_denied/directive.tsx deleted file mode 100644 index e16d5736db6ec..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/access_denied/directive.tsx +++ /dev/null @@ -1,50 +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 React from 'react'; -import ReactDOM from 'react-dom'; - -// @ts-ignore -import { uiModules } from 'ui/modules'; -import uiChrome from 'ui/chrome'; - -const module = uiModules.get('apps/ml', ['react']); - -import { I18nContext } from 'ui/i18n'; -import { InjectorService } from '../../../../common/types/angular'; - -import { Page } from './page'; - -module.directive('mlDataFrameAccessDenied', ($injector: InjectorService) => { - return { - scope: {}, - restrict: 'E', - link: (scope: ng.IScope, element: ng.IAugmentedJQuery) => { - const kbnBaseUrl = $injector.get('kbnBaseUrl'); - const kbnUrl = $injector.get('kbnUrl'); - - const goToKibana = () => { - window.location.href = uiChrome.getBasePath() + kbnBaseUrl; - }; - - const retry = () => { - kbnUrl.redirect('/data_frames'); - }; - - ReactDOM.render( - - - , - element[0] - ); - - element.on('$destroy', () => { - ReactDOM.unmountComponentAtNode(element[0]); - scope.$destroy(); - }); - }, - }; -}); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/access_denied/page.test.tsx b/x-pack/legacy/plugins/ml/public/data_frame/pages/access_denied/page.test.tsx deleted file mode 100644 index 378600ac44e1a..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/access_denied/page.test.tsx +++ /dev/null @@ -1,42 +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 React from 'react'; - -import { render, fireEvent, cleanup } from 'react-testing-library'; - -import { I18nProvider } from '@kbn/i18n/react'; - -import { Page } from './page'; - -jest.mock('../../../components/navigation_menu/navigation_menu', () => ({ - NavigationMenu: () =>
, -})); - -afterEach(cleanup); - -describe('Data Frame: Access denied ', () => { - test('Minimal initialization', () => { - const props = { - goToKibana: jest.fn(), - retry: jest.fn(), - }; - - const tree = ( - - - - ); - - const { getByText } = render(tree); - - fireEvent.click(getByText(/Back to Kibana home/i)); - fireEvent.click(getByText(/Retry/i)); - - expect(props.goToKibana).toHaveBeenCalledTimes(1); - expect(props.retry).toHaveBeenCalledTimes(1); - }); -}); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/access_denied/page.tsx b/x-pack/legacy/plugins/ml/public/data_frame/pages/access_denied/page.tsx deleted file mode 100644 index 0966bb184afeb..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/access_denied/page.tsx +++ /dev/null @@ -1,98 +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 React, { FC, Fragment } from 'react'; - -import { FormattedMessage } from '@kbn/i18n/react'; -import { i18n } from '@kbn/i18n'; - -import { - EuiButton, - EuiCallOut, - EuiFlexGroup, - EuiFlexItem, - EuiPage, - EuiPageBody, - EuiPageContentBody, - EuiPageContentHeader, - EuiPageContentHeaderSection, - EuiSpacer, - EuiText, - EuiTitle, -} from '@elastic/eui'; - -import { NavigationMenu } from '../../../components/navigation_menu/navigation_menu'; - -interface PageProps { - goToKibana: () => void; - retry: () => void; -} -export const Page: FC = ({ goToKibana, retry }) => ( - - - - - - - -

- -

-
-
-
- - - - -

- kibana_user, - dataFrameUserParam: ( - data_frame_transforms_user - ), - br:
, - }} - /> -

-
-
- - - - - - - - - - - - - -
-
-
-
-); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/access_denied/route.ts b/x-pack/legacy/plugins/ml/public/data_frame/pages/access_denied/route.ts deleted file mode 100644 index 50cf8d05aa434..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/access_denied/route.ts +++ /dev/null @@ -1,17 +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 uiRoutes from 'ui/routes'; - -// @ts-ignore -import { getDataFrameBreadcrumbs } from '../../breadcrumbs'; - -const template = ``; - -uiRoutes.when('/data_frames/access-denied', { - template, - k7Breadcrumbs: getDataFrameBreadcrumbs, -}); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_list/_aggregation_label_form.scss b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_list/_aggregation_label_form.scss deleted file mode 100644 index 712a67373c034..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_list/_aggregation_label_form.scss +++ /dev/null @@ -1,7 +0,0 @@ -.mlAggregationLabel--button { - width: $euiSizeL; -} - -.mlAggregationLabel--text { - min-width: 0; -} diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/_group_by_label_form.scss b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/_group_by_label_form.scss deleted file mode 100644 index 7bd29fa2e7fa3..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/_group_by_label_form.scss +++ /dev/null @@ -1,11 +0,0 @@ -.mlGroupByLabel--button { - width: $euiSizeL; -} - -.mlGroupByLabel--text { - min-width: 0; -} - -.mlGroupByLabel--interval { - max-width: 25%; -} diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/__snapshots__/source_index_preview.test.tsx.snap b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/__snapshots__/source_index_preview.test.tsx.snap deleted file mode 100644 index 9179d9c8bcf61..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/__snapshots__/source_index_preview.test.tsx.snap +++ /dev/null @@ -1,59 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Data Frame: Minimal initialization 1`] = ` -
- - - -
-`; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_create/__snapshots__/step_create_form.test.tsx.snap b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_create/__snapshots__/step_create_form.test.tsx.snap deleted file mode 100644 index 26844efb711e5..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_create/__snapshots__/step_create_form.test.tsx.snap +++ /dev/null @@ -1,62 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Data Frame: Minimal initialization 1`] = ` -
- - - -
-`; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/__snapshots__/pivot_preview.test.tsx.snap b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/__snapshots__/pivot_preview.test.tsx.snap deleted file mode 100644 index 192d9d2cff625..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/__snapshots__/pivot_preview.test.tsx.snap +++ /dev/null @@ -1,79 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Data Frame: Minimal initialization 1`] = ` -
- - - -
-`; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/__snapshots__/step_define_form.test.tsx.snap b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/__snapshots__/step_define_form.test.tsx.snap deleted file mode 100644 index 033eea8cf290e..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/__snapshots__/step_define_form.test.tsx.snap +++ /dev/null @@ -1,52 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Data Frame: Minimal initialization 1`] = ` -
- - - -
-`; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/__snapshots__/step_define_summary.test.tsx.snap b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/__snapshots__/step_define_summary.test.tsx.snap deleted file mode 100644 index c3b75584f0a51..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/__snapshots__/step_define_summary.test.tsx.snap +++ /dev/null @@ -1,77 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Data Frame: Minimal initialization 1`] = ` -
- - - -
-`; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/step_define_summary.tsx b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/step_define_summary.tsx deleted file mode 100644 index 21250cb64ec70..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/step_define_summary.tsx +++ /dev/null @@ -1,134 +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 React, { Fragment, SFC } from 'react'; - -import { i18n } from '@kbn/i18n'; - -import { - EuiCodeBlock, - EuiFlexGroup, - EuiFlexItem, - EuiForm, - EuiFormRow, - EuiText, -} from '@elastic/eui'; - -import { useKibanaContext } from '../../../../../contexts/kibana'; - -import { AggListSummary } from '../aggregation_list'; -import { GroupByListSummary } from '../group_by_list'; -import { PivotPreview } from './pivot_preview'; - -import { getPivotQuery } from '../../../../common'; -import { StepDefineExposedState } from './step_define_form'; - -const defaultSearch = '*'; -const emptySearch = ''; - -export const StepDefineSummary: SFC = ({ - searchString, - searchQuery, - groupByList, - aggList, -}) => { - const kibanaContext = useKibanaContext(); - - const pivotQuery = getPivotQuery(searchQuery); - let useCodeBlock = false; - let displaySearch; - // searchString set to empty once source config editor used - display query instead - if (searchString === emptySearch) { - displaySearch = JSON.stringify(searchQuery, null, 2); - useCodeBlock = true; - } else if (searchString === defaultSearch) { - displaySearch = emptySearch; - } else { - displaySearch = searchString; - } - - return ( - - - - {kibanaContext.currentSavedSearch.id === undefined && typeof searchString === 'string' && ( - - - {kibanaContext.currentIndexPattern.title} - - {useCodeBlock === false && displaySearch !== emptySearch && ( - - {displaySearch} - - )} - {useCodeBlock === true && displaySearch !== emptySearch && ( - - - {displaySearch} - - - )} - - )} - - {kibanaContext.currentSavedSearch.id !== undefined && ( - - {kibanaContext.currentSavedSearch.title} - - )} - - - - - - - - - - - - - - - - - - ); -}; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/directive.tsx b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/directive.tsx deleted file mode 100644 index 75c9bf48e0642..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/directive.tsx +++ /dev/null @@ -1,65 +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 React from 'react'; -import ReactDOM from 'react-dom'; - -// @ts-ignore -import { uiModules } from 'ui/modules'; -const module = uiModules.get('apps/ml', ['react']); - -import { IndexPatterns } from 'ui/index_patterns'; -import { I18nContext } from 'ui/i18n'; -import { IPrivate } from 'ui/private'; -import { timefilter } from 'ui/timefilter'; - -import { InjectorService } from '../../../../common/types/angular'; - -import { SearchItemsProvider } from '../../../jobs/new_job/utils/new_job_utils'; -import { KibanaConfigTypeFix, KibanaContext } from '../../../contexts/kibana'; -import { Page } from './page'; - -module.directive('mlNewDataFrame', ($injector: InjectorService) => { - return { - scope: {}, - restrict: 'E', - link: (scope: ng.IScope, element: ng.IAugmentedJQuery) => { - const indexPatterns = $injector.get('indexPatterns'); - const kbnBaseUrl = $injector.get('kbnBaseUrl'); - const kibanaConfig = $injector.get('config'); - const Private = $injector.get('Private'); - - timefilter.disableTimeRangeSelector(); - timefilter.disableAutoRefreshSelector(); - - const createSearchItems = Private(SearchItemsProvider); - const { indexPattern, savedSearch, combinedQuery } = createSearchItems(); - - const kibanaContext = { - combinedQuery, - currentIndexPattern: indexPattern, - currentSavedSearch: savedSearch, - indexPatterns, - kbnBaseUrl, - kibanaConfig, - }; - - ReactDOM.render( - - - - - , - element[0] - ); - - element.on('$destroy', () => { - ReactDOM.unmountComponentAtNode(element[0]); - scope.$destroy(); - }); - }, - }; -}); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/page.tsx b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/page.tsx deleted file mode 100644 index 2aaa1fb8a6ac3..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/page.tsx +++ /dev/null @@ -1,62 +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 React, { FC, Fragment } from 'react'; - -import { FormattedMessage } from '@kbn/i18n/react'; -import { i18n } from '@kbn/i18n'; - -import { - EuiBetaBadge, - EuiPage, - EuiPageBody, - EuiPageContentBody, - EuiPageContentHeader, - EuiPageContentHeaderSection, - EuiSpacer, - EuiTitle, -} from '@elastic/eui'; - -import { NavigationMenu } from '../../../components/navigation_menu/navigation_menu'; -import { Wizard } from './components/wizard'; - -export const Page: FC = () => ( - - - - - - - -

- -   - -

-
-
-
- - - - -
-
-
-); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/route.ts b/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/route.ts deleted file mode 100644 index acb7a47ba8fcb..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/route.ts +++ /dev/null @@ -1,49 +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 uiRoutes from 'ui/routes'; - -// @ts-ignore -import { checkBasicLicense } from '../../../license/check_license'; -import { checkCreateDataFrameTransformPrivilege } from '../../../privilege/check_privilege'; -import { - loadCurrentIndexPattern, - loadCurrentSavedSearch, - loadIndexPatterns, -} from '../../../util/index_utils'; - -import { - getDataFrameCreateBreadcrumbs, - getDataFrameIndexOrSearchBreadcrumbs, -} from '../../breadcrumbs'; - -const wizardTemplate = ``; - -uiRoutes.when('/data_frames/new_transform/step/pivot?', { - template: wizardTemplate, - k7Breadcrumbs: getDataFrameCreateBreadcrumbs, - resolve: { - CheckLicense: checkBasicLicense, - privileges: checkCreateDataFrameTransformPrivilege, - indexPattern: loadCurrentIndexPattern, - savedSearch: loadCurrentSavedSearch, - }, -}); - -uiRoutes.when('/data_frames/new_transform', { - redirectTo: '/data_frames/new_transform/step/index_or_search', -}); - -uiRoutes.when('/data_frames/new_transform/step/index_or_search', { - template: '', - k7Breadcrumbs: getDataFrameIndexOrSearchBreadcrumbs, - resolve: { - CheckLicense: checkBasicLicense, - privileges: checkCreateDataFrameTransformPrivilege, - indexPatterns: loadIndexPatterns, - nextStepPath: () => '#data_frames/new_transform/step/pivot', - }, -}); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/__snapshots__/page.test.tsx.snap b/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/__snapshots__/page.test.tsx.snap deleted file mode 100644 index 370d8b9ab685e..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/__snapshots__/page.test.tsx.snap +++ /dev/null @@ -1,74 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Data Frame: Job List Minimal initialization 1`] = ` - - - - - - - - -

- - -   - - -

-
-
- - - - - - - - - - -
- - - - - - -
-
-
-`; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/create_transform_button/__snapshots__/create_transform_button.test.tsx.snap b/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/create_transform_button/__snapshots__/create_transform_button.test.tsx.snap deleted file mode 100644 index bc20f0aec255f..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/create_transform_button/__snapshots__/create_transform_button.test.tsx.snap +++ /dev/null @@ -1,24 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Data Frame: Transform List Minimal initialization 1`] = ` - - - - - -`; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/create_transform_button/create_transform_button.tsx b/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/create_transform_button/create_transform_button.tsx deleted file mode 100644 index e1b95ad95232f..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/create_transform_button/create_transform_button.tsx +++ /dev/null @@ -1,51 +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 React, { SFC } from 'react'; - -import { EuiButton, EuiToolTip } from '@elastic/eui'; - -import { FormattedMessage } from '@kbn/i18n/react'; - -import { - checkPermission, - createPermissionFailureMessage, -} from '../../../../../privilege/check_privilege'; - -import { moveToDataFrameWizard } from '../../../../common'; - -export const CreateTransformButton: SFC = () => { - const disabled = - !checkPermission('canCreateDataFrame') || - !checkPermission('canPreviewDataFrame') || - !checkPermission('canStartStopDataFrame'); - - const button = ( - - - - ); - - if (disabled) { - return ( - - {button} - - ); - } - - return button; -}; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/action_delete.test.tsx b/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/action_delete.test.tsx deleted file mode 100644 index b94a787055eb6..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/action_delete.test.tsx +++ /dev/null @@ -1,28 +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 { shallow } from 'enzyme'; -import React from 'react'; - -import { DataFrameTransformListRow } from '../../../../common'; -import { DeleteAction } from './action_delete'; - -import dataFrameTransformListRow from '../../../../common/__mocks__/data_frame_transform_list_row.json'; - -describe('Data Frame: Transform List Actions ', () => { - test('Minimal initialization', () => { - const item: DataFrameTransformListRow = dataFrameTransformListRow; - const props = { - disabled: false, - items: [item], - deleteTransform(d: DataFrameTransformListRow) {}, - }; - - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - }); -}); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/action_start.test.tsx b/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/action_start.test.tsx deleted file mode 100644 index 17bfe36366f7e..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/action_start.test.tsx +++ /dev/null @@ -1,28 +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 { shallow } from 'enzyme'; -import React from 'react'; - -import { DataFrameTransformListRow } from '../../../../common'; -import { StartAction } from './action_start'; - -import dataFrameTransformListRow from '../../../../common/__mocks__/data_frame_transform_list_row.json'; - -describe('Data Frame: Transform List Actions ', () => { - test('Minimal initialization', () => { - const item: DataFrameTransformListRow = dataFrameTransformListRow; - const props = { - disabled: false, - items: [item], - startTransform(d: DataFrameTransformListRow) {}, - }; - - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - }); -}); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/action_stop.test.tsx b/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/action_stop.test.tsx deleted file mode 100644 index b2ff630c54343..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/action_stop.test.tsx +++ /dev/null @@ -1,28 +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 { shallow } from 'enzyme'; -import React from 'react'; - -import { DataFrameTransformListRow } from '../../../../common'; -import { StopAction } from './action_stop'; - -import dataFrameTransformListRow from '../../../../common/__mocks__/data_frame_transform_list_row.json'; - -describe('Data Frame: Transform List Actions ', () => { - test('Minimal initialization', () => { - const item: DataFrameTransformListRow = dataFrameTransformListRow; - const props = { - disabled: false, - items: [item], - stopTransform(d: DataFrameTransformListRow) {}, - }; - - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - }); -}); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/directive.tsx b/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/directive.tsx deleted file mode 100644 index 749fe1dc31536..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/directive.tsx +++ /dev/null @@ -1,35 +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 React from 'react'; -import ReactDOM from 'react-dom'; - -// @ts-ignore -import { uiModules } from 'ui/modules'; -const module = uiModules.get('apps/ml', ['react']); - -import { I18nContext } from 'ui/i18n'; -import { Page } from './page'; - -module.directive('mlDataFramePage', () => { - return { - scope: {}, - restrict: 'E', - link: (scope: ng.IScope, element: ng.IAugmentedJQuery) => { - ReactDOM.render( - - - , - element[0] - ); - - element.on('$destroy', () => { - ReactDOM.unmountComponentAtNode(element[0]); - scope.$destroy(); - }); - }, - }; -}); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/route.ts b/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/route.ts deleted file mode 100644 index 6f3b4576b10ce..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/route.ts +++ /dev/null @@ -1,28 +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 uiRoutes from 'ui/routes'; - -// @ts-ignore -import { checkBasicLicense } from '../../../license/check_license'; -// @ts-ignore -import { checkGetDataFrameTransformsPrivilege } from '../../../privilege/check_privilege'; -// @ts-ignore -import { loadIndexPatterns } from '../../../util/index_utils'; -// @ts-ignore -import { getDataFrameBreadcrumbs } from '../../breadcrumbs'; - -const template = ``; - -uiRoutes.when('/data_frames/?', { - template, - k7Breadcrumbs: getDataFrameBreadcrumbs, - resolve: { - CheckLicense: checkBasicLicense, - privileges: checkGetDataFrameTransformsPrivilege, - indexPatterns: loadIndexPatterns, - }, -}); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/services/transform_service/delete_transform.ts b/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/services/transform_service/delete_transform.ts deleted file mode 100644 index 71cc42a126521..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/services/transform_service/delete_transform.ts +++ /dev/null @@ -1,54 +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 { i18n } from '@kbn/i18n'; -import { toastNotifications } from 'ui/notify'; -import { ml } from '../../../../../services/ml_api_service'; -import { - DataFrameTransformListRow, - refreshTransformList$, - REFRESH_TRANSFORM_LIST_STATE, -} from '../../../../common'; -import { - DataFrameTransformEndpointRequest, - DataFrameTransformEndpointResult, -} from '../../components/transform_list/common'; - -import { mlMessageBarService } from '../../../../../../public/components/messagebar/messagebar_service'; - -export const deleteTransforms = async (dataFrames: DataFrameTransformListRow[]) => { - const dataFramesInfo: DataFrameTransformEndpointRequest[] = dataFrames.map(df => ({ - id: df.config.id, - state: df.stats.state, - })); - const results: DataFrameTransformEndpointResult = await ml.dataFrame.deleteDataFrameTransforms( - dataFramesInfo - ); - - for (const transformId in results) { - // hasOwnProperty check to ensure only properties on object itself, and not its prototypes - if (results.hasOwnProperty(transformId)) { - if (results[transformId].success === true) { - toastNotifications.addSuccess( - i18n.translate('xpack.ml.dataframe.transformList.deleteTransformSuccessMessage', { - defaultMessage: 'Request to delete data frame transform {transformId} acknowledged.', - values: { transformId }, - }) - ); - } else { - toastNotifications.addDanger( - i18n.translate('xpack.ml.dataframe.transformList.deleteTransformErrorMessage', { - defaultMessage: 'An error occurred deleting the data frame transform {transformId}', - values: { transformId }, - }) - ); - mlMessageBarService.notify.error(results[transformId].error); - } - } - } - - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH); -}; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/services/transform_service/start_transform.ts b/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/services/transform_service/start_transform.ts deleted file mode 100644 index d121e3db3b2fd..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/services/transform_service/start_transform.ts +++ /dev/null @@ -1,56 +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 { i18n } from '@kbn/i18n'; -import { toastNotifications } from 'ui/notify'; -import { ml } from '../../../../../services/ml_api_service'; - -import { - DataFrameTransformListRow, - refreshTransformList$, - REFRESH_TRANSFORM_LIST_STATE, -} from '../../../../common'; - -import { - DataFrameTransformEndpointRequest, - DataFrameTransformEndpointResult, -} from '../../components/transform_list/common'; - -import { mlMessageBarService } from '../../../../../../public/components/messagebar/messagebar_service'; - -export const startTransforms = async (dataFrames: DataFrameTransformListRow[]) => { - const dataFramesInfo: DataFrameTransformEndpointRequest[] = dataFrames.map(df => ({ - id: df.config.id, - state: df.stats.state, - })); - const results: DataFrameTransformEndpointResult = await ml.dataFrame.startDataFrameTransforms( - dataFramesInfo - ); - - for (const transformId in results) { - // hasOwnProperty check to ensure only properties on object itself, and not its prototypes - if (results.hasOwnProperty(transformId)) { - if (results[transformId].success === true) { - toastNotifications.addSuccess( - i18n.translate('xpack.ml.dataframe.transformList.startTransformSuccessMessage', { - defaultMessage: 'Request to start data frame transform {transformId} acknowledged.', - values: { transformId }, - }) - ); - } else { - toastNotifications.addDanger( - i18n.translate('xpack.ml.dataframe.transformList.startTransformErrorMessage', { - defaultMessage: 'An error occurred starting the data frame transform {transformId}', - values: { transformId }, - }) - ); - mlMessageBarService.notify.error(results[transformId].error); - } - } - } - - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH); -}; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/services/transform_service/stop_transform.ts b/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/services/transform_service/stop_transform.ts deleted file mode 100644 index 5050109d318ea..0000000000000 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/services/transform_service/stop_transform.ts +++ /dev/null @@ -1,56 +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 { i18n } from '@kbn/i18n'; -import { toastNotifications } from 'ui/notify'; -import { ml } from '../../../../../services/ml_api_service'; - -import { - DataFrameTransformListRow, - refreshTransformList$, - REFRESH_TRANSFORM_LIST_STATE, -} from '../../../../common'; - -import { - DataFrameTransformEndpointRequest, - DataFrameTransformEndpointResult, -} from '../../components/transform_list/common'; - -import { mlMessageBarService } from '../../../../../../public/components/messagebar/messagebar_service'; - -export const stopTransforms = async (dataFrames: DataFrameTransformListRow[]) => { - const dataFramesInfo: DataFrameTransformEndpointRequest[] = dataFrames.map(df => ({ - id: df.config.id, - state: df.stats.state, - })); - const results: DataFrameTransformEndpointResult = await ml.dataFrame.stopDataFrameTransforms( - dataFramesInfo - ); - - for (const transformId in results) { - // hasOwnProperty check to ensure only properties on object itself, and not its prototypes - if (results.hasOwnProperty(transformId)) { - if (results[transformId].success === true) { - toastNotifications.addSuccess( - i18n.translate('xpack.ml.dataframe.transformList.stopTransformSuccessMessage', { - defaultMessage: 'Request to stop data frame transform {transformId} acknowledged.', - values: { transformId }, - }) - ); - } else { - toastNotifications.addDanger( - i18n.translate('xpack.ml.dataframe.transformList.stopTransformErrorMessage', { - defaultMessage: 'An error occurred stopping the data frame transform {transformId}', - values: { transformId }, - }) - ); - mlMessageBarService.notify.error(results[transformId].error); - } - } - } - - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH); -}; diff --git a/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row.tsx b/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row.tsx index cb9407271c746..8c3d3803393b1 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row.tsx +++ b/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row.tsx @@ -103,6 +103,12 @@ export const ExpandedRow: FC = ({ item }) => { }, */ ]; + + // Using `expand=false` here so the tabs themselves don't spread + // across the full width. The 100% width is used so the bottom line + // as well as the tab content spans across the full width. + // EuiTabbedContent would do that usually anyway, + // it just doesn't seem to work within certain layouts. return ( = ({ item }) => { initialSelectedTab={tabs[0]} onTabClick={() => {}} expand={false} + style={{ width: '100%' }} /> ); }; diff --git a/x-pack/legacy/plugins/ml/public/index.scss b/x-pack/legacy/plugins/ml/public/index.scss index a3fefb7b1fac8..4ecda43179eba 100644 --- a/x-pack/legacy/plugins/ml/public/index.scss +++ b/x-pack/legacy/plugins/ml/public/index.scss @@ -21,7 +21,6 @@ @import 'app'; // Sub applications - @import 'data_frame/index'; @import 'data_frame_analytics/index'; @import 'datavisualizer/index'; @import 'explorer/index'; // SASSTODO: This file needs to be rewritten diff --git a/x-pack/legacy/plugins/ml/public/privilege/check_privilege.ts b/x-pack/legacy/plugins/ml/public/privilege/check_privilege.ts index 7f2985eda9da8..d930763c3cac5 100644 --- a/x-pack/legacy/plugins/ml/public/privilege/check_privilege.ts +++ b/x-pack/legacy/plugins/ml/public/privilege/check_privilege.ts @@ -88,42 +88,6 @@ export function checkFindFileStructurePrivilege(kbnUrl: any): Promise { - return new Promise((resolve, reject) => { - getPrivileges().then(({ capabilities }) => { - privileges = capabilities; - // the minimum privilege for using ML with a basic license is being able to use the data frames. - // all other functionality is controlled by the return privileges object - if (privileges.canGetDataFrame) { - return resolve(privileges); - } else { - kbnUrl.redirect('/data_frames/access-denied'); - return reject(); - } - }); - }); -} - -export function checkCreateDataFrameTransformPrivilege(kbnUrl: any): Promise { - return new Promise((resolve, reject) => { - getPrivileges().then(({ capabilities }) => { - privileges = capabilities; - if ( - privileges.canCreateDataFrame && - privileges.canPreviewDataFrame && - privileges.canStartStopDataFrame - ) { - return resolve(privileges); - } else { - // if the user has no permission to create a data frame transform, - // redirect them back to the Data Frame Transforms Management page - kbnUrl.redirect('/data_frames'); - return reject(); - } - }); - }); -} - // check the privilege type and the license to see whether a user has permission to access a feature. // takes the name of the privilege variable as specified in get_privileges.js export function checkPermission(privilegeType: keyof Privileges) { @@ -168,21 +132,6 @@ export function createPermissionFailureMessage(privilegeType: keyof Privileges) message = i18n.translate('xpack.ml.privilege.noPermission.runForecastsTooltip', { defaultMessage: 'You do not have permission to run forecasts.', }); - } else if (privilegeType === 'canCreateDataFrame') { - message = i18n.translate('xpack.ml.privilege.noPermission.createDataFrameTransformTooltip', { - defaultMessage: 'You do not have permission to create data frame transforms.', - }); - } else if (privilegeType === 'canStartStopDataFrame') { - message = i18n.translate( - 'xpack.ml.privilege.noPermission.startOrStopDataFrameTransformTooltip', - { - defaultMessage: 'You do not have permission to start or stop data frame transforms.', - } - ); - } else if (privilegeType === 'canDeleteDataFrame') { - message = i18n.translate('xpack.ml.privilege.noPermission.deleteDataFrameTransformTooltip', { - defaultMessage: 'You do not have permission to delete data frame transforms.', - }); } return i18n.translate('xpack.ml.privilege.pleaseContactAdministratorTooltip', { defaultMessage: '{message} Please contact your administrator.', diff --git a/x-pack/legacy/plugins/ml/public/services/ml_api_service/data_frame.js b/x-pack/legacy/plugins/ml/public/services/ml_api_service/data_frame.js deleted file mode 100644 index a0c8c2a10ccb6..0000000000000 --- a/x-pack/legacy/plugins/ml/public/services/ml_api_service/data_frame.js +++ /dev/null @@ -1,83 +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 chrome from 'ui/chrome'; - -import { http } from '../../services/http_service'; - -const basePath = chrome.addBasePath('/api/ml'); - -export const dataFrame = { - getDataFrameTransforms(transformId) { - const transformIdString = transformId !== undefined ? `/${transformId}` : ''; - return http({ - url: `${basePath}/_data_frame/transforms${transformIdString}`, - method: 'GET' - }); - }, - getDataFrameTransformsStats(transformId) { - if (transformId !== undefined) { - return http({ - url: `${basePath}/_data_frame/transforms/${transformId}/_stats`, - method: 'GET' - }); - } - - return http({ - url: `${basePath}/_data_frame/transforms/_stats`, - method: 'GET' - }); - }, - createDataFrameTransform(transformId, transformConfig) { - return http({ - url: `${basePath}/_data_frame/transforms/${transformId}`, - method: 'PUT', - data: transformConfig - }); - }, - deleteDataFrameTransforms(transformsInfo) { - return http({ - url: `${basePath}/_data_frame/transforms/delete_transforms`, - method: 'POST', - data: { - transformsInfo - } - }); - }, - getDataFrameTransformsPreview(obj) { - return http({ - url: `${basePath}/_data_frame/transforms/_preview`, - method: 'POST', - data: obj - }); - }, - startDataFrameTransforms(transformsInfo) { - return http({ - url: `${basePath}/_data_frame/transforms/start_transforms`, - method: 'POST', - data: { - transformsInfo, - } - }); - }, - stopDataFrameTransforms(transformsInfo) { - return http({ - url: `${basePath}/_data_frame/transforms/stop_transforms`, - method: 'POST', - data: { - transformsInfo, - } - }); - }, - getTransformAuditMessages(transformId) { - return http({ - url: `${basePath}/_data_frame/transforms/${transformId}/messages`, - method: 'GET', - }); - }, -}; diff --git a/x-pack/legacy/plugins/ml/public/services/ml_api_service/index.d.ts b/x-pack/legacy/plugins/ml/public/services/ml_api_service/index.d.ts index 475e723f9fbc4..f8b3fd468d598 100644 --- a/x-pack/legacy/plugins/ml/public/services/ml_api_service/index.d.ts +++ b/x-pack/legacy/plugins/ml/public/services/ml_api_service/index.d.ts @@ -8,10 +8,6 @@ import { Annotation } from '../../../common/types/annotations'; import { AggFieldNamePair } from '../../../common/types/fields'; import { ExistingJobsAndGroups } from '../job_service'; import { PrivilegesResponse } from '../../../common/types/privileges'; -import { - DataFrameTransformEndpointRequest, - DataFrameTransformEndpointResult, -} from '../../data_frame/pages/transform_management/components/transform_list/common'; import { MlSummaryJobs } from '../../../common/types/jobs'; // TODO This is not a complete representation of all methods of `ml.*`. @@ -48,23 +44,6 @@ declare interface Ml { getAnalyticsAuditMessages(analyticsId: string): Promise; }; - dataFrame: { - getDataFrameTransforms(jobId?: string): Promise; - getDataFrameTransformsStats(jobId?: string): Promise; - createDataFrameTransform(jobId: string, jobConfig: any): Promise; - deleteDataFrameTransforms( - jobsData: DataFrameTransformEndpointRequest[] - ): Promise; - getDataFrameTransformsPreview(payload: any): Promise; - startDataFrameTransforms( - jobsData: DataFrameTransformEndpointRequest[] - ): Promise; - stopDataFrameTransforms( - jobsData: DataFrameTransformEndpointRequest[] - ): Promise; - getTransformAuditMessages(transformId: string): Promise; - }; - hasPrivileges(obj: object): Promise; checkMlPrivileges(): Promise; diff --git a/x-pack/legacy/plugins/ml/public/services/ml_api_service/index.js b/x-pack/legacy/plugins/ml/public/services/ml_api_service/index.js index b153aa4e07f68..577499fd9eb60 100644 --- a/x-pack/legacy/plugins/ml/public/services/ml_api_service/index.js +++ b/x-pack/legacy/plugins/ml/public/services/ml_api_service/index.js @@ -12,7 +12,6 @@ import chrome from 'ui/chrome'; import { http } from '../../services/http_service'; import { annotations } from './annotations'; -import { dataFrame } from './data_frame'; import { dataFrameAnalytics } from './data_frame_analytics'; import { filters } from './filters'; import { results } from './results'; @@ -450,7 +449,6 @@ export const ml = { }, annotations, - dataFrame, dataFrameAnalytics, filters, results, diff --git a/x-pack/legacy/plugins/ml/server/client/elasticsearch_ml.js b/x-pack/legacy/plugins/ml/server/client/elasticsearch_ml.js index 2a186988a750d..87d3215a426ea 100644 --- a/x-pack/legacy/plugins/ml/server/client/elasticsearch_ml.js +++ b/x-pack/legacy/plugins/ml/server/client/elasticsearch_ml.js @@ -205,119 +205,6 @@ export const elasticsearchJsPlugin = (Client, config, components) => { method: 'POST' }); - // Currently the endpoint uses a default size of 100 unless a size is supplied. - // So until paging is supported in the UI, explicitly supply a size of 1000 - // to match the max number of docs that the endpoint can return. - ml.getDataFrameTransforms = ca({ - urls: [ - { - fmt: '/_data_frame/transforms/<%=transformId%>', - req: { - transformId: { - type: 'string' - } - } - }, - { - fmt: '/_data_frame/transforms/_all?size=1000', - } - ], - method: 'GET' - }); - - ml.getDataFrameTransformsStats = ca({ - urls: [ - { - fmt: '/_data_frame/transforms/<%=transformId%>/_stats', - req: { - transformId: { - type: 'string' - } - } - }, - { - // Currently the endpoint uses a default size of 100 unless a size is supplied. - // So until paging is supported in the UI, explicitly supply a size of 1000 - // to match the max number of docs that the endpoint can return. - fmt: '/_data_frame/transforms/_all/_stats?size=1000', - } - ], - method: 'GET' - }); - - ml.createDataFrameTransform = ca({ - urls: [ - { - fmt: '/_data_frame/transforms/<%=transformId%>', - req: { - transformId: { - type: 'string' - } - } - } - ], - needBody: true, - method: 'PUT' - }); - - ml.deleteDataFrameTransform = ca({ - urls: [ - { - fmt: '/_data_frame/transforms/<%=transformId%>', - req: { - transformId: { - type: 'string' - } - } - } - ], - method: 'DELETE' - }); - - ml.getDataFrameTransformsPreview = ca({ - urls: [ - { - fmt: '/_data_frame/transforms/_preview' - } - ], - needBody: true, - method: 'POST' - }); - - ml.startDataFrameTransform = ca({ - urls: [ - { - fmt: '/_data_frame/transforms/<%=transformId%>/_start', - req: { - transformId: { - type: 'string' - }, - } - } - ], - method: 'POST' - }); - - ml.stopDataFrameTransform = ca({ - urls: [ - { - fmt: '/_data_frame/transforms/<%=transformId%>/_stop?&force=<%=force%>&wait_for_completion=<%waitForCompletion%>', - req: { - transformId: { - type: 'string' - }, - force: { - type: 'boolean' - }, - waitForCompletion: { - type: 'boolean' - } - } - } - ], - method: 'POST' - }); - ml.deleteJob = ca({ urls: [ { diff --git a/x-pack/legacy/plugins/ml/server/lib/check_privileges/__mocks__/call_with_request.ts b/x-pack/legacy/plugins/ml/server/lib/check_privileges/__mocks__/call_with_request.ts index b5650a23b8ca0..ef82003ec80d6 100644 --- a/x-pack/legacy/plugins/ml/server/lib/check_privileges/__mocks__/call_with_request.ts +++ b/x-pack/legacy/plugins/ml/server/lib/check_privileges/__mocks__/call_with_request.ts @@ -105,27 +105,19 @@ const fullClusterPrivileges = { 'cluster:monitor/xpack/ml/calendars/get': true, 'cluster:admin/xpack/ml/filters/get': true, 'cluster:monitor/xpack/ml/datafeeds/get': true, - 'cluster:admin/data_frame/start_task': true, 'cluster:admin/xpack/ml/filters/update': true, 'cluster:admin/xpack/ml/calendars/events/post': true, - 'cluster:monitor/data_frame/get': true, 'cluster:admin/xpack/ml/job/close': true, 'cluster:monitor/xpack/ml/datafeeds/stats/get': true, - 'cluster:admin/data_frame/preview': true, 'cluster:admin/xpack/ml/calendars/jobs/update': true, - 'cluster:admin/data_frame/put': true, 'cluster:admin/xpack/ml/calendars/put': true, - 'cluster:monitor/data_frame/stats/get': true, - 'cluster:admin/data_frame/stop': true, 'cluster:admin/xpack/ml/calendars/events/delete': true, 'cluster:admin/xpack/ml/datafeeds/put': true, 'cluster:admin/xpack/ml/job/open': true, 'cluster:admin/xpack/ml/job/delete': true, 'cluster:monitor/xpack/ml/job/get': true, - 'cluster:admin/data_frame/delete': true, 'cluster:admin/xpack/ml/job/put': true, 'cluster:admin/xpack/ml/job/update': true, - 'cluster:admin/data_frame/start': true, 'cluster:admin/xpack/ml/calendars/delete': true, 'cluster:monitor/xpack/ml/findfilestructure': true, }; @@ -144,27 +136,19 @@ const partialClusterPrivileges = { 'cluster:monitor/xpack/ml/calendars/get': true, 'cluster:admin/xpack/ml/filters/get': false, 'cluster:monitor/xpack/ml/datafeeds/get': true, - 'cluster:admin/data_frame/start_task': false, 'cluster:admin/xpack/ml/filters/update': false, 'cluster:admin/xpack/ml/calendars/events/post': false, - 'cluster:monitor/data_frame/get': false, 'cluster:admin/xpack/ml/job/close': false, 'cluster:monitor/xpack/ml/datafeeds/stats/get': true, - 'cluster:admin/data_frame/preview': false, 'cluster:admin/xpack/ml/calendars/jobs/update': false, - 'cluster:admin/data_frame/put': false, 'cluster:admin/xpack/ml/calendars/put': false, - 'cluster:monitor/data_frame/stats/get': false, - 'cluster:admin/data_frame/stop': false, 'cluster:admin/xpack/ml/calendars/events/delete': false, 'cluster:admin/xpack/ml/datafeeds/put': false, 'cluster:admin/xpack/ml/job/open': false, 'cluster:admin/xpack/ml/job/delete': false, 'cluster:monitor/xpack/ml/job/get': true, - 'cluster:admin/data_frame/delete': false, 'cluster:admin/xpack/ml/job/put': false, 'cluster:admin/xpack/ml/job/update': false, - 'cluster:admin/data_frame/start': false, 'cluster:admin/xpack/ml/calendars/delete': false, 'cluster:monitor/xpack/ml/findfilestructure': true, }; diff --git a/x-pack/legacy/plugins/ml/server/lib/check_privileges/check_privileges.test.ts b/x-pack/legacy/plugins/ml/server/lib/check_privileges/check_privileges.test.ts index 8e2a11667b5cd..da8ef25b2f4df 100644 --- a/x-pack/legacy/plugins/ml/server/lib/check_privileges/check_privileges.test.ts +++ b/x-pack/legacy/plugins/ml/server/lib/check_privileges/check_privileges.test.ts @@ -91,7 +91,7 @@ describe('check_privileges', () => { describe('getPrivileges() - right number of capabilities', () => { test('es capabilities count', async done => { const count = mlPrivileges.cluster.length; - expect(count).toBe(35); + expect(count).toBe(27); done(); }); @@ -104,7 +104,7 @@ describe('check_privileges', () => { ); const { capabilities } = await getPrivileges(); const count = Object.keys(capabilities).length; - expect(count).toBe(27); + expect(count).toBe(22); done(); }); }); @@ -138,11 +138,6 @@ describe('check_privileges', () => { expect(capabilities.canCreateFilter).toBe(false); expect(capabilities.canDeleteFilter).toBe(false); expect(capabilities.canFindFileStructure).toBe(true); - expect(capabilities.canGetDataFrame).toBe(false); - expect(capabilities.canDeleteDataFrame).toBe(false); - expect(capabilities.canPreviewDataFrame).toBe(false); - expect(capabilities.canCreateDataFrame).toBe(false); - expect(capabilities.canStartStopDataFrame).toBe(false); expect(capabilities.canGetDataFrameAnalytics).toBe(true); expect(capabilities.canDeleteDataFrameAnalytics).toBe(false); expect(capabilities.canCreateDataFrameAnalytics).toBe(false); @@ -178,11 +173,6 @@ describe('check_privileges', () => { expect(capabilities.canCreateFilter).toBe(true); expect(capabilities.canDeleteFilter).toBe(true); expect(capabilities.canFindFileStructure).toBe(true); - expect(capabilities.canGetDataFrame).toBe(true); - expect(capabilities.canDeleteDataFrame).toBe(true); - expect(capabilities.canPreviewDataFrame).toBe(true); - expect(capabilities.canCreateDataFrame).toBe(true); - expect(capabilities.canStartStopDataFrame).toBe(true); expect(capabilities.canGetDataFrameAnalytics).toBe(true); expect(capabilities.canDeleteDataFrameAnalytics).toBe(true); expect(capabilities.canCreateDataFrameAnalytics).toBe(true); @@ -218,11 +208,6 @@ describe('check_privileges', () => { expect(capabilities.canCreateFilter).toBe(false); expect(capabilities.canDeleteFilter).toBe(false); expect(capabilities.canFindFileStructure).toBe(true); - expect(capabilities.canGetDataFrame).toBe(true); - expect(capabilities.canDeleteDataFrame).toBe(false); - expect(capabilities.canPreviewDataFrame).toBe(false); - expect(capabilities.canCreateDataFrame).toBe(false); - expect(capabilities.canStartStopDataFrame).toBe(false); expect(capabilities.canGetDataFrameAnalytics).toBe(true); expect(capabilities.canDeleteDataFrameAnalytics).toBe(false); expect(capabilities.canCreateDataFrameAnalytics).toBe(false); @@ -258,11 +243,6 @@ describe('check_privileges', () => { expect(capabilities.canCreateFilter).toBe(false); expect(capabilities.canDeleteFilter).toBe(false); expect(capabilities.canFindFileStructure).toBe(true); - expect(capabilities.canGetDataFrame).toBe(false); - expect(capabilities.canDeleteDataFrame).toBe(false); - expect(capabilities.canPreviewDataFrame).toBe(false); - expect(capabilities.canCreateDataFrame).toBe(false); - expect(capabilities.canStartStopDataFrame).toBe(false); expect(capabilities.canGetDataFrameAnalytics).toBe(true); expect(capabilities.canDeleteDataFrameAnalytics).toBe(false); expect(capabilities.canCreateDataFrameAnalytics).toBe(false); @@ -298,11 +278,6 @@ describe('check_privileges', () => { expect(capabilities.canCreateFilter).toBe(false); expect(capabilities.canDeleteFilter).toBe(false); expect(capabilities.canFindFileStructure).toBe(true); - expect(capabilities.canGetDataFrame).toBe(false); - expect(capabilities.canDeleteDataFrame).toBe(false); - expect(capabilities.canPreviewDataFrame).toBe(false); - expect(capabilities.canCreateDataFrame).toBe(false); - expect(capabilities.canStartStopDataFrame).toBe(false); expect(capabilities.canGetDataFrameAnalytics).toBe(false); expect(capabilities.canDeleteDataFrameAnalytics).toBe(false); expect(capabilities.canCreateDataFrameAnalytics).toBe(false); @@ -338,11 +313,6 @@ describe('check_privileges', () => { expect(capabilities.canCreateFilter).toBe(false); expect(capabilities.canDeleteFilter).toBe(false); expect(capabilities.canFindFileStructure).toBe(true); - expect(capabilities.canGetDataFrame).toBe(true); - expect(capabilities.canDeleteDataFrame).toBe(true); - expect(capabilities.canPreviewDataFrame).toBe(true); - expect(capabilities.canCreateDataFrame).toBe(true); - expect(capabilities.canStartStopDataFrame).toBe(true); expect(capabilities.canGetDataFrameAnalytics).toBe(false); expect(capabilities.canDeleteDataFrameAnalytics).toBe(false); expect(capabilities.canCreateDataFrameAnalytics).toBe(false); @@ -378,11 +348,6 @@ describe('check_privileges', () => { expect(capabilities.canCreateFilter).toBe(false); expect(capabilities.canDeleteFilter).toBe(false); expect(capabilities.canFindFileStructure).toBe(false); - expect(capabilities.canGetDataFrame).toBe(false); - expect(capabilities.canDeleteDataFrame).toBe(false); - expect(capabilities.canPreviewDataFrame).toBe(false); - expect(capabilities.canCreateDataFrame).toBe(false); - expect(capabilities.canStartStopDataFrame).toBe(false); expect(capabilities.canGetDataFrameAnalytics).toBe(false); expect(capabilities.canDeleteDataFrameAnalytics).toBe(false); expect(capabilities.canCreateDataFrameAnalytics).toBe(false); @@ -420,11 +385,6 @@ describe('check_privileges', () => { expect(capabilities.canCreateFilter).toBe(true); expect(capabilities.canDeleteFilter).toBe(true); expect(capabilities.canFindFileStructure).toBe(true); - expect(capabilities.canGetDataFrame).toBe(true); - expect(capabilities.canDeleteDataFrame).toBe(true); - expect(capabilities.canPreviewDataFrame).toBe(true); - expect(capabilities.canCreateDataFrame).toBe(true); - expect(capabilities.canStartStopDataFrame).toBe(true); expect(capabilities.canGetDataFrameAnalytics).toBe(true); expect(capabilities.canDeleteDataFrameAnalytics).toBe(true); expect(capabilities.canCreateDataFrameAnalytics).toBe(true); @@ -460,11 +420,6 @@ describe('check_privileges', () => { expect(capabilities.canCreateFilter).toBe(false); expect(capabilities.canDeleteFilter).toBe(false); expect(capabilities.canFindFileStructure).toBe(true); - expect(capabilities.canGetDataFrame).toBe(true); - expect(capabilities.canDeleteDataFrame).toBe(false); - expect(capabilities.canPreviewDataFrame).toBe(false); - expect(capabilities.canCreateDataFrame).toBe(false); - expect(capabilities.canStartStopDataFrame).toBe(false); expect(capabilities.canGetDataFrameAnalytics).toBe(true); expect(capabilities.canDeleteDataFrameAnalytics).toBe(false); expect(capabilities.canCreateDataFrameAnalytics).toBe(false); @@ -500,11 +455,6 @@ describe('check_privileges', () => { expect(capabilities.canCreateFilter).toBe(false); expect(capabilities.canDeleteFilter).toBe(false); expect(capabilities.canFindFileStructure).toBe(true); - expect(capabilities.canGetDataFrame).toBe(true); - expect(capabilities.canDeleteDataFrame).toBe(false); - expect(capabilities.canPreviewDataFrame).toBe(false); - expect(capabilities.canCreateDataFrame).toBe(false); - expect(capabilities.canStartStopDataFrame).toBe(false); expect(capabilities.canGetDataFrameAnalytics).toBe(true); expect(capabilities.canDeleteDataFrameAnalytics).toBe(false); expect(capabilities.canCreateDataFrameAnalytics).toBe(false); @@ -540,11 +490,6 @@ describe('check_privileges', () => { expect(capabilities.canCreateFilter).toBe(false); expect(capabilities.canDeleteFilter).toBe(false); expect(capabilities.canFindFileStructure).toBe(true); - expect(capabilities.canGetDataFrame).toBe(true); - expect(capabilities.canDeleteDataFrame).toBe(true); - expect(capabilities.canPreviewDataFrame).toBe(true); - expect(capabilities.canCreateDataFrame).toBe(true); - expect(capabilities.canStartStopDataFrame).toBe(true); expect(capabilities.canGetDataFrameAnalytics).toBe(false); expect(capabilities.canDeleteDataFrameAnalytics).toBe(false); expect(capabilities.canCreateDataFrameAnalytics).toBe(false); @@ -580,11 +525,6 @@ describe('check_privileges', () => { expect(capabilities.canCreateFilter).toBe(false); expect(capabilities.canDeleteFilter).toBe(false); expect(capabilities.canFindFileStructure).toBe(true); - expect(capabilities.canGetDataFrame).toBe(true); - expect(capabilities.canDeleteDataFrame).toBe(true); - expect(capabilities.canPreviewDataFrame).toBe(true); - expect(capabilities.canCreateDataFrame).toBe(true); - expect(capabilities.canStartStopDataFrame).toBe(true); expect(capabilities.canGetDataFrameAnalytics).toBe(false); expect(capabilities.canDeleteDataFrameAnalytics).toBe(false); expect(capabilities.canCreateDataFrameAnalytics).toBe(false); @@ -620,11 +560,6 @@ describe('check_privileges', () => { expect(capabilities.canCreateFilter).toBe(false); expect(capabilities.canDeleteFilter).toBe(false); expect(capabilities.canFindFileStructure).toBe(false); - expect(capabilities.canGetDataFrame).toBe(false); - expect(capabilities.canDeleteDataFrame).toBe(false); - expect(capabilities.canPreviewDataFrame).toBe(false); - expect(capabilities.canCreateDataFrame).toBe(false); - expect(capabilities.canStartStopDataFrame).toBe(false); expect(capabilities.canGetDataFrameAnalytics).toBe(false); expect(capabilities.canDeleteDataFrameAnalytics).toBe(false); expect(capabilities.canCreateDataFrameAnalytics).toBe(false); diff --git a/x-pack/legacy/plugins/ml/server/lib/check_privileges/check_privileges.ts b/x-pack/legacy/plugins/ml/server/lib/check_privileges/check_privileges.ts index 0ce60fffd836d..e7c896bb36ed8 100644 --- a/x-pack/legacy/plugins/ml/server/lib/check_privileges/check_privileges.ts +++ b/x-pack/legacy/plugins/ml/server/lib/check_privileges/check_privileges.ts @@ -129,14 +129,6 @@ function setFullGettingPrivileges( privileges.canFindFileStructure = true; } - // Data Frame Transforms - if ( - forceTrue || - (cluster['cluster:monitor/data_frame/get'] && cluster['cluster:monitor/data_frame/stats/get']) - ) { - privileges.canGetDataFrame = true; - } - // Data Frame Analytics if ( forceTrue || @@ -234,28 +226,6 @@ function setFullActionPrivileges( privileges.canDeleteFilter = true; } - // Data Frame Transforms - if (forceTrue || cluster['cluster:admin/data_frame/put']) { - privileges.canCreateDataFrame = true; - } - - if (forceTrue || cluster['cluster:admin/data_frame/delete']) { - privileges.canDeleteDataFrame = true; - } - - if (forceTrue || cluster['cluster:admin/data_frame/preview']) { - privileges.canPreviewDataFrame = true; - } - - if ( - forceTrue || - (cluster['cluster:admin/data_frame/start'] && - cluster['cluster:admin/data_frame/start_task'] && - cluster['cluster:admin/data_frame/stop']) - ) { - privileges.canStartStopDataFrame = true; - } - // Data Frame Analytics if ( forceTrue || @@ -293,40 +263,10 @@ function setBasicGettingPrivileges( if (forceTrue || cluster['cluster:monitor/xpack/ml/findfilestructure']) { privileges.canFindFileStructure = true; } - - // Data Frame Transforms - if ( - forceTrue || - (cluster['cluster:monitor/data_frame/get'] && cluster['cluster:monitor/data_frame/stats/get']) - ) { - privileges.canGetDataFrame = true; - } } function setBasicActionPrivileges( cluster: ClusterPrivilege = {}, privileges: Privileges, forceTrue = false -) { - // Data Frame Transforms - if (forceTrue || cluster['cluster:admin/data_frame/put']) { - privileges.canCreateDataFrame = true; - } - - if (forceTrue || cluster['cluster:admin/data_frame/delete']) { - privileges.canDeleteDataFrame = true; - } - - if (forceTrue || cluster['cluster:admin/data_frame/preview']) { - privileges.canPreviewDataFrame = true; - } - - if ( - forceTrue || - (cluster['cluster:admin/data_frame/start'] && - cluster['cluster:admin/data_frame/start_task'] && - cluster['cluster:admin/data_frame/stop']) - ) { - privileges.canStartStopDataFrame = true; - } -} +) {} diff --git a/x-pack/legacy/plugins/ml/server/lib/check_privileges/privileges.ts b/x-pack/legacy/plugins/ml/server/lib/check_privileges/privileges.ts index f0de6e7ac505f..9fcd28dd68105 100644 --- a/x-pack/legacy/plugins/ml/server/lib/check_privileges/privileges.ts +++ b/x-pack/legacy/plugins/ml/server/lib/check_privileges/privileges.ts @@ -6,19 +6,11 @@ export const mlPrivileges = { cluster: [ - 'cluster:monitor/data_frame/get', - 'cluster:monitor/data_frame/stats/get', 'cluster:monitor/xpack/ml/job/get', 'cluster:monitor/xpack/ml/job/stats/get', 'cluster:monitor/xpack/ml/datafeeds/get', 'cluster:monitor/xpack/ml/datafeeds/stats/get', 'cluster:monitor/xpack/ml/calendars/get', - 'cluster:admin/data_frame/delete', - 'cluster:admin/data_frame/preview', - 'cluster:admin/data_frame/put', - 'cluster:admin/data_frame/start', - 'cluster:admin/data_frame/start_task', - 'cluster:admin/data_frame/stop', 'cluster:admin/xpack/ml/job/put', 'cluster:admin/xpack/ml/job/delete', 'cluster:admin/xpack/ml/job/update', diff --git a/x-pack/legacy/plugins/ml/server/models/data_frame/transforms.ts b/x-pack/legacy/plugins/ml/server/models/data_frame/transforms.ts deleted file mode 100644 index f5bce55763498..0000000000000 --- a/x-pack/legacy/plugins/ml/server/models/data_frame/transforms.ts +++ /dev/null @@ -1,145 +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 { callWithRequestType } from '../../../common/types/kibana'; -import { DATA_FRAME_TRANSFORM_STATE } from '../../../public/data_frame/common'; -import { - DataFrameTransformEndpointRequest, - DataFrameTransformEndpointResult, -} from '../../../public/data_frame/pages/transform_management/components/transform_list/common'; -import { DataFrameTransformId } from '../../../public/data_frame/common/transform'; -import { isRequestTimeout, fillResultsWithTimeouts } from './error_utils'; - -enum TRANSFORM_ACTIONS { - STOP = 'stop', - START = 'start', - DELETE = 'delete', -} - -interface StartTransformOptions { - transformId: DataFrameTransformId; -} - -interface StopTransformOptions { - transformId: DataFrameTransformId; - force?: boolean; - waitForCompletion?: boolean; -} - -export function transformServiceProvider(callWithRequest: callWithRequestType) { - async function deleteTransform(transformId: DataFrameTransformId) { - return callWithRequest('ml.deleteDataFrameTransform', { transformId }); - } - - async function stopTransform(options: StopTransformOptions) { - return callWithRequest('ml.stopDataFrameTransform', options); - } - - async function startTransform(options: StartTransformOptions) { - return callWithRequest('ml.startDataFrameTransform', options); - } - - async function deleteTransforms(transformsInfo: DataFrameTransformEndpointRequest[]) { - const results: DataFrameTransformEndpointResult = {}; - - for (const transformInfo of transformsInfo) { - const transformId = transformInfo.id; - try { - if (transformInfo.state === DATA_FRAME_TRANSFORM_STATE.FAILED) { - try { - await stopTransform({ - transformId, - force: true, - waitForCompletion: true, - }); - } catch (e) { - if (isRequestTimeout(e)) { - return fillResultsWithTimeouts({ - results, - id: transformId, - items: transformsInfo, - action: TRANSFORM_ACTIONS.DELETE, - }); - } - } - } - - await deleteTransform(transformId); - results[transformId] = { success: true }; - } catch (e) { - if (isRequestTimeout(e)) { - return fillResultsWithTimeouts({ - results, - id: transformInfo.id, - items: transformsInfo, - action: TRANSFORM_ACTIONS.DELETE, - }); - } - results[transformId] = { success: false, error: JSON.stringify(e) }; - } - } - return results; - } - - async function startTransforms(transformsInfo: DataFrameTransformEndpointRequest[]) { - const results: DataFrameTransformEndpointResult = {}; - - for (const transformInfo of transformsInfo) { - const transformId = transformInfo.id; - try { - await startTransform({ transformId }); - results[transformId] = { success: true }; - } catch (e) { - if (isRequestTimeout(e)) { - return fillResultsWithTimeouts({ - results, - id: transformId, - items: transformsInfo, - action: TRANSFORM_ACTIONS.START, - }); - } - results[transformId] = { success: false, error: JSON.stringify(e) }; - } - } - return results; - } - - async function stopTransforms(transformsInfo: DataFrameTransformEndpointRequest[]) { - const results: DataFrameTransformEndpointResult = {}; - - for (const transformInfo of transformsInfo) { - const transformId = transformInfo.id; - try { - await stopTransform({ - transformId, - force: - transformInfo.state !== undefined - ? transformInfo.state === DATA_FRAME_TRANSFORM_STATE.FAILED - : false, - waitForCompletion: true, - }); - results[transformId] = { success: true }; - } catch (e) { - if (isRequestTimeout(e)) { - return fillResultsWithTimeouts({ - results, - id: transformId, - items: transformsInfo, - action: TRANSFORM_ACTIONS.STOP, - }); - } - results[transformId] = { success: false, error: JSON.stringify(e) }; - } - } - return results; - } - - return { - deleteTransforms, - startTransforms, - stopTransforms, - }; -} diff --git a/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts b/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts index 695326073dd67..26eb6cebc1c13 100644 --- a/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts +++ b/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts @@ -37,8 +37,6 @@ import { notificationRoutes } from '../routes/notification_settings'; // @ts-ignore: could not find declaration file for module import { systemRoutes } from '../routes/system'; // @ts-ignore: could not find declaration file for module -import { dataFrameRoutes } from '../routes/data_frame'; -// @ts-ignore: could not find declaration file for module import { dataFrameAnalyticsRoutes } from '../routes/data_frame_analytics'; // @ts-ignore: could not find declaration file for module import { dataRecognizer } from '../routes/modules'; @@ -222,7 +220,6 @@ export class Plugin { annotationRoutes(routeInitializationDeps); jobRoutes(routeInitializationDeps); dataFeedRoutes(routeInitializationDeps); - dataFrameRoutes(routeInitializationDeps); dataFrameAnalyticsRoutes(routeInitializationDeps); indicesRoutes(routeInitializationDeps); jobValidationRoutes(extendedRouteInitializationDeps); diff --git a/x-pack/legacy/plugins/ml/server/routes/data_frame.js b/x-pack/legacy/plugins/ml/server/routes/data_frame.js deleted file mode 100644 index e2a72267374b7..0000000000000 --- a/x-pack/legacy/plugins/ml/server/routes/data_frame.js +++ /dev/null @@ -1,155 +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 { callWithRequestFactory } from '../client/call_with_request_factory'; -import { wrapError } from '../client/errors'; -import { transformAuditMessagesProvider } from '../models/data_frame/transform_audit_messages'; -import { transformServiceProvider } from '../models/data_frame'; - -export function dataFrameRoutes({ commonRouteConfig, elasticsearchPlugin, route }) { - - route({ - method: 'GET', - path: '/api/ml/_data_frame/transforms', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - return callWithRequest('ml.getDataFrameTransforms') - .catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig - } - }); - - route({ - method: 'GET', - path: '/api/ml/_data_frame/transforms/{transformId}', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const { transformId } = request.params; - return callWithRequest('ml.getDataFrameTransforms', { transformId }) - .catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig - } - }); - - route({ - method: 'GET', - path: '/api/ml/_data_frame/transforms/_stats', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - return callWithRequest('ml.getDataFrameTransformsStats') - .catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig - } - }); - - route({ - method: 'GET', - path: '/api/ml/_data_frame/transforms/{transformId}/_stats', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const { transformId } = request.params; - return callWithRequest('ml.getDataFrameTransformsStats', { transformId }) - .catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig - } - }); - - route({ - method: 'PUT', - path: '/api/ml/_data_frame/transforms/{transformId}', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const { transformId } = request.params; - return callWithRequest('ml.createDataFrameTransform', { body: request.payload, transformId }) - .catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig - } - }); - - route({ - method: 'POST', - path: '/api/ml/_data_frame/transforms/delete_transforms', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const { deleteTransforms } = transformServiceProvider(callWithRequest); - const { transformsInfo } = request.payload; - return deleteTransforms(transformsInfo) - .catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig - } - }); - - route({ - method: 'POST', - path: '/api/ml/_data_frame/transforms/_preview', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - return callWithRequest('ml.getDataFrameTransformsPreview', { body: request.payload }) - .catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig - } - }); - - route({ - method: 'POST', - path: '/api/ml/_data_frame/transforms/start_transforms', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const { startTransforms } = transformServiceProvider(callWithRequest); - const { transformsInfo } = request.payload; - return startTransforms(transformsInfo) - .catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig - } - }); - - route({ - method: 'POST', - path: '/api/ml/_data_frame/transforms/stop_transforms', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const { stopTransforms } = transformServiceProvider(callWithRequest); - const { transformsInfo } = request.payload; - return stopTransforms(transformsInfo) - .catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig - } - }); - - route({ - method: 'GET', - path: '/api/ml/_data_frame/transforms/{transformId}/messages', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const { getTransformAuditMessages } = transformAuditMessagesProvider(callWithRequest); - const { transformId } = request.params; - return getTransformAuditMessages(transformId) - .catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig - } - }); - -} diff --git a/x-pack/legacy/plugins/transform/common/constants.ts b/x-pack/legacy/plugins/transform/common/constants.ts new file mode 100644 index 0000000000000..3c6224c96d6f2 --- /dev/null +++ b/x-pack/legacy/plugins/transform/common/constants.ts @@ -0,0 +1,63 @@ +/* + * 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 { i18n } from '@kbn/i18n'; + +import { LICENSE_TYPE_BASIC, LicenseType } from '../../../common/constants'; + +export const DEFAULT_REFRESH_INTERVAL_MS = 30000; +export const MINIMUM_REFRESH_INTERVAL_MS = 1000; +export const PROGRESS_REFRESH_INTERVAL_MS = 2000; + +export const PLUGIN = { + ID: 'transform', + MINIMUM_LICENSE_REQUIRED: LICENSE_TYPE_BASIC as LicenseType, + getI18nName: (): string => { + return i18n.translate('xpack.transform.appName', { + defaultMessage: 'Transforms', + }); + }, +}; + +export const API_BASE_PATH = '/api/transform/'; + +// Current df_admin permission requirements: +// 1. `read` on source index +// 2. `all` on source index to create and start transform +// 3. `all` on dest index (could be less tbd) +// 3. `monitor` cluster privilege +// 4. builtin `data_frame_transforms_admin` +// 5. builtin `kibana_user` +// 6. builtin `data_frame_transforms_user` (although this is probably included in the admin) + +export const APP_CLUSTER_PRIVILEGES = [ + 'cluster:monitor/data_frame/get', + 'cluster:monitor/data_frame/stats/get', + 'cluster:admin/data_frame/delete', + 'cluster:admin/data_frame/preview', + 'cluster:admin/data_frame/put', + 'cluster:admin/data_frame/start', + 'cluster:admin/data_frame/start_task', + 'cluster:admin/data_frame/stop', +]; + +// Equivalent of capabilities.canGetTransform +export const APP_GET_TRANSFORM_CLUSTER_PRIVILEGES = [ + 'cluster.cluster:monitor/data_frame/get', + 'cluster.cluster:monitor/data_frame/stats/get', +]; + +// Equivalent of capabilities.canGetTransform +export const APP_CREATE_TRANSFORM_CLUSTER_PRIVILEGES = [ + 'cluster.cluster:monitor/data_frame/get', + 'cluster.cluster:monitor/data_frame/stats/get', + 'cluster.cluster:admin/data_frame/preview', + 'cluster.cluster:admin/data_frame/put', + 'cluster.cluster:admin/data_frame/start', + 'cluster.cluster:admin/data_frame/start_task', +]; + +export const APP_INDEX_PRIVILEGES = ['monitor']; diff --git a/x-pack/legacy/plugins/transform/common/types/common.ts b/x-pack/legacy/plugins/transform/common/types/common.ts new file mode 100644 index 0000000000000..3f3493863e0f5 --- /dev/null +++ b/x-pack/legacy/plugins/transform/common/types/common.ts @@ -0,0 +1,21 @@ +/* + * 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 interface Dictionary { + [id: string]: TValue; +} + +// converts a dictionary to an array. note this loses the dictionary `key` information. +// however it's able to retain the type information of the dictionary elements. +export function dictionaryToArray(dict: Dictionary): TValue[] { + return Object.keys(dict).map(key => dict[key]); +} + +// A recursive partial type to allow passing nested partial attributes. +// Used for example for the optional `jobConfig.dest.results_field` property. +export type DeepPartial = { + [P in keyof T]?: DeepPartial; +}; diff --git a/x-pack/legacy/plugins/transform/common/types/messages.ts b/x-pack/legacy/plugins/transform/common/types/messages.ts new file mode 100644 index 0000000000000..868935eca0a3d --- /dev/null +++ b/x-pack/legacy/plugins/transform/common/types/messages.ts @@ -0,0 +1,26 @@ +/* + * 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 interface AuditMessageBase { + message: string; + level: string; + timestamp: number; + node_name: string; + text?: string; +} + +export interface AuditMessage { + _index: string; + _type: string; + _id: string; + _score: null | number; + _source: TransformMessage; + sort?: any; +} + +export interface TransformMessage extends AuditMessageBase { + transform_id: string; +} diff --git a/x-pack/legacy/plugins/transform/common/utils/date_utils.ts b/x-pack/legacy/plugins/transform/common/utils/date_utils.ts new file mode 100644 index 0000000000000..2acde91413aca --- /dev/null +++ b/x-pack/legacy/plugins/transform/common/utils/date_utils.ts @@ -0,0 +1,22 @@ +/* + * 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. + */ + +// utility functions for handling dates + +// @ts-ignore +import { formatDate } from '@elastic/eui/lib/services/format'; + +export function formatHumanReadableDate(ts: number) { + return formatDate(ts, 'MMMM Do YYYY'); +} + +export function formatHumanReadableDateTime(ts: number) { + return formatDate(ts, 'MMMM Do YYYY, HH:mm'); +} + +export function formatHumanReadableDateTimeSeconds(ts: number) { + return formatDate(ts, 'MMMM Do YYYY, HH:mm:ss'); +} diff --git a/x-pack/legacy/plugins/transform/common/utils/es_utils.ts b/x-pack/legacy/plugins/transform/common/utils/es_utils.ts new file mode 100644 index 0000000000000..c52b99c350e38 --- /dev/null +++ b/x-pack/legacy/plugins/transform/common/utils/es_utils.ts @@ -0,0 +1,41 @@ +/* + * 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. + */ + +interface WindowWithTextEncoder extends Window { + TextEncoder: any; +} + +const windowWithTextEncoder = window as WindowWithTextEncoder; + +function isValidIndexNameLength(indexName: string) { + if ( + windowWithTextEncoder.TextEncoder && + new windowWithTextEncoder.TextEncoder('utf-8').encode(indexName).length > 255 + ) { + return false; + } + + // If TextEncoder is not available just check for string.length + return indexName.length <= 255; +} + +// rules taken from +// https://github.com/elastic/elasticsearch/blob/master/docs/reference/indices/create-index.asciidoc +export function isValidIndexName(indexName: string) { + return ( + // Lowercase only + indexName === indexName.toLowerCase() && + // Cannot include \, /, *, ?, ", <, >, |, space character, comma, #, : + /^[^\*\\/\?"<>|\s,#:]+$/.test(indexName) && + // Cannot start with -, _, + + /^[^-_\+]+$/.test(indexName.charAt(0)) && + // Cannot be . or .. + (indexName !== '.' && indexName !== '..') && + // Cannot be longer than 255 bytes (note it is bytes, + // so multi-byte characters will count towards the 255 limit faster) + isValidIndexNameLength(indexName) + ); +} diff --git a/x-pack/legacy/plugins/transform/common/utils/object_utils.ts b/x-pack/legacy/plugins/transform/common/utils/object_utils.ts new file mode 100644 index 0000000000000..1facc761d6379 --- /dev/null +++ b/x-pack/legacy/plugins/transform/common/utils/object_utils.ts @@ -0,0 +1,17 @@ +/* + * 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 { idx } from '@kbn/elastic-idx'; + +// This is similar to lodash's get() except that it's TypeScript aware and is able to infer return types. +// It splits the attribute key string and uses reduce with an idx check to access nested attributes. +export const getNestedProperty = ( + obj: Record, + accessor: string, + defaultValue?: any +) => { + return accessor.split('.').reduce((o, i) => idx(o, _ => _[i]), obj) || defaultValue; +}; diff --git a/x-pack/legacy/plugins/transform/index.ts b/x-pack/legacy/plugins/transform/index.ts new file mode 100644 index 0000000000000..d0799f46cbd25 --- /dev/null +++ b/x-pack/legacy/plugins/transform/index.ts @@ -0,0 +1,39 @@ +/* + * 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 { Legacy } from 'kibana'; +import { resolve } from 'path'; +import { PLUGIN } from './common/constants'; +import { Plugin as TransformPlugin } from './server/plugin'; +import { createServerShim } from './server/shim'; + +export function transform(kibana: any) { + return new kibana.Plugin({ + id: PLUGIN.ID, + configPrefix: 'xpack.transform', + publicDir: resolve(__dirname, 'public'), + require: ['kibana', 'elasticsearch', 'xpack_main'], + uiExports: { + styleSheetPaths: resolve(__dirname, 'public/app/index.scss'), + managementSections: ['plugins/transform'], + }, + init(server: Legacy.Server) { + const { core, plugins } = createServerShim(server, PLUGIN.ID); + const transformPlugin = new TransformPlugin(); + + // Start plugin + transformPlugin.start(core, plugins); + + // Register license checker + plugins.license.registerLicenseChecker( + server, + PLUGIN.ID, + PLUGIN.getI18nName(), + PLUGIN.MINIMUM_LICENSE_REQUIRED + ); + }, + }); +} diff --git a/x-pack/legacy/plugins/transform/public/app/app.tsx b/x-pack/legacy/plugins/transform/public/app/app.tsx new file mode 100644 index 0000000000000..825c1761bf619 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/app.tsx @@ -0,0 +1,66 @@ +/* + * 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 React, { useContext, FC } from 'react'; +import { render } from 'react-dom'; +import { Redirect, Route, Switch } from 'react-router-dom'; + +import { FormattedMessage } from '@kbn/i18n/react'; + +import { SectionError } from './components'; +import { CLIENT_BASE_PATH, SECTION_SLUG } from './constants'; +import { getAppProviders } from './app_dependencies'; +import { AuthorizationContext } from './lib/authorization'; +import { AppDependencies } from '../shim'; + +import { CreateTransformSection } from './sections/create_transform'; +import { TransformManagementSection } from './sections/transform_management'; + +export const App: FC = () => { + const { apiError } = useContext(AuthorizationContext); + + if (apiError) { + return ( + + } + error={apiError} + /> + ); + } + + return ( +
+ + + + + +
+ ); +}; + +export const renderReact = (elem: Element, appDependencies: AppDependencies) => { + const Providers = getAppProviders(appDependencies); + + render( + + + , + elem + ); +}; diff --git a/x-pack/legacy/plugins/transform/public/app/app_dependencies.tsx b/x-pack/legacy/plugins/transform/public/app/app_dependencies.tsx new file mode 100644 index 0000000000000..28a54e67bf838 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/app_dependencies.tsx @@ -0,0 +1,46 @@ +/* + * 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 React, { createContext, useContext, ReactNode } from 'react'; +import { HashRouter } from 'react-router-dom'; + +import { API_BASE_PATH } from '../../common/constants'; +import { AuthorizationProvider } from './lib/authorization'; +import { AppDependencies } from '../shim'; + +let DependenciesContext: React.Context; + +const setAppDependencies = (deps: AppDependencies) => { + DependenciesContext = createContext(deps); + return DependenciesContext.Provider; +}; + +export const useAppDependencies = () => { + if (!DependenciesContext) { + throw new Error(`The app dependencies Context hasn't been set. + Use the "setAppDependencies()" method when bootstrapping the app.`); + } + return useContext(DependenciesContext); +}; + +export const getAppProviders = (deps: AppDependencies) => { + const I18nContext = deps.core.i18n.Context; + + // Create App dependencies context and get its provider + const AppDependenciesProvider = setAppDependencies(deps); + + return ({ children }: { children: ReactNode }) => ( + + + + {children} + + + + ); +}; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/common/__mocks__/data_frame_transform_list_row.json b/x-pack/legacy/plugins/transform/public/app/common/__mocks__/transform_list_row.json similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/common/__mocks__/data_frame_transform_list_row.json rename to x-pack/legacy/plugins/transform/public/app/common/__mocks__/transform_list_row.json diff --git a/x-pack/legacy/plugins/ml/public/data_frame/common/__mocks__/data_frame_transform_stats.json b/x-pack/legacy/plugins/transform/public/app/common/__mocks__/transform_stats.json similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/common/__mocks__/data_frame_transform_stats.json rename to x-pack/legacy/plugins/transform/public/app/common/__mocks__/transform_stats.json diff --git a/x-pack/legacy/plugins/ml/public/data_frame/common/aggregations.test.ts b/x-pack/legacy/plugins/transform/public/app/common/aggregations.test.ts similarity index 95% rename from x-pack/legacy/plugins/ml/public/data_frame/common/aggregations.test.ts rename to x-pack/legacy/plugins/transform/public/app/common/aggregations.test.ts index 82035a29e9d97..fdd0532f273ed 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/common/aggregations.test.ts +++ b/x-pack/legacy/plugins/transform/public/app/common/aggregations.test.ts @@ -6,7 +6,7 @@ import { isAggName } from './aggregations'; -describe('Data Frame: Aggregations', () => { +describe('Transform: Aggregations', () => { test('isAggName()', () => { expect(isAggName('avg(responsetime)')).toEqual(true); expect(isAggName('avg_responsetime')).toEqual(true); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/common/aggregations.ts b/x-pack/legacy/plugins/transform/public/app/common/aggregations.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/common/aggregations.ts rename to x-pack/legacy/plugins/transform/public/app/common/aggregations.ts diff --git a/x-pack/legacy/plugins/ml/public/data_frame/common/dropdown.ts b/x-pack/legacy/plugins/transform/public/app/common/dropdown.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/common/dropdown.ts rename to x-pack/legacy/plugins/transform/public/app/common/dropdown.ts diff --git a/x-pack/legacy/plugins/ml/public/data_frame/common/fields.ts b/x-pack/legacy/plugins/transform/public/app/common/fields.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/common/fields.ts rename to x-pack/legacy/plugins/transform/public/app/common/fields.ts diff --git a/x-pack/legacy/plugins/ml/public/data_frame/common/index.ts b/x-pack/legacy/plugins/transform/public/app/common/index.ts similarity index 85% rename from x-pack/legacy/plugins/ml/public/data_frame/common/index.ts rename to x-pack/legacy/plugins/transform/public/app/common/index.ts index 7af8c7ee73cff..f42b36f2a38e4 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/common/index.ts +++ b/x-pack/legacy/plugins/transform/public/app/common/index.ts @@ -22,22 +22,22 @@ export { useRefreshTransformList, CreateRequestBody, PreviewRequestBody, - DataFrameTransformId, - DataFrameTransformPivotConfig, + TransformId, + TransformPivotConfig, IndexName, IndexPattern, REFRESH_TRANSFORM_LIST_STATE, } from './transform'; -export { DATA_FRAME_TRANSFORM_LIST_COLUMN, DataFrameTransformListRow } from './transform_list'; +export { TRANSFORM_LIST_COLUMN, TransformListRow } from './transform_list'; export { getTransformProgress, isCompletedBatchTransform, - isDataFrameTransformStats, - DataFrameTransformStats, - DATA_FRAME_MODE, - DATA_FRAME_TRANSFORM_STATE, + isTransformStats, + TransformStats, + TRANSFORM_MODE, + TRANSFORM_STATE, } from './transform_stats'; -export { moveToDataFrameWizard, getDiscoverUrl } from './navigation'; +export { getDiscoverUrl } from './navigation'; export { getEsAggFromAggConfig, isPivotAggsConfigWithUiSupport, diff --git a/x-pack/legacy/plugins/ml/public/data_frame/common/navigation.test.ts b/x-pack/legacy/plugins/transform/public/app/common/navigation.test.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/common/navigation.test.ts rename to x-pack/legacy/plugins/transform/public/app/common/navigation.test.tsx diff --git a/x-pack/legacy/plugins/ml/public/data_frame/common/navigation.ts b/x-pack/legacy/plugins/transform/public/app/common/navigation.tsx similarity index 56% rename from x-pack/legacy/plugins/ml/public/data_frame/common/navigation.ts rename to x-pack/legacy/plugins/transform/public/app/common/navigation.tsx index e8726e8c2eedd..ac98d92fdba83 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/common/navigation.ts +++ b/x-pack/legacy/plugins/transform/public/app/common/navigation.tsx @@ -4,15 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ +import React, { FC } from 'react'; +import { Redirect } from 'react-router-dom'; import rison from 'rison-node'; -export function moveToDataFrameWizard() { - window.location.href = '#/data_frames/new_transform'; -} +import { CLIENT_BASE_PATH, SECTION_SLUG } from '../constants'; /** * Gets a url for navigating to Discover page. - * @param indexPatternId Index pattern id. + * @param indexPatternId Index pattern ID. * @param baseUrl Base url. */ export function getDiscoverUrl(indexPatternId: string, baseUrl: string): string { @@ -27,3 +27,11 @@ export function getDiscoverUrl(indexPatternId: string, baseUrl: string): string return `${baseUrl}${hash}`; } + +export const RedirectToTransformManagement: FC = () => ( + +); + +export const RedirectToCreateTransform: FC<{ savedObjectId: string }> = ({ savedObjectId }) => ( + +); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/common/pivot_aggs.ts b/x-pack/legacy/plugins/transform/public/app/common/pivot_aggs.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/common/pivot_aggs.ts rename to x-pack/legacy/plugins/transform/public/app/common/pivot_aggs.ts diff --git a/x-pack/legacy/plugins/ml/public/data_frame/common/pivot_group_by.ts b/x-pack/legacy/plugins/transform/public/app/common/pivot_group_by.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/common/pivot_group_by.ts rename to x-pack/legacy/plugins/transform/public/app/common/pivot_group_by.ts diff --git a/x-pack/legacy/plugins/ml/public/data_frame/common/request.test.ts b/x-pack/legacy/plugins/transform/public/app/common/request.test.ts similarity index 95% rename from x-pack/legacy/plugins/ml/public/data_frame/common/request.test.ts rename to x-pack/legacy/plugins/transform/public/app/common/request.test.ts index ae15ed11b8a23..0a433df539efe 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/common/request.test.ts +++ b/x-pack/legacy/plugins/transform/public/app/common/request.test.ts @@ -6,8 +6,8 @@ import { PivotGroupByConfig } from '../common'; -import { StepDefineExposedState } from '../pages/data_frame_new_pivot/components/step_define/step_define_form'; -import { StepDetailsExposedState } from '../pages/data_frame_new_pivot/components/step_details/step_details_form'; +import { StepDefineExposedState } from '../sections/create_transform/components/step_define/step_define_form'; +import { StepDetailsExposedState } from '../sections/create_transform/components/step_details/step_details_form'; import { PIVOT_SUPPORTED_GROUP_BY_AGGS } from './pivot_group_by'; import { PivotAggsConfig, PIVOT_SUPPORTED_AGGS } from './pivot_aggs'; @@ -24,7 +24,7 @@ const defaultQuery: PivotQuery = { query_string: { query: '*' } }; const matchAllQuery: PivotQuery = { match_all: {} }; const simpleQuery: PivotQuery = { query_string: { query: 'airline:AAL' } }; -describe('Data Frame: Common', () => { +describe('Transform: Common', () => { test('isSimpleQuery()', () => { expect(isSimpleQuery(defaultQuery)).toBe(true); expect(isSimpleQuery(matchAllQuery)).toBe(false); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/common/request.ts b/x-pack/legacy/plugins/transform/public/app/common/request.ts similarity index 93% rename from x-pack/legacy/plugins/ml/public/data_frame/common/request.ts rename to x-pack/legacy/plugins/transform/public/app/common/request.ts index ecef6fcc2f740..5f0c778695523 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/common/request.ts +++ b/x-pack/legacy/plugins/transform/public/app/common/request.ts @@ -9,10 +9,10 @@ import { DefaultOperator } from 'elasticsearch'; import { IndexPattern } from 'ui/index_patterns'; import { dictionaryToArray } from '../../../common/types/common'; -import { SavedSearchQuery } from '../../contexts/kibana'; +import { SavedSearchQuery } from '../lib/kibana'; -import { StepDefineExposedState } from '../pages/data_frame_new_pivot/components/step_define/step_define_form'; -import { StepDetailsExposedState } from '../pages/data_frame_new_pivot/components/step_details/step_details_form'; +import { StepDefineExposedState } from '../sections/create_transform/components/step_define/step_define_form'; +import { StepDetailsExposedState } from '../sections/create_transform/components/step_details/step_details_form'; import { getEsAggFromAggConfig, diff --git a/x-pack/legacy/plugins/transform/public/app/common/transform.test.ts b/x-pack/legacy/plugins/transform/public/app/common/transform.test.ts new file mode 100644 index 0000000000000..7d42a768ebd0f --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/common/transform.test.ts @@ -0,0 +1,28 @@ +/* + * 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 { isTransformIdValid } from './transform'; + +describe('Transform: isTransformIdValid()', () => { + test('returns true for job ID: "good_job-name"', () => { + expect(isTransformIdValid('good_job-name')).toBe(true); + }); + test('returns false for job ID: "_bad_job-name"', () => { + expect(isTransformIdValid('_bad_job-name')).toBe(false); + }); + test('returns false for job ID: "bad_job-name_"', () => { + expect(isTransformIdValid('bad_job-name_')).toBe(false); + }); + test('returns false for job ID: "-bad_job-name"', () => { + expect(isTransformIdValid('-bad_job-name')).toBe(false); + }); + test('returns false for job ID: "bad_job-name-"', () => { + expect(isTransformIdValid('bad_job-name-')).toBe(false); + }); + test('returns false for job ID: "bad&job-name"', () => { + expect(isTransformIdValid('bad&job-name')).toBe(false); + }); +}); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/common/transform.ts b/x-pack/legacy/plugins/transform/public/app/common/transform.ts similarity index 85% rename from x-pack/legacy/plugins/ml/public/data_frame/common/transform.ts rename to x-pack/legacy/plugins/transform/public/app/common/transform.ts index 464c7b81d8976..7670ab1f1cca1 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/common/transform.ts +++ b/x-pack/legacy/plugins/transform/public/app/common/transform.ts @@ -9,17 +9,18 @@ import { BehaviorSubject } from 'rxjs'; import { filter, distinctUntilChanged } from 'rxjs/operators'; import { Subscription } from 'rxjs'; -// @ts-ignore -import { isJobIdValid } from '../../../common/util/job_utils'; - import { PivotAggDict } from './pivot_aggs'; import { PivotGroupByDict } from './pivot_group_by'; -export const isTransformIdValid = isJobIdValid; - export type IndexName = string; export type IndexPattern = string; -export type DataFrameTransformId = string; +export type TransformId = string; + +// Transform name must contain lowercase alphanumeric (a-z and 0-9), hyphens or underscores; +// It must also start and end with an alphanumeric character. +export function isTransformIdValid(transformId: TransformId) { + return /^[a-z0-9\-\_]+$/g.test(transformId) && !/^([_-].*)?(.*[_-])?$/g.test(transformId); +} export interface PreviewRequestBody { pivot: { @@ -45,8 +46,8 @@ export interface CreateRequestBody extends PreviewRequestBody { }; } -export interface DataFrameTransformPivotConfig extends CreateRequestBody { - id: DataFrameTransformId; +export interface TransformPivotConfig extends CreateRequestBody { + id: TransformId; } export enum REFRESH_TRANSFORM_LIST_STATE { diff --git a/x-pack/legacy/plugins/ml/public/data_frame/common/transform_list.ts b/x-pack/legacy/plugins/transform/public/app/common/transform_list.ts similarity index 60% rename from x-pack/legacy/plugins/ml/public/data_frame/common/transform_list.ts rename to x-pack/legacy/plugins/transform/public/app/common/transform_list.ts index 0f84acf5d72cf..8925923ed9d8f 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/common/transform_list.ts +++ b/x-pack/legacy/plugins/transform/public/app/common/transform_list.ts @@ -4,20 +4,20 @@ * you may not use this file except in compliance with the Elastic License. */ -import { DataFrameTransformId, DataFrameTransformPivotConfig } from './transform'; -import { DataFrameTransformStats } from './transform_stats'; +import { TransformId, TransformPivotConfig } from './transform'; +import { TransformStats } from './transform_stats'; // Used to pass on attribute names to table columns -export enum DATA_FRAME_TRANSFORM_LIST_COLUMN { +export enum TRANSFORM_LIST_COLUMN { CONFIG_DEST_INDEX = 'config.dest.index', CONFIG_SOURCE_INDEX = 'config.source.index', DESCRIPTION = 'config.description', ID = 'id', } -export interface DataFrameTransformListRow { - id: DataFrameTransformId; - config: DataFrameTransformPivotConfig; +export interface TransformListRow { + id: TransformId; + config: TransformPivotConfig; mode?: string; // added property on client side to allow filtering by this field - stats: DataFrameTransformStats; + stats: TransformStats; } diff --git a/x-pack/legacy/plugins/ml/public/data_frame/common/transform_stats.test.ts b/x-pack/legacy/plugins/transform/public/app/common/transform_stats.test.ts similarity index 73% rename from x-pack/legacy/plugins/ml/public/data_frame/common/transform_stats.test.ts rename to x-pack/legacy/plugins/transform/public/app/common/transform_stats.test.ts index a8da8bc90b43d..342ca77a67b38 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/common/transform_stats.test.ts +++ b/x-pack/legacy/plugins/transform/public/app/common/transform_stats.test.ts @@ -4,24 +4,24 @@ * you may not use this file except in compliance with the Elastic License. */ -import mockDataFrameTransformListRow from './__mocks__/data_frame_transform_list_row.json'; -import mockDataFrameTransformStats from './__mocks__/data_frame_transform_stats.json'; +import mockTransformListRow from './__mocks__/transform_list_row.json'; +import mockTransformStats from './__mocks__/transform_stats.json'; -import { DataFrameTransformListRow } from './transform_list'; +import { TransformListRow } from './transform_list'; import { getTransformProgress, isCompletedBatchTransform } from './transform_stats'; const getRow = (statsId: string) => { return { - ...(mockDataFrameTransformListRow as DataFrameTransformListRow), + ...(mockTransformListRow as TransformListRow), stats: { - ...mockDataFrameTransformStats.transforms.find( - (stats: DataFrameTransformListRow['stats']) => stats.id === statsId + ...mockTransformStats.transforms.find( + (stats: TransformListRow['stats']) => stats.id === statsId ), }, }; }; -describe('Data Frame: Transform stats.', () => { +describe('Transform: Transform stats.', () => { test('getTransformProgress()', () => { // At the moment, any kind of stopped jobs don't include progress information. // We cannot infer progress for now from an unfinished job that has been stopped for now. diff --git a/x-pack/legacy/plugins/ml/public/data_frame/common/transform_stats.ts b/x-pack/legacy/plugins/transform/public/app/common/transform_stats.ts similarity index 73% rename from x-pack/legacy/plugins/ml/public/data_frame/common/transform_stats.ts rename to x-pack/legacy/plugins/transform/public/app/common/transform_stats.ts index 303a953c0d3c8..955dc831e05e2 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/common/transform_stats.ts +++ b/x-pack/legacy/plugins/transform/public/app/common/transform_stats.ts @@ -6,11 +6,11 @@ import { idx } from '@kbn/elastic-idx'; -import { DataFrameTransformId } from './transform'; -import { DataFrameTransformListRow } from './transform_list'; +import { TransformId } from './transform'; +import { TransformListRow } from './transform_list'; // reflects https://github.com/elastic/elasticsearch/blob/master/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/dataframe/transforms/DataFrameTransformStats.java#L243 -export enum DATA_FRAME_TRANSFORM_STATE { +export enum TRANSFORM_STATE { ABORTING = 'aborting', FAILED = 'failed', INDEXING = 'indexing', @@ -19,13 +19,13 @@ export enum DATA_FRAME_TRANSFORM_STATE { STOPPING = 'stopping', } -export enum DATA_FRAME_MODE { +export enum TRANSFORM_MODE { BATCH = 'batch', CONTINUOUS = 'continuous', } -export interface DataFrameTransformStats { - id: DataFrameTransformId; +export interface TransformStats { + id: TransformId; checkpointing: { last: { checkpoint: number; @@ -61,19 +61,19 @@ export interface DataFrameTransformStats { trigger_count: number; }; reason?: string; - state: DATA_FRAME_TRANSFORM_STATE; + state: TRANSFORM_STATE; } -export function isDataFrameTransformStats(arg: any): arg is DataFrameTransformStats { +export function isTransformStats(arg: any): arg is TransformStats { return ( typeof arg === 'object' && arg !== null && {}.hasOwnProperty.call(arg, 'state') && - Object.values(DATA_FRAME_TRANSFORM_STATE).includes(arg.state) + Object.values(TRANSFORM_STATE).includes(arg.state) ); } -export function getTransformProgress(item: DataFrameTransformListRow) { +export function getTransformProgress(item: TransformListRow) { if (isCompletedBatchTransform(item)) { return 100; } @@ -83,12 +83,12 @@ export function getTransformProgress(item: DataFrameTransformListRow) { return progress !== undefined ? Math.round(progress) : undefined; } -export function isCompletedBatchTransform(item: DataFrameTransformListRow) { +export function isCompletedBatchTransform(item: TransformListRow) { // If `checkpoint=1`, `sync` is missing from the config and state is stopped, - // then this is a completed batch data frame transform. + // then this is a completed batch transform. return ( item.stats.checkpointing.last.checkpoint === 1 && item.config.sync === undefined && - item.stats.state === DATA_FRAME_TRANSFORM_STATE.STOPPED + item.stats.state === TRANSFORM_STATE.STOPPED ); } diff --git a/x-pack/legacy/plugins/ml/public/data_frame/common/validators.test.ts b/x-pack/legacy/plugins/transform/public/app/common/validators.test.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/common/validators.test.ts rename to x-pack/legacy/plugins/transform/public/app/common/validators.test.ts diff --git a/x-pack/legacy/plugins/ml/public/data_frame/common/validators.ts b/x-pack/legacy/plugins/transform/public/app/common/validators.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/common/validators.ts rename to x-pack/legacy/plugins/transform/public/app/common/validators.ts diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/services/transform_service/index.ts b/x-pack/legacy/plugins/transform/public/app/components/index.ts similarity index 52% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/services/transform_service/index.ts rename to x-pack/legacy/plugins/transform/public/app/components/index.ts index 6af676fa2c3f6..dbef5a2dd46dc 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/services/transform_service/index.ts +++ b/x-pack/legacy/plugins/transform/public/app/components/index.ts @@ -4,7 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export { getTransformsFactory } from './get_transforms'; -export { deleteTransforms } from './delete_transform'; -export { startTransforms } from './start_transform'; -export { stopTransforms } from './stop_transform'; +export { SectionError } from './section_error'; +export { SectionLoading } from './section_loading'; diff --git a/x-pack/legacy/plugins/transform/public/app/components/job_icon.tsx b/x-pack/legacy/plugins/transform/public/app/components/job_icon.tsx new file mode 100644 index 0000000000000..af5dac2b8466b --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/components/job_icon.tsx @@ -0,0 +1,44 @@ +/* + * 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 React, { FC } from 'react'; + +import { EuiIcon, EuiToolTip } from '@elastic/eui'; +import { AuditMessageBase } from '../../../common/types/messages'; + +interface Props { + message: AuditMessageBase; + showTooltip?: boolean; +} + +const [INFO, WARNING, ERROR] = ['info', 'warning', 'error']; + +export const JobIcon: FC = ({ message, showTooltip = false }) => { + if (message === undefined) { + return ; + } + + let color = 'primary'; + const icon = 'alert'; + + if (message.level === INFO) { + color = 'primary'; + } else if (message.level === WARNING) { + color = 'warning'; + } else if (message.level === ERROR) { + color = 'danger'; + } + + if (showTooltip) { + return ( + + + + ); + } else { + return ; + } +}; diff --git a/x-pack/legacy/plugins/transform/public/app/components/section_error.tsx b/x-pack/legacy/plugins/transform/public/app/components/section_error.tsx new file mode 100644 index 0000000000000..2ad6f0870c140 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/components/section_error.tsx @@ -0,0 +1,50 @@ +/* + * 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 { EuiCallOut, EuiSpacer } from '@elastic/eui'; +import React, { Fragment } from 'react'; + +interface Props { + title: React.ReactNode; + error: { + data: { + error: string; + cause?: string[]; + message?: string; + }; + }; + actions?: JSX.Element; +} + +export const SectionError: React.FunctionComponent = ({ + title, + error, + actions, + ...rest +}) => { + const { + error: errorString, + cause, // wrapEsError() on the server adds a "cause" array + message, + } = error.data; + + return ( + + {cause ? message || errorString :

{message || errorString}

} + {cause && ( + + +
    + {cause.map((causeMsg, i) => ( +
  • {causeMsg}
  • + ))} +
+
+ )} + {actions ? actions : null} +
+ ); +}; diff --git a/x-pack/legacy/plugins/transform/public/app/components/section_loading.tsx b/x-pack/legacy/plugins/transform/public/app/components/section_loading.tsx new file mode 100644 index 0000000000000..aff3363c0aa60 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/components/section_loading.tsx @@ -0,0 +1,47 @@ +/* + * 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 React from 'react'; + +import { + EuiEmptyPrompt, + EuiLoadingSpinner, + EuiText, + EuiFlexGroup, + EuiFlexItem, + EuiTextColor, +} from '@elastic/eui'; + +interface Props { + inline?: boolean; + children: React.ReactNode; + [key: string]: any; +} + +export const SectionLoading: React.FunctionComponent = ({ inline, children, ...rest }) => { + if (inline) { + return ( + + + + + + + {children} + + + + ); + } + + return ( + } + body={{children}} + data-test-subj="sectionLoading" + /> + ); +}; diff --git a/x-pack/legacy/plugins/transform/public/app/constants/index.ts b/x-pack/legacy/plugins/transform/public/app/constants/index.ts new file mode 100644 index 0000000000000..4988ea660b418 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/constants/index.ts @@ -0,0 +1,25 @@ +/* + * 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 const CLIENT_BASE_PATH = '/management/elasticsearch/transform'; + +export enum SECTION_SLUG { + HOME = 'transform_management', + CREATE_TRANSFORM = 'create_transform', +} + +export enum TRANSFORM_DOC_PATHS { + default = 'docs.html', + plugins = 'plugins.html', +} + +// UI Metric constants +export const UIM_APP_NAME = 'transform'; +export const UIM_TRANSFORM_LIST_LOAD = 'transform_list_load'; +export const UIM_TRANSFORM_CREATE = 'transform_create'; +export const UIM_TRANSFORM_DELETE = 'transform_delete'; +export const UIM_TRANSFORM_DELETE_MANY = 'transform_delete_many'; +export const UIM_TRANSFORM_SHOW_DETAILS_CLICK = 'transform_show_details_click'; diff --git a/x-pack/legacy/plugins/transform/public/app/hooks/__mocks__/use_api.ts b/x-pack/legacy/plugins/transform/public/app/hooks/__mocks__/use_api.ts new file mode 100644 index 0000000000000..d3f8057492201 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/hooks/__mocks__/use_api.ts @@ -0,0 +1,72 @@ +/* + * 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 { PreviewRequestBody, TransformId } from '../../common'; + +import { TransformEndpointRequest } from '../use_api_types'; + +const apiFactory = () => ({ + getTransforms(transformId?: TransformId): Promise { + return new Promise((resolve, reject) => { + resolve([]); + }); + }, + getTransformsStats(transformId?: TransformId): Promise { + if (transformId !== undefined) { + return new Promise((resolve, reject) => { + resolve([]); + }); + } + + return new Promise((resolve, reject) => { + resolve([]); + }); + }, + createTransform(transformId: TransformId, transformConfig: any): Promise { + return new Promise((resolve, reject) => { + resolve([]); + }); + }, + deleteTransforms(transformsInfo: TransformEndpointRequest[]) { + return new Promise((resolve, reject) => { + resolve([]); + }); + }, + getTransformsPreview(obj: PreviewRequestBody): Promise { + return new Promise((resolve, reject) => { + resolve([]); + }); + }, + startTransforms(transformsInfo: TransformEndpointRequest[]) { + return new Promise((resolve, reject) => { + resolve([]); + }); + }, + stopTransforms(transformsInfo: TransformEndpointRequest[]) { + return new Promise((resolve, reject) => { + resolve([]); + }); + }, + getTransformAuditMessages(transformId: TransformId): Promise { + return new Promise((resolve, reject) => { + resolve([]); + }); + }, + esSearch(payload: any) { + return new Promise((resolve, reject) => { + resolve([]); + }); + }, + getIndices() { + return new Promise((resolve, reject) => { + resolve([]); + }); + }, +}); + +export const useApi = () => { + return apiFactory(); +}; diff --git a/x-pack/legacy/plugins/transform/public/app/hooks/index.ts b/x-pack/legacy/plugins/transform/public/app/hooks/index.ts new file mode 100644 index 0000000000000..7981f560a525f --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/hooks/index.ts @@ -0,0 +1,11 @@ +/* + * 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 { useApi } from './use_api'; +export { useGetTransforms } from './use_get_transforms'; +export { useDeleteTransforms } from './use_delete_transform'; +export { useStartTransforms } from './use_start_transform'; +export { useStopTransforms } from './use_stop_transform'; diff --git a/x-pack/legacy/plugins/transform/public/app/hooks/use_api.ts b/x-pack/legacy/plugins/transform/public/app/hooks/use_api.ts new file mode 100644 index 0000000000000..c71299eccb34d --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/hooks/use_api.ts @@ -0,0 +1,103 @@ +/* + * 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 { useAppDependencies } from '../app_dependencies'; + +import { PreviewRequestBody, TransformId } from '../common'; + +import { http } from '../services/http_service'; + +import { EsIndex, TransformEndpointRequest, TransformEndpointResult } from './use_api_types'; + +const apiFactory = (basePath: string, indicesBasePath: string) => ({ + getTransforms(transformId?: TransformId): Promise { + const transformIdString = transformId !== undefined ? `/${transformId}` : ''; + return http({ + url: `${basePath}/transforms${transformIdString}`, + method: 'GET', + }); + }, + getTransformsStats(transformId?: TransformId): Promise { + if (transformId !== undefined) { + return http({ + url: `${basePath}/transforms/${transformId}/_stats`, + method: 'GET', + }); + } + + return http({ + url: `${basePath}/transforms/_stats`, + method: 'GET', + }); + }, + createTransform(transformId: TransformId, transformConfig: any): Promise { + return http({ + url: `${basePath}/transforms/${transformId}`, + method: 'PUT', + data: transformConfig, + }); + }, + deleteTransforms(transformsInfo: TransformEndpointRequest[]) { + return http({ + url: `${basePath}/delete_transforms`, + method: 'POST', + data: transformsInfo, + }) as Promise; + }, + getTransformsPreview(obj: PreviewRequestBody): Promise { + return http({ + url: `${basePath}/transforms/_preview`, + method: 'POST', + data: obj, + }); + }, + startTransforms(transformsInfo: TransformEndpointRequest[]) { + return http({ + url: `${basePath}/start_transforms`, + method: 'POST', + data: { + transformsInfo, + }, + }) as Promise; + }, + stopTransforms(transformsInfo: TransformEndpointRequest[]) { + return http({ + url: `${basePath}/stop_transforms`, + method: 'POST', + data: { + transformsInfo, + }, + }) as Promise; + }, + getTransformAuditMessages(transformId: TransformId): Promise { + return http({ + url: `${basePath}/transforms/${transformId}/messages`, + method: 'GET', + }); + }, + esSearch(payload: any) { + return http({ + url: `${basePath}/es_search`, + method: 'POST', + data: payload, + }) as Promise; + }, + getIndices() { + return http({ + url: `${indicesBasePath}/index_management/indices`, + method: 'GET', + }) as Promise; + }, +}); + +export const useApi = () => { + const appDeps = useAppDependencies(); + + const basePath = appDeps.core.http.basePath.prepend('/api/transform'); + const indicesBasePath = appDeps.core.http.basePath.prepend('/api'); + + return apiFactory(basePath, indicesBasePath); +}; diff --git a/x-pack/legacy/plugins/transform/public/app/hooks/use_api_types.ts b/x-pack/legacy/plugins/transform/public/app/hooks/use_api_types.ts new file mode 100644 index 0000000000000..d0f81a058b7b3 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/hooks/use_api_types.ts @@ -0,0 +1,25 @@ +/* + * 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 { TransformId, TRANSFORM_STATE } from '../common'; + +export interface EsIndex { + name: string; +} + +export interface TransformEndpointRequest { + id: TransformId; + state?: TRANSFORM_STATE; +} + +export interface ResultData { + success: boolean; + error?: any; +} + +export interface TransformEndpointResult { + [key: string]: ResultData; +} diff --git a/x-pack/legacy/plugins/transform/public/app/hooks/use_delete_transform.ts b/x-pack/legacy/plugins/transform/public/app/hooks/use_delete_transform.ts new file mode 100644 index 0000000000000..de9c92e758aa3 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/hooks/use_delete_transform.ts @@ -0,0 +1,56 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { toastNotifications } from 'ui/notify'; + +import { TransformListRow, refreshTransformList$, REFRESH_TRANSFORM_LIST_STATE } from '../common'; + +import { useApi } from './use_api'; +import { TransformEndpointRequest, TransformEndpointResult } from './use_api_types'; + +export const useDeleteTransforms = () => { + const api = useApi(); + + return async (transforms: TransformListRow[]) => { + const transformsInfo: TransformEndpointRequest[] = transforms.map(tf => ({ + id: tf.config.id, + state: tf.stats.state, + })); + + try { + const results: TransformEndpointResult = await api.deleteTransforms(transformsInfo); + for (const transformId in results) { + // hasOwnProperty check to ensure only properties on object itself, and not its prototypes + if (results.hasOwnProperty(transformId)) { + if (results[transformId].success === true) { + toastNotifications.addSuccess( + i18n.translate('xpack.transform.transformList.deleteTransformSuccessMessage', { + defaultMessage: 'Request to delete transform {transformId} acknowledged.', + values: { transformId }, + }) + ); + } else { + toastNotifications.addDanger( + i18n.translate('xpack.transform.transformList.deleteTransformErrorMessage', { + defaultMessage: 'An error occurred deleting the transform {transformId}', + values: { transformId }, + }) + ); + } + } + } + + refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH); + } catch (e) { + toastNotifications.addDanger( + i18n.translate('xpack.transform.transformList.deleteTransformGenericErrorMessage', { + defaultMessage: 'An error occurred calling the API endpoint to delete transforms.', + }) + ); + } + }; +}; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/services/transform_service/get_transforms.ts b/x-pack/legacy/plugins/transform/public/app/hooks/use_get_transforms.ts similarity index 65% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/services/transform_service/get_transforms.ts rename to x-pack/legacy/plugins/transform/public/app/hooks/use_get_transforms.ts index 34ee8f0797cfb..df2ce6b56a5af 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/services/transform_service/get_transforms.ts +++ b/x-pack/legacy/plugins/transform/public/app/hooks/use_get_transforms.ts @@ -4,31 +4,30 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ml } from '../../../../../services/ml_api_service'; import { - DataFrameTransformListRow, - DataFrameTransformStats, - DATA_FRAME_MODE, - isDataFrameTransformStats, - DataFrameTransformPivotConfig, + TransformListRow, + TransformStats, + TRANSFORM_MODE, + isTransformStats, + TransformPivotConfig, refreshTransformList$, REFRESH_TRANSFORM_LIST_STATE, -} from '../../../../common'; +} from '../common'; -interface GetDataFrameTransformsResponse { +import { useApi } from './use_api'; + +interface GetTransformsResponse { count: number; - transforms: DataFrameTransformPivotConfig[]; + transforms: TransformPivotConfig[]; } -interface GetDataFrameTransformsStatsResponseOk { +interface GetTransformsStatsResponseOk { node_failures?: object; count: number; - transforms: DataFrameTransformStats[]; + transforms: TransformStats[]; } -const isGetDataFrameTransformsStatsResponseOk = ( - arg: any -): arg is GetDataFrameTransformsStatsResponseOk => { +const isGetTransformsStatsResponseOk = (arg: any): arg is GetTransformsStatsResponseOk => { return ( {}.hasOwnProperty.call(arg, 'count') && {}.hasOwnProperty.call(arg, 'transforms') && @@ -36,26 +35,26 @@ const isGetDataFrameTransformsStatsResponseOk = ( ); }; -interface GetDataFrameTransformsStatsResponseError { +interface GetTransformsStatsResponseError { statusCode: number; error: string; message: string; } -type GetDataFrameTransformsStatsResponse = - | GetDataFrameTransformsStatsResponseOk - | GetDataFrameTransformsStatsResponseError; +type GetTransformsStatsResponse = GetTransformsStatsResponseOk | GetTransformsStatsResponseError; export type GetTransforms = (forceRefresh?: boolean) => void; -export const getTransformsFactory = ( - setTransforms: React.Dispatch>, +export const useGetTransforms = ( + setTransforms: React.Dispatch>, setErrorMessage: React.Dispatch< - React.SetStateAction + React.SetStateAction >, setIsInitialized: React.Dispatch>, blockRefresh: boolean ): GetTransforms => { + const api = useApi(); + let concurrentLoads = 0; const getTransforms = async (forceRefresh = false) => { @@ -68,18 +67,18 @@ export const getTransformsFactory = ( } try { - const transformConfigs: GetDataFrameTransformsResponse = await ml.dataFrame.getDataFrameTransforms(); - const transformStats: GetDataFrameTransformsStatsResponse = await ml.dataFrame.getDataFrameTransformsStats(); + const transformConfigs: GetTransformsResponse = await api.getTransforms(); + const transformStats: GetTransformsStatsResponse = await api.getTransformsStats(); const tableRows = transformConfigs.transforms.reduce( (reducedtableRows, config) => { - const stats = isGetDataFrameTransformsStatsResponseOk(transformStats) + const stats = isGetTransformsStatsResponseOk(transformStats) ? transformStats.transforms.find(d => config.id === d.id) : undefined; // A newly created transform might not have corresponding stats yet. // If that's the case we just skip the transform and don't add it to the transform list yet. - if (!isDataFrameTransformStats(stats)) { + if (!isTransformStats(stats)) { return reducedtableRows; } @@ -89,13 +88,13 @@ export const getTransformsFactory = ( config, mode: typeof config.sync !== 'undefined' - ? DATA_FRAME_MODE.CONTINUOUS - : DATA_FRAME_MODE.BATCH, + ? TRANSFORM_MODE.CONTINUOUS + : TRANSFORM_MODE.BATCH, stats, }); return reducedtableRows; }, - [] as DataFrameTransformListRow[] + [] as TransformListRow[] ); setTransforms(tableRows); diff --git a/x-pack/legacy/plugins/transform/public/app/hooks/use_start_transform.ts b/x-pack/legacy/plugins/transform/public/app/hooks/use_start_transform.ts new file mode 100644 index 0000000000000..d6b216accebd9 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/hooks/use_start_transform.ts @@ -0,0 +1,48 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { toastNotifications } from 'ui/notify'; + +import { TransformListRow, refreshTransformList$, REFRESH_TRANSFORM_LIST_STATE } from '../common'; + +import { useApi } from './use_api'; +import { TransformEndpointRequest, TransformEndpointResult } from './use_api_types'; + +export const useStartTransforms = () => { + const api = useApi(); + + return async (transforms: TransformListRow[]) => { + const transformsInfo: TransformEndpointRequest[] = transforms.map(tf => ({ + id: tf.config.id, + state: tf.stats.state, + })); + const results: TransformEndpointResult = await api.startTransforms(transformsInfo); + + for (const transformId in results) { + // hasOwnProperty check to ensure only properties on object itself, and not its prototypes + if (results.hasOwnProperty(transformId)) { + if (results[transformId].success === true) { + toastNotifications.addSuccess( + i18n.translate('xpack.transform.transformList.startTransformSuccessMessage', { + defaultMessage: 'Request to start transform {transformId} acknowledged.', + values: { transformId }, + }) + ); + } else { + toastNotifications.addDanger( + i18n.translate('xpack.transform.transformList.startTransformErrorMessage', { + defaultMessage: 'An error occurred starting the transform {transformId}', + values: { transformId }, + }) + ); + } + } + } + + refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH); + }; +}; diff --git a/x-pack/legacy/plugins/transform/public/app/hooks/use_stop_transform.ts b/x-pack/legacy/plugins/transform/public/app/hooks/use_stop_transform.ts new file mode 100644 index 0000000000000..bf6edf995bb1f --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/hooks/use_stop_transform.ts @@ -0,0 +1,48 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { toastNotifications } from 'ui/notify'; + +import { TransformListRow, refreshTransformList$, REFRESH_TRANSFORM_LIST_STATE } from '../common'; + +import { useApi } from './use_api'; +import { TransformEndpointRequest, TransformEndpointResult } from './use_api_types'; + +export const useStopTransforms = () => { + const api = useApi(); + + return async (transforms: TransformListRow[]) => { + const transformsInfo: TransformEndpointRequest[] = transforms.map(df => ({ + id: df.config.id, + state: df.stats.state, + })); + const results: TransformEndpointResult = await api.stopTransforms(transformsInfo); + + for (const transformId in results) { + // hasOwnProperty check to ensure only properties on object itself, and not its prototypes + if (results.hasOwnProperty(transformId)) { + if (results[transformId].success === true) { + toastNotifications.addSuccess( + i18n.translate('xpack.transform.transformList.stopTransformSuccessMessage', { + defaultMessage: 'Request to stop data frame transform {transformId} acknowledged.', + values: { transformId }, + }) + ); + } else { + toastNotifications.addDanger( + i18n.translate('xpack.transform.transformList.stopTransformErrorMessage', { + defaultMessage: 'An error occurred stopping the data frame transform {transformId}', + values: { transformId }, + }) + ); + } + } + } + + refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH); + }; +}; diff --git a/x-pack/legacy/plugins/transform/public/app/index.scss b/x-pack/legacy/plugins/transform/public/app/index.scss new file mode 100644 index 0000000000000..28459d06b5cb1 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/index.scss @@ -0,0 +1,17 @@ +// Import the EUI global scope so we can use EUI constants +@import 'src/legacy/ui/public/styles/_styling_constants'; + +// Transform plugin styles + +// Prefix all styles with "transform" to avoid conflicts. +// Examples +// transform +// transform__legend +// transform__legend--small +// transform__legend-isLoading + +@import 'sections/create_transform/components/aggregation_list/index'; +@import 'sections/create_transform/components/group_by_list/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'; diff --git a/x-pack/legacy/plugins/transform/public/app/lib/authorization/components/authorization_provider.tsx b/x-pack/legacy/plugins/transform/public/app/lib/authorization/components/authorization_provider.tsx new file mode 100644 index 0000000000000..84c7d616c19b8 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/lib/authorization/components/authorization_provider.tsx @@ -0,0 +1,90 @@ +/* + * 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 React, { createContext } from 'react'; +import { useRequest } from '../../../services/http/use_request'; +import { hasPrivilegeFactory, Capabilities, Privileges } from './common'; + +interface ApiError { + data: { + error: string; + cause?: string[]; + message?: string; + }; +} + +interface Authorization { + isLoading: boolean; + apiError: ApiError | null; + privileges: Privileges; + capabilities: Capabilities; +} + +const initialCapabalities: Capabilities = { + canGetTransform: false, + canDeleteTransform: false, + canPreviewTransform: false, + canCreateTransform: false, + canStartStopTransform: false, +}; + +const initialValue: Authorization = { + isLoading: true, + apiError: null, + privileges: { + hasAllPrivileges: false, + missingPrivileges: {}, + }, + capabilities: initialCapabalities, +}; + +export const AuthorizationContext = createContext({ ...initialValue }); + +interface Props { + privilegesEndpoint: string; + children: React.ReactNode; +} + +export const AuthorizationProvider = ({ privilegesEndpoint, children }: Props) => { + const { isLoading, error, data: privilegesData } = useRequest({ + path: privilegesEndpoint, + method: 'get', + }); + + const value = { + isLoading, + privileges: isLoading ? { ...initialValue.privileges } : privilegesData, + capabilities: { ...initialCapabalities }, + apiError: error ? (error as ApiError) : null, + }; + + const hasPrivilege = hasPrivilegeFactory(value.privileges); + + value.capabilities.canGetTransform = + hasPrivilege(['cluster', 'cluster:monitor/data_frame/get']) && + hasPrivilege(['cluster', 'cluster:monitor/data_frame/stats/get']); + + value.capabilities.canCreateTransform = hasPrivilege(['cluster', 'cluster:admin/data_frame/put']); + + value.capabilities.canDeleteTransform = hasPrivilege([ + 'cluster', + 'cluster:admin/data_frame/delete', + ]); + + value.capabilities.canPreviewTransform = hasPrivilege([ + 'cluster', + 'cluster:admin/data_frame/preview', + ]); + + value.capabilities.canStartStopTransform = + hasPrivilege(['cluster', 'cluster:admin/data_frame/start']) && + hasPrivilege(['cluster', 'cluster:admin/data_frame/start_task']) && + hasPrivilege(['cluster', 'cluster:admin/data_frame/stop']); + + return ( + {children} + ); +}; diff --git a/x-pack/legacy/plugins/transform/public/app/lib/authorization/components/common.ts b/x-pack/legacy/plugins/transform/public/app/lib/authorization/components/common.ts new file mode 100644 index 0000000000000..5aec2ac041db3 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/lib/authorization/components/common.ts @@ -0,0 +1,80 @@ +/* + * 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 { i18n } from '@kbn/i18n'; + +export interface Capabilities { + canGetTransform: boolean; + canDeleteTransform: boolean; + canPreviewTransform: boolean; + canCreateTransform: boolean; + canStartStopTransform: boolean; +} + +export type Privilege = [string, string]; + +export interface Privileges { + hasAllPrivileges: boolean; + missingPrivileges: MissingPrivileges; +} + +export interface MissingPrivileges { + [key: string]: string[] | undefined; +} +export const toArray = (value: string | string[]): string[] => + Array.isArray(value) ? value : [value]; + +export const hasPrivilegeFactory = (privileges: Privileges) => (privilege: Privilege) => { + const [section, requiredPrivilege] = privilege; + if (!privileges.missingPrivileges[section]) { + // if the section does not exist in our missingPrivileges, everything is OK + return true; + } + if (privileges.missingPrivileges[section]!.length === 0) { + return true; + } + if (requiredPrivilege === '*') { + // If length > 0 and we require them all... KO + return false; + } + // If we require _some_ privilege, we make sure that the one + // we require is *not* in the missingPrivilege array + return !privileges.missingPrivileges[section]!.includes(requiredPrivilege); +}; + +// create the text for button's tooltips if the user +// doesn't have the permission to press that button +export function createCapabilityFailureMessage(capability: keyof Capabilities) { + let message = ''; + + switch (capability) { + case 'canCreateTransform': + message = i18n.translate('xpack.transform.capability.noPermission.createTransformTooltip', { + defaultMessage: 'You do not have permission to create transforms.', + }); + break; + case 'canStartStopTransform': + message = i18n.translate( + 'xpack.transform.capability.noPermission.startOrStopTransformTooltip', + { + defaultMessage: 'You do not have permission to start or stop transforms.', + } + ); + break; + case 'canDeleteTransform': + message = i18n.translate('xpack.transform.capability.noPermission.deleteTransformTooltip', { + defaultMessage: 'You do not have permission to delete transforms.', + }); + break; + } + + return i18n.translate('xpack.transform.capability.pleaseContactAdministratorTooltip', { + defaultMessage: '{message} Please contact your administrator.', + values: { + message, + }, + }); +} diff --git a/x-pack/legacy/plugins/transform/public/app/lib/authorization/components/index.ts b/x-pack/legacy/plugins/transform/public/app/lib/authorization/components/index.ts new file mode 100644 index 0000000000000..9b37fa1b4393d --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/lib/authorization/components/index.ts @@ -0,0 +1,10 @@ +/* + * 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 { createCapabilityFailureMessage, Privileges } from './common'; +export { AuthorizationProvider, AuthorizationContext } from './authorization_provider'; +export { PrivilegesWrapper } from './with_privileges'; +export { NotAuthorizedSection } from './not_authorized_section'; diff --git a/x-pack/legacy/plugins/transform/public/app/lib/authorization/components/not_authorized_section.tsx b/x-pack/legacy/plugins/transform/public/app/lib/authorization/components/not_authorized_section.tsx new file mode 100644 index 0000000000000..3fc13245708e8 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/lib/authorization/components/not_authorized_section.tsx @@ -0,0 +1,17 @@ +/* + * 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 React from 'react'; +import { EuiEmptyPrompt } from '@elastic/eui'; + +interface Props { + title: React.ReactNode; + message: React.ReactNode | string; +} + +export const NotAuthorizedSection = ({ title, message }: Props) => ( + {title}} body={

{message}

} /> +); diff --git a/x-pack/legacy/plugins/transform/public/app/lib/authorization/components/with_privileges.tsx b/x-pack/legacy/plugins/transform/public/app/lib/authorization/components/with_privileges.tsx new file mode 100644 index 0000000000000..8bf7ea66d28b1 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/lib/authorization/components/with_privileges.tsx @@ -0,0 +1,129 @@ +/* + * 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 React, { useContext, FC } from 'react'; + +import { EuiPageContent } from '@elastic/eui'; + +import { FormattedMessage } from '@kbn/i18n/react'; + +import { SectionLoading } from '../../../components'; + +import { AuthorizationContext } from './authorization_provider'; +import { NotAuthorizedSection } from './not_authorized_section'; +import { hasPrivilegeFactory, toArray, MissingPrivileges, Privilege } from './common'; + +interface Props { + /** + * Each required privilege must have the format "section.privilege". + * To indicate that *all* privileges from a section are required, we can use the asterix + * e.g. "index.*" + */ + privileges: string | string[]; + children: (childrenProps: { + isLoading: boolean; + hasPrivileges: boolean; + privilegesMissing: MissingPrivileges; + }) => JSX.Element; +} + +export const WithPrivileges = ({ privileges: requiredPrivileges, children }: Props) => { + const { isLoading, privileges } = useContext(AuthorizationContext); + + const privilegesToArray: Privilege[] = toArray(requiredPrivileges).map(p => { + const [section, privilege] = p.split('.'); + if (!privilege) { + // Oh! we forgot to use the dot "." notation. + throw new Error('Required privilege must have the format "section.privilege"'); + } + return [section, privilege]; + }); + + const hasPrivilege = hasPrivilegeFactory(privileges); + const hasPrivileges = isLoading ? false : privilegesToArray.every(hasPrivilege); + + const privilegesMissing = privilegesToArray.reduce( + (acc, [section, privilege]) => { + if (privilege === '*') { + acc[section] = privileges.missingPrivileges[section] || []; + } else if ( + privileges.missingPrivileges[section] && + privileges.missingPrivileges[section]!.includes(privilege) + ) { + const missing: string[] = acc[section] || []; + acc[section] = [...missing, privilege]; + } + + return acc; + }, + {} as MissingPrivileges + ); + + return children({ isLoading, hasPrivileges, privilegesMissing }); +}; + +interface MissingClusterPrivilegesProps { + missingPrivileges: string; + privilegesCount: number; +} + +const MissingClusterPrivileges: FC = ({ + missingPrivileges, + privilegesCount, +}) => ( + + + } + message={ + + } + /> + +); + +export const PrivilegesWrapper: FC<{ privileges: string | string[] }> = ({ + children, + privileges, +}) => ( + + {({ isLoading, hasPrivileges, privilegesMissing }) => { + if (isLoading) { + return ( + + + + ); + } + + if (!hasPrivileges) { + return ( + + ); + } + + return <>{children}; + }} + +); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/page.test.mocks.ts b/x-pack/legacy/plugins/transform/public/app/lib/authorization/index.ts similarity index 82% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/page.test.mocks.ts rename to x-pack/legacy/plugins/transform/public/app/lib/authorization/index.ts index 46178a7d02977..73bbde465146c 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/page.test.mocks.ts +++ b/x-pack/legacy/plugins/transform/public/app/lib/authorization/index.ts @@ -4,6 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -jest.mock('ui/timefilter', () => { - return {}; -}); +export * from './components'; diff --git a/x-pack/legacy/plugins/transform/public/app/lib/kibana/common.ts b/x-pack/legacy/plugins/transform/public/app/lib/kibana/common.ts new file mode 100644 index 0000000000000..7291eba04057d --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/lib/kibana/common.ts @@ -0,0 +1,119 @@ +/* + * 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. + */ + +// @ts-ignore +import { buildEsQuery, getEsQueryConfig } from '@kbn/es-query'; + +import { SavedObjectsClientContract, UiSettingsClientContract } from 'src/core/public'; + +import { + IndexPattern as IndexPatternType, + IndexPatterns as IndexPatternsType, +} from 'ui/index_patterns'; + +type IndexPatternId = string; +type SavedSearchId = string; + +let indexPatternCache = []; +let fullIndexPatterns; +let currentIndexPattern = null; +let currentSavedSearch = null; + +export let refreshIndexPatterns: () => Promise; + +export function loadIndexPatterns( + savedObjectsClient: SavedObjectsClientContract, + indexPatterns: IndexPatternsType +) { + fullIndexPatterns = indexPatterns; + return savedObjectsClient + .find({ + type: 'index-pattern', + fields: ['id', 'title', 'type', 'fields'], + perPage: 10000, + }) + .then(response => { + indexPatternCache = response.savedObjects; + + if (refreshIndexPatterns === null) { + refreshIndexPatterns = () => { + return new Promise((resolve, reject) => { + loadIndexPatterns(savedObjectsClient, indexPatterns) + .then(resp => { + resolve(resp); + }) + .catch(error => { + reject(error); + }); + }); + }; + } + + return indexPatternCache; + }); +} + +type CombinedQuery = Record<'bool', any> | unknown; + +export function loadCurrentIndexPattern( + indexPatterns: IndexPatternsType, + indexPatternId: IndexPatternId +) { + fullIndexPatterns = indexPatterns; + currentIndexPattern = fullIndexPatterns.get(indexPatternId); + return currentIndexPattern; +} + +export function loadCurrentSavedSearch(savedSearches: any, savedSearchId: SavedSearchId) { + currentSavedSearch = savedSearches.get(savedSearchId); + return currentSavedSearch; +} + +// Helper for creating the items used for searching and job creation. +export function createSearchItems( + indexPattern: IndexPatternType | undefined, + savedSearch: any, + config: UiSettingsClientContract +) { + // query is only used by the data visualizer as it needs + // a lucene query_string. + // Using a blank query will cause match_all:{} to be used + // when passed through luceneStringToDsl + let query = { + query: '', + language: 'lucene', + }; + + let combinedQuery: CombinedQuery = { + bool: { + must: [ + { + match_all: {}, + }, + ], + }, + }; + + if (indexPattern === undefined && savedSearch !== null && savedSearch.id !== undefined) { + const searchSource = savedSearch.searchSource; + indexPattern = searchSource.getField('index'); + + query = searchSource.getField('query'); + const fs = searchSource.getField('filter'); + + const filters = fs.length ? fs : []; + + const esQueryConfigs = getEsQueryConfig(config); + combinedQuery = buildEsQuery(indexPattern, [query], filters, esQueryConfigs); + } + + return { + indexPattern, + savedSearch, + query, + combinedQuery, + }; +} diff --git a/x-pack/legacy/plugins/transform/public/app/lib/kibana/index.ts b/x-pack/legacy/plugins/transform/public/app/lib/kibana/index.ts new file mode 100644 index 0000000000000..08cf7d0046e97 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/lib/kibana/index.ts @@ -0,0 +1,14 @@ +/* + * 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 { + isKibanaContextInitialized, + KibanaContext, + KibanaContextValue, + SavedSearchQuery, +} from './kibana_context'; +export { KibanaProvider } from './kibana_provider'; +export { useCurrentIndexPattern } from './use_current_index_pattern'; diff --git a/x-pack/legacy/plugins/transform/public/app/lib/kibana/kibana_context.tsx b/x-pack/legacy/plugins/transform/public/app/lib/kibana/kibana_context.tsx new file mode 100644 index 0000000000000..2e4f0dfd4696a --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/lib/kibana/kibana_context.tsx @@ -0,0 +1,43 @@ +/* + * 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 { createContext } from 'react'; + +import { + IndexPattern as IndexPatternType, + IndexPatterns as IndexPatternsType, +} from 'ui/index_patterns'; + +import { SavedSearch } from '../../../../../../../../src/legacy/core_plugins/kibana/public/discover/types'; +import { KibanaConfig } from '../../../../../../../../src/legacy/server/kbn_server'; + +// set() method is missing in original d.ts +export interface KibanaConfigTypeFix extends KibanaConfig { + set(key: string, value: any): void; +} + +interface UninitializedKibanaContextValue { + initialized: boolean; +} +interface InitializedKibanaContextValue { + combinedQuery: any; + currentIndexPattern: IndexPatternType; + currentSavedSearch: SavedSearch; + indexPatterns: IndexPatternsType; + initialized: boolean; + kbnBaseUrl: string; + kibanaConfig: KibanaConfigTypeFix; +} + +export type KibanaContextValue = UninitializedKibanaContextValue | InitializedKibanaContextValue; + +export function isKibanaContextInitialized(arg: any): arg is InitializedKibanaContextValue { + return arg.initialized; +} + +export type SavedSearchQuery = object; + +export const KibanaContext = createContext({ initialized: false }); diff --git a/x-pack/legacy/plugins/transform/public/app/lib/kibana/kibana_provider.tsx b/x-pack/legacy/plugins/transform/public/app/lib/kibana/kibana_provider.tsx new file mode 100644 index 0000000000000..d8fc8b30ab120 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/lib/kibana/kibana_provider.tsx @@ -0,0 +1,81 @@ +/* + * 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 React, { useEffect, useState, FC } from 'react'; + +import { npStart } from 'ui/new_platform'; + +import { setup as data } from '../../../../../../../../src/legacy/core_plugins/data/public/legacy'; + +import { useAppDependencies } from '../../app_dependencies'; + +import { + createSearchItems, + loadCurrentIndexPattern, + loadIndexPatterns, + loadCurrentSavedSearch, +} from './common'; + +import { KibanaContext, KibanaContextValue } from './kibana_context'; + +const { indexPatterns } = data.indexPatterns; +const savedObjectsClient = npStart.core.savedObjects.client; + +interface Props { + savedObjectId: string; +} + +export const KibanaProvider: FC = ({ savedObjectId, children }) => { + const appDeps = useAppDependencies(); + const savedSearches = appDeps.plugins.savedSearches.getClient(); + + const [contextValue, setContextValue] = useState({ initialized: false }); + + async function fetchSavedObject(id: string) { + await loadIndexPatterns(savedObjectsClient, indexPatterns); + + let fetchedIndexPattern; + let fetchedSavedSearch; + + try { + fetchedIndexPattern = await loadCurrentIndexPattern(indexPatterns, id); + } catch (e) { + // Just let fetchedIndexPattern stay undefined in case it doesn't exist. + } + + try { + fetchedSavedSearch = await loadCurrentSavedSearch(savedSearches, id); + } catch (e) { + // Just let fetchedSavedSearch stay undefined in case it doesn't exist. + } + + const kibanaConfig = npStart.core.uiSettings; + + const { indexPattern, savedSearch, combinedQuery } = createSearchItems( + fetchedIndexPattern, + fetchedSavedSearch, + kibanaConfig + ); + + const kibanaContext = { + combinedQuery, + currentIndexPattern: indexPattern, + currentSavedSearch: savedSearch, + indexPatterns, + initialized: true, + kbnBaseUrl: npStart.core.injectedMetadata.getBasePath(), + kibanaConfig, + }; + + setContextValue(kibanaContext); + } + + useEffect(() => { + fetchSavedObject(savedObjectId); + }, [savedObjectId]); + + return {children}; +}; diff --git a/x-pack/legacy/plugins/transform/public/app/lib/kibana/use_current_index_pattern.ts b/x-pack/legacy/plugins/transform/public/app/lib/kibana/use_current_index_pattern.ts new file mode 100644 index 0000000000000..e4b0725c324b4 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/lib/kibana/use_current_index_pattern.ts @@ -0,0 +1,19 @@ +/* + * 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 { useContext } from 'react'; + +import { isKibanaContextInitialized, KibanaContext } from './kibana_context'; + +export const useCurrentIndexPattern = () => { + const context = useContext(KibanaContext); + + if (!isKibanaContextInitialized(context)) { + throw new Error('currentIndexPattern is undefined'); + } + + return context.currentIndexPattern; +}; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_dropdown/dropdown.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_dropdown/dropdown.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_dropdown/dropdown.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_dropdown/dropdown.tsx diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_dropdown/index.ts b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_dropdown/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_dropdown/index.ts rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_dropdown/index.ts diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_list/__snapshots__/agg_label_form.test.tsx.snap b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/agg_label_form.test.tsx.snap similarity index 83% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_list/__snapshots__/agg_label_form.test.tsx.snap rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/agg_label_form.test.tsx.snap index 0ff0c497a5580..835ed9dc9f849 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_list/__snapshots__/agg_label_form.test.tsx.snap +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/agg_label_form.test.tsx.snap @@ -1,13 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Data Frame: Date histogram aggregation 1`] = ` +exports[`Transform: Date histogram aggregation 1`] = ` Date histogram aggregation 1`] = ` Date histogram aggregation 1`] = ` closePopover={[Function]} display="inlineBlock" hasArrow={true} - id="mlFormPopover" + id="transformFormPopover" isOpen={false} ownFocus={true} panelPaddingSize="m" @@ -53,7 +53,7 @@ exports[`Data Frame: Date histogram aggregation 1`] = ` Minimal initialization 1`] = ` +exports[`Transform: Minimal initialization 1`] = ` Minimal initialization 1`] = ` +exports[`Transform: Minimal initialization 1`] = ` Minimal initialization 1`] = ` +exports[`Transform: Aggregation Minimal initialization 1`] = ` ', () => { +describe('Transform: ', () => { test('Date histogram aggregation', () => { const item: PivotAggsConfig = { agg: PIVOT_SUPPORTED_AGGS.CARDINALITY, diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_list/agg_label_form.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_list/agg_label_form.tsx similarity index 82% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_list/agg_label_form.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_list/agg_label_form.tsx index 5d36b1c6238b1..312d36637c8e2 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_list/agg_label_form.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_list/agg_label_form.tsx @@ -38,16 +38,16 @@ export const AggLabelForm: React.SFC = ({ return ( - + {item.aggName} - + = ({ /> - + ', () => { +describe('Transform: ', () => { test('Minimal initialization', () => { const item: PivotAggsConfig = { agg: PIVOT_SUPPORTED_AGGS.AVG, diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_list/list_form.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_list/list_form.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_list/list_form.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_list/list_form.tsx diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_list/list_summary.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_list/list_summary.test.tsx similarity index 94% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_list/list_summary.test.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_list/list_summary.test.tsx index 35c657595ca23..923d52ba5cec1 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_list/list_summary.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_list/list_summary.test.tsx @@ -11,7 +11,7 @@ import { PivotAggsConfig, PIVOT_SUPPORTED_AGGS } from '../../../../common'; import { AggListSummary, AggListSummaryProps } from './list_summary'; -describe('Data Frame: ', () => { +describe('Transform: ', () => { test('Minimal initialization', () => { const item: PivotAggsConfig = { agg: PIVOT_SUPPORTED_AGGS.AVG, diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_list/list_summary.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_list/list_summary.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_list/list_summary.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_list/list_summary.tsx diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_list/popover_form.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_list/popover_form.test.tsx similarity index 94% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_list/popover_form.test.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_list/popover_form.test.tsx index a3f6f85a7cf63..b3e770a269681 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_list/popover_form.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_list/popover_form.test.tsx @@ -11,7 +11,7 @@ import { AggName, PIVOT_SUPPORTED_AGGS, PivotAggsConfig } from '../../../../comm import { PopoverForm } from './popover_form'; -describe('Data Frame: Aggregation ', () => { +describe('Transform: Aggregation ', () => { test('Minimal initialization', () => { const defaultData: PivotAggsConfig = { agg: PIVOT_SUPPORTED_AGGS.CARDINALITY, diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_list/popover_form.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_list/popover_form.tsx similarity index 87% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_list/popover_form.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_list/popover_form.tsx index cf538678579ca..e7f79b240d81a 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/aggregation_list/popover_form.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_list/popover_form.tsx @@ -75,7 +75,7 @@ export const PopoverForm: React.SFC = ({ let validAggName = isAggName(aggName); if (!validAggName) { - aggNameError = i18n.translate('xpack.ml.dataframe.agg.popoverForm.aggNameInvalidCharError', { + aggNameError = i18n.translate('xpack.transform.agg.popoverForm.aggNameInvalidCharError', { defaultMessage: 'Invalid name. The characters "[", "]", and ">" are not allowed and the name must not start or end with a space character.', }); @@ -83,7 +83,7 @@ export const PopoverForm: React.SFC = ({ if (validAggName) { validAggName = !otherAggNames.includes(aggName); - aggNameError = i18n.translate('xpack.ml.dataframe.agg.popoverForm.aggNameAlreadyUsedError', { + aggNameError = i18n.translate('xpack.transform.agg.popoverForm.aggNameAlreadyUsedError', { defaultMessage: 'Another aggregation already uses that name.', }); } @@ -97,13 +97,13 @@ export const PopoverForm: React.SFC = ({ isInvalid={!validAggName} helpText={ isUnsupportedAgg - ? i18n.translate('xpack.ml.dataframe.agg.popoverForm.unsupportedAggregationHelpText', { + ? i18n.translate('xpack.transform.agg.popoverForm.unsupportedAggregationHelpText', { defaultMessage: 'Only the aggregation name can be edited in this form. Please use the advanced editor to edit the other parts of the aggregation.', }) : '' } - label={i18n.translate('xpack.ml.dataframe.agg.popoverForm.nameLabel', { + label={i18n.translate('xpack.transform.agg.popoverForm.nameLabel', { defaultMessage: 'Aggregation name', })} > @@ -115,7 +115,7 @@ export const PopoverForm: React.SFC = ({ {availableAggs.length > 0 && ( @@ -128,7 +128,7 @@ export const PopoverForm: React.SFC = ({ )} {availableFields.length > 0 && ( @@ -156,7 +156,7 @@ export const PopoverForm: React.SFC = ({ isDisabled={!formValid} onClick={() => onChange({ ...defaultData, aggName, agg, field })} > - {i18n.translate('xpack.ml.dataframe.agg.popoverForm.submitButtonLabel', { + {i18n.translate('xpack.transform.agg.popoverForm.submitButtonLabel', { defaultMessage: 'Apply', })} diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/__snapshots__/group_by_label_form.test.tsx.snap b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/group_by_label_form.test.tsx.snap similarity index 81% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/__snapshots__/group_by_label_form.test.tsx.snap rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/group_by_label_form.test.tsx.snap index cc1957ce543a2..b0603efe50b5e 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/__snapshots__/group_by_label_form.test.tsx.snap +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/group_by_label_form.test.tsx.snap @@ -1,13 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Data Frame: Date histogram aggregation 1`] = ` +exports[`Transform: Date histogram aggregation 1`] = ` Date histogram aggregation 1`] = ` Date histogram aggregation 1`] = ` Date histogram aggregation 1`] = ` closePopover={[Function]} display="inlineBlock" hasArrow={true} - id="mlIntervalFormPopover" + id="transformIntervalFormPopover" isOpen={false} ownFocus={true} panelPaddingSize="m" @@ -65,7 +65,7 @@ exports[`Data Frame: Date histogram aggregation 1`] = ` Date histogram aggregation 1`] = ` `; -exports[`Data Frame: Histogram aggregation 1`] = ` +exports[`Transform: Histogram aggregation 1`] = ` Histogram aggregation 1`] = ` Histogram aggregation 1`] = ` Histogram aggregation 1`] = ` closePopover={[Function]} display="inlineBlock" hasArrow={true} - id="mlIntervalFormPopover" + id="transformIntervalFormPopover" isOpen={false} ownFocus={true} panelPaddingSize="m" @@ -143,7 +143,7 @@ exports[`Data Frame: Histogram aggregation 1`] = ` Histogram aggregation 1`] = ` `; -exports[`Data Frame: Terms aggregation 1`] = ` +exports[`Transform: Terms aggregation 1`] = ` Terms aggregation 1`] = ` Terms aggregation 1`] = ` closePopover={[Function]} display="inlineBlock" hasArrow={true} - id="mlIntervalFormPopover" + id="transformIntervalFormPopover" isOpen={false} ownFocus={true} panelPaddingSize="m" @@ -209,7 +209,7 @@ exports[`Data Frame: Terms aggregation 1`] = ` Date histogram aggregation 1`] = ` +exports[`Transform: Date histogram aggregation 1`] = ` Date histogram aggregation 1`] = ` Date histogram aggregation 1`] = ` `; -exports[`Data Frame: Histogram aggregation 1`] = ` +exports[`Transform: Histogram aggregation 1`] = ` Histogram aggregation 1`] = ` Histogram aggregation 1`] = ` `; -exports[`Data Frame: Terms aggregation 1`] = ` +exports[`Transform: Terms aggregation 1`] = ` Minimal initialization 1`] = ` +exports[`Transform: Minimal initialization 1`] = ` Minimal initialization 1`] = ` +exports[`Transform: Minimal initialization 1`] = ` Minimal initialization 1`] = ` +exports[`Transform: Group By Minimal initialization 1`] = ` ', () => { +describe('Transform: ', () => { test('Date histogram aggregation', () => { const item: PivotGroupByConfig = { agg: PIVOT_SUPPORTED_GROUP_BY_AGGS.DATE_HISTOGRAM, diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/group_by_label_form.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/group_by_label_form.tsx similarity index 78% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/group_by_label_form.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/group_by_label_form.tsx index c39846ce84940..bf52b2b4184c0 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/group_by_label_form.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/group_by_label_form.tsx @@ -52,28 +52,28 @@ export const GroupByLabelForm: React.SFC = ({ return ( - + {item.aggName} {interval !== undefined && ( - + {interval} )} - + setPopoverVisibility(!isPopoverVisible)} @@ -90,9 +90,9 @@ export const GroupByLabelForm: React.SFC = ({ /> - + ', () => { +describe('Transform: ', () => { test('Date histogram aggregation', () => { const item: PivotGroupByConfig = { agg: PIVOT_SUPPORTED_GROUP_BY_AGGS.DATE_HISTOGRAM, diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/group_by_label_summary.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/group_by_label_summary.tsx similarity index 85% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/group_by_label_summary.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/group_by_label_summary.tsx index 2936e6132d2d5..511eb091c6d42 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/group_by_label_summary.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/group_by_label_summary.tsx @@ -26,11 +26,14 @@ export const GroupByLabelSummary: React.SFC = ({ item, optionsDataId }) = return ( - + {optionsDataId} {interval !== undefined && ( - + {interval} diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/index.ts b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/index.ts rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/index.ts diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/list_form.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_form.test.tsx similarity index 94% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/list_form.test.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_form.test.tsx index 0eecf4e216995..67460b074acdd 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/list_form.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_form.test.tsx @@ -11,7 +11,7 @@ import { PivotGroupByConfig, PIVOT_SUPPORTED_GROUP_BY_AGGS } from '../../../../c import { GroupByListForm } from './list_form'; -describe('Data Frame: ', () => { +describe('Transform: ', () => { test('Minimal initialization', () => { const item: PivotGroupByConfig = { agg: PIVOT_SUPPORTED_GROUP_BY_AGGS.TERMS, diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/list_form.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_form.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/list_form.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_form.tsx diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/list_summary.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_summary.test.tsx similarity index 94% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/list_summary.test.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_summary.test.tsx index 4db0b109d60e9..d888feb160d30 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/list_summary.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_summary.test.tsx @@ -11,7 +11,7 @@ import { PivotGroupByConfig, PIVOT_SUPPORTED_GROUP_BY_AGGS } from '../../../../c import { GroupByListSummary } from './list_summary'; -describe('Data Frame: ', () => { +describe('Transform: ', () => { test('Minimal initialization', () => { const item: PivotGroupByConfig = { agg: PIVOT_SUPPORTED_GROUP_BY_AGGS.TERMS, diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/list_summary.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_summary.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/list_summary.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_summary.tsx diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/popover_form.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/popover_form.test.tsx similarity index 98% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/popover_form.test.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/popover_form.test.tsx index dae6781345209..090f3b19f47fb 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/popover_form.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/popover_form.test.tsx @@ -73,7 +73,7 @@ describe('isIntervalValid()', () => { }); }); -describe('Data Frame: Group By ', () => { +describe('Transform: Group By ', () => { test('Minimal initialization', () => { const defaultData: PivotGroupByConfig = { agg: PIVOT_SUPPORTED_GROUP_BY_AGGS.DATE_HISTOGRAM, diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/popover_form.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/popover_form.tsx similarity index 87% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/popover_form.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/popover_form.tsx index 7f2b746f07640..09290cce01704 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/group_by_list/popover_form.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/popover_form.tsx @@ -142,23 +142,17 @@ export const PopoverForm: React.SFC = ({ let validAggName = isAggName(aggName); if (!validAggName) { - aggNameError = i18n.translate( - 'xpack.ml.dataframe.groupBy.popoverForm.aggNameInvalidCharError', - { - defaultMessage: - 'Invalid name. The characters "[", "]", and ">" are not allowed and the name must not start or end with a space character.', - } - ); + aggNameError = i18n.translate('xpack.transform.groupBy.popoverForm.aggNameInvalidCharError', { + defaultMessage: + 'Invalid name. The characters "[", "]", and ">" are not allowed and the name must not start or end with a space character.', + }); } if (validAggName) { validAggName = !otherAggNames.includes(aggName); - aggNameError = i18n.translate( - 'xpack.ml.dataframe.groupBy.popoverForm.aggNameAlreadyUsedError', - { - defaultMessage: 'Another group by configuration already uses that name.', - } - ); + aggNameError = i18n.translate('xpack.transform.groupBy.popoverForm.aggNameAlreadyUsedError', { + defaultMessage: 'Another group by configuration already uses that name.', + }); } const validInterval = @@ -177,13 +171,13 @@ export const PopoverForm: React.SFC = ({ isInvalid={!validAggName} helpText={ isUnsupportedAgg - ? i18n.translate('xpack.ml.dataframe.groupBy.popoverForm.unsupportedGroupByHelpText', { + ? i18n.translate('xpack.transform.groupBy.popoverForm.unsupportedGroupByHelpText', { defaultMessage: 'Only the group_by name can be edited in this form. Please use the advanced editor to edit the other parts of the group_by configuration.', }) : '' } - label={i18n.translate('xpack.ml.dataframe.groupBy.popoverForm.nameLabel', { + label={i18n.translate('xpack.transform.groupBy.popoverForm.nameLabel', { defaultMessage: 'Group by name', })} > @@ -195,7 +189,7 @@ export const PopoverForm: React.SFC = ({ {availableAggs.length > 0 && ( @@ -208,7 +202,7 @@ export const PopoverForm: React.SFC = ({ )} {availableFields.length > 0 && ( @@ -223,13 +217,13 @@ export const PopoverForm: React.SFC = ({ @@ -276,7 +270,7 @@ export const PopoverForm: React.SFC = ({ )} onChange(getUpdatedItem())}> - {i18n.translate('xpack.ml.dataframe.groupBy.popoverForm.submitButtonLabel', { + {i18n.translate('xpack.transform.groupBy.popoverForm.submitButtonLabel', { defaultMessage: 'Apply', })} diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/__snapshots__/expanded_row.test.tsx.snap b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/__snapshots__/expanded_row.test.tsx.snap similarity index 91% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/__snapshots__/expanded_row.test.tsx.snap rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/__snapshots__/expanded_row.test.tsx.snap index 41316437e8673..b668c7d8e4a69 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/__snapshots__/expanded_row.test.tsx.snap +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/__snapshots__/expanded_row.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Data Frame: Test against strings, objects and arrays. 1`] = ` +exports[`Transform: Test against strings, objects and arrays. 1`] = ` Minimal initialization 1`] = ` +
+ + + +
+`; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/common.test.ts b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/common.test.ts similarity index 93% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/common.test.ts rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/common.test.ts index bf7f678b185fc..d3bf81bba2e56 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/common.test.ts +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/common.test.ts @@ -8,7 +8,7 @@ import { SimpleQuery } from '../../../../common'; import { getSourceIndexDevConsoleStatement } from './common'; -describe('Data Frame: Source Index Preview Common', () => { +describe('Transform: Source Index Preview Common', () => { test('getSourceIndexDevConsoleStatement()', () => { const query: SimpleQuery = { query_string: { diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/common.ts b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/common.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/common.ts rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/common.ts diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/expanded_row.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/expanded_row.test.tsx similarity index 91% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/expanded_row.test.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/expanded_row.test.tsx index 611ae1b892dcc..ea81b33afbd23 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/expanded_row.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/expanded_row.test.tsx @@ -7,12 +7,12 @@ import { shallow } from 'enzyme'; import React from 'react'; -import { getNestedProperty } from '../../../../../util/object_utils'; +import { getNestedProperty } from '../../../../../../common/utils/object_utils'; import { getFlattenedFields } from '../../../../common'; import { ExpandedRow } from './expanded_row'; -describe('Data Frame: ', () => { +describe('Transform: ', () => { test('Test against strings, objects and arrays.', () => { const source = { name: 'the-name', diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/expanded_row.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/expanded_row.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/expanded_row.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/expanded_row.tsx diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/index.ts b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/index.ts rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/index.ts diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/source_index_preview.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/source_index_preview.test.tsx similarity index 77% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/source_index_preview.test.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/source_index_preview.test.tsx index 0e8d9809274f1..f326199271592 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/source_index_preview.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/source_index_preview.test.tsx @@ -7,20 +7,20 @@ import { shallow } from 'enzyme'; import React from 'react'; -import { KibanaContext } from '../../../../../contexts/kibana'; -import { kibanaContextValueMock } from '../../../../../contexts/kibana/__mocks__/kibana_context_value'; - +import { KibanaContext } from '../../../../lib/kibana'; import { getPivotQuery } from '../../../../common'; import { SourceIndexPreview } from './source_index_preview'; +jest.mock('ui/new_platform'); + // workaround to make React.memo() work with enzyme jest.mock('react', () => { const r = jest.requireActual('react'); return { ...r, memo: (x: any) => x }; }); -describe('Data Frame: ', () => { +describe('Transform: ', () => { test('Minimal initialization', () => { const props = { query: getPivotQuery('the-query'), @@ -30,7 +30,7 @@ describe('Data Frame: ', () => { // with the Provider being the outer most component. const wrapper = shallow(
- +
diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/source_index_preview.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/source_index_preview.tsx similarity index 84% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/source_index_preview.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/source_index_preview.tsx index b21ee2a45561c..27234af868fbd 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/source_index_preview.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/source_index_preview.tsx @@ -33,13 +33,13 @@ import { MlInMemoryTableBasic, SortingPropType, SORT_DIRECTION, -} from '../../../../../components/ml_in_memory_table'; +} from '../../../../../shared_imports'; import { KBN_FIELD_TYPES } from '../../../../../../../../../../src/plugins/data/public'; import { Dictionary } from '../../../../../../common/types/common'; -import { formatHumanReadableDateTimeSeconds } from '../../../../../util/date_utils'; +import { formatHumanReadableDateTimeSeconds } from '../../../../../../common/utils/date_utils'; -import { useCurrentIndexPattern } from '../../../../../contexts/kibana'; +import { useCurrentIndexPattern } from '../../../../lib/kibana'; import { toggleSelectedField, @@ -63,7 +63,7 @@ interface SourceIndexPreviewTitle { const SourceIndexPreviewTitle: React.SFC = ({ indexPatternTitle }) => ( - {i18n.translate('xpack.ml.dataframe.sourceIndexPreview.sourceIndexPatternTitle', { + {i18n.translate('xpack.transform.sourceIndexPreview.sourceIndexPatternTitle', { defaultMessage: 'Source index {indexPatternTitle}', values: { indexPatternTitle }, })} @@ -136,7 +136,7 @@ export const SourceIndexPreview: React.SFC = React.memo(({ cellClick, que = React.memo(({ cellClick, que = React.memo(({ cellClick, que color="primary" >

- {i18n.translate( - 'xpack.ml.dataframe.sourceIndexPreview.dataFrameSourceIndexNoDataCalloutBody', - { - defaultMessage: - 'The query for the source index returned no results. Please make sure the index contains documents and your query is not too restrictive.', - } - )} + {i18n.translate('xpack.transform.sourceIndexPreview.SourceIndexNoDataCalloutBody', { + defaultMessage: + 'The query for the source index returned no results. Please make sure the index contains documents and your query is not too restrictive.', + })}

@@ -213,7 +210,7 @@ export const SourceIndexPreview: React.SFC = React.memo(({ cellClick, que return ( = React.memo(({ cellClick, que )} > - {i18n.translate( - 'xpack.ml.dataframe.sourceIndexPreview.dataFrameSourceIndexArrayBadgeContent', - { - defaultMessage: 'array', - } - )} + {i18n.translate('xpack.transform.sourceIndexPreview.SourceIndexArrayBadgeContent', { + defaultMessage: 'array', + })} ); @@ -236,7 +230,7 @@ export const SourceIndexPreview: React.SFC = React.memo(({ cellClick, que return ( = React.memo(({ cellClick, que )} > - {i18n.translate( - 'xpack.ml.dataframe.sourceIndexPreview.dataFrameSourceIndexObjectBadgeContent', - { - defaultMessage: 'object', - } - )} + {i18n.translate('xpack.transform.sourceIndexPreview.SourceIndexObjectBadgeContent', { + defaultMessage: 'object', + })} ); @@ -309,10 +300,10 @@ export const SourceIndexPreview: React.SFC = React.memo(({ cellClick, que onClick={() => toggleDetails(item)} aria-label={ itemIdToExpandedRowMap[item._id] - ? i18n.translate('xpack.ml.dataframe.sourceIndexPreview.rowCollapse', { + ? i18n.translate('xpack.transform.sourceIndexPreview.rowCollapse', { defaultMessage: 'Collapse', }) - : i18n.translate('xpack.ml.dataframe.sourceIndexPreview.rowExpand', { + : i18n.translate('xpack.transform.sourceIndexPreview.rowExpand', { defaultMessage: 'Expand', }) } @@ -321,7 +312,7 @@ export const SourceIndexPreview: React.SFC = React.memo(({ cellClick, que ), }); - const euiCopyText = i18n.translate('xpack.ml.dataframe.sourceIndexPreview.copyClipboardTooltip', { + const euiCopyText = i18n.translate('xpack.transform.sourceIndexPreview.copyClipboardTooltip', { defaultMessage: 'Copy Dev Console statement of the source index preview to the clipboard.', }); @@ -336,7 +327,7 @@ export const SourceIndexPreview: React.SFC = React.memo(({ cellClick, que {docFieldsCount > MAX_COLUMNS && ( - {i18n.translate('xpack.ml.dataframe.sourceIndexPreview.fieldSelection', { + {i18n.translate('xpack.transform.sourceIndexPreview.fieldSelection', { defaultMessage: '{selectedFieldsLength, number} of {docFieldsCount, number} {docFieldsCount, plural, one {field} other {fields}} selected', values: { selectedFieldsLength: selectedFields.length, docFieldsCount }, @@ -353,7 +344,7 @@ export const SourceIndexPreview: React.SFC = React.memo(({ cellClick, que iconType="gear" onClick={toggleColumnsPopover} aria-label={i18n.translate( - 'xpack.ml.dataframe.sourceIndexPreview.selectColumnsAriaLabel', + 'xpack.transform.sourceIndexPreview.selectColumnsAriaLabel', { defaultMessage: 'Select columns', } @@ -365,12 +356,9 @@ export const SourceIndexPreview: React.SFC = React.memo(({ cellClick, que ownFocus > - {i18n.translate( - 'xpack.ml.dataframe.sourceIndexPreview.selectFieldsPopoverTitle', - { - defaultMessage: 'Select fields', - } - )} + {i18n.translate('xpack.transform.sourceIndexPreview.selectFieldsPopoverTitle', { + defaultMessage: 'Select fields', + })}
{docFields.map(d => ( diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/use_source_index_data.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/use_source_index_data.test.tsx similarity index 87% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/use_source_index_data.test.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/use_source_index_data.test.tsx index 9e93bb64af762..3bfe6c2cd0c5f 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/use_source_index_data.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/use_source_index_data.test.tsx @@ -8,7 +8,6 @@ import React, { SFC } from 'react'; import ReactDOM from 'react-dom'; import { act } from 'react-dom/test-utils'; -import { ml } from '../../../../../services/ml_api_service'; import { SimpleQuery } from '../../../../common'; import { SOURCE_INDEX_STATUS, @@ -16,7 +15,7 @@ import { UseSourceIndexDataReturnType, } from './use_source_index_data'; -jest.mock('../../../../../services/ml_api_service'); +jest.mock('../../../../hooks/use_api'); type Callback = () => void; interface TestHookProps { @@ -61,9 +60,8 @@ describe('useSourceIndexData', () => { expect(sourceIndexObj.errorMessage).toBe(''); expect(sourceIndexObj.status).toBe(SOURCE_INDEX_STATUS.LOADING); expect(sourceIndexObj.tableItems).toEqual([]); - expect(ml.esSearch).toHaveBeenCalledTimes(1); }); - // TODO add more tests to check data retrieved via `ml.esSearch()`. + // TODO add more tests to check data retrieved via `api.esSearch()`. // This needs more investigation in regards to jest/enzyme's React Hooks support. }); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/use_source_index_data.ts b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/use_source_index_data.ts similarity index 93% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/use_source_index_data.ts rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/use_source_index_data.ts index 591bc1701e226..9d60e3550fd75 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/source_index_preview/use_source_index_data.ts +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/source_index_preview/use_source_index_data.ts @@ -10,8 +10,8 @@ import { SearchResponse } from 'elasticsearch'; import { StaticIndexPattern } from 'ui/index_patterns'; -import { ml } from '../../../../../services/ml_api_service'; -import { getNestedProperty } from '../../../../../util/object_utils'; +import { useApi } from '../../../../hooks/use_api'; +import { getNestedProperty } from '../../../../../../common/utils/object_utils'; import { getDefaultSelectableFields, @@ -47,13 +47,14 @@ export const useSourceIndexData = ( const [errorMessage, setErrorMessage] = useState(''); const [status, setStatus] = useState(SOURCE_INDEX_STATUS.UNUSED); const [tableItems, setTableItems] = useState([]); + const api = useApi(); const getSourceIndexData = async function() { setErrorMessage(''); setStatus(SOURCE_INDEX_STATUS.LOADING); try { - const resp: SearchResponse = await ml.esSearch({ + const resp: SearchResponse = await api.esSearch({ index: indexPattern.title, size: SEARCH_SIZE, // Instead of using the default query (`*`), fall back to a more efficient `match_all` query. diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/__snapshots__/step_create_form.test.tsx.snap b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/__snapshots__/step_create_form.test.tsx.snap new file mode 100644 index 0000000000000..e034badea9b11 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/__snapshots__/step_create_form.test.tsx.snap @@ -0,0 +1,27 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Transform: Minimal initialization 1`] = ` +
+ + + +
+`; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_create/index.ts b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_create/index.ts rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/index.ts diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_create/step_create_form.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.test.tsx similarity index 76% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_create/step_create_form.test.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.test.tsx index c99d2c657e71f..055f0613e4e44 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_create/step_create_form.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.test.tsx @@ -7,12 +7,11 @@ import { shallow } from 'enzyme'; import React from 'react'; -import { KibanaContext } from '../../../../../contexts/kibana'; -import { kibanaContextValueMock } from '../../../../../contexts/kibana/__mocks__/kibana_context_value'; +import { KibanaContext } from '../../../../lib/kibana'; import { StepCreateForm } from './step_create_form'; -jest.mock('../../../../../contexts/ui/use_ui_chrome_context'); +jest.mock('ui/new_platform'); // workaround to make React.memo() work with enzyme jest.mock('react', () => { @@ -20,7 +19,7 @@ jest.mock('react', () => { return { ...r, memo: (x: any) => x }; }); -describe('Data Frame: ', () => { +describe('Transform: ', () => { test('Minimal initialization', () => { const props = { createIndexPattern: false, @@ -34,7 +33,7 @@ describe('Data Frame: ', () => { // with the Provider being the outer most component. const wrapper = shallow(
- +
diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_create/step_create_form.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx similarity index 69% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_create/step_create_form.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx index ab6abb5c53226..0c5ff04800037 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_create/step_create_form.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment, SFC, useEffect, useState } from 'react'; +import React, { Fragment, SFC, useContext, useEffect, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { toastNotifications } from 'ui/notify'; @@ -29,10 +29,10 @@ import { EuiText, } from '@elastic/eui'; -import { ml } from '../../../../../services/ml_api_service'; -import { useKibanaContext } from '../../../../../contexts/kibana/use_kibana_context'; -import { useUiChromeContext } from '../../../../../contexts/ui/use_ui_chrome_context'; -import { PROGRESS_JOBS_REFRESH_INTERVAL_MS } from '../../../../../../common/constants/jobs_list'; +import { useApi } from '../../../../hooks/use_api'; +import { isKibanaContextInitialized, KibanaContext } from '../../../../lib/kibana'; +import { RedirectToTransformManagement } from '../../../../common/navigation'; +import { PROGRESS_REFRESH_INTERVAL_MS } from '../../../../../../common/constants'; import { getTransformProgress, getDiscoverUrl } from '../../../../common'; @@ -62,6 +62,8 @@ export const StepCreateForm: SFC = React.memo( ({ createIndexPattern, transformConfig, transformId, onChange, overrides }) => { const defaults = { ...getDefaultStepCreateState(), ...overrides }; + const [redirectToTransformManagement, setRedirectToTransformManagement] = useState(false); + const [created, setCreated] = useState(defaults.created); const [started, setStarted] = useState(defaults.started); const [indexPatternId, setIndexPatternId] = useState(defaults.indexPatternId); @@ -69,30 +71,34 @@ export const StepCreateForm: SFC = React.memo( undefined ); - const kibanaContext = useKibanaContext(); - const baseUrl = useUiChromeContext().addBasePath(kibanaContext.kbnBaseUrl); + const kibanaContext = useContext(KibanaContext); useEffect(() => { onChange({ created, started, indexPatternId }); }, [created, started, indexPatternId]); - async function createDataFrame() { + const api = useApi(); + + if (!isKibanaContextInitialized(kibanaContext)) { + return null; + } + + async function createTransform() { setCreated(true); try { - await ml.dataFrame.createDataFrameTransform(transformId, transformConfig); + await api.createTransform(transformId, transformConfig); toastNotifications.addSuccess( - i18n.translate('xpack.ml.dataframe.stepCreateForm.createTransformSuccessMessage', { - defaultMessage: 'Request to create data frame transform {transformId} acknowledged.', + i18n.translate('xpack.transform.stepCreateForm.createTransformSuccessMessage', { + defaultMessage: 'Request to create transform {transformId} acknowledged.', values: { transformId }, }) ); } catch (e) { setCreated(false); toastNotifications.addDanger( - i18n.translate('xpack.ml.dataframe.stepCreateForm.createTransformErrorMessage', { - defaultMessage: - 'An error occurred creating the data frame transform {transformId}: {error}', + i18n.translate('xpack.transform.stepCreateForm.createTransformErrorMessage', { + defaultMessage: 'An error occurred creating the transform {transformId}: {error}', values: { transformId, error: JSON.stringify(e) }, }) ); @@ -106,33 +112,32 @@ export const StepCreateForm: SFC = React.memo( return true; } - async function startDataFrame() { + async function startTransform() { setStarted(true); try { - await ml.dataFrame.startDataFrameTransforms([{ id: transformId }]); + await api.startTransforms([{ id: transformId }]); toastNotifications.addSuccess( - i18n.translate('xpack.ml.dataframe.stepCreateForm.startTransformSuccessMessage', { - defaultMessage: 'Request to start data frame transform {transformId} acknowledged.', + i18n.translate('xpack.transform.stepCreateForm.startTransformSuccessMessage', { + defaultMessage: 'Request to start transform {transformId} acknowledged.', values: { transformId }, }) ); } catch (e) { setStarted(false); toastNotifications.addDanger( - i18n.translate('xpack.ml.dataframe.stepCreateForm.startTransformErrorMessage', { - defaultMessage: - 'An error occurred starting the data frame transform {transformId}: {error}', + i18n.translate('xpack.transform.stepCreateForm.startTransformErrorMessage', { + defaultMessage: 'An error occurred starting the transform {transformId}: {error}', values: { transformId, error: JSON.stringify(e) }, }) ); } } - async function createAndStartDataFrame() { - const success = await createDataFrame(); + async function createAndStartTransform() { + const success = await createTransform(); if (success) { - await startDataFrame(); + await startTransform(); } } @@ -152,7 +157,7 @@ export const StepCreateForm: SFC = React.memo( // id returns false if there's a duplicate index pattern. if (id === false) { toastNotifications.addDanger( - i18n.translate('xpack.ml.dataframe.stepCreateForm.duplicateIndexPatternErrorMessage', { + i18n.translate('xpack.transform.stepCreateForm.duplicateIndexPatternErrorMessage', { defaultMessage: 'An error occurred creating the Kibana index pattern {indexPatternName}: The index pattern already exists.', values: { indexPatternName }, @@ -168,7 +173,7 @@ export const StepCreateForm: SFC = React.memo( } toastNotifications.addSuccess( - i18n.translate('xpack.ml.dataframe.stepCreateForm.createIndexPatternSuccessMessage', { + i18n.translate('xpack.transform.stepCreateForm.createIndexPatternSuccessMessage', { defaultMessage: 'Kibana index pattern {indexPatternName} created successfully.', values: { indexPatternName }, }) @@ -178,7 +183,7 @@ export const StepCreateForm: SFC = React.memo( return true; } catch (e) { toastNotifications.addDanger( - i18n.translate('xpack.ml.dataframe.stepCreateForm.createIndexPatternErrorMessage', { + i18n.translate('xpack.transform.stepCreateForm.createIndexPatternErrorMessage', { defaultMessage: 'An error occurred creating the Kibana index pattern {indexPatternName}: {error}', values: { indexPatternName, error: JSON.stringify(e) }, @@ -195,7 +200,7 @@ export const StepCreateForm: SFC = React.memo( function startProgressBar() { const interval = setInterval(async () => { try { - const stats = await ml.dataFrame.getDataFrameTransformsStats(transformId); + const stats = await api.getTransformsStats(transformId); if (stats && Array.isArray(stats.transforms) && stats.transforms.length > 0) { const percent = getTransformProgress({ @@ -210,14 +215,14 @@ export const StepCreateForm: SFC = React.memo( } } catch (e) { toastNotifications.addDanger( - i18n.translate('xpack.ml.dataframe.stepCreateForm.progressErrorMessage', { + i18n.translate('xpack.transform.stepCreateForm.progressErrorMessage', { defaultMessage: 'An error occurred getting the progress percentage: {error}', values: { error: JSON.stringify(e) }, }) ); clearInterval(interval); } - }, PROGRESS_JOBS_REFRESH_INTERVAL_MS); + }, PROGRESS_REFRESH_INTERVAL_MS); setProgressPercentComplete(0); } @@ -237,13 +242,17 @@ export const StepCreateForm: SFC = React.memo( const FLEX_ITEM_STYLE = { width: '200px' }; const PANEL_ITEM_STYLE = { width: '300px' }; + if (redirectToTransformManagement) { + return ; + } + return ( {!created && ( - - {i18n.translate('xpack.ml.dataframe.stepCreateForm.createAndStartDataFrameButton', { + + {i18n.translate('xpack.transform.stepCreateForm.createAndStartTransformButton', { defaultMessage: 'Create and start', })} @@ -251,10 +260,10 @@ export const StepCreateForm: SFC = React.memo( {i18n.translate( - 'xpack.ml.dataframe.stepCreateForm.createAndStartDataFrameDescription', + 'xpack.transform.stepCreateForm.createAndStartTransformDescription', { defaultMessage: - 'Creates and starts the data frame transform. A data frame transform will increase search and indexing load in your cluster. Please stop the transform if excessive load is experienced. After the transform is started, you will be offered options to continue exploring the data frame transform.', + 'Creates and starts the transform. A transform will increase search and indexing load in your cluster. Please stop the transform if excessive load is experienced. After the transform is started, you will be offered options to continue exploring the transform.', } )} @@ -264,17 +273,17 @@ export const StepCreateForm: SFC = React.memo( {created && ( - - {i18n.translate('xpack.ml.dataframe.stepCreateForm.startDataFrameButton', { + + {i18n.translate('xpack.transform.stepCreateForm.startTransformButton', { defaultMessage: 'Start', })} - {i18n.translate('xpack.ml.dataframe.stepCreateForm.startDataFrameDescription', { + {i18n.translate('xpack.transform.stepCreateForm.startTransformDescription', { defaultMessage: - 'Starts the data frame transform. A data frame transform will increase search and indexing load in your cluster. Please stop the transform if excessive load is experienced. After the transform is started, you will be offered options to continue exploring the data frame transform.', + 'Starts the transform. A transform will increase search and indexing load in your cluster. Please stop the transform if excessive load is experienced. After the transform is started, you will be offered options to continue exploring the transform.', })} @@ -282,17 +291,17 @@ export const StepCreateForm: SFC = React.memo( )} - - {i18n.translate('xpack.ml.dataframe.stepCreateForm.createDataFrameButton', { + + {i18n.translate('xpack.transform.stepCreateForm.createTransformButton', { defaultMessage: 'Create', })} - {i18n.translate('xpack.ml.dataframe.stepCreateForm.createDataFrameDescription', { + {i18n.translate('xpack.transform.stepCreateForm.createTransformDescription', { defaultMessage: - 'Create the data frame transform without starting it. You will be able to start the transform later by returning to the data frame transforms list.', + 'Create the transform without starting it. You will be able to start the transform later by returning to the transforms list.', })} @@ -303,7 +312,7 @@ export const StepCreateForm: SFC = React.memo( {(copy: () => void) => ( {i18n.translate( - 'xpack.ml.dataframe.stepCreateForm.copyTransformConfigToClipboardButton', + 'xpack.transform.stepCreateForm.copyTransformConfigToClipboardButton', { defaultMessage: 'Copy to clipboard', } @@ -315,7 +324,7 @@ export const StepCreateForm: SFC = React.memo( {i18n.translate( - 'xpack.ml.dataframe.stepCreateForm.copyTransformConfigToClipboardDescription', + 'xpack.transform.stepCreateForm.copyTransformConfigToClipboardDescription', { defaultMessage: 'Copies to the clipboard the Kibana Dev Console command for creating the transform.', @@ -329,7 +338,7 @@ export const StepCreateForm: SFC = React.memo( - {i18n.translate('xpack.ml.dataframe.stepCreateForm.progressTitle', { + {i18n.translate('xpack.transform.stepCreateForm.progressTitle', { defaultMessage: 'Progress', })} @@ -351,19 +360,16 @@ export const StepCreateForm: SFC = React.memo( } - title={i18n.translate( - 'xpack.ml.dataframe.stepCreateForm.transformListCardTitle', - { - defaultMessage: 'Data frame transforms', - } - )} + title={i18n.translate('xpack.transform.stepCreateForm.transformListCardTitle', { + defaultMessage: 'Transforms', + })} description={i18n.translate( - 'xpack.ml.dataframe.stepCreateForm.transformListCardDescription', + 'xpack.transform.stepCreateForm.transformListCardDescription', { - defaultMessage: 'Return to the data frame transform management page.', + defaultMessage: 'Return to the transform management page.', } )} - href="#/data_frames" + onClick={() => setRedirectToTransformManagement(true)} /> {started === true && createIndexPattern === true && indexPatternId === undefined && ( @@ -373,7 +379,7 @@ export const StepCreateForm: SFC = React.memo(

{i18n.translate( - 'xpack.ml.dataframe.stepCreateForm.creatingIndexPatternMessage', + 'xpack.transform.stepCreateForm.creatingIndexPatternMessage', { defaultMessage: 'Creating Kibana index pattern ...', } @@ -387,16 +393,16 @@ export const StepCreateForm: SFC = React.memo( } - title={i18n.translate('xpack.ml.dataframe.stepCreateForm.discoverCardTitle', { + title={i18n.translate('xpack.transform.stepCreateForm.discoverCardTitle', { defaultMessage: 'Discover', })} description={i18n.translate( - 'xpack.ml.dataframe.stepCreateForm.discoverCardDescription', + 'xpack.transform.stepCreateForm.discoverCardDescription', { - defaultMessage: 'Use Discover to explore the data frame pivot.', + defaultMessage: 'Use Discover to explore the transform.', } )} - href={getDiscoverUrl(indexPatternId, baseUrl)} + href={getDiscoverUrl(indexPatternId, kibanaContext.kbnBaseUrl)} /> )} diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_create/step_create_summary.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_summary.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_create/step_create_summary.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_summary.tsx diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/__snapshots__/pivot_preview.test.tsx.snap b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/__snapshots__/pivot_preview.test.tsx.snap new file mode 100644 index 0000000000000..a7da172a67b8a --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/__snapshots__/pivot_preview.test.tsx.snap @@ -0,0 +1,44 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Transform: Minimal initialization 1`] = ` +

+ + + +
+`; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/__snapshots__/step_define_form.test.tsx.snap b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/__snapshots__/step_define_form.test.tsx.snap new file mode 100644 index 0000000000000..70a0bfc12b208 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/__snapshots__/step_define_form.test.tsx.snap @@ -0,0 +1,17 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Transform: Minimal initialization 1`] = ` +
+ + + +
+`; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/__snapshots__/step_define_summary.test.tsx.snap b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/__snapshots__/step_define_summary.test.tsx.snap new file mode 100644 index 0000000000000..b18233e5c53e3 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/__snapshots__/step_define_summary.test.tsx.snap @@ -0,0 +1,42 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Transform: Minimal initialization 1`] = ` +
+ + + +
+`; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/common.test.ts b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/common.test.ts similarity index 98% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/common.test.ts rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/common.test.ts index f96bab17df715..b02bf704983ee 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/common.test.ts +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/common.test.ts @@ -16,7 +16,7 @@ import { import { getPivotPreviewDevConsoleStatement, getPivotDropdownOptions } from './common'; import { IndexPattern } from 'ui/index_patterns'; -describe('Data Frame: Define Pivot Common', () => { +describe('Transform: Define Pivot Common', () => { test('getPivotDropdownOptions()', () => { // The field name includes the characters []> as well as a leading and ending space charcter // which cannot be used for aggregation names. The test results verifies that the characters diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/common.ts b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/common.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/common.ts rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/common.ts diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/index.ts b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/index.ts rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/index.ts diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/pivot_preview.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_preview.test.tsx similarity index 85% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/pivot_preview.test.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_preview.test.tsx index a7350247c2dba..4ff1190415dba 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/pivot_preview.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_preview.test.tsx @@ -7,8 +7,7 @@ import { shallow } from 'enzyme'; import React from 'react'; -import { KibanaContext } from '../../../../../contexts/kibana'; -import { kibanaContextValueMock } from '../../../../../contexts/kibana/__mocks__/kibana_context_value'; +import { KibanaContext } from '../../../../lib/kibana'; import { getPivotQuery, @@ -20,13 +19,15 @@ import { import { PivotPreview } from './pivot_preview'; +jest.mock('ui/new_platform'); + // workaround to make React.memo() work with enzyme jest.mock('react', () => { const r = jest.requireActual('react'); return { ...r, memo: (x: any) => x }; }); -describe('Data Frame: ', () => { +describe('Transform: ', () => { test('Minimal initialization', () => { const groupBy: PivotGroupByConfig = { agg: PIVOT_SUPPORTED_GROUP_BY_AGGS.TERMS, @@ -50,7 +51,7 @@ describe('Data Frame: ', () => { // with the Provider being the outer most component. const wrapper = shallow(
- +
diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/pivot_preview.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_preview.tsx similarity index 81% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/pivot_preview.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_preview.tsx index 695b7dcf6e0f5..3ac87f61d4c89 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/pivot_preview.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_preview.tsx @@ -21,16 +21,12 @@ import { EuiTitle, } from '@elastic/eui'; -import { - ColumnType, - MlInMemoryTableBasic, - SORT_DIRECTION, -} from '../../../../../components/ml_in_memory_table'; +import { ColumnType, MlInMemoryTableBasic, SORT_DIRECTION } from '../../../../../shared_imports'; import { dictionaryToArray } from '../../../../../../common/types/common'; import { ES_FIELD_TYPES } from '../../../../../../../../../../src/plugins/data/public'; -import { formatHumanReadableDateTimeSeconds } from '../../../../../util/date_utils'; +import { formatHumanReadableDateTimeSeconds } from '../../../../../../common/utils/date_utils'; -import { useCurrentIndexPattern } from '../../../../../contexts/kibana'; +import { useCurrentIndexPattern } from '../../../../lib/kibana'; import { getFlattenedFields, @@ -73,7 +69,7 @@ interface PreviewTitleProps { } const PreviewTitle: SFC = ({ previewRequest }) => { - const euiCopyText = i18n.translate('xpack.ml.dataframe.pivotPreview.copyClipboardTooltip', { + const euiCopyText = i18n.translate('xpack.transform.pivotPreview.copyClipboardTooltip', { defaultMessage: 'Copy Dev Console statement of the pivot preview to the clipboard.', }); @@ -82,8 +78,8 @@ const PreviewTitle: SFC = ({ previewRequest }) => { - {i18n.translate('xpack.ml.dataframe.pivotPreview.dataFramePivotPreviewTitle', { - defaultMessage: 'Data frame pivot preview', + {i18n.translate('xpack.transform.pivotPreview.PivotPreviewTitle', { + defaultMessage: 'Transform pivot preview', })} @@ -109,7 +105,7 @@ interface ErrorMessageProps { const ErrorMessage: SFC = ({ message }) => { const error = JSON.parse(message); - const statusCodeLabel = i18n.translate('xpack.ml.dataframe.pivotPreview.statusCodeLabel', { + const statusCodeLabel = i18n.translate('xpack.transform.pivotPreview.statusCodeLabel', { defaultMessage: 'Status code', }); @@ -137,8 +133,8 @@ export const PivotPreview: SFC = React.memo(({ aggs, groupBy, const indexPattern = useCurrentIndexPattern(); const { - dataFramePreviewData, - dataFramePreviewMappings, + previewData, + previewMappings, errorMessage, previewRequest, status, @@ -155,8 +151,8 @@ export const PivotPreview: SFC = React.memo(({ aggs, groupBy, // - After that the table gets re-enabled. To make sure React // doesn't consolidate the state updates, setTimeout is used. const firstColumnName = - dataFramePreviewData.length > 0 - ? Object.keys(dataFramePreviewData[0]).sort(sortColumns(groupByArr))[0] + previewData.length > 0 + ? Object.keys(previewData[0]).sort(sortColumns(groupByArr))[0] : undefined; const firstColumnNameChanged = usePrevious(firstColumnName) !== firstColumnName; @@ -178,7 +174,7 @@ export const PivotPreview: SFC = React.memo(({ aggs, groupBy, = React.memo(({ aggs, groupBy, ); } - if (dataFramePreviewData.length === 0) { + if (previewData.length === 0) { let noDataMessage = i18n.translate( - 'xpack.ml.dataframe.pivotPreview.dataFramePivotPreviewNoDataCalloutBody', + 'xpack.transform.pivotPreview.PivotPreviewNoDataCalloutBody', { defaultMessage: 'The preview request did not return any data. Please ensure the optional query returns data and that values exist for the field used by group-by and aggregation fields.', @@ -202,7 +198,7 @@ export const PivotPreview: SFC = React.memo(({ aggs, groupBy, const aggsArr = dictionaryToArray(aggs); if (aggsArr.length === 0 || groupByArr.length === 0) { noDataMessage = i18n.translate( - 'xpack.ml.dataframe.pivotPreview.dataFramePivotPreviewIncompleteConfigCalloutBody', + 'xpack.transform.pivotPreview.PivotPreviewIncompleteConfigCalloutBody', { defaultMessage: 'Please choose at least one group-by field and aggregation.', } @@ -212,12 +208,9 @@ export const PivotPreview: SFC = React.memo(({ aggs, groupBy,

{noDataMessage}

@@ -226,7 +219,7 @@ export const PivotPreview: SFC = React.memo(({ aggs, groupBy, ); } - const columnKeys = getFlattenedFields(dataFramePreviewData[0]); + const columnKeys = getFlattenedFields(previewData[0]); columnKeys.sort(sortColumns(groupByArr)); const columns = columnKeys.map(k => { @@ -236,8 +229,8 @@ export const PivotPreview: SFC = React.memo(({ aggs, groupBy, sortable: true, truncateText: true, }; - if (typeof dataFramePreviewMappings.properties[k] !== 'undefined') { - const esFieldType = dataFramePreviewMappings.properties[k].type; + if (typeof previewMappings.properties[k] !== 'undefined') { + const esFieldType = previewMappings.properties[k].type; switch (esFieldType) { case ES_FIELD_TYPES.BOOLEAN: column.dataType = 'boolean'; @@ -283,11 +276,11 @@ export const PivotPreview: SFC = React.memo(({ aggs, groupBy, {status !== PIVOT_PREVIEW_STATUS.LOADING && ( )} - {dataFramePreviewData.length > 0 && clearTable === false && columns.length > 0 && ( + {previewData.length > 0 && clearTable === false && columns.length > 0 && ( { const r = jest.requireActual('react'); return { ...r, memo: (x: any) => x }; }); -describe('Data Frame: ', () => { +describe('Transform: ', () => { test('Minimal initialization', () => { // Using a wrapping
element because shallow() would fail // with the Provider being the outer most component. const wrapper = shallow(
- + {}} />
@@ -40,7 +41,7 @@ describe('Data Frame: ', () => { }); }); -describe('Data Frame: isAggNameConflict()', () => { +describe('Transform: isAggNameConflict()', () => { test('detect aggregation name conflicts', () => { const aggList: PivotAggsConfigDict = { 'the-agg-name': { diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/step_define_form.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx similarity index 86% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/step_define_form.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx index 388694650d01c..c89dfd12fa4ff 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/step_define_form.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment, SFC, useEffect, useState } from 'react'; +import React, { Fragment, SFC, useContext, useEffect, useState } from 'react'; import { i18n } from '@kbn/i18n'; @@ -33,15 +33,15 @@ import { AggListForm } from '../aggregation_list'; import { GroupByListForm } from '../group_by_list'; import { SourceIndexPreview } from '../source_index_preview'; import { PivotPreview } from './pivot_preview'; -// @ts-ignore: could not find declaration file for module -import { KqlFilterBar } from '../../../../../components/kql_filter_bar'; +import { KqlFilterBar } from '../../../../../shared_imports'; import { SwitchModal } from './switch_modal'; import { - useKibanaContext, + isKibanaContextInitialized, + KibanaContext, KibanaContextValue, SavedSearchQuery, -} from '../../../../../contexts/kibana'; +} from '../../../../lib/kibana'; import { AggName, @@ -83,11 +83,11 @@ export function getDefaultStepDefineState( isAdvancedPivotEditorEnabled: false, isAdvancedSourceEditorEnabled: false, searchString: - kibanaContext.currentSavedSearch.id !== undefined + isKibanaContextInitialized(kibanaContext) && kibanaContext.currentSavedSearch !== undefined ? kibanaContext.combinedQuery : defaultSearch, searchQuery: - kibanaContext.currentSavedSearch.id !== undefined + isKibanaContextInitialized(kibanaContext) && kibanaContext.currentSavedSearch !== undefined ? kibanaContext.combinedQuery : defaultSearch, sourceConfigUpdated: false, @@ -101,7 +101,7 @@ export function isAggNameConflict( ) { if (aggList[aggName] !== undefined) { toastNotifications.addDanger( - i18n.translate('xpack.ml.dataframe.stepDefineForm.aggExistsErrorMessage', { + i18n.translate('xpack.transform.stepDefineForm.aggExistsErrorMessage', { defaultMessage: `An aggregation configuration with the name '{aggName}' already exists.`, values: { aggName }, }) @@ -111,7 +111,7 @@ export function isAggNameConflict( if (groupByList[aggName] !== undefined) { toastNotifications.addDanger( - i18n.translate('xpack.ml.dataframe.stepDefineForm.groupByExistsErrorMessage', { + i18n.translate('xpack.transform.stepDefineForm.groupByExistsErrorMessage', { defaultMessage: `A group by configuration with the name '{aggName}' already exists.`, values: { aggName }, }) @@ -128,7 +128,7 @@ export function isAggNameConflict( aggNameCheck = aggNameCheck === undefined ? aggNamePart : `${aggNameCheck}.${aggNamePart}`; if (aggList[aggNameCheck] !== undefined || groupByList[aggNameCheck] !== undefined) { toastNotifications.addDanger( - i18n.translate('xpack.ml.dataframe.stepDefineForm.nestedConflictErrorMessage', { + i18n.translate('xpack.transform.stepDefineForm.nestedConflictErrorMessage', { defaultMessage: `Couldn't add configuration '{aggName}' because of a nesting conflict with '{aggNameCheck}'.`, values: { aggName, aggNameCheck }, }) @@ -150,7 +150,7 @@ export function isAggNameConflict( aggListNameCheck === undefined ? aggListNamePart : `${aggListNameCheck}.${aggListNamePart}`; if (aggListNameCheck === aggName) { toastNotifications.addDanger( - i18n.translate('xpack.ml.dataframe.stepDefineForm.nestedAggListConflictErrorMessage', { + i18n.translate('xpack.transform.stepDefineForm.nestedAggListConflictErrorMessage', { defaultMessage: `Couldn't add configuration '{aggName}' because of a nesting conflict with '{aggListName}'.`, values: { aggName, aggListName }, }) @@ -176,13 +176,10 @@ export function isAggNameConflict( : `${groupByListNameCheck}.${groupByListNamePart}`; if (groupByListNameCheck === aggName) { toastNotifications.addDanger( - i18n.translate( - 'xpack.ml.dataframe.stepDefineForm.nestedGroupByListConflictErrorMessage', - { - defaultMessage: `Couldn't add configuration '{aggName}' because of a nesting conflict with '{groupByListName}'.`, - values: { aggName, groupByListName }, - } - ) + i18n.translate('xpack.transform.stepDefineForm.nestedGroupByListConflictErrorMessage', { + defaultMessage: `Couldn't add configuration '{aggName}' because of a nesting conflict with '{groupByListName}'.`, + values: { aggName, groupByListName }, + }) ); return true; } @@ -199,9 +196,7 @@ interface Props { } export const StepDefineForm: SFC = React.memo(({ overrides = {}, onChange }) => { - const kibanaContext = useKibanaContext(); - - const indexPattern = kibanaContext.currentIndexPattern; + const kibanaContext = useContext(KibanaContext); const defaults = { ...getDefaultStepDefineState(kibanaContext), ...overrides }; @@ -229,6 +224,12 @@ export const StepDefineForm: SFC = React.memo(({ overrides = {}, onChange // The list of selected group by fields const [groupByList, setGroupByList] = useState(defaults.groupByList); + if (!isKibanaContextInitialized(kibanaContext)) { + return null; + } + + const indexPattern = kibanaContext.currentIndexPattern; + const { groupByOptions, groupByOptionsData, @@ -430,12 +431,12 @@ export const StepDefineForm: SFC = React.memo(({ overrides = {}, onChange const docsUrl = `https://www.elastic.co/guide/en/elasticsearch/reference/${metadata.branch}/transform-pivot.html`; const advancedEditorHelpText = ( - {i18n.translate('xpack.ml.dataframe.stepDefineForm.advancedEditorHelpText', { + {i18n.translate('xpack.transform.stepDefineForm.advancedEditorHelpText', { defaultMessage: - 'The advanced editor allows you to edit the pivot configuration of the data frame transform.', + 'The advanced editor allows you to edit the pivot configuration of the transform.', })}{' '} - {i18n.translate('xpack.ml.dataframe.stepDefineForm.advancedEditorHelpTextLink', { + {i18n.translate('xpack.transform.stepDefineForm.advancedEditorHelpTextLink', { defaultMessage: 'Learn more about available options.', })} @@ -445,12 +446,12 @@ export const StepDefineForm: SFC = React.memo(({ overrides = {}, onChange const sourceDocsUrl = `https://www.elastic.co/guide/en/elasticsearch/reference/${metadata.branch}/query-dsl.html`; const advancedSourceEditorHelpText = ( - {i18n.translate('xpack.ml.dataframe.stepDefineForm.advancedSourceEditorHelpText', { + {i18n.translate('xpack.transform.stepDefineForm.advancedSourceEditorHelpText', { defaultMessage: - 'The advanced editor allows you to edit the source query clause of the data frame transform.', + 'The advanced editor allows you to edit the source query clause of the transform.', })}{' '} - {i18n.translate('xpack.ml.dataframe.stepDefineForm.advancedEditorHelpTextLink', { + {i18n.translate('xpack.transform.stepDefineForm.advancedEditorHelpTextLink', { defaultMessage: 'Learn more about available options.', })} @@ -505,15 +506,15 @@ export const StepDefineForm: SFC = React.memo(({ overrides = {}, onChange - {kibanaContext.currentSavedSearch.id === undefined && typeof searchString === 'string' && ( + {kibanaContext.currentSavedSearch === undefined && typeof searchString === 'string' && ( = React.memo(({ overrides = {}, onChange : '' } > - {kibanaContext.currentIndexPattern.title} + {indexPattern.title} {!disabledQuery && ( {!isAdvancedSourceEditorEnabled && ( @@ -542,7 +543,7 @@ export const StepDefineForm: SFC = React.memo(({ overrides = {}, onChange onSubmit={searchHandler} initialValue={searchString === defaultSearch ? emptySearch : searchString} placeholder={i18n.translate( - 'xpack.ml.dataframe.stepDefineForm.queryPlaceholder', + 'xpack.transform.stepDefineForm.queryPlaceholder', { defaultMessage: 'e.g. {example}', values: { example: 'method : "GET" or status : "404"' }, @@ -559,12 +560,9 @@ export const StepDefineForm: SFC = React.memo(({ overrides = {}, onChange {isAdvancedSourceEditorEnabled && ( @@ -594,7 +592,7 @@ export const StepDefineForm: SFC = React.memo(({ overrides = {}, onChange fontSize: '12px', }} aria-label={i18n.translate( - 'xpack.ml.dataframe.stepDefineForm.advancedSourceEditorAriaLabel', + 'xpack.transform.stepDefineForm.advancedSourceEditorAriaLabel', { defaultMessage: 'Advanced query editor', } @@ -604,13 +602,13 @@ export const StepDefineForm: SFC = React.memo(({ overrides = {}, onChange )} - {kibanaContext.currentSavedSearch.id === undefined && ( + {kibanaContext.currentSavedSearch === undefined && ( = React.memo(({ overrides = {}, onChange disabled={!isAdvancedSourceEditorApplyButtonEnabled} > {i18n.translate( - 'xpack.ml.dataframe.stepDefineForm.advancedSourceEditorApplyButtonText', + 'xpack.transform.stepDefineForm.advancedSourceEditorApplyButtonText', { defaultMessage: 'Apply changes', } @@ -654,20 +652,21 @@ export const StepDefineForm: SFC = React.memo(({ overrides = {}, onChange )} - {kibanaContext.currentSavedSearch.id !== undefined && ( - - {kibanaContext.currentSavedSearch.title} - - )} + {kibanaContext.currentSavedSearch !== undefined && + kibanaContext.currentSavedSearch.id !== undefined && ( + + {kibanaContext.currentSavedSearch.title} + + )} {!isAdvancedPivotEditorEnabled && ( @@ -682,7 +681,7 @@ export const StepDefineForm: SFC = React.memo(({ overrides = {}, onChange changeHandler={addGroupBy} options={groupByOptions} placeholder={i18n.translate( - 'xpack.ml.dataframe.stepDefineForm.groupByPlaceholder', + 'xpack.transform.stepDefineForm.groupByPlaceholder', { defaultMessage: 'Add a group by field ...', } @@ -692,7 +691,7 @@ export const StepDefineForm: SFC = React.memo(({ overrides = {}, onChange @@ -707,7 +706,7 @@ export const StepDefineForm: SFC = React.memo(({ overrides = {}, onChange changeHandler={addAggregation} options={aggOptions} placeholder={i18n.translate( - 'xpack.ml.dataframe.stepDefineForm.aggregationsPlaceholder', + 'xpack.transform.stepDefineForm.aggregationsPlaceholder', { defaultMessage: 'Add an aggregation ...', } @@ -721,7 +720,7 @@ export const StepDefineForm: SFC = React.memo(({ overrides = {}, onChange {isAdvancedPivotEditorEnabled && ( = React.memo(({ overrides = {}, onChange fontSize: '12px', }} aria-label={i18n.translate( - 'xpack.ml.dataframe.stepDefineForm.advancedEditorAriaLabel', + 'xpack.transform.stepDefineForm.advancedEditorAriaLabel', { defaultMessage: 'Advanced pivot editor', } @@ -768,7 +767,7 @@ export const StepDefineForm: SFC = React.memo(({ overrides = {}, onChange = React.memo(({ overrides = {}, onChange onClick={applyAdvancedPivotEditorChanges} disabled={!isAdvancedPivotEditorApplyButtonEnabled} > - {i18n.translate( - 'xpack.ml.dataframe.stepDefineForm.advancedEditorApplyButtonText', - { - defaultMessage: 'Apply changes', - } - )} + {i18n.translate('xpack.transform.stepDefineForm.advancedEditorApplyButtonText', { + defaultMessage: 'Apply changes', + })} )} @@ -819,9 +815,9 @@ export const StepDefineForm: SFC = React.memo(({ overrides = {}, onChange - {i18n.translate('xpack.ml.dataframe.stepDefineForm.formHelp', { + {i18n.translate('xpack.transform.stepDefineForm.formHelp', { defaultMessage: - 'Data frame transforms are scalable and automated processes for pivoting. Choose at least one group-by and aggregation to get started.', + 'Transforms are scalable and automated processes for pivoting. Choose at least one group-by and aggregation to get started.', })} diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/step_define_summary.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.test.tsx similarity index 86% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/step_define_summary.test.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.test.tsx index 7015912fd2e29..2d9895e8ddcf1 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/step_define_summary.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.test.tsx @@ -7,8 +7,7 @@ import { shallow } from 'enzyme'; import React from 'react'; -import { KibanaContext } from '../../../../../contexts/kibana'; -import { kibanaContextValueMock } from '../../../../../contexts/kibana/__mocks__/kibana_context_value'; +import { KibanaContext } from '../../../../lib/kibana'; import { PivotAggsConfig, @@ -19,13 +18,15 @@ import { import { StepDefineExposedState } from './step_define_form'; import { StepDefineSummary } from './step_define_summary'; +jest.mock('ui/new_platform'); + // workaround to make React.memo() work with enzyme jest.mock('react', () => { const r = jest.requireActual('react'); return { ...r, memo: (x: any) => x }; }); -describe('Data Frame: ', () => { +describe('Transform: ', () => { test('Minimal initialization', () => { const groupBy: PivotGroupByConfig = { agg: PIVOT_SUPPORTED_GROUP_BY_AGGS.TERMS, @@ -54,7 +55,7 @@ describe('Data Frame: ', () => { // with the Provider being the outer most component. const wrapper = shallow(
- +
diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.tsx new file mode 100644 index 0000000000000..5f1f265b5f5bb --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.tsx @@ -0,0 +1,138 @@ +/* + * 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 React, { useContext, Fragment, FC } from 'react'; + +import { i18n } from '@kbn/i18n'; + +import { + EuiCodeBlock, + EuiFlexGroup, + EuiFlexItem, + EuiForm, + EuiFormRow, + EuiText, +} from '@elastic/eui'; + +import { isKibanaContextInitialized, KibanaContext } from '../../../../lib/kibana'; + +import { AggListSummary } from '../aggregation_list'; +import { GroupByListSummary } from '../group_by_list'; +import { PivotPreview } from './pivot_preview'; + +import { getPivotQuery } from '../../../../common'; +import { StepDefineExposedState } from './step_define_form'; + +const defaultSearch = '*'; +const emptySearch = ''; + +export const StepDefineSummary: FC = ({ + searchString, + searchQuery, + groupByList, + aggList, +}) => { + const kibanaContext = useContext(KibanaContext); + + if (!isKibanaContextInitialized(kibanaContext)) { + return null; + } + + const pivotQuery = getPivotQuery(searchQuery); + let useCodeBlock = false; + let displaySearch; + // searchString set to empty once source config editor used - display query instead + if (searchString === emptySearch) { + displaySearch = JSON.stringify(searchQuery, null, 2); + useCodeBlock = true; + } else if (searchString === defaultSearch) { + displaySearch = emptySearch; + } else { + displaySearch = searchString; + } + + return ( + + + + {kibanaContext.currentSavedSearch !== undefined && + kibanaContext.currentSavedSearch.id === undefined && + typeof searchString === 'string' && ( + + + {kibanaContext.currentIndexPattern.title} + + {useCodeBlock === false && displaySearch !== emptySearch && ( + + {displaySearch} + + )} + {useCodeBlock === true && displaySearch !== emptySearch && ( + + + {displaySearch} + + + )} + + )} + + {kibanaContext.currentSavedSearch !== undefined && + kibanaContext.currentSavedSearch.id !== undefined && ( + + {kibanaContext.currentSavedSearch.title} + + )} + + + + + + + + + + + + + + + + + + ); +}; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/switch_modal.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/switch_modal.tsx similarity index 77% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/switch_modal.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/switch_modal.tsx index 000f079dad2f3..43d024a8e869d 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/switch_modal.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/switch_modal.tsx @@ -14,43 +14,43 @@ interface Props { } const pivotModalTitle = i18n.translate( - 'xpack.ml.dataframe.stepDefineForm.advancedEditorSwitchModalTitle', + 'xpack.transform.stepDefineForm.advancedEditorSwitchModalTitle', { defaultMessage: 'Unapplied changes', } ); const sourceModalTitle = i18n.translate( - 'xpack.ml.dataframe.stepDefineForm.advancedSourceEditorSwitchModalTitle', + 'xpack.transform.stepDefineForm.advancedSourceEditorSwitchModalTitle', { defaultMessage: 'Edits will be lost', } ); const pivotModalMessage = i18n.translate( - 'xpack.ml.dataframe.stepDefineForm.advancedEditorSwitchModalBodyText', + 'xpack.transform.stepDefineForm.advancedEditorSwitchModalBodyText', { defaultMessage: `The changes in the advanced editor haven't been applied yet. By disabling the advanced editor you will lose your edits.`, } ); const sourceModalMessage = i18n.translate( - 'xpack.ml.dataframe.stepDefineForm.advancedSourceEditorSwitchModalBodyText', + 'xpack.transform.stepDefineForm.advancedSourceEditorSwitchModalBodyText', { defaultMessage: `By switching back to KQL query bar you will lose your edits.`, } ); const pivotModalConfirmButtonText = i18n.translate( - 'xpack.ml.dataframe.stepDefineForm.advancedEditorSwitchModalConfirmButtonText', + 'xpack.transform.stepDefineForm.advancedEditorSwitchModalConfirmButtonText', { defaultMessage: 'Disable advanced editor', } ); const sourceModalConfirmButtonText = i18n.translate( - 'xpack.ml.dataframe.stepDefineForm.advancedSourceEditorSwitchModalConfirmButtonText', + 'xpack.transform.stepDefineForm.advancedSourceEditorSwitchModalConfirmButtonText', { defaultMessage: 'Switch to KQL', } ); const cancelButtonText = i18n.translate( - 'xpack.ml.dataframe.stepDefineForm.advancedEditorSwitchModalCancelButtonText', + 'xpack.transform.stepDefineForm.advancedEditorSwitchModalCancelButtonText', { defaultMessage: 'Cancel', } diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/use_pivot_preview_data.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/use_pivot_preview_data.test.tsx similarity index 78% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/use_pivot_preview_data.test.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/use_pivot_preview_data.test.tsx index 615d4f75744cb..0843dfc306f85 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/use_pivot_preview_data.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/use_pivot_preview_data.test.tsx @@ -7,7 +7,6 @@ import React, { SFC } from 'react'; import ReactDOM from 'react-dom'; -import { ml } from '../../../../../services/ml_api_service'; import { SimpleQuery } from '../../../../common'; import { PIVOT_PREVIEW_STATUS, @@ -17,7 +16,7 @@ import { import { IndexPattern } from 'ui/index_patterns'; -jest.mock('../../../../../services/ml_api_service'); +jest.mock('../../../../hooks/use_api'); type Callback = () => void; interface TestHookProps { @@ -57,8 +56,7 @@ describe('usePivotPreviewData', () => { expect(pivotPreviewObj.errorMessage).toBe(''); expect(pivotPreviewObj.status).toBe(PIVOT_PREVIEW_STATUS.UNUSED); - expect(pivotPreviewObj.dataFramePreviewData).toEqual([]); - expect(ml.dataFrame.getDataFrameTransformsPreview).not.toHaveBeenCalled(); + expect(pivotPreviewObj.previewData).toEqual([]); }); test('indexPattern set triggers loading', () => { @@ -75,12 +73,9 @@ describe('usePivotPreviewData', () => { // ideally this should be LOADING instead of UNUSED but jest/enzyme/hooks doesn't // trigger that state upate yet. expect(pivotPreviewObj.status).toBe(PIVOT_PREVIEW_STATUS.UNUSED); - expect(pivotPreviewObj.dataFramePreviewData).toEqual([]); - // ideally this should be 1 instead of 0 but jest/enzyme/hooks doesn't - // trigger that state upate yet. - expect(ml.dataFrame.getDataFrameTransformsPreview).toHaveBeenCalledTimes(0); + expect(pivotPreviewObj.previewData).toEqual([]); }); - // TODO add more tests to check data retrieved via `ml.esSearch()`. + // TODO add more tests to check data retrieved via `api.esSearch()`. // This needs more investigation in regards to jest/enzyme's React Hooks support. }); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/use_pivot_preview_data.ts b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/use_pivot_preview_data.ts similarity index 64% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/use_pivot_preview_data.ts rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/use_pivot_preview_data.ts index 5232daa5189aa..7f7d06a7d18e6 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_define/use_pivot_preview_data.ts +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_define/use_pivot_preview_data.ts @@ -9,7 +9,7 @@ import { useEffect, useState } from 'react'; import { IndexPattern } from 'ui/index_patterns'; import { dictionaryToArray } from '../../../../../../common/types/common'; -import { ml } from '../../../../../services/ml_api_service'; +import { useApi } from '../../../../hooks/use_api'; import { Dictionary } from '../../../../../../common/types/common'; import { ES_FIELD_TYPES } from '../../../../../../../../../../src/plugins/data/public'; @@ -32,22 +32,22 @@ interface EsMappingType { type: ES_FIELD_TYPES; } -type DataFramePreviewData = Array>; -interface DataFramePreviewMappings { +type PreviewData = Array>; +interface PreviewMappings { properties: Dictionary; } export interface UsePivotPreviewDataReturnType { errorMessage: string; status: PIVOT_PREVIEW_STATUS; - dataFramePreviewData: DataFramePreviewData; - dataFramePreviewMappings: DataFramePreviewMappings; + previewData: PreviewData; + previewMappings: PreviewMappings; previewRequest: PreviewRequestBody; } -export interface GetDataFrameTransformsResponse { - preview: DataFramePreviewData; - mappings: DataFramePreviewMappings; +export interface GetTransformsResponse { + preview: PreviewData; + mappings: PreviewMappings; } export const usePivotPreviewData = ( @@ -58,19 +58,18 @@ export const usePivotPreviewData = ( ): UsePivotPreviewDataReturnType => { const [errorMessage, setErrorMessage] = useState(''); const [status, setStatus] = useState(PIVOT_PREVIEW_STATUS.UNUSED); - const [dataFramePreviewData, setDataFramePreviewData] = useState([]); - const [dataFramePreviewMappings, setDataFramePreviewMappings] = useState< - DataFramePreviewMappings - >({ properties: {} }); + const [previewData, setPreviewData] = useState([]); + const [previewMappings, setPreviewMappings] = useState({ properties: {} }); + const api = useApi(); const aggsArr = dictionaryToArray(aggs); const groupByArr = dictionaryToArray(groupBy); const previewRequest = getPreviewRequestBody(indexPattern.title, query, groupByArr, aggsArr); - const getDataFramePreviewData = async () => { + const getPreviewData = async () => { if (aggsArr.length === 0 || groupByArr.length === 0) { - setDataFramePreviewData([]); + setPreviewData([]); return; } @@ -78,27 +77,25 @@ export const usePivotPreviewData = ( setStatus(PIVOT_PREVIEW_STATUS.LOADING); try { - const resp: GetDataFrameTransformsResponse = await ml.dataFrame.getDataFrameTransformsPreview( - previewRequest - ); - setDataFramePreviewData(resp.preview); - setDataFramePreviewMappings(resp.mappings); + const resp: GetTransformsResponse = await api.getTransformsPreview(previewRequest); + setPreviewData(resp.preview); + setPreviewMappings(resp.mappings); setStatus(PIVOT_PREVIEW_STATUS.LOADED); } catch (e) { setErrorMessage(JSON.stringify(e)); - setDataFramePreviewData([]); - setDataFramePreviewMappings({ properties: {} }); + setPreviewData([]); + setPreviewMappings({ properties: {} }); setStatus(PIVOT_PREVIEW_STATUS.ERROR); } }; useEffect(() => { - getDataFramePreviewData(); + getPreviewData(); }, [ indexPattern.title, JSON.stringify(aggsArr), JSON.stringify(groupByArr), JSON.stringify(query), ]); - return { errorMessage, status, dataFramePreviewData, dataFramePreviewMappings, previewRequest }; + return { errorMessage, status, previewData, previewMappings, previewRequest }; }; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_details/common.ts b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/common.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_details/common.ts rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/common.ts diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_details/index.ts b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_details/index.ts rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/index.ts diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_details/step_details_form.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx similarity index 66% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_details/step_details_form.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx index c210a48915360..88cf1bf471c46 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_details/step_details_form.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment, SFC, useEffect, useState } from 'react'; +import React, { Fragment, SFC, useContext, useEffect, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { metadata } from 'ui/metadata'; @@ -12,16 +12,12 @@ import { toastNotifications } from 'ui/notify'; import { EuiLink, EuiSwitch, EuiFieldText, EuiForm, EuiFormRow, EuiSelect } from '@elastic/eui'; -import { useKibanaContext } from '../../../../../contexts/kibana'; -import { isValidIndexName } from '../../../../../../common/util/es_utils'; +import { isKibanaContextInitialized, KibanaContext } from '../../../../lib/kibana'; +import { isValidIndexName } from '../../../../../../common/utils/es_utils'; -import { ml } from '../../../../../services/ml_api_service'; +import { useApi } from '../../../../hooks/use_api'; -import { - isTransformIdValid, - DataFrameTransformId, - DataFrameTransformPivotConfig, -} from '../../../../common'; +import { isTransformIdValid, TransformId, TransformPivotConfig } from '../../../../common'; import { EsIndexName, IndexPatternTitle } from './common'; import { delayValidator } from '../../../../common/validators'; @@ -32,7 +28,7 @@ export interface StepDetailsExposedState { destinationIndex: EsIndexName; isContinuousModeEnabled: boolean; touched: boolean; - transformId: DataFrameTransformId; + transformId: TransformId; transformDescription: string; valid: boolean; } @@ -57,16 +53,16 @@ interface Props { } export const StepDetailsForm: SFC = React.memo(({ overrides = {}, onChange }) => { - const kibanaContext = useKibanaContext(); + const kibanaContext = useContext(KibanaContext); const defaults = { ...getDefaultStepDetailsState(), ...overrides }; - const [transformId, setTransformId] = useState(defaults.transformId); + const [transformId, setTransformId] = useState(defaults.transformId); const [transformDescription, setTransformDescription] = useState( defaults.transformDescription ); const [destinationIndex, setDestinationIndex] = useState(defaults.destinationIndex); - const [transformIds, setTransformIds] = useState([]); + const [transformIds, setTransformIds] = useState([]); const [indexNames, setIndexNames] = useState([]); const [indexPatternTitles, setIndexPatternTitles] = useState([]); const [createIndexPattern, setCreateIndexPattern] = useState(defaults.createIndexPattern); @@ -75,6 +71,59 @@ export const StepDetailsForm: SFC = React.memo(({ overrides = {}, onChang const [isContinuousModeEnabled, setContinuousModeEnabled] = useState( defaults.isContinuousModeEnabled ); + + const api = useApi(); + + // fetch existing transform IDs and indices once for form validation + useEffect(() => { + // use an IIFE to avoid returning a Promise to useEffect. + (async function() { + if (isKibanaContextInitialized(kibanaContext)) { + try { + setTransformIds( + (await api.getTransforms()).transforms.map( + (transform: TransformPivotConfig) => transform.id + ) + ); + } catch (e) { + toastNotifications.addDanger( + i18n.translate('xpack.transform.stepDetailsForm.errorGettingTransformList', { + defaultMessage: 'An error occurred getting the existing transform IDs: {error}', + values: { error: JSON.stringify(e) }, + }) + ); + } + + try { + setIndexNames((await api.getIndices()).map(index => index.name)); + } catch (e) { + toastNotifications.addDanger( + i18n.translate('xpack.transform.stepDetailsForm.errorGettingIndexNames', { + defaultMessage: 'An error occurred getting the existing index names: {error}', + values: { error: JSON.stringify(e) }, + }) + ); + } + + try { + setIndexPatternTitles(await kibanaContext.indexPatterns.getTitles()); + } catch (e) { + toastNotifications.addDanger( + i18n.translate('xpack.transform.stepDetailsForm.errorGettingIndexPatternTitles', { + defaultMessage: + 'An error occurred getting the existing index pattern titles: {error}', + values: { error: JSON.stringify(e) }, + }) + ); + } + } + })(); + }, [kibanaContext.initialized]); + + if (!isKibanaContextInitialized(kibanaContext)) { + return null; + } + const dateFieldNames = kibanaContext.currentIndexPattern.fields .filter(f => f.type === 'date') .map(f => f.name) @@ -86,50 +135,6 @@ export const StepDetailsForm: SFC = React.memo(({ overrides = {}, onChang const [continuousModeDelay, setContinuousModeDelay] = useState(defaults.continuousModeDelay); const isContinuousModeDelayValid = delayValidator(continuousModeDelay); - // fetch existing transform IDs and indices once for form validation - useEffect(() => { - // use an IIFE to avoid returning a Promise to useEffect. - (async function() { - try { - setTransformIds( - (await ml.dataFrame.getDataFrameTransforms()).transforms.map( - (transform: DataFrameTransformPivotConfig) => transform.id - ) - ); - } catch (e) { - toastNotifications.addDanger( - i18n.translate('xpack.ml.dataframe.stepDetailsForm.errorGettingDataFrameTransformList', { - defaultMessage: - 'An error occurred getting the existing data frame transform Ids: {error}', - values: { error: JSON.stringify(e) }, - }) - ); - } - - try { - setIndexNames((await ml.getIndices()).map(index => index.name)); - } catch (e) { - toastNotifications.addDanger( - i18n.translate('xpack.ml.dataframe.stepDetailsForm.errorGettingDataFrameIndexNames', { - defaultMessage: 'An error occurred getting the existing index names: {error}', - values: { error: JSON.stringify(e) }, - }) - ); - } - - try { - setIndexPatternTitles(await kibanaContext.indexPatterns.getTitles()); - } catch (e) { - toastNotifications.addDanger( - i18n.translate('xpack.ml.dataframe.stepDetailsForm.errorGettingIndexPatternTitles', { - defaultMessage: 'An error occurred getting the existing index pattern titles: {error}', - values: { error: JSON.stringify(e) }, - }) - ); - } - })(); - }, []); - const transformIdExists = transformIds.some(id => transformId === id); const transformIdEmpty = transformId === ''; const transformIdValid = isTransformIdValid(transformId); @@ -175,14 +180,14 @@ export const StepDetailsForm: SFC = React.memo(({ overrides = {}, onChang return ( = React.memo(({ overrides = {}, onChang : []), ...(transformIdExists ? [ - i18n.translate('xpack.ml.dataframe.stepDetailsForm.transformIdExistsError', { - defaultMessage: 'A transform with this id already exists.', + i18n.translate('xpack.transform.stepDetailsForm.transformIdExistsError', { + defaultMessage: 'A transform with this ID already exists.', }), ] : []), ]} > setTransformId(e.target.value)} - aria-label={i18n.translate( - 'xpack.ml.dataframe.stepDetailsForm.transformIdInputAriaLabel', - { - defaultMessage: 'Choose a unique transform id.', - } - )} + aria-label={i18n.translate('xpack.transform.stepDetailsForm.transformIdInputAriaLabel', { + defaultMessage: 'Choose a unique transform ID.', + })} isInvalid={(!transformIdEmpty && !transformIdValid) || transformIdExists} /> setTransformDescription(e.target.value)} aria-label={i18n.translate( - 'xpack.ml.dataframe.stepDetailsForm.transformDescriptionInputAriaLabel', + 'xpack.transform.stepDetailsForm.transformDescriptionInputAriaLabel', { defaultMessage: 'Choose an optional transform description.', } @@ -234,13 +233,13 @@ export const StepDetailsForm: SFC = React.memo(({ overrides = {}, onChang /> = React.memo(({ overrides = {}, onChang !indexNameEmpty && !indexNameValid && [ - {i18n.translate('xpack.ml.dataframe.stepDetailsForm.destinationIndexInvalidError', { + {i18n.translate('xpack.transform.stepDetailsForm.destinationIndexInvalidError', { defaultMessage: 'Invalid destination index name.', })}
@@ -258,7 +257,7 @@ export const StepDetailsForm: SFC = React.memo(({ overrides = {}, onChang target="_blank" > {i18n.translate( - 'xpack.ml.dataframe.stepDetailsForm.destinationIndexInvalidErrorLink', + 'xpack.transform.stepDetailsForm.destinationIndexInvalidErrorLink', { defaultMessage: 'Learn more about index name limitations.', } @@ -273,7 +272,7 @@ export const StepDetailsForm: SFC = React.memo(({ overrides = {}, onChang value={destinationIndex} onChange={e => setDestinationIndex(e.target.value)} aria-label={i18n.translate( - 'xpack.ml.dataframe.stepDetailsForm.destinationIndexInputAriaLabel', + 'xpack.transform.stepDetailsForm.destinationIndexInputAriaLabel', { defaultMessage: 'Choose a unique destination index name.', } @@ -286,15 +285,15 @@ export const StepDetailsForm: SFC = React.memo(({ overrides = {}, onChang error={ createIndexPattern && indexPatternTitleExists && [ - i18n.translate('xpack.ml.dataframe.stepDetailsForm.indexPatternTitleError', { + i18n.translate('xpack.transform.stepDetailsForm.indexPatternTitleError', { defaultMessage: 'An index pattern with this title already exists.', }), ] } > = React.memo(({ overrides = {}, onChang = React.memo(({ overrides = {}, onChang {isContinuousModeEnabled && ( = React.memo(({ overrides = {}, onChang /> = React.memo(({ overrides = {}, onChang value={continuousModeDelay} onChange={e => setContinuousModeDelay(e.target.value)} aria-label={i18n.translate( - 'xpack.ml.dataframe.stepDetailsForm.continuousModeAriaLabel', + 'xpack.transform.stepDetailsForm.continuousModeAriaLabel', { defaultMessage: 'Choose a delay.', } diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_details/step_details_summary.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_summary.tsx similarity index 78% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_details/step_details_summary.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_summary.tsx index b06f2aeced0ee..1f2280fa4fb19 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/step_details/step_details_summary.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_summary.tsx @@ -27,7 +27,7 @@ export const StepDetailsSummary: SFC = React.memo( } const destinationIndexHelpText = createIndexPattern - ? i18n.translate('xpack.ml.dataframe.stepDetailsSummary.createIndexPatternMessage', { + ? i18n.translate('xpack.transform.stepDetailsSummary.createIndexPatternMessage', { defaultMessage: 'A Kibana index pattern will be created for this transform.', }) : ''; @@ -35,14 +35,14 @@ export const StepDetailsSummary: SFC = React.memo( return ( @@ -50,7 +50,7 @@ export const StepDetailsSummary: SFC = React.memo( @@ -59,7 +59,7 @@ export const StepDetailsSummary: SFC = React.memo( {isContinuousModeEnabled && ( = ({ }; export const Wizard: SFC = React.memo(() => { - const kibanaContext = useKibanaContext(); - - const indexPattern = kibanaContext.currentIndexPattern; + const kibanaContext = useContext(KibanaContext); // The current WIZARD_STEP const [currentStep, setCurrentStep] = useState(WIZARD_STEPS.DEFINE); @@ -83,15 +81,22 @@ export const Wizard: SFC = React.memo(() => { ); + // The CREATE state + const [stepCreateState, setStepCreateState] = useState(getDefaultStepCreateState); + + if (!isKibanaContextInitialized(kibanaContext)) { + // TODO proper loading indicator + return null; + } + + const indexPattern = kibanaContext.currentIndexPattern; + const transformConfig = getCreateRequestBody( indexPattern.title, stepDefineState, stepDetailsState ); - // The CREATE state - const [stepCreateState, setStepCreateState] = useState(getDefaultStepCreateState); - const stepCreate = currentStep === WIZARD_STEPS.CREATE ? ( { const stepsConfig = [ { - title: i18n.translate('xpack.ml.dataframe.transformsWizard.stepDefineTitle', { + title: i18n.translate('xpack.transform.transformsWizard.stepDefineTitle', { defaultMessage: 'Define pivot', }), children: ( @@ -132,7 +137,7 @@ export const Wizard: SFC = React.memo(() => { ), }, { - title: i18n.translate('xpack.ml.dataframe.transformsWizard.stepDetailsTitle', { + title: i18n.translate('xpack.transform.transformsWizard.stepDetailsTitle', { defaultMessage: 'Transform details', }), children: ( @@ -153,7 +158,7 @@ export const Wizard: SFC = React.memo(() => { status: currentStep >= WIZARD_STEPS.DETAILS ? undefined : ('incomplete' as EuiStepStatus), }, { - title: i18n.translate('xpack.ml.dataframe.transformsWizard.stepCreateTitle', { + title: i18n.translate('xpack.transform.transformsWizard.stepCreateTitle', { defaultMessage: 'Create', }), children: ( diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/wizard_nav/index.ts b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/wizard_nav/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/wizard_nav/index.ts rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/wizard_nav/index.ts diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/wizard_nav/wizard_nav.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/wizard_nav/wizard_nav.tsx similarity index 88% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/wizard_nav/wizard_nav.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/wizard_nav/wizard_nav.tsx index 49388a5c53167..78273d825c152 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/data_frame_new_pivot/components/wizard_nav/wizard_nav.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/wizard_nav/wizard_nav.tsx @@ -28,7 +28,7 @@ export const WizardNav: SFC = ({ {previous && ( - {i18n.translate('xpack.ml.dataframe.wizard.previousStepButton', { + {i18n.translate('xpack.transform.wizard.previousStepButton', { defaultMessage: 'Previous', })} @@ -37,7 +37,7 @@ export const WizardNav: SFC = ({ {next && ( - {i18n.translate('xpack.ml.dataframe.wizard.nextStepButton', { + {i18n.translate('xpack.transform.wizard.nextStepButton', { defaultMessage: 'Next', })} diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/create_transform_section.tsx b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/create_transform_section.tsx new file mode 100644 index 0000000000000..8e33b2ebac89a --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/create_transform_section.tsx @@ -0,0 +1,77 @@ +/* + * 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 React, { useEffect, FC } from 'react'; +import { RouteComponentProps } from 'react-router-dom'; + +import { FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; + +import { + EuiBetaBadge, + EuiPage, + EuiPageBody, + EuiPageContentBody, + EuiPageContentHeader, + EuiPageContentHeaderSection, + EuiSpacer, + EuiTitle, +} from '@elastic/eui'; + +import { APP_CREATE_TRANSFORM_CLUSTER_PRIVILEGES } from '../../../../common/constants'; +import { breadcrumbService, docTitleService, BREADCRUMB_SECTION } from '../../services/navigation'; +import { PrivilegesWrapper } from '../../lib/authorization'; +import { KibanaProvider } from '../../lib/kibana'; + +import { Wizard } from './components/wizard'; + +type Props = RouteComponentProps<{ savedObjectId: string }>; +export const CreateTransformSection: FC = ({ match }) => { + // Set breadcrumb and page title + useEffect(() => { + breadcrumbService.setBreadcrumbs(BREADCRUMB_SECTION.CREATE_TRANSFORM); + docTitleService.setTitle('createTransform'); + }, []); + + return ( + + + + + + + +

+ +   + +

+
+
+
+ + + + +
+
+
+
+ ); +}; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/index.ts b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/index.ts new file mode 100644 index 0000000000000..a6946e87ca8cb --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/index.ts @@ -0,0 +1,7 @@ +/* + * 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 { CreateTransformSection } from './create_transform_section'; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/__snapshots__/transform_management_section.test.tsx.snap b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/__snapshots__/transform_management_section.test.tsx.snap new file mode 100644 index 0000000000000..df8002cb7145d --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/__snapshots__/transform_management_section.test.tsx.snap @@ -0,0 +1,14 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Transform: Minimal initialization 1`] = ` + + + +`; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/create_transform_button/__snapshots__/create_transform_button.test.tsx.snap b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/create_transform_button/__snapshots__/create_transform_button.test.tsx.snap new file mode 100644 index 0000000000000..94841ad026f80 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/create_transform_button/__snapshots__/create_transform_button.test.tsx.snap @@ -0,0 +1,24 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Transform: Transform List Minimal initialization 1`] = ` + + + + + +`; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/create_transform_button/_index.scss b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/create_transform_button/_index.scss new file mode 100644 index 0000000000000..caf02294781b0 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/create_transform_button/_index.scss @@ -0,0 +1 @@ +@import 'transform_search_dialog'; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/create_transform_button/_transform_search_dialog.scss b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/create_transform_button/_transform_search_dialog.scss new file mode 100644 index 0000000000000..e8559e0ab38af --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/create_transform_button/_transform_search_dialog.scss @@ -0,0 +1,4 @@ +.transformCreateTransformSearchDialog { + width: $euiSizeL * 30; + min-height: $euiSizeL * 25; +} diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/create_transform_button/create_transform_button.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.test.tsx similarity index 72% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/create_transform_button/create_transform_button.test.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.test.tsx index cf421a03f0d25..673e60de54572 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/create_transform_button/create_transform_button.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.test.tsx @@ -9,9 +9,11 @@ import React from 'react'; import { CreateTransformButton } from './create_transform_button'; -describe('Data Frame: Transform List ', () => { +jest.mock('ui/new_platform'); + +describe('Transform: Transform List ', () => { test('Minimal initialization', () => { - const wrapper = shallow(); + const wrapper = shallow(); expect(wrapper).toMatchSnapshot(); }); diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.tsx new file mode 100644 index 0000000000000..c06be15f259d0 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.tsx @@ -0,0 +1,55 @@ +/* + * 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 React, { useContext, FC, MouseEventHandler } from 'react'; + +import { EuiButton, EuiToolTip } from '@elastic/eui'; + +import { FormattedMessage } from '@kbn/i18n/react'; + +import { + createCapabilityFailureMessage, + AuthorizationContext, +} from '../../../../lib/authorization'; + +interface CreateTransformButtonProps { + onClick: MouseEventHandler; +} + +export const CreateTransformButton: FC = ({ onClick }) => { + const { capabilities } = useContext(AuthorizationContext); + + const disabled = + !capabilities.canCreateTransform || + !capabilities.canPreviewTransform || + !capabilities.canStartStopTransform; + + const createTransformButton = ( + + + + ); + + if (disabled) { + return ( + + {createTransformButton} + + ); + } + + return createTransformButton; +}; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/create_transform_button/index.ts b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/create_transform_button/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/create_transform_button/index.ts rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/create_transform_button/index.ts diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/refresh_transform_list_button/index.ts b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/refresh_transform_list_button/index.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/refresh_transform_list_button/index.ts rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/refresh_transform_list_button/index.ts diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/refresh_transform_list_button/refresh_transform_list_button.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/refresh_transform_list_button/refresh_transform_list_button.tsx similarity index 86% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/refresh_transform_list_button/refresh_transform_list_button.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/refresh_transform_list_button/refresh_transform_list_button.tsx index 2a7aa525af410..e8ebc42ecc180 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/refresh_transform_list_button/refresh_transform_list_button.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/refresh_transform_list_button/refresh_transform_list_button.tsx @@ -18,12 +18,12 @@ export const RefreshTransformListButton: FC = ({ isLoading, }) => ( diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/index.ts b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/search_selection/index.ts similarity index 80% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/index.ts rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/search_selection/index.ts index 4c0832c7e6481..c2cf409df1f26 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/index.ts +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/search_selection/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { DataFrameTransformList } from './transform_list'; +export { SearchSelection } from './search_selection'; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/search_selection/search_selection.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/search_selection/search_selection.tsx new file mode 100644 index 0000000000000..1a270505d61a6 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/search_selection/search_selection.tsx @@ -0,0 +1,72 @@ +/* + * 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 { EuiModalBody, EuiModalHeader, EuiModalHeaderTitle } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import React, { FC } from 'react'; + +import { SavedObjectFinder } from 'ui/saved_objects/components/saved_object_finder'; + +interface SearchSelectionProps { + onSearchSelected: (searchId: string, searchType: string) => void; +} + +const fixedPageSize: number = 8; + +export const SearchSelection: FC = ({ onSearchSelected }) => ( + <> + + + {' '} + /{' '} + + + + + 'search', + name: i18n.translate( + 'xpack.transform.newTransform.searchSelection.savedObjectType.search', + { + defaultMessage: 'Saved search', + } + ), + }, + { + type: 'index-pattern', + getIconForSavedObject: () => 'indexPatternApp', + name: i18n.translate( + 'xpack.transform.newTransform.searchSelection.savedObjectType.indexPattern', + { + defaultMessage: 'Index pattern', + } + ), + }, + ]} + fixedPageSize={fixedPageSize} + /> + + +); diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/stats_bar/_index.scss b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/stats_bar/_index.scss new file mode 100644 index 0000000000000..e8d8e85763eff --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/stats_bar/_index.scss @@ -0,0 +1,2 @@ +@import 'stat'; +@import 'stats_bar'; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/stats_bar/_stat.scss b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/stats_bar/_stat.scss new file mode 100644 index 0000000000000..7f6ee44a738a5 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/stats_bar/_stat.scss @@ -0,0 +1,3 @@ +.transformStat { + margin-right: $euiSizeS; +} diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/stats_bar/_stats_bar.scss b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/stats_bar/_stats_bar.scss new file mode 100644 index 0000000000000..88153c0ef6507 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/stats_bar/_stats_bar.scss @@ -0,0 +1,6 @@ +.transformStatsBar { + // SASSTODO: proper calcs + height: 42px; + padding: 14px; + background-color: $euiColorLightestShade; +} diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/stats_bar/index.ts b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/stats_bar/index.ts new file mode 100644 index 0000000000000..4c781afe0a64c --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/stats_bar/index.ts @@ -0,0 +1,7 @@ +/* + * 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 { StatsBar, TransformStatsBarStats } from './stats_bar'; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/stats_bar/stat.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/stats_bar/stat.tsx new file mode 100644 index 0000000000000..4f0f360779e04 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/stats_bar/stat.tsx @@ -0,0 +1,24 @@ +/* + * 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 React, { FC } from 'react'; + +export interface StatsBarStat { + label: string; + value: string | number; + show?: boolean; +} +interface StatProps { + stat: StatsBarStat; +} + +export const Stat: FC = ({ stat }) => { + return ( + + {stat.label}: {stat.value} + + ); +}; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/stats_bar/stats_bar.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/stats_bar/stats_bar.tsx new file mode 100644 index 0000000000000..59e68c4421f01 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/stats_bar/stats_bar.tsx @@ -0,0 +1,40 @@ +/* + * 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 React, { FC } from 'react'; +import { Stat, StatsBarStat } from './stat'; + +interface Stats { + total: StatsBarStat; + failed: StatsBarStat; +} + +export interface TransformStatsBarStats extends Stats { + batch: StatsBarStat; + continuous: StatsBarStat; + started: StatsBarStat; +} + +type StatsBarStats = TransformStatsBarStats; +type StatsKey = keyof StatsBarStats; + +interface StatsBarProps { + stats: StatsBarStats; + dataTestSub: string; +} + +export const StatsBar: FC = ({ stats, dataTestSub }) => { + const statsList = Object.keys(stats).map(k => stats[k as StatsKey]); + return ( +
+ {statsList + .filter((s: StatsBarStat) => s.show) + .map((s: StatsBarStat) => ( + + ))} +
+ ); +}; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/__snapshots__/action_delete.test.tsx.snap b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/action_delete.test.tsx.snap similarity index 64% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/__snapshots__/action_delete.test.tsx.snap rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/action_delete.test.tsx.snap index 736559eb63cf5..5695b8a847496 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/__snapshots__/action_delete.test.tsx.snap +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/action_delete.test.tsx.snap @@ -1,9 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Data Frame: Transform List Actions Minimal initialization 1`] = ` +exports[`Transform: Transform List Actions Minimal initialization 1`] = ` diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/__snapshots__/action_start.test.tsx.snap b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/action_start.test.tsx.snap similarity index 63% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/__snapshots__/action_start.test.tsx.snap rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/action_start.test.tsx.snap index 3e6cf9368e23f..17018576ad719 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/__snapshots__/action_start.test.tsx.snap +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/action_start.test.tsx.snap @@ -1,9 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Data Frame: Transform List Actions Minimal initialization 1`] = ` +exports[`Transform: Transform List Actions Minimal initialization 1`] = ` diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/__snapshots__/action_stop.test.tsx.snap b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/action_stop.test.tsx.snap similarity index 59% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/__snapshots__/action_stop.test.tsx.snap rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/action_stop.test.tsx.snap index d8b0b088580f7..95962ac11b658 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/__snapshots__/action_stop.test.tsx.snap +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/action_stop.test.tsx.snap @@ -1,8 +1,8 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Data Frame: Transform List Actions Minimal initialization 1`] = ` +exports[`Transform: Transform List Actions Minimal initialization 1`] = ` diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/__snapshots__/expanded_row.test.tsx.snap b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/expanded_row.test.tsx.snap similarity index 97% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/__snapshots__/expanded_row.test.tsx.snap rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/expanded_row.test.tsx.snap index 1744c2c2635b1..40ad836ad9969 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/__snapshots__/expanded_row.test.tsx.snap +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/expanded_row.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Data Frame: Transform List Minimal initialization 1`] = ` +exports[`Transform: Transform List Minimal initialization 1`] = ` Minimal initialization 1`] = "items": Array [ Object { "description": "fq_date_histogram_1m_1441", - "title": "id", + "title": "ID", }, Object { "description": "stopped", @@ -96,6 +96,11 @@ exports[`Data Frame: Transform List Minimal initialization 1`] = } onTabClick={[Function]} size="s" + style={ + Object { + "width": "100%", + } + } tabs={ Array [ Object { @@ -106,7 +111,7 @@ exports[`Data Frame: Transform List Minimal initialization 1`] = "items": Array [ Object { "description": "fq_date_histogram_1m_1441", - "title": "id", + "title": "ID", }, Object { "description": "stopped", diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/__snapshots__/expanded_row_details_pane.test.tsx.snap b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/expanded_row_details_pane.test.tsx.snap similarity index 83% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/__snapshots__/expanded_row_details_pane.test.tsx.snap rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/expanded_row_details_pane.test.tsx.snap index 3fee6229a71aa..b55a1c410d687 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/__snapshots__/expanded_row_details_pane.test.tsx.snap +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/expanded_row_details_pane.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Data Frame: Job List Expanded Row Minimal initialization 1`] = ` +exports[`Transform: Job List Expanded Row Minimal initialization 1`] = ` Minimal in `; -exports[`Data Frame: Job List Expanded Row
Minimal initialization 1`] = ` +exports[`Transform: Job List Expanded Row
Minimal initialization 1`] = ` Minimal initialization 1`] = ` +exports[`Transform: Transform List Expanded Row Minimal initialization 1`] = ` Minimal initialization 1`] = ` +exports[`Transform: Transform List Minimal initialization 1`] = ` Minimal initializ Array [ - Create your first data frame transform + Create your first transform , ] } - data-test-subj="mlNoDataFrameTransformsFound" + data-test-subj="transformNoTransformsFound" title={

- No data frame transforms found + No transforms found

} /> diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/_index.scss b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/_index.scss similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/_index.scss rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/_index.scss diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/_transform_table.scss b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/_transform_table.scss similarity index 82% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/_transform_table.scss rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/_transform_table.scss index d16a83cb1539f..a9e2e4d790436 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/_transform_table.scss +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/_transform_table.scss @@ -1,4 +1,4 @@ -.mlTransformTable { +.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. @@ -17,14 +17,14 @@ animation: none !important; } } -.mlTransformBulkActionItem { +.transform__BulkActionItem { display: block; padding: $euiSizeS; width: 100%; text-align: left; } -.mlTransformBulkActionsBorder { +.transform__BulkActionsBorder { height: 20px; border-right: $euiBorderThin; width: 1px; @@ -35,14 +35,14 @@ margin-top: -5px; } -.mlTransformProgressBar { +.transform__ProgressBar { margin-bottom: $euiSizeM; } -.mlTaskStateBadge, .mlTaskModeBadge { +.transform__TaskStateBadge, .transform__TaskModeBadge { max-width: 100px; } -.mlTransformTable__messagesPaneTable .euiTableCellContent__text { +.transform__TransformTable__messagesPaneTable .euiTableCellContent__text { text-align: left; } diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_delete.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_delete.test.tsx new file mode 100644 index 0000000000000..979da13b1f83a --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_delete.test.tsx @@ -0,0 +1,41 @@ +/* + * 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 { shallow } from 'enzyme'; +import React from 'react'; + +import { createPublicShim } from '../../../../../shim'; +import { getAppProviders } from '../../../../app_dependencies'; + +import { TransformListRow } from '../../../../common'; +import { DeleteAction } from './action_delete'; + +import transformListRow from '../../../../common/__mocks__/transform_list_row.json'; + +jest.mock('ui/new_platform'); + +describe('Transform: Transform List Actions ', () => { + test('Minimal initialization', () => { + const Providers = getAppProviders(createPublicShim()); + + const item: TransformListRow = transformListRow; + const props = { + disabled: false, + items: [item], + deleteTransform(d: TransformListRow) {}, + }; + + const wrapper = shallow( + + + + ) + .find(DeleteAction) + .shallow(); + + expect(wrapper).toMatchSnapshot(); + }); +}); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/action_delete.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_delete.tsx similarity index 66% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/action_delete.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_delete.tsx index 3bf660d2bdd37..08db7a608be2c 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/action_delete.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_delete.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment, FC, useState } from 'react'; +import React, { Fragment, FC, useContext, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiButtonEmpty, @@ -14,28 +14,27 @@ import { EUI_MODAL_CONFIRM_BUTTON, } from '@elastic/eui'; -import { deleteTransforms } from '../../services/transform_service'; +import { useDeleteTransforms } from '../../../../hooks'; import { - checkPermission, - createPermissionFailureMessage, -} from '../../../../../privilege/check_privilege'; + createCapabilityFailureMessage, + AuthorizationContext, +} from '../../../../lib/authorization'; -import { DataFrameTransformListRow, DATA_FRAME_TRANSFORM_STATE } from '../../../../common'; +import { TransformListRow, TRANSFORM_STATE } from '../../../../common'; interface DeleteActionProps { - items: DataFrameTransformListRow[]; + items: TransformListRow[]; forceDisable?: boolean; } export const DeleteAction: FC = ({ items, forceDisable }) => { const isBulkAction = items.length > 1; - const disabled = items.some( - (i: DataFrameTransformListRow) => i.stats.state !== DATA_FRAME_TRANSFORM_STATE.STOPPED - ); + const disabled = items.some((i: TransformListRow) => i.stats.state !== TRANSFORM_STATE.STOPPED); - const canDeleteDataFrame: boolean = checkPermission('canDeleteDataFrame'); + const { canDeleteTransform } = useContext(AuthorizationContext).capabilities; + const deleteTransforms = useDeleteTransforms(); const [isModalVisible, setModalVisible] = useState(false); @@ -46,42 +45,41 @@ export const DeleteAction: FC = ({ items, forceDisable }) => }; const openModal = () => setModalVisible(true); - const buttonDeleteText = i18n.translate('xpack.ml.dataframe.transformList.deleteActionName', { + const buttonDeleteText = i18n.translate('xpack.transform.transformList.deleteActionName', { defaultMessage: 'Delete', }); const bulkDeleteButtonDisabledText = i18n.translate( - 'xpack.ml.dataframe.transformList.deleteBulkActionDisabledToolTipContent', + 'xpack.transform.transformList.deleteBulkActionDisabledToolTipContent', { - defaultMessage: - 'One or more selected data frame transforms must be stopped in order to be deleted.', + defaultMessage: 'One or more selected transforms must be stopped in order to be deleted.', } ); const deleteButtonDisabledText = i18n.translate( - 'xpack.ml.dataframe.transformList.deleteActionDisabledToolTipContent', + 'xpack.transform.transformList.deleteActionDisabledToolTipContent', { - defaultMessage: 'Stop the data frame transform in order to delete it.', + defaultMessage: 'Stop the transform in order to delete it.', } ); const bulkDeleteModalTitle = i18n.translate( - 'xpack.ml.dataframe.transformList.bulkDeleteModalTitle', + 'xpack.transform.transformList.bulkDeleteModalTitle', { defaultMessage: 'Delete {count} {count, plural, one {transform} other {transforms}}?', values: { count: items.length }, } ); - const deleteModalTitle = i18n.translate('xpack.ml.dataframe.transformList.deleteModalTitle', { + const deleteModalTitle = i18n.translate('xpack.transform.transformList.deleteModalTitle', { defaultMessage: 'Delete {transformId}', values: { transformId: items[0] && items[0].config.id }, }); const bulkDeleteModalMessage = i18n.translate( - 'xpack.ml.dataframe.transformList.bulkDeleteModalBody', + 'xpack.transform.transformList.bulkDeleteModalBody', { defaultMessage: "Are you sure you want to delete {count, plural, one {this} other {these}} {count} {count, plural, one {transform} other {transforms}}? The transform's destination index and optional Kibana index pattern will not be deleted.", values: { count: items.length }, } ); - const deleteModalMessage = i18n.translate('xpack.ml.dataframe.transformList.deleteModalBody', { + const deleteModalMessage = i18n.translate('xpack.transform.transformList.deleteModalBody', { defaultMessage: `Are you sure you want to delete this transform? The transform's destination index and optional Kibana index pattern will not be deleted.`, }); @@ -89,7 +87,7 @@ export const DeleteAction: FC = ({ items, forceDisable }) => = ({ items, forceDisable }) => ); - if (disabled || !canDeleteDataFrame) { + if (disabled || !canDeleteTransform) { let content; if (disabled) { content = isBulkAction === true ? bulkDeleteButtonDisabledText : deleteButtonDisabledText; } else { - content = createPermissionFailureMessage('canStartStopDataFrame'); + content = createCapabilityFailureMessage('canDeleteTransform'); } deleteButton = ( @@ -123,13 +121,13 @@ export const DeleteAction: FC = ({ items, forceDisable }) => onCancel={closeModal} onConfirm={deleteAndCloseModal} cancelButtonText={i18n.translate( - 'xpack.ml.dataframe.transformList.deleteModalCancelButton', + 'xpack.transform.transformList.deleteModalCancelButton', { defaultMessage: 'Cancel', } )} confirmButtonText={i18n.translate( - 'xpack.ml.dataframe.transformList.deleteModalDeleteButton', + 'xpack.transform.transformList.deleteModalDeleteButton', { defaultMessage: 'Delete', } diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_start.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_start.test.tsx new file mode 100644 index 0000000000000..71a2eff39506d --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_start.test.tsx @@ -0,0 +1,41 @@ +/* + * 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 { shallow } from 'enzyme'; +import React from 'react'; + +import { createPublicShim } from '../../../../../shim'; +import { getAppProviders } from '../../../../app_dependencies'; + +import { TransformListRow } from '../../../../common'; +import { StartAction } from './action_start'; + +import transformListRow from '../../../../common/__mocks__/transform_list_row.json'; + +jest.mock('ui/new_platform'); + +describe('Transform: Transform List Actions ', () => { + test('Minimal initialization', () => { + const Providers = getAppProviders(createPublicShim()); + + const item: TransformListRow = transformListRow; + const props = { + disabled: false, + items: [item], + startTransform(d: TransformListRow) {}, + }; + + const wrapper = shallow( + + + + ) + .find(StartAction) + .shallow(); + + expect(wrapper).toMatchSnapshot(); + }); +}); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/action_start.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_start.tsx similarity index 59% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/action_start.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_start.tsx index 224ce99ac7ca0..c81661f218443 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/action_start.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_start.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment, FC, useState } from 'react'; +import React, { Fragment, FC, useContext, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiButtonEmpty, @@ -14,27 +14,24 @@ import { EUI_MODAL_CONFIRM_BUTTON, } from '@elastic/eui'; -import { startTransforms } from '../../services/transform_service'; +import { useStartTransforms } from '../../../../hooks'; import { - checkPermission, - createPermissionFailureMessage, -} from '../../../../../privilege/check_privilege'; + createCapabilityFailureMessage, + AuthorizationContext, +} from '../../../../lib/authorization'; -import { - DataFrameTransformListRow, - isCompletedBatchTransform, - DATA_FRAME_TRANSFORM_STATE, -} from '../../../../common'; +import { TransformListRow, isCompletedBatchTransform, TRANSFORM_STATE } from '../../../../common'; interface StartActionProps { - items: DataFrameTransformListRow[]; + items: TransformListRow[]; forceDisable?: boolean; } export const StartAction: FC = ({ items, forceDisable }) => { const isBulkAction = items.length > 1; - const canStartStopDataFrameTransform: boolean = checkPermission('canStartStopDataFrame'); + const { canStartStopTransform } = useContext(AuthorizationContext).capabilities; + const startTransforms = useStartTransforms(); const [isModalVisible, setModalVisible] = useState(false); @@ -45,17 +42,15 @@ export const StartAction: FC = ({ items, forceDisable }) => { }; const openModal = () => setModalVisible(true); - const buttonStartText = i18n.translate('xpack.ml.dataframe.transformList.startActionName', { + const buttonStartText = i18n.translate('xpack.transform.transformList.startActionName', { defaultMessage: 'Start', }); // Disable start for batch transforms which have completed. - const completedBatchTransform = items.some((i: DataFrameTransformListRow) => - isCompletedBatchTransform(i) - ); + const completedBatchTransform = items.some((i: TransformListRow) => isCompletedBatchTransform(i)); // Disable start action if one of the transforms is already started or trying to restart will throw error const startedTransform = items.some( - (i: DataFrameTransformListRow) => i.stats.state === DATA_FRAME_TRANSFORM_STATE.STARTED + (i: TransformListRow) => i.stats.state === TRANSFORM_STATE.STARTED ); let startedTransformMessage; @@ -63,28 +58,28 @@ export const StartAction: FC = ({ items, forceDisable }) => { if (isBulkAction === true) { startedTransformMessage = i18n.translate( - 'xpack.ml.dataframe.transformList.startedTransformBulkToolTip', + 'xpack.transform.transformList.startedTransformBulkToolTip', { - defaultMessage: 'One or more selected data frame transforms is already started.', + defaultMessage: 'One or more transforms are already started.', } ); completedBatchTransformMessage = i18n.translate( - 'xpack.ml.dataframe.transformList.completeBatchTransformBulkActionToolTip', + 'xpack.transform.transformList.completeBatchTransformBulkActionToolTip', { defaultMessage: - 'One or more selected data frame transforms is a completed batch transform and cannot be restarted.', + 'One or more transforms are completed batch transforms and cannot be restarted.', } ); } else { startedTransformMessage = i18n.translate( - 'xpack.ml.dataframe.transformList.startedTransformToolTip', + 'xpack.transform.transformList.startedTransformToolTip', { defaultMessage: '{transformId} is already started.', values: { transformId: items[0] && items[0].config.id }, } ); completedBatchTransformMessage = i18n.translate( - 'xpack.ml.dataframe.transformList.completeBatchTransformToolTip', + 'xpack.transform.transformList.completeBatchTransformToolTip', { defaultMessage: '{transformId} is a completed batch transform and cannot be restarted.', values: { transformId: items[0] && items[0].config.id }, @@ -92,8 +87,7 @@ export const StartAction: FC = ({ items, forceDisable }) => { ); } - const actionIsDisabled = - !canStartStopDataFrameTransform || completedBatchTransform || startedTransform; + const actionIsDisabled = !canStartStopTransform || completedBatchTransform || startedTransform; let startButton = ( = ({ items, forceDisable }) => { if (actionIsDisabled) { let content; - if (!canStartStopDataFrameTransform) { - content = createPermissionFailureMessage('canStartStopDataFrame'); + if (!canStartStopTransform) { + content = createCapabilityFailureMessage('canStartStopTransform'); } else if (completedBatchTransform) { content = completedBatchTransformMessage; } else if (startedTransform) { @@ -125,14 +119,11 @@ export const StartAction: FC = ({ items, forceDisable }) => { ); } - const bulkStartModalTitle = i18n.translate( - 'xpack.ml.dataframe.transformList.bulkStartModalTitle', - { - defaultMessage: 'Start {count} {count, plural, one {transform} other {transforms}}?', - values: { count: items && items.length }, - } - ); - const startModalTitle = i18n.translate('xpack.ml.dataframe.transformList.startModalTitle', { + const bulkStartModalTitle = i18n.translate('xpack.transform.transformList.bulkStartModalTitle', { + defaultMessage: 'Start {count} {count, plural, one {transform} other {transforms}}?', + values: { count: items && items.length }, + }); + const startModalTitle = i18n.translate('xpack.transform.transformList.startModalTitle', { defaultMessage: 'Start {transformId}', values: { transformId: items[0] && items[0].config.id }, }); @@ -147,13 +138,13 @@ export const StartAction: FC = ({ items, forceDisable }) => { onCancel={closeModal} onConfirm={startAndCloseModal} cancelButtonText={i18n.translate( - 'xpack.ml.dataframe.transformList.startModalCancelButton', + 'xpack.transform.transformList.startModalCancelButton', { defaultMessage: 'Cancel', } )} confirmButtonText={i18n.translate( - 'xpack.ml.dataframe.transformList.startModalStartButton', + 'xpack.transform.transformList.startModalStartButton', { defaultMessage: 'Start', } @@ -162,9 +153,9 @@ export const StartAction: FC = ({ items, forceDisable }) => { buttonColor="primary" >

- {i18n.translate('xpack.ml.dataframe.transformList.startModalBody', { + {i18n.translate('xpack.transform.transformList.startModalBody', { defaultMessage: - 'A data frame transform will increase search and indexing load in your cluster. Please stop the transform if excessive load is experienced. Are you sure you want to start {count, plural, one {this} other {these}} {count} {count, plural, one {transform} other {transforms}}?', + 'A transform will increase search and indexing load in your cluster. Please stop the transform if excessive load is experienced. Are you sure you want to start {count, plural, one {this} other {these}} {count} {count, plural, one {transform} other {transforms}}?', values: { count: items.length }, })}

diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_stop.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_stop.test.tsx new file mode 100644 index 0000000000000..c3b67f7661a1a --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_stop.test.tsx @@ -0,0 +1,41 @@ +/* + * 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 { shallow } from 'enzyme'; +import React from 'react'; + +import { createPublicShim } from '../../../../../shim'; +import { getAppProviders } from '../../../../app_dependencies'; + +import { TransformListRow } from '../../../../common'; +import { StopAction } from './action_stop'; + +import transformListRow from '../../../../common/__mocks__/transform_list_row.json'; + +jest.mock('ui/new_platform'); + +describe('Transform: Transform List Actions ', () => { + test('Minimal initialization', () => { + const Providers = getAppProviders(createPublicShim()); + + const item: TransformListRow = transformListRow; + const props = { + disabled: false, + items: [item], + stopTransform(d: TransformListRow) {}, + }; + + const wrapper = shallow( + + + + ) + .find(StopAction) + .shallow(); + + expect(wrapper).toMatchSnapshot(); + }); +}); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/action_stop.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_stop.tsx similarity index 59% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/action_stop.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_stop.tsx index fc069c0df21d6..98aec0acf0bf6 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/action_stop.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/action_stop.tsx @@ -4,45 +4,46 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { FC } from 'react'; +import React, { FC, useContext } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiButtonEmpty, EuiToolTip } from '@elastic/eui'; -import { DataFrameTransformListRow, DATA_FRAME_TRANSFORM_STATE } from '../../../../common'; +import { TransformListRow, TRANSFORM_STATE } from '../../../../common'; import { - checkPermission, - createPermissionFailureMessage, -} from '../../../../../privilege/check_privilege'; -import { stopTransforms } from '../../services/transform_service'; + createCapabilityFailureMessage, + AuthorizationContext, +} from '../../../../lib/authorization'; +import { useStopTransforms } from '../../../../hooks'; interface StopActionProps { - items: DataFrameTransformListRow[]; + items: TransformListRow[]; forceDisable?: boolean; } export const StopAction: FC = ({ items, forceDisable }) => { const isBulkAction = items.length > 1; - const canStartStopDataFrame: boolean = checkPermission('canStartStopDataFrame'); - const buttonStopText = i18n.translate('xpack.ml.dataframe.transformList.stopActionName', { + const { canStartStopTransform } = useContext(AuthorizationContext).capabilities; + const stopTransforms = useStopTransforms(); + const buttonStopText = i18n.translate('xpack.transform.transformList.stopActionName', { defaultMessage: 'Stop', }); // Disable stop action if one of the transforms is stopped already const stoppedTransform = items.some( - (i: DataFrameTransformListRow) => i.stats.state === DATA_FRAME_TRANSFORM_STATE.STOPPED + (i: TransformListRow) => i.stats.state === TRANSFORM_STATE.STOPPED ); let stoppedTransformMessage; if (isBulkAction === true) { stoppedTransformMessage = i18n.translate( - 'xpack.ml.dataframe.transformList.stoppedTransformBulkToolTip', + 'xpack.transform.transformList.stoppedTransformBulkToolTip', { - defaultMessage: 'One or more selected data frame transforms is already stopped.', + defaultMessage: 'One or more transforms are already stopped.', } ); } else { stoppedTransformMessage = i18n.translate( - 'xpack.ml.dataframe.transformList.stoppedTransformToolTip', + 'xpack.transform.transformList.stoppedTransformToolTip', { defaultMessage: '{transformId} is already stopped.', values: { transformId: items[0] && items[0].config.id }, @@ -58,7 +59,7 @@ export const StopAction: FC = ({ items, forceDisable }) => { = ({ items, forceDisable }) => { {buttonStopText} ); - if (!canStartStopDataFrame || stoppedTransform) { + if (!canStartStopTransform || stoppedTransform) { return ( diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/actions.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/actions.test.tsx similarity index 87% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/actions.test.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/actions.test.tsx index 049d812aae7a7..3d847890b2bd5 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/actions.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/actions.test.tsx @@ -6,7 +6,9 @@ import { getActions } from './actions'; -describe('Data Frame: Transform List Actions', () => { +jest.mock('ui/new_platform'); + +describe('Transform: Transform List Actions', () => { test('getActions()', () => { const actions = getActions({ forceDisable: false }); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/actions.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/actions.tsx similarity index 75% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/actions.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/actions.tsx index 0bce8ec6bb3de..1773405e36e39 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/actions.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/actions.tsx @@ -5,7 +5,7 @@ */ import React from 'react'; -import { DataFrameTransformListRow, DATA_FRAME_TRANSFORM_STATE } from '../../../../common'; +import { TransformListRow, TRANSFORM_STATE } from '../../../../common'; import { StartAction } from './action_start'; import { StopAction } from './action_stop'; import { DeleteAction } from './action_delete'; @@ -14,15 +14,15 @@ export const getActions = ({ forceDisable }: { forceDisable: boolean }) => { return [ { isPrimary: true, - render: (item: DataFrameTransformListRow) => { - if (item.stats.state === DATA_FRAME_TRANSFORM_STATE.STOPPED) { + render: (item: TransformListRow) => { + if (item.stats.state === TRANSFORM_STATE.STOPPED) { return ; } return ; }, }, { - render: (item: DataFrameTransformListRow) => { + render: (item: TransformListRow) => { return ; }, }, diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/columns.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/columns.test.tsx similarity index 91% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/columns.test.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/columns.test.tsx index c5fdd8d5941a3..f16130bfe618b 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/columns.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/columns.test.tsx @@ -6,7 +6,9 @@ import { getColumns } from './columns'; -describe('Data Frame: Job List Columns', () => { +jest.mock('ui/new_platform'); + +describe('Transform: Job List Columns', () => { test('getColumns()', () => { const columns = getColumns([], () => {}, []); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/columns.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/columns.tsx similarity index 65% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/columns.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/columns.tsx index 6d92386180439..700b659028b7e 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/columns.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/columns.tsx @@ -22,15 +22,15 @@ import { ComputedColumnType, ExpanderColumnType, FieldDataColumnType, -} from '../../../../../components/ml_in_memory_table'; +} from '../../../../../shared_imports'; import { getTransformProgress, - DataFrameTransformId, - DataFrameTransformListRow, - DataFrameTransformStats, - DATA_FRAME_TRANSFORM_LIST_COLUMN, - DATA_FRAME_TRANSFORM_STATE, + TransformId, + TransformListRow, + TransformStats, + TRANSFORM_LIST_COLUMN, + TRANSFORM_STATE, } from '../../../../common'; import { getActions } from './actions'; @@ -44,15 +44,15 @@ enum STATE_COLOR { } export const getTaskStateBadge = ( - state: DataFrameTransformStats['state'], - reason?: DataFrameTransformStats['reason'] + state: TransformStats['state'], + reason?: TransformStats['reason'] ) => { const color = STATE_COLOR[state]; - if (state === DATA_FRAME_TRANSFORM_STATE.FAILED && reason !== undefined) { + if (state === TRANSFORM_STATE.FAILED && reason !== undefined) { return ( - + {state} @@ -60,20 +60,20 @@ export const getTaskStateBadge = ( } return ( - + {state} ); }; export const getColumns = ( - expandedRowItemIds: DataFrameTransformId[], - setExpandedRowItemIds: React.Dispatch>, - transformSelection: DataFrameTransformListRow[] + expandedRowItemIds: TransformId[], + setExpandedRowItemIds: React.Dispatch>, + transformSelection: TransformListRow[] ) => { const actions = getActions({ forceDisable: transformSelection.length > 0 }); - function toggleDetails(item: DataFrameTransformListRow) { + function toggleDetails(item: TransformListRow) { const index = expandedRowItemIds.indexOf(item.config.id); if (index !== -1) { expandedRowItemIds.splice(index, 1); @@ -101,16 +101,16 @@ export const getColumns = ( align: RIGHT_ALIGNMENT, width: '40px', isExpander: true, - render: (item: DataFrameTransformListRow) => ( + render: (item: TransformListRow) => ( toggleDetails(item)} aria-label={ expandedRowItemIds.includes(item.config.id) - ? i18n.translate('xpack.ml.dataframe.transformList.rowCollapse', { + ? i18n.translate('xpack.transform.transformList.rowCollapse', { defaultMessage: 'Hide details for {transformId}', values: { transformId: item.config.id }, }) - : i18n.translate('xpack.ml.dataframe.transformList.rowExpand', { + : i18n.translate('xpack.transform.transformList.rowExpand', { defaultMessage: 'Show details for {transformId}', values: { transformId: item.config.id }, }) @@ -120,45 +120,45 @@ export const getColumns = ( ), }, { - field: DATA_FRAME_TRANSFORM_LIST_COLUMN.ID, + field: TRANSFORM_LIST_COLUMN.ID, name: 'ID', sortable: true, truncateText: true, }, { - field: DATA_FRAME_TRANSFORM_LIST_COLUMN.DESCRIPTION, - name: i18n.translate('xpack.ml.dataframe.description', { defaultMessage: 'Description' }), + field: TRANSFORM_LIST_COLUMN.DESCRIPTION, + name: i18n.translate('xpack.transform.description', { defaultMessage: 'Description' }), sortable: true, truncateText: true, }, { - field: DATA_FRAME_TRANSFORM_LIST_COLUMN.CONFIG_SOURCE_INDEX, - name: i18n.translate('xpack.ml.dataframe.sourceIndex', { defaultMessage: 'Source index' }), + field: TRANSFORM_LIST_COLUMN.CONFIG_SOURCE_INDEX, + name: i18n.translate('xpack.transform.sourceIndex', { defaultMessage: 'Source index' }), sortable: true, truncateText: true, }, { - field: DATA_FRAME_TRANSFORM_LIST_COLUMN.CONFIG_DEST_INDEX, - name: i18n.translate('xpack.ml.dataframe.destinationIndex', { + field: TRANSFORM_LIST_COLUMN.CONFIG_DEST_INDEX, + name: i18n.translate('xpack.transform.destinationIndex', { defaultMessage: 'Destination index', }), sortable: true, truncateText: true, }, { - name: i18n.translate('xpack.ml.dataframe.status', { defaultMessage: 'Status' }), - sortable: (item: DataFrameTransformListRow) => item.stats.state, + name: i18n.translate('xpack.transform.status', { defaultMessage: 'Status' }), + sortable: (item: TransformListRow) => item.stats.state, truncateText: true, - render(item: DataFrameTransformListRow) { + render(item: TransformListRow) { return getTaskStateBadge(item.stats.state, item.stats.reason); }, width: '100px', }, { - name: i18n.translate('xpack.ml.dataframe.mode', { defaultMessage: 'Mode' }), - sortable: (item: DataFrameTransformListRow) => item.mode, + name: i18n.translate('xpack.transform.mode', { defaultMessage: 'Mode' }), + sortable: (item: TransformListRow) => item.mode, truncateText: true, - render(item: DataFrameTransformListRow) { + render(item: TransformListRow) { const mode = item.mode; const color = 'hollow'; return {mode}; @@ -166,10 +166,10 @@ export const getColumns = ( width: '100px', }, { - name: i18n.translate('xpack.ml.dataframe.progress', { defaultMessage: 'Progress' }), - sortable: (item: DataFrameTransformListRow) => getTransformProgress(item) || 0, + name: i18n.translate('xpack.transform.progress', { defaultMessage: 'Progress' }), + sortable: (item: TransformListRow) => getTransformProgress(item) || 0, truncateText: true, - render(item: DataFrameTransformListRow) { + render(item: TransformListRow) { const progress = getTransformProgress(item); const isBatchTransform = typeof item.config.sync === 'undefined'; @@ -196,13 +196,13 @@ export const getColumns = ( {/* If not stopped or failed show the animated progress bar */} - {item.stats.state !== DATA_FRAME_TRANSFORM_STATE.STOPPED && - item.stats.state !== DATA_FRAME_TRANSFORM_STATE.FAILED && ( + {item.stats.state !== TRANSFORM_STATE.STOPPED && + item.stats.state !== TRANSFORM_STATE.FAILED && ( )} {/* If stopped or failed show an empty (0%) progress bar */} - {(item.stats.state === DATA_FRAME_TRANSFORM_STATE.STOPPED || - item.stats.state === DATA_FRAME_TRANSFORM_STATE.FAILED) && ( + {(item.stats.state === TRANSFORM_STATE.STOPPED || + item.stats.state === TRANSFORM_STATE.FAILED) && ( )} @@ -217,7 +217,7 @@ export const getColumns = ( width: '100px', }, { - name: i18n.translate('xpack.ml.dataframe.tableActionLabel', { defaultMessage: 'Actions' }), + name: i18n.translate('xpack.transform.tableActionLabel', { defaultMessage: 'Actions' }), actions, width: '200px', }, diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/common.test.ts b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/common.test.ts similarity index 54% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/common.test.ts rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/common.test.ts index 8be5bf36b635f..c2030e814aa95 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/common.test.ts +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/common.test.ts @@ -4,27 +4,23 @@ * you may not use this file except in compliance with the Elastic License. */ -import mockDataFrameTransformListRow from '../../../../common/__mocks__/data_frame_transform_list_row.json'; +import mockTransformListRow from '../../../../common/__mocks__/transform_list_row.json'; -import { - DataFrameTransformListRow, - isCompletedBatchTransform, - DATA_FRAME_TRANSFORM_STATE, -} from '../../../../common'; +import { TransformListRow, isCompletedBatchTransform, TRANSFORM_STATE } from '../../../../common'; -describe('Data Frame: isCompletedBatchTransform()', () => { +describe('Transform: isCompletedBatchTransform()', () => { test('isCompletedBatchTransform()', () => { // check the transform config/state against the conditions // that will be used by isCompletedBatchTransform() // followed by a call to isCompletedBatchTransform() itself - const row = mockDataFrameTransformListRow as DataFrameTransformListRow; + const row = mockTransformListRow as TransformListRow; expect(row.stats.checkpointing.last.checkpoint === 1).toBe(true); expect(row.config.sync === undefined).toBe(true); - expect(row.stats.state === DATA_FRAME_TRANSFORM_STATE.STOPPED).toBe(true); - expect(isCompletedBatchTransform(mockDataFrameTransformListRow)).toBe(true); + expect(row.stats.state === TRANSFORM_STATE.STOPPED).toBe(true); + expect(isCompletedBatchTransform(mockTransformListRow)).toBe(true); // adapt the mock config to resemble a non-completed transform. row.stats.checkpointing.last.checkpoint = 0; - expect(isCompletedBatchTransform(mockDataFrameTransformListRow)).toBe(false); + expect(isCompletedBatchTransform(mockTransformListRow)).toBe(false); }); }); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/common.ts b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/common.ts similarity index 57% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/common.ts rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/common.ts index af06276227c90..a6d69dd655c0c 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/common.ts +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/common.ts @@ -4,8 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { DataFrameTransformId, DATA_FRAME_TRANSFORM_STATE } from '../../../../common'; - export interface Clause { type: string; value: string; @@ -20,18 +18,4 @@ export interface Query { syntax: any; } -export interface DataFrameTransformEndpointRequest { - id: DataFrameTransformId; - state?: DATA_FRAME_TRANSFORM_STATE; -} - -export interface ResultData { - success: boolean; - error?: any; -} - -export interface DataFrameTransformEndpointResult { - [key: string]: ResultData; -} - export type ItemIdToExpandedRowMap = Record; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/expanded_row.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.test.tsx similarity index 70% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/expanded_row.test.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.test.tsx index 2d49299438447..4f992707cbf1a 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/expanded_row.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.test.tsx @@ -8,12 +8,12 @@ import { shallow } from 'enzyme'; import React from 'react'; import moment from 'moment-timezone'; -import { DataFrameTransformListRow } from '../../../../common'; +import { TransformListRow } from '../../../../common'; import { ExpandedRow } from './expanded_row'; -import dataFrameTransformListRow from '../../../../common/__mocks__/data_frame_transform_list_row.json'; +import transformListRow from '../../../../common/__mocks__/transform_list_row.json'; -describe('Data Frame: Transform List ', () => { +describe('Transform: Transform List ', () => { // Set timezone to US/Eastern for consistent test results. beforeEach(() => { moment.tz.setDefault('US/Eastern'); @@ -24,7 +24,7 @@ describe('Data Frame: Transform List ', () => { }); test('Minimal initialization', () => { - const item: DataFrameTransformListRow = dataFrameTransformListRow; + const item: TransformListRow = transformListRow; const wrapper = shallow(); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/expanded_row.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.tsx similarity index 86% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/expanded_row.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.tsx index ea894b7a2c720..24d09c899580e 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/expanded_row.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.tsx @@ -10,9 +10,9 @@ import { EuiTabbedContent } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { formatHumanReadableDateTimeSeconds } from '../../../../../util/date_utils'; +import { formatHumanReadableDateTimeSeconds } from '../../../../../../common/utils/date_utils'; -import { DataFrameTransformListRow } from '../../../../common'; +import { TransformListRow } from '../../../../common'; import { ExpandedRowDetailsPane, SectionConfig } from './expanded_row_details_pane'; import { ExpandedRowJsonPane } from './expanded_row_json_pane'; import { ExpandedRowMessagesPane } from './expanded_row_messages_pane'; @@ -32,7 +32,7 @@ interface Item { } interface Props { - item: DataFrameTransformListRow; + item: TransformListRow; } export const ExpandedRow: SFC = ({ item }) => { @@ -43,7 +43,7 @@ export const ExpandedRow: SFC = ({ item }) => { const stateItems: Item[] = []; stateItems.push( { - title: 'id', + title: 'ID', description: item.id, }, { @@ -123,7 +123,7 @@ export const ExpandedRow: SFC = ({ item }) => { { id: 'transform-details', name: i18n.translate( - 'xpack.ml.dataframe.transformList.transformDetails.tabs.transformSettingsLabel', + 'xpack.transform.transformList.transformDetails.tabs.transformSettingsLabel', { defaultMessage: 'Transform details', } @@ -138,7 +138,7 @@ export const ExpandedRow: SFC = ({ item }) => { { id: 'transform-messages', name: i18n.translate( - 'xpack.ml.dataframe.transformList.transformDetails.tabs.transformMessagesLabel', + 'xpack.transform.transformList.transformDetails.tabs.transformMessagesLabel', { defaultMessage: 'Messages', } @@ -148,7 +148,7 @@ export const ExpandedRow: SFC = ({ item }) => { { id: 'transform-preview', name: i18n.translate( - 'xpack.ml.dataframe.transformList.transformDetails.tabs.transformPreviewLabel', + 'xpack.transform.transformList.transformDetails.tabs.transformPreviewLabel', { defaultMessage: 'Preview', } @@ -156,6 +156,11 @@ export const ExpandedRow: SFC = ({ item }) => { content: , }, ]; + + // Using `expand=false` here so the tabs themselves don't spread + // across the full width. The 100% width is used so the bottom line + // as well as the tab content spans across the full width, + // even if the tab content wouldn't extend to the full width. return ( = ({ item }) => { initialSelectedTab={tabs[0]} onTabClick={() => {}} expand={false} + style={{ width: '100%' }} /> ); }; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/expanded_row_details_pane.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_details_pane.test.tsx similarity index 86% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/expanded_row_details_pane.test.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_details_pane.test.tsx index 8e9037579d169..89fe503f974c1 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/expanded_row_details_pane.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_details_pane.test.tsx @@ -20,7 +20,7 @@ const section: SectionConfig = { ], }; -describe('Data Frame: Job List Expanded Row ', () => { +describe('Transform: Job List Expanded Row ', () => { test('Minimal initialization', () => { const wrapper = shallow(); @@ -28,7 +28,7 @@ describe('Data Frame: Job List Expanded Row ', () => { }); }); -describe('Data Frame: Job List Expanded Row
', () => { +describe('Transform: Job List Expanded Row
', () => { test('Minimal initialization', () => { const wrapper = shallow(
); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/expanded_row_details_pane.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_details_pane.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/expanded_row_details_pane.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_details_pane.tsx diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/expanded_row_json_pane.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_json_pane.test.tsx similarity index 62% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/expanded_row_json_pane.test.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_json_pane.test.tsx index 6dc327caa419c..970110573585f 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/expanded_row_json_pane.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_json_pane.test.tsx @@ -7,13 +7,13 @@ import { shallow } from 'enzyme'; import React from 'react'; -import dataFrameTransformListRow from '../../../../common/__mocks__/data_frame_transform_list_row.json'; +import transformListRow from '../../../../common/__mocks__/transform_list_row.json'; import { ExpandedRowJsonPane } from './expanded_row_json_pane'; -describe('Data Frame: Transform List Expanded Row ', () => { +describe('Transform: Transform List Expanded Row ', () => { test('Minimal initialization', () => { - const wrapper = shallow(); + const wrapper = shallow(); expect(wrapper).toMatchSnapshot(); }); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/expanded_row_json_pane.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_json_pane.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/expanded_row_json_pane.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_json_pane.tsx diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/expanded_row_messages_pane.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx similarity index 73% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/expanded_row_messages_pane.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx index 11ab4a3fff54b..526152a829963 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/expanded_row_messages_pane.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx @@ -11,10 +11,9 @@ import { EuiSpacer, EuiBasicTable } from '@elastic/eui'; import { formatDate } from '@elastic/eui/lib/services/format'; import { i18n } from '@kbn/i18n'; import theme from '@elastic/eui/dist/eui_theme_light.json'; -import { ml } from '../../../../../services/ml_api_service'; -// @ts-ignore -import { JobIcon } from '../../../../../components/job_message_icon'; -import { TransformMessage } from '../../../../../../common/types/audit_message'; +import { useApi } from '../../../../hooks/use_api'; +import { JobIcon } from '../../../../components/job_icon'; +import { TransformMessage } from '../../../../../../common/types/messages'; import { useRefreshTransformList } from '../../../../common'; const TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss'; @@ -24,13 +23,15 @@ interface Props { } export const ExpandedRowMessagesPane: React.SFC = ({ transformId }) => { - const [messages, setMessages] = useState([]); + const [messages, setMessages] = useState([]); const [isLoading, setIsLoading] = useState(false); const [errorMessage, setErrorMessage] = useState(''); const [pageIndex, setPageIndex] = useState(0); const [pageSize, setPageSize] = useState(10); + const api = useApi(); + const getMessagesFactory = () => { let concurrentLoads = 0; @@ -43,9 +44,9 @@ export const ExpandedRowMessagesPane: React.SFC = ({ transformId }) => { } setIsLoading(true); - const messagesResp = await ml.dataFrame.getTransformAuditMessages(transformId); + const messagesResp = await api.getTransformAuditMessages(transformId); setIsLoading(false); - setMessages(messagesResp); + setMessages(messagesResp as any[]); concurrentLoads--; @@ -56,9 +57,12 @@ export const ExpandedRowMessagesPane: React.SFC = ({ transformId }) => { } catch (error) { setIsLoading(false); setErrorMessage( - i18n.translate('xpack.ml.dfTransformList.transformDetails.messagesPane.errorMessage', { - defaultMessage: 'Messages could not be loaded', - }) + i18n.translate( + 'xpack.transform.transformList.transformDetails.messagesPane.errorMessage', + { + defaultMessage: 'Messages could not be loaded', + } + ) ); } }; @@ -73,22 +77,31 @@ export const ExpandedRowMessagesPane: React.SFC = ({ transformId }) => { width: `${theme.euiSizeXL}px`, }, { - name: i18n.translate('xpack.ml.dfTransformList.transformDetails.messagesPane.timeLabel', { - defaultMessage: 'Time', - }), + name: i18n.translate( + 'xpack.transform.transformList.transformDetails.messagesPane.timeLabel', + { + defaultMessage: 'Time', + } + ), render: (message: any) => formatDate(message.timestamp, TIME_FORMAT), }, { field: 'node_name', - name: i18n.translate('xpack.ml.dfTransformList.transformDetails.messagesPane.nodeLabel', { - defaultMessage: 'Node', - }), + name: i18n.translate( + 'xpack.transform.transformList.transformDetails.messagesPane.nodeLabel', + { + defaultMessage: 'Node', + } + ), }, { field: 'message', - name: i18n.translate('xpack.ml.dfTransformList.transformDetails.messagesPane.messageLabel', { - defaultMessage: 'Message', - }), + name: i18n.translate( + 'xpack.transform.transformList.transformDetails.messagesPane.messageLabel', + { + defaultMessage: 'Message', + } + ), width: '50%', }, ]; @@ -133,7 +146,7 @@ export const ExpandedRowMessagesPane: React.SFC = ({ transformId }) => { = ({ transformConfig }) => { - const [dataFramePreviewData, setDataFramePreviewData] = useState([]); + const [previewData, setPreviewData] = useState([]); const [columns, setColumns] = useState([]); const [pageIndex, setPageIndex] = useState(0); const [pageSize, setPageSize] = useState(10); @@ -79,6 +75,7 @@ export const ExpandedRowPreviewPane: FC = ({ transformConfig }) => { const [sortDirection, setSortDirection] = useState(SORT_DIRECTION.ASC); const [isLoading, setIsLoading] = useState(false); const [errorMessage, setErrorMessage] = useState(''); + const api = useApi(); const getPreviewFactory = () => { let concurrentLoads = 0; @@ -93,7 +90,7 @@ export const ExpandedRowPreviewPane: FC = ({ transformConfig }) => { const { previewRequest, groupByArr } = getDataFromTransform(transformConfig); setIsLoading(true); - const resp: any = await ml.dataFrame.getDataFrameTransformsPreview(previewRequest); + const resp: any = await api.getTransformsPreview(previewRequest); setIsLoading(false); if (resp.preview.length > 0) { @@ -139,7 +136,7 @@ export const ExpandedRowPreviewPane: FC = ({ transformConfig }) => { return column; }); - setDataFramePreviewData(resp.preview); + setPreviewData(resp.preview); setColumns(tableColumns); setSortField(sortField); setSortDirection(sortDirection); @@ -153,7 +150,7 @@ export const ExpandedRowPreviewPane: FC = ({ transformConfig }) => { } catch (error) { setIsLoading(false); setErrorMessage( - i18n.translate('xpack.ml.dfTransformList.stepDetails.previewPane.errorMessage', { + i18n.translate('xpack.transform.transformList.stepDetails.previewPane.errorMessage', { defaultMessage: 'Preview could not be loaded', }) ); @@ -166,7 +163,7 @@ export const ExpandedRowPreviewPane: FC = ({ transformConfig }) => { const pagination = { initialPageIndex: pageIndex, initialPageSize: pageSize, - totalItemCount: dataFramePreviewData.length, + totalItemCount: previewData.length, pageSizeOptions: [10, 20], hidePerPageOptions: false, }; @@ -197,9 +194,9 @@ export const ExpandedRowPreviewPane: FC = ({ transformConfig }) => { return ( ', () => { +jest.mock('ui/new_platform'); + +describe('Transform: Transform List ', () => { test('Minimal initialization', () => { const wrapper = shallow( - ); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/transform_list.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx similarity index 73% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/transform_list.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx index bf2894fe7dc24..1037fdebbed6a 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/transform_list.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment, SFC, useState } from 'react'; +import React, { Fragment, MouseEventHandler, FC, useContext, useState } from 'react'; import { i18n } from '@kbn/i18n'; @@ -18,21 +18,16 @@ import { EuiTitle, } from '@elastic/eui'; -import { - OnTableChangeArg, - SortDirection, - SORT_DIRECTION, -} from '../../../../../components/ml_in_memory_table'; +import { OnTableChangeArg, SortDirection, SORT_DIRECTION } from '../../../../../shared_imports'; import { - DataFrameTransformId, - DataFrameTransformListRow, - moveToDataFrameWizard, - DATA_FRAME_MODE, - DATA_FRAME_TRANSFORM_LIST_COLUMN, - DATA_FRAME_TRANSFORM_STATE, + TransformId, + TransformListRow, + TRANSFORM_MODE, + TRANSFORM_LIST_COLUMN, + TRANSFORM_STATE, } from '../../../../common'; -import { checkPermission } from '../../../../../privilege/check_privilege'; +import { AuthorizationContext } from '../../../../lib/authorization'; import { getTaskStateBadge } from './columns'; import { DeleteAction } from './action_delete'; import { StartAction } from './action_start'; @@ -44,12 +39,12 @@ import { ExpandedRow } from './expanded_row'; import { ProgressBar, TransformTable } from './transform_table'; function getItemIdToExpandedRowMap( - itemIds: DataFrameTransformId[], - dataFrameTransforms: DataFrameTransformListRow[] + itemIds: TransformId[], + transforms: TransformListRow[] ): ItemIdToExpandedRowMap { return itemIds.reduce( - (m: ItemIdToExpandedRowMap, transformId: DataFrameTransformId) => { - const item = dataFrameTransforms.find(transform => transform.config.id === transformId); + (m: ItemIdToExpandedRowMap, transformId: TransformId) => { + const item = transforms.find(transform => transform.config.id === transformId); if (item !== undefined) { m[transformId] = ; } @@ -68,25 +63,27 @@ function stringMatch(str: string | undefined, substr: string) { } interface Props { - isInitialized: boolean; - transforms: DataFrameTransformListRow[]; errorMessage: any; + isInitialized: boolean; + onCreateTransform: MouseEventHandler; + transforms: TransformListRow[]; transformsLoading: boolean; } -export const DataFrameTransformList: SFC = ({ +export const TransformList: FC = ({ + errorMessage, isInitialized, + onCreateTransform, transforms, - errorMessage, transformsLoading, }) => { const [isLoading, setIsLoading] = useState(false); const [filterActive, setFilterActive] = useState(false); - const [filteredTransforms, setFilteredTransforms] = useState([]); - const [expandedRowItemIds, setExpandedRowItemIds] = useState([]); + const [filteredTransforms, setFilteredTransforms] = useState([]); + const [expandedRowItemIds, setExpandedRowItemIds] = useState([]); - const [transformSelection, setTransformSelection] = useState([]); + const [transformSelection, setTransformSelection] = useState([]); const [isActionsMenuOpen, setIsActionsMenuOpen] = useState(false); const [searchError, setSearchError] = useState(undefined); @@ -94,13 +91,14 @@ export const DataFrameTransformList: SFC = ({ const [pageIndex, setPageIndex] = useState(0); const [pageSize, setPageSize] = useState(10); - const [sortField, setSortField] = useState(DATA_FRAME_TRANSFORM_LIST_COLUMN.ID); + const [sortField, setSortField] = useState(TRANSFORM_LIST_COLUMN.ID); const [sortDirection, setSortDirection] = useState(SORT_DIRECTION.ASC); + const { capabilities } = useContext(AuthorizationContext); const disabled = - !checkPermission('canCreateDataFrame') || - !checkPermission('canPreviewDataFrame') || - !checkPermission('canStartStopDataFrame'); + !capabilities.canCreateTransform || + !capabilities.canPreviewTransform || + !capabilities.canStartStopTransform; const onQueryChange = ({ query, error }: { query: Query; error: any }) => { if (error) { @@ -140,7 +138,7 @@ export const DataFrameTransformList: SFC = ({ if (c.type === 'term') { // filter term based clauses, e.g. bananas - // match on id and description + // match on ID and description // if the term has been negated, AND the matches if (bool === true) { ts = transforms.filter( @@ -178,7 +176,7 @@ export const DataFrameTransformList: SFC = ({ }; // Before the transforms have been loaded for the first time, display the loading indicator only. - // Otherwise a user would see 'No data frame transforms found' during the initial loading. + // Otherwise a user would see 'No transforms found' during the initial loading. if (!isInitialized) { return ; } @@ -188,8 +186,8 @@ export const DataFrameTransformList: SFC = ({ = ({ - {i18n.translate('xpack.ml.dataFrame.list.emptyPromptTitle', { - defaultMessage: 'No data frame transforms found', + {i18n.translate('xpack.transform.list.emptyPromptTitle', { + defaultMessage: 'No transforms found', })} } actions={[ - - {i18n.translate('xpack.ml.dataFrame.list.emptyPromptButtonText', { - defaultMessage: 'Create your first data frame transform', + + {i18n.translate('xpack.transform.list.emptyPromptButtonText', { + defaultMessage: 'Create your first transform', })} , ]} - data-test-subj="mlNoDataFrameTransformsFound" + data-test-subj="transformNoTransformsFound" /> ); @@ -245,13 +243,13 @@ export const DataFrameTransformList: SFC = ({ }; const bulkActionMenuItems = [ -
+
, -
+
, -
+
, ]; @@ -266,7 +264,7 @@ export const DataFrameTransformList: SFC = ({ setIsActionsMenuOpen(true); }} aria-label={i18n.translate( - 'xpack.ml.dataframe.multiTransformActionsMenu.managementActionsAriaLabel', + 'xpack.transform.multiTransformActionsMenu.managementActionsAriaLabel', { defaultMessage: 'Management actions', } @@ -291,13 +289,13 @@ export const DataFrameTransformList: SFC = ({ return [

- {i18n.translate('xpack.ml.dataframe.multiTransformActionsMenu.transformsCount', { + {i18n.translate('xpack.transform.multiTransformActionsMenu.transformsCount', { defaultMessage: '{count} {count, plural, one {transform} other {transforms}} selected', values: { count: transformSelection.length }, })}

, -
, +
, bulkActionIcon, ]; }; @@ -312,9 +310,9 @@ export const DataFrameTransformList: SFC = ({ { type: 'field_value_selection', field: 'state.state', - name: i18n.translate('xpack.ml.dataframe.statusFilter', { defaultMessage: 'Status' }), + name: i18n.translate('xpack.transform.statusFilter', { defaultMessage: 'Status' }), multiSelect: 'or', - options: Object.values(DATA_FRAME_TRANSFORM_STATE).map(val => ({ + options: Object.values(TRANSFORM_STATE).map(val => ({ value: val, name: val, view: getTaskStateBadge(val), @@ -323,13 +321,13 @@ export const DataFrameTransformList: SFC = ({ { type: 'field_value_selection', field: 'mode', - name: i18n.translate('xpack.ml.dataframe.modeFilter', { defaultMessage: 'Mode' }), + name: i18n.translate('xpack.transform.modeFilter', { defaultMessage: 'Mode' }), multiSelect: false, - options: Object.values(DATA_FRAME_MODE).map(val => ({ + options: Object.values(TRANSFORM_MODE).map(val => ({ value: val, name: val, view: ( - + {val} ), @@ -340,7 +338,7 @@ export const DataFrameTransformList: SFC = ({ const onTableChange = ({ page = { index: 0, size: 10 }, - sort = { field: DATA_FRAME_TRANSFORM_LIST_COLUMN.ID, direction: SORT_DIRECTION.ASC }, + sort = { field: TRANSFORM_LIST_COLUMN.ID, direction: SORT_DIRECTION.ASC }, }: OnTableChangeArg) => { const { index, size } = page; setPageIndex(index); @@ -352,7 +350,7 @@ export const DataFrameTransformList: SFC = ({ }; const selection = { - onSelectionChange: (selected: DataFrameTransformListRow[]) => setTransformSelection(selected), + onSelectionChange: (selected: TransformListRow[]) => setTransformSelection(selected), }; return ( @@ -360,21 +358,21 @@ export const DataFrameTransformList: SFC = ({ ); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/transform_table.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_table.tsx similarity index 93% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/transform_table.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_table.tsx index fe4a32371242d..cd6f6654a8e9e 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/transform_table.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_table.tsx @@ -11,7 +11,7 @@ import React, { Fragment } from 'react'; import { EuiProgress } from '@elastic/eui'; -import { MlInMemoryTableBasic } from '../../../../../components/ml_in_memory_table'; +import { MlInMemoryTableBasic } 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 @@ -22,9 +22,9 @@ import { MlInMemoryTableBasic } from '../../../../../components/ml_in_memory_tab export const ProgressBar = ({ isLoading = false }) => { return ( - {isLoading && } + {isLoading && } {!isLoading && ( - + )} ); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/transforms_stats_bar.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/transforms_stats_bar.tsx similarity index 61% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/transforms_stats_bar.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/transforms_stats_bar.tsx index 823a2e4c90b83..dd2369e199d0d 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/transforms_stats_bar.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/transforms_stats_bar.tsx @@ -6,45 +6,41 @@ import React, { FC } from 'react'; import { i18n } from '@kbn/i18n'; -import { StatsBar, TransformStatsBarStats } from '../../../../../components/stats_bar'; -import { - DATA_FRAME_TRANSFORM_STATE, - DATA_FRAME_MODE, - DataFrameTransformListRow, -} from '../../../../common'; +import { StatsBar, TransformStatsBarStats } from '../stats_bar'; +import { TRANSFORM_STATE, TRANSFORM_MODE, TransformListRow } from '../../../../common'; -function createTranformStats(transformsList: DataFrameTransformListRow[]) { +function createTranformStats(transformsList: TransformListRow[]) { const transformStats = { total: { - label: i18n.translate('xpack.ml.dataFrame.statsBar.totalTransformsLabel', { + label: i18n.translate('xpack.transform.statsBar.totalTransformsLabel', { defaultMessage: 'Total transforms', }), value: 0, show: true, }, batch: { - label: i18n.translate('xpack.ml.dataFrame.statsBar.batchTransformsLabel', { + label: i18n.translate('xpack.transform.statsBar.batchTransformsLabel', { defaultMessage: 'Batch', }), value: 0, show: true, }, continuous: { - label: i18n.translate('xpack.ml.dataFrame.statsBar.continuousTransformsLabel', { + label: i18n.translate('xpack.transform.statsBar.continuousTransformsLabel', { defaultMessage: 'Continuous', }), value: 0, show: true, }, failed: { - label: i18n.translate('xpack.ml.dataFrame.statsBar.failedTransformsLabel', { + label: i18n.translate('xpack.transform.statsBar.failedTransformsLabel', { defaultMessage: 'Failed', }), value: 0, show: false, }, started: { - label: i18n.translate('xpack.ml.dataFrame.statsBar.startedTransformsLabel', { + label: i18n.translate('xpack.transform.statsBar.startedTransformsLabel', { defaultMessage: 'Started', }), value: 0, @@ -60,15 +56,15 @@ function createTranformStats(transformsList: DataFrameTransformListRow[]) { let startedTransforms = 0; transformsList.forEach(transform => { - if (transform.mode === DATA_FRAME_MODE.CONTINUOUS) { + if (transform.mode === TRANSFORM_MODE.CONTINUOUS) { transformStats.continuous.value++; - } else if (transform.mode === DATA_FRAME_MODE.BATCH) { + } else if (transform.mode === TRANSFORM_MODE.BATCH) { transformStats.batch.value++; } - if (transform.stats.state === DATA_FRAME_TRANSFORM_STATE.FAILED) { + if (transform.stats.state === TRANSFORM_STATE.FAILED) { failedTransforms++; - } else if (transform.stats.state === DATA_FRAME_TRANSFORM_STATE.STARTED) { + } else if (transform.stats.state === TRANSFORM_STATE.STARTED) { startedTransforms++; } }); @@ -87,11 +83,11 @@ function createTranformStats(transformsList: DataFrameTransformListRow[]) { } interface Props { - transformsList: DataFrameTransformListRow[]; + transformsList: TransformListRow[]; } export const TransformStatsBar: FC = ({ transformsList }) => { const transformStats: TransformStatsBarStats = createTranformStats(transformsList); - return ; + return ; }; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/use_refresh_interval.ts b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/use_refresh_interval.ts similarity index 97% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/use_refresh_interval.ts rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/use_refresh_interval.ts index 3361811cb9e3e..7a2e6b9e623fb 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/components/transform_list/use_refresh_interval.ts +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/components/transform_list/use_refresh_interval.ts @@ -11,7 +11,7 @@ import { timefilter } from 'ui/timefilter'; import { DEFAULT_REFRESH_INTERVAL_MS, MINIMUM_REFRESH_INTERVAL_MS, -} from '../../../../../../common/constants/jobs_list'; +} from '../../../../../../common/constants'; import { useRefreshTransformList } from '../../../../common'; diff --git a/x-pack/legacy/plugins/transform/public/app/sections/transform_management/index.ts b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/index.ts new file mode 100644 index 0000000000000..d65dae4d767a4 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/index.ts @@ -0,0 +1,7 @@ +/* + * 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 { TransformManagementSection } from './transform_management_section'; diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/page.test.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/transform_management_section.test.tsx similarity index 58% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/page.test.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/transform_management_section.test.tsx index 9cc02bb1bf796..c94f5c1d57d49 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/page.test.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/transform_management_section.test.tsx @@ -7,12 +7,16 @@ import { shallow } from 'enzyme'; import React from 'react'; -import './page.test.mocks'; -import { Page } from './page'; +import { TransformManagementSection } from './transform_management_section'; -describe('Data Frame: Job List ', () => { +jest.mock('ui/new_platform'); +jest.mock('ui/timefilter', () => { + return {}; +}); + +describe('Transform: ', () => { test('Minimal initialization', () => { - const wrapper = shallow(); + const wrapper = shallow(); expect(wrapper).toMatchSnapshot(); }); diff --git a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/page.tsx b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx similarity index 53% rename from x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/page.tsx rename to x-pack/legacy/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx index 45b282bbf8355..2c17446df830b 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame/pages/transform_management/page.tsx +++ b/x-pack/legacy/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { FC, Fragment, useState } from 'react'; +import React, { FC, Fragment, useEffect, useState } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; @@ -13,6 +13,8 @@ import { EuiBetaBadge, EuiFlexGroup, EuiFlexItem, + EuiModal, + EuiOverlayMask, EuiPage, EuiPageBody, EuiPageContentBody, @@ -23,25 +25,30 @@ import { EuiTitle, } from '@elastic/eui'; -import { NavigationMenu } from '../../../components/navigation_menu/navigation_menu'; -import { useRefreshTransformList, DataFrameTransformListRow } from '../../common'; +import { APP_GET_TRANSFORM_CLUSTER_PRIVILEGES } from '../../../../common/constants'; +import { useRefreshTransformList, TransformListRow } from '../../common'; +import { useGetTransforms } from '../../hooks'; +import { RedirectToCreateTransform } from '../../common/navigation'; +import { PrivilegesWrapper } from '../../lib/authorization'; +import { breadcrumbService, docTitleService, BREADCRUMB_SECTION } from '../../services/navigation'; + +import { useRefreshInterval } from './components/transform_list/use_refresh_interval'; import { CreateTransformButton } from './components/create_transform_button'; -import { DataFrameTransformList } from './components/transform_list'; import { RefreshTransformListButton } from './components/refresh_transform_list_button'; -import { TransformStatsBar } from '../transform_management/components/transform_list/transforms_stats_bar'; -import { getTransformsFactory } from './services/transform_service'; -import { useRefreshInterval } from './components/transform_list/use_refresh_interval'; +import { SearchSelection } from './components/search_selection'; +import { TransformList } from './components/transform_list'; +import { TransformStatsBar } from './components/transform_list/transforms_stats_bar'; -export const Page: FC = () => { +export const TransformManagement: FC = () => { const [isLoading, setIsLoading] = useState(false); const [transformsLoading, setTransformsLoading] = useState(false); const [isInitialized, setIsInitialized] = useState(false); const [blockRefresh, setBlockRefresh] = useState(false); - const [transforms, setTransforms] = useState([]); + const [transforms, setTransforms] = useState([]); const [errorMessage, setErrorMessage] = useState(undefined); const { refresh } = useRefreshTransformList({ isLoading: setIsLoading }); - const getTransforms = getTransformsFactory( + const getTransforms = useGetTransforms( setTransforms, setErrorMessage, setIsInitialized, @@ -56,29 +63,40 @@ export const Page: FC = () => { // Call useRefreshInterval() after the subscription above is set up. useRefreshInterval(setBlockRefresh); + const [isSearchSelectionVisible, setIsSearchSelectionVisible] = useState(false); + const [savedObjectId, setSavedObjectId] = useState(null); + + if (savedObjectId !== null) { + return ; + } + + const onCloseModal = () => setIsSearchSelectionVisible(false); + const onOpenModal = () => setIsSearchSelectionVisible(true); + const onSearchSelected = (id: string, type: string) => { + setSavedObjectId(id); + }; + return ( - - - +

  @@ -93,24 +111,48 @@ export const Page: FC = () => { {/* grow={false} fixes IE11 issue with nested flex */} - + + + - + {isSearchSelectionVisible && ( + + + + + + )} ); }; + +export const TransformManagementSection: FC = () => { + // Set breadcrumb and page title + useEffect(() => { + breadcrumbService.setBreadcrumbs(BREADCRUMB_SECTION.HOME); + docTitleService.setTitle('home'); + }, []); + + return ( + + + + ); +}; diff --git a/x-pack/legacy/plugins/transform/public/app/services/documentation/documentation_links.ts b/x-pack/legacy/plugins/transform/public/app/services/documentation/documentation_links.ts new file mode 100644 index 0000000000000..ea44d64600d7c --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/services/documentation/documentation_links.ts @@ -0,0 +1,20 @@ +/* + * 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 { TRANSFORM_DOC_PATHS } from '../../constants'; + +class DocumentationLinksService { + private esPluginDocBasePath: string = ''; + + public init(esPluginDocBasePath: string): void { + this.esPluginDocBasePath = esPluginDocBasePath; + } + + public getTransformPluginDocUrl() { + return `${this.esPluginDocBasePath}${TRANSFORM_DOC_PATHS.plugins}`; + } +} + +export const documentationLinksService = new DocumentationLinksService(); diff --git a/x-pack/legacy/plugins/transform/public/app/services/documentation/index.ts b/x-pack/legacy/plugins/transform/public/app/services/documentation/index.ts new file mode 100644 index 0000000000000..34209d10c6b8b --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/services/documentation/index.ts @@ -0,0 +1,7 @@ +/* + * 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 { documentationLinksService } from './documentation_links'; diff --git a/x-pack/legacy/plugins/transform/public/app/services/http/http.ts b/x-pack/legacy/plugins/transform/public/app/services/http/http.ts new file mode 100644 index 0000000000000..71c5cdaf685b4 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/services/http/http.ts @@ -0,0 +1,18 @@ +/* + * 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. + */ +class HttpService { + private client: any; + + public init(httpClient: any): void { + this.client = httpClient; + } + + public get httpClient(): any { + return this.client; + } +} + +export const httpService = new HttpService(); diff --git a/x-pack/legacy/plugins/transform/public/app/services/http/index.ts b/x-pack/legacy/plugins/transform/public/app/services/http/index.ts new file mode 100644 index 0000000000000..a129998e48e1f --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/services/http/index.ts @@ -0,0 +1,6 @@ +/* + * 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 { httpService } from './http'; diff --git a/x-pack/legacy/plugins/transform/public/app/services/http/use_request.ts b/x-pack/legacy/plugins/transform/public/app/services/http/use_request.ts new file mode 100644 index 0000000000000..dc5f3d9b990a6 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/services/http/use_request.ts @@ -0,0 +1,22 @@ +/* + * 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 { + SendRequestConfig, + SendRequestResponse, + UseRequestConfig, + sendRequest as _sendRequest, + useRequest as _useRequest, +} from '../../../shared_imports'; +import { httpService } from './index'; + +export const sendRequest = (config: SendRequestConfig): Promise> => { + return _sendRequest(httpService.httpClient, config); +}; + +export const useRequest = (config: UseRequestConfig) => { + return _useRequest(httpService.httpClient, config); +}; diff --git a/x-pack/legacy/plugins/transform/public/app/services/http_service.ts b/x-pack/legacy/plugins/transform/public/app/services/http_service.ts new file mode 100644 index 0000000000000..11ba5119b1394 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/services/http_service.ts @@ -0,0 +1,52 @@ +/* + * 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. + */ + +// service for interacting with the server + +import chrome from 'ui/chrome'; + +// @ts-ignore +import { addSystemApiHeader } from 'ui/system_api'; + +import { Dictionary } from '../../../common/types/common'; + +export function http(options: Dictionary) { + return new Promise((resolve, reject) => { + if (options && options.url) { + let url = ''; + url = url + (options.url || ''); + const headers = addSystemApiHeader({ + 'Content-Type': 'application/json', + 'kbn-version': chrome.getXsrfToken(), + ...options.headers, + }); + + const allHeaders = + options.headers === undefined ? headers : { ...options.headers, ...headers }; + const body = options.data === undefined ? null : JSON.stringify(options.data); + + const payload: Dictionary = { + method: options.method || 'GET', + headers: allHeaders, + credentials: 'same-origin', + }; + + if (body !== null) { + payload.body = body; + } + + fetch(url, payload) + .then(resp => { + resp.json().then(resp.ok === true ? resolve : reject); + }) + .catch(resp => { + reject(resp); + }); + } else { + reject(); + } + }); +} diff --git a/x-pack/legacy/plugins/transform/public/app/services/navigation/breadcrumb.ts b/x-pack/legacy/plugins/transform/public/app/services/navigation/breadcrumb.ts new file mode 100644 index 0000000000000..0e0b174f28f99 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/services/navigation/breadcrumb.ts @@ -0,0 +1,71 @@ +/* + * 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 { textService } from '../text'; +import { linkToHome } from './links'; + +export enum BREADCRUMB_SECTION { + MANAGEMENT = 'management', + HOME = 'home', + CREATE_TRANSFORM = 'createTransform', +} + +interface BreadcrumbItem { + text: string; + href?: string; +} + +type Breadcrumbs = { + [key in BREADCRUMB_SECTION]: BreadcrumbItem[]; +}; + +class BreadcrumbService { + private chrome: any; + private breadcrumbs: Breadcrumbs = { + management: [], + home: [], + createTransform: [], + }; + + public init(chrome: any, managementBreadcrumb: any): void { + this.chrome = chrome; + this.breadcrumbs.management = [managementBreadcrumb]; + + // Home and sections + this.breadcrumbs.home = [ + ...this.breadcrumbs.management, + { + text: textService.breadcrumbs.home, + href: linkToHome(), + }, + ]; + this.breadcrumbs.createTransform = [ + ...this.breadcrumbs.home, + { + text: textService.breadcrumbs.createTransform, + }, + ]; + } + + public setBreadcrumbs(type: BREADCRUMB_SECTION): void { + const newBreadcrumbs = this.breadcrumbs[type] + ? [...this.breadcrumbs[type]] + : [...this.breadcrumbs.home]; + + // Pop off last breadcrumb + const lastBreadcrumb = newBreadcrumbs.pop() as BreadcrumbItem; + + // Put last breadcrumb back without href + newBreadcrumbs.push({ + ...lastBreadcrumb, + href: undefined, + }); + + this.chrome.setBreadcrumbs(newBreadcrumbs); + } +} + +export const breadcrumbService = new BreadcrumbService(); diff --git a/x-pack/legacy/plugins/transform/public/app/services/navigation/doc_title.ts b/x-pack/legacy/plugins/transform/public/app/services/navigation/doc_title.ts new file mode 100644 index 0000000000000..a42d09f2a2f45 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/services/navigation/doc_title.ts @@ -0,0 +1,24 @@ +/* + * 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 { textService } from '../text'; + +class DocTitleService { + private changeDocTitle: any = () => {}; + + public init(changeDocTitle: any): void { + this.changeDocTitle = changeDocTitle; + } + + public setTitle(page?: string): void { + if (!page || page === 'home') { + this.changeDocTitle(`${textService.breadcrumbs.home}`); + } else if (textService.breadcrumbs[page]) { + this.changeDocTitle(`${textService.breadcrumbs[page]} - ${textService.breadcrumbs.home}`); + } + } +} + +export const docTitleService = new DocTitleService(); diff --git a/x-pack/legacy/plugins/transform/public/app/services/navigation/index.ts b/x-pack/legacy/plugins/transform/public/app/services/navigation/index.ts new file mode 100644 index 0000000000000..40a6d6d9fbdc4 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/services/navigation/index.ts @@ -0,0 +1,9 @@ +/* + * 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 { breadcrumbService, BREADCRUMB_SECTION } from './breadcrumb'; +export { docTitleService } from './doc_title'; +export * from './links'; diff --git a/x-pack/legacy/plugins/ml/server/models/data_frame/index.js b/x-pack/legacy/plugins/transform/public/app/services/navigation/links.ts similarity index 64% rename from x-pack/legacy/plugins/ml/server/models/data_frame/index.js rename to x-pack/legacy/plugins/transform/public/app/services/navigation/links.ts index 2bb11e320b153..85088c3a4a69d 100644 --- a/x-pack/legacy/plugins/ml/server/models/data_frame/index.js +++ b/x-pack/legacy/plugins/transform/public/app/services/navigation/links.ts @@ -4,6 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ +import { CLIENT_BASE_PATH } from '../../constants'; -export { transformAuditMessagesProvider } from './transform_audit_messages'; -export { transformServiceProvider } from './transforms'; +export function linkToHome() { + return `#${CLIENT_BASE_PATH}`; +} diff --git a/x-pack/legacy/plugins/transform/public/app/services/text/index.ts b/x-pack/legacy/plugins/transform/public/app/services/text/index.ts new file mode 100644 index 0000000000000..3bed86f69937a --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/services/text/index.ts @@ -0,0 +1,7 @@ +/* + * 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 { textService } from './text'; diff --git a/x-pack/legacy/plugins/transform/public/app/services/text/text.ts b/x-pack/legacy/plugins/transform/public/app/services/text/text.ts new file mode 100644 index 0000000000000..df1b07e171c62 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/services/text/text.ts @@ -0,0 +1,36 @@ +/* + * 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 { i18n } from '@kbn/i18n'; + +class TextService { + public breadcrumbs: { [key: string]: string } = {}; + + public init(): void { + this.breadcrumbs = { + home: i18n.translate('xpack.transform.home.breadcrumbTitle', { + defaultMessage: 'Transforms', + }), + createTransform: i18n.translate('xpack.transform.createTransform.breadcrumbTitle', { + defaultMessage: 'Create transform', + }), + }; + } + + public getSizeNotationHelpText() { + return i18n.translate('xpack.transform.transformForm.sizeNotationPlaceholder', { + defaultMessage: 'Examples: {example1}, {example2}, {example3}, {example4}', + values: { + example1: '1g', + example2: '10mb', + example3: '5k', + example4: '1024B', + }, + }); + } +} + +export const textService = new TextService(); diff --git a/x-pack/legacy/plugins/transform/public/app/services/ui_metric/index.ts b/x-pack/legacy/plugins/transform/public/app/services/ui_metric/index.ts new file mode 100644 index 0000000000000..e7c3f961824e3 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/services/ui_metric/index.ts @@ -0,0 +1,6 @@ +/* + * 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 { uiMetricService } from './ui_metric'; diff --git a/x-pack/legacy/plugins/transform/public/app/services/ui_metric/ui_metric.ts b/x-pack/legacy/plugins/transform/public/app/services/ui_metric/ui_metric.ts new file mode 100644 index 0000000000000..a2f0a6e1a5482 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/app/services/ui_metric/ui_metric.ts @@ -0,0 +1,25 @@ +/* + * 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 { UIM_APP_NAME } from '../../constants'; +import { + createUiStatsReporter, + METRIC_TYPE, +} from '../../../../../../../../src/legacy/core_plugins/ui_metric/public'; + +class UiMetricService { + track?: ReturnType; + + public init = (getReporter: typeof createUiStatsReporter): void => { + this.track = getReporter(UIM_APP_NAME); + }; + + public trackUiMetric = (eventName: string): void => { + if (!this.track) throw Error('UiMetricService not initialized.'); + return this.track(METRIC_TYPE.COUNT, eventName); + }; +} + +export const uiMetricService = new UiMetricService(); diff --git a/x-pack/legacy/plugins/transform/public/index.ts b/x-pack/legacy/plugins/transform/public/index.ts new file mode 100644 index 0000000000000..28c9c06f86e24 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/index.ts @@ -0,0 +1,11 @@ +/* + * 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 { Plugin as TransformPlugin } from './plugin'; +import { createPublicShim } from './shim'; + +const { core, plugins } = createPublicShim(); +const transformPlugin = new TransformPlugin(); +transformPlugin.start(core, plugins); diff --git a/x-pack/legacy/plugins/transform/public/plugin.ts b/x-pack/legacy/plugins/transform/public/plugin.ts new file mode 100644 index 0000000000000..7dfb9daead574 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/plugin.ts @@ -0,0 +1,114 @@ +/* + * 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 { unmountComponentAtNode } from 'react-dom'; + +import { i18n } from '@kbn/i18n'; + +import { SavedSearchLoader } from '../../../../../src/legacy/core_plugins/kibana/public/discover/types'; + +import { PLUGIN } from '../common/constants'; +import { CLIENT_BASE_PATH } from './app/constants'; +import { renderReact } from './app/app'; +import { Core, Plugins } from './shim'; + +import { breadcrumbService, docTitleService } from './app/services/navigation'; +import { documentationLinksService } from './app/services/documentation'; +import { httpService } from './app/services/http'; +import { textService } from './app/services/text'; +import { uiMetricService } from './app/services/ui_metric'; + +const REACT_ROOT_ID = 'transformReactRoot'; +const KBN_MANAGEMENT_SECTION = 'elasticsearch/transform'; + +const template = `
`; + +export class Plugin { + public start(core: Core, plugins: Plugins): void { + const { http, routing, legacyHttp, chrome, documentation, docTitle } = core; + const { management, savedSearches: coreSavedSearches, uiMetric } = plugins; + + // AppCore/AppPlugins to be passed on as React context + const AppDependencies = { + core: { chrome, http, i18n: core.i18n }, + plugins: { + management: { sections: management.sections }, + savedSearches: coreSavedSearches, + }, + }; + + // Register management section + const esSection = management.sections.getSection('elasticsearch'); + esSection.register(PLUGIN.ID, { + visible: true, + display: i18n.translate('xpack.transform.appName', { + defaultMessage: 'Transforms', + }), + order: 3, + url: `#${CLIENT_BASE_PATH}`, + }); + + // Initialize services + textService.init(); + breadcrumbService.init(chrome, management.constants.BREADCRUMB); + uiMetricService.init(uiMetric.createUiStatsReporter); + documentationLinksService.init(documentation.esPluginDocBasePath); + docTitleService.init(docTitle.change); + + const unmountReactApp = (): void => { + const elem = document.getElementById(REACT_ROOT_ID); + if (elem) { + unmountComponentAtNode(elem); + } + }; + + // Register react root + routing.registerAngularRoute(`${CLIENT_BASE_PATH}/:section?/:subsection?/:view?/:id?`, { + template, + controllerAs: 'transformController', + controller: ( + $scope: any, + $route: any, + $http: ng.IHttpService, + savedSearches: SavedSearchLoader + ) => { + // NOTE: We depend upon Angular's $http service because it's decorated with interceptors, + // e.g. to check license status per request. + legacyHttp.setClient($http); + httpService.init(legacyHttp.getClient()); + coreSavedSearches.setClient(savedSearches); + + // Angular Lifecycle + const appRoute = $route.current; + const stopListeningForLocationChange = $scope.$on('$locationChangeSuccess', () => { + const currentRoute = $route.current; + const isNavigationInApp = currentRoute.$$route.template === appRoute.$$route.template; + + // When we navigate within Transform, prevent Angular from re-matching the route and rebuild the app + if (isNavigationInApp) { + $route.current = appRoute; + } else { + // Any clean up when user leaves Transform + } + + $scope.$on('$destroy', () => { + if (stopListeningForLocationChange) { + stopListeningForLocationChange(); + } + unmountReactApp(); + }); + }); + + $scope.$$postDigest(() => { + unmountReactApp(); + const elem = document.getElementById(REACT_ROOT_ID); + if (elem) { + renderReact(elem, AppDependencies); + } + }); + }, + }); + } +} diff --git a/x-pack/legacy/plugins/transform/public/shared_imports.ts b/x-pack/legacy/plugins/transform/public/shared_imports.ts new file mode 100644 index 0000000000000..35bcac16921b9 --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/shared_imports.ts @@ -0,0 +1,36 @@ +/* + * 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 { + SendRequestConfig, + SendRequestResponse, + UseRequestConfig, + sendRequest, + useRequest, +} from '../../../../../src/plugins/es_ui_shared/public/request'; + +export { + CronEditor, + 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, + MlInMemoryTableBasic, + OnTableChangeArg, + SortingPropType, + SortDirection, + SORT_DIRECTION, +} from '../../ml/public/components/ml_in_memory_table'; + +// @ts-ignore: could not find declaration file for module +export { KqlFilterBar } from '../../ml/public/components/kql_filter_bar'; diff --git a/x-pack/legacy/plugins/transform/public/shim.ts b/x-pack/legacy/plugins/transform/public/shim.ts new file mode 100644 index 0000000000000..d5d831e3f314a --- /dev/null +++ b/x-pack/legacy/plugins/transform/public/shim.ts @@ -0,0 +1,119 @@ +/* + * 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 { npStart } from 'ui/new_platform'; + +import { management, MANAGEMENT_BREADCRUMB } from 'ui/management'; +import routes from 'ui/routes'; +import { docTitle } from 'ui/doc_title/doc_title'; + +// @ts-ignore: allow traversal to fail on x-pack build +import { createUiStatsReporter } from '../../../../../src/legacy/core_plugins/ui_metric/public'; +import { SavedSearchLoader } from '../../../../../src/legacy/core_plugins/kibana/public/discover/types'; + +export type npCore = typeof npStart.core; + +// AppCore/AppPlugins is the set of core features/plugins +// we pass on via context/hooks to the app and its components. +export type AppCore = Pick; + +export interface AppPlugins { + management: { + sections: typeof management; + }; + savedSearches: { + getClient(): any; + setClient(client: any): void; + }; +} + +export interface AppDependencies { + core: AppCore; + plugins: AppPlugins; +} + +export interface Core extends npCore { + legacyHttp: { + getClient(): any; + setClient(client: any): void; + }; + routing: { + registerAngularRoute(path: string, config: object): void; + }; + documentation: { + esDocBasePath: string; + esPluginDocBasePath: string; + esStackOverviewDocBasePath: string; + }; + docTitle: { + change: typeof docTitle.change; + }; +} + +export interface Plugins extends AppPlugins { + management: { + sections: typeof management; + constants: { + BREADCRUMB: typeof MANAGEMENT_BREADCRUMB; + }; + }; + uiMetric: { + createUiStatsReporter: typeof createUiStatsReporter; + }; +} + +export function createPublicShim(): { core: Core; plugins: Plugins } { + // This is an Angular service, which is why we use this provider pattern + // to access it within our React app. + let httpClient: ng.IHttpService; + // This is an Angular service, which is why we use this provider pattern + // to access it within our React app. + let savedSearches: SavedSearchLoader; + + const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = npStart.core.docLinks; + + return { + core: { + ...npStart.core, + routing: { + registerAngularRoute: (path: string, config: object): void => { + routes.when(path, config); + }, + }, + legacyHttp: { + setClient: (client: any): void => { + httpClient = client; + }, + getClient: (): any => httpClient, + }, + documentation: { + esDocBasePath: `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/reference/${DOC_LINK_VERSION}/`, + esPluginDocBasePath: `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/plugins/${DOC_LINK_VERSION}/`, + esStackOverviewDocBasePath: `${ELASTIC_WEBSITE_URL}guide/en/elastic-stack-overview/${DOC_LINK_VERSION}/`, + }, + docTitle: { + change: docTitle.change, + }, + }, + plugins: { + management: { + sections: management, + constants: { + BREADCRUMB: MANAGEMENT_BREADCRUMB, + }, + }, + savedSearches: { + setClient: (client: any): void => { + savedSearches = client; + }, + getClient: (): any => savedSearches, + }, + uiMetric: { + createUiStatsReporter, + }, + }, + }; +} diff --git a/x-pack/legacy/plugins/transform/server/client/elasticsearch_transform.ts b/x-pack/legacy/plugins/transform/server/client/elasticsearch_transform.ts new file mode 100644 index 0000000000000..5b8b82dc8d3cf --- /dev/null +++ b/x-pack/legacy/plugins/transform/server/client/elasticsearch_transform.ts @@ -0,0 +1,126 @@ +/* + * 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 const elasticsearchJsPlugin = (Client: any, config: any, components: any) => { + const ca = components.clientAction.factory; + + Client.prototype.transform = components.clientAction.namespaceFactory(); + const transform = Client.prototype.transform.prototype; + + // Currently the endpoint uses a default size of 100 unless a size is supplied. + // So until paging is supported in the UI, explicitly supply a size of 1000 + // to match the max number of docs that the endpoint can return. + transform.getTransforms = ca({ + urls: [ + { + fmt: '/_data_frame/transforms/<%=transformId%>', + req: { + transformId: { + type: 'string', + }, + }, + }, + { + fmt: '/_data_frame/transforms/_all?size=1000', + }, + ], + method: 'GET', + }); + + transform.getTransformsStats = ca({ + urls: [ + { + fmt: '/_data_frame/transforms/<%=transformId%>/_stats', + req: { + transformId: { + type: 'string', + }, + }, + }, + { + // Currently the endpoint uses a default size of 100 unless a size is supplied. + // So until paging is supported in the UI, explicitly supply a size of 1000 + // to match the max number of docs that the endpoint can return. + fmt: '/_data_frame/transforms/_all/_stats?size=1000', + }, + ], + method: 'GET', + }); + + transform.createTransform = ca({ + urls: [ + { + fmt: '/_data_frame/transforms/<%=transformId%>', + req: { + transformId: { + type: 'string', + }, + }, + }, + ], + needBody: true, + method: 'PUT', + }); + + transform.deleteTransform = ca({ + urls: [ + { + fmt: '/_data_frame/transforms/<%=transformId%>', + req: { + transformId: { + type: 'string', + }, + }, + }, + ], + method: 'DELETE', + }); + + transform.getTransformsPreview = ca({ + urls: [ + { + fmt: '/_data_frame/transforms/_preview', + }, + ], + needBody: true, + method: 'POST', + }); + + transform.startTransform = ca({ + urls: [ + { + fmt: '/_data_frame/transforms/<%=transformId%>/_start', + req: { + transformId: { + type: 'string', + }, + }, + }, + ], + method: 'POST', + }); + + transform.stopTransform = ca({ + urls: [ + { + fmt: + '/_data_frame/transforms/<%=transformId%>/_stop?&force=<%=force%>&wait_for_completion=<%waitForCompletion%>', + req: { + transformId: { + type: 'string', + }, + force: { + type: 'boolean', + }, + waitForCompletion: { + type: 'boolean', + }, + }, + }, + ], + method: 'POST', + }); +}; diff --git a/x-pack/legacy/plugins/transform/server/plugin.ts b/x-pack/legacy/plugins/transform/server/plugin.ts new file mode 100644 index 0000000000000..f9264ee1f2507 --- /dev/null +++ b/x-pack/legacy/plugins/transform/server/plugin.ts @@ -0,0 +1,17 @@ +/* + * 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 { API_BASE_PATH } from '../common/constants'; +import { registerRoutes } from './routes/api/register_routes'; +import { Core, Plugins } from './shim'; + +export class Plugin { + public start(core: Core, plugins: Plugins): void { + const router = core.http.createRouter(API_BASE_PATH); + + // Register routes + registerRoutes(router, plugins); + } +} diff --git a/x-pack/legacy/plugins/transform/server/routes/api/app.ts b/x-pack/legacy/plugins/transform/server/routes/api/app.ts new file mode 100644 index 0000000000000..c3189794b6eb0 --- /dev/null +++ b/x-pack/legacy/plugins/transform/server/routes/api/app.ts @@ -0,0 +1,99 @@ +/* + * 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 { Router, RouterRouteHandler } from '../../../../../server/lib/create_router'; +import { wrapCustomError } from '../../../../../server/lib/create_router/error_wrappers'; +import { APP_CLUSTER_PRIVILEGES, APP_INDEX_PRIVILEGES } from '../../../common/constants'; +// NOTE: now we import it from our "public" folder, but when the Authorisation lib +// will move to the "es_ui_shared" plugin, it will be imported from its "static" folder +import { Privileges } from '../../../public/app/lib/authorization'; +import { Plugins } from '../../shim'; + +let xpackMainPlugin: any; + +export function registerAppRoutes(router: Router, plugins: Plugins) { + xpackMainPlugin = plugins.xpack_main; + router.get('privileges', getPrivilegesHandler); +} + +export function getXpackMainPlugin() { + return xpackMainPlugin; +} + +const extractMissingPrivileges = (privilegesObject: { [key: string]: boolean } = {}): string[] => + Object.keys(privilegesObject).reduce((privileges: string[], privilegeName: string): string[] => { + if (!privilegesObject[privilegeName]) { + privileges.push(privilegeName); + } + return privileges; + }, []); + +export const getPrivilegesHandler: RouterRouteHandler = async ( + req, + callWithRequest +): Promise => { + const xpackInfo = getXpackMainPlugin() && getXpackMainPlugin().info; + if (!xpackInfo) { + // xpackInfo is updated via poll, so it may not be available until polling has begun. + // In this rare situation, tell the client the service is temporarily unavailable. + throw wrapCustomError(new Error('Security info unavailable'), 503); + } + + const privilegesResult: Privileges = { + hasAllPrivileges: true, + missingPrivileges: { + cluster: [], + index: [], + }, + }; + + const securityInfo = xpackInfo && xpackInfo.isAvailable() && xpackInfo.feature('security'); + if (!securityInfo || !securityInfo.isAvailable() || !securityInfo.isEnabled()) { + // If security isn't enabled, let the user use app. + return privilegesResult; + } + + // Get cluster priviliges + const { has_all_requested: hasAllPrivileges, cluster } = await callWithRequest( + 'transport.request', + { + path: '/_security/user/_has_privileges', + method: 'POST', + body: { + cluster: APP_CLUSTER_PRIVILEGES, + }, + } + ); + + // Find missing cluster privileges and set overall app privileges + privilegesResult.missingPrivileges.cluster = extractMissingPrivileges(cluster); + privilegesResult.hasAllPrivileges = hasAllPrivileges; + + // Get all index privileges the user has + const { indices } = await callWithRequest('transport.request', { + path: '/_security/user/_privileges', + method: 'GET', + }); + + // Check if they have all the required index privileges for at least one index + const oneIndexWithAllPrivileges = indices.find(({ privileges }: { privileges: string[] }) => { + if (privileges.includes('all')) { + return true; + } + + const indexHasAllPrivileges = APP_INDEX_PRIVILEGES.every(privilege => + privileges.includes(privilege) + ); + + return indexHasAllPrivileges; + }); + + // If they don't, return list of required index privileges + if (!oneIndexWithAllPrivileges) { + privilegesResult.missingPrivileges.index = [...APP_INDEX_PRIVILEGES]; + } + + return privilegesResult; +}; diff --git a/x-pack/legacy/plugins/ml/server/models/data_frame/error_utils.ts b/x-pack/legacy/plugins/transform/server/routes/api/error_utils.ts similarity index 65% rename from x-pack/legacy/plugins/ml/server/models/data_frame/error_utils.ts rename to x-pack/legacy/plugins/transform/server/routes/api/error_utils.ts index 7c816aa12d42c..094c0308ff20f 100644 --- a/x-pack/legacy/plugins/ml/server/models/data_frame/error_utils.ts +++ b/x-pack/legacy/plugins/transform/server/routes/api/error_utils.ts @@ -5,17 +5,21 @@ */ import { i18n } from '@kbn/i18n'; -// @ts-ignore no declaration file for module -export { isRequestTimeout } from '../job_service/error_utils'; import { - DataFrameTransformEndpointRequest, - DataFrameTransformEndpointResult, -} from '../../../public/data_frame/pages/transform_management/components/transform_list/common'; + TransformEndpointRequest, + TransformEndpointResult, +} from '../../../public/app/hooks/use_api_types'; + +const REQUEST_TIMEOUT = 'RequestTimeout'; + +export function isRequestTimeout(error: any) { + return error.displayName === REQUEST_TIMEOUT; +} interface Params { - results: DataFrameTransformEndpointResult; + results: TransformEndpointResult; id: string; - items: DataFrameTransformEndpointRequest[]; + items: TransformEndpointRequest[]; action: string; } @@ -23,9 +27,12 @@ interface Params { export function fillResultsWithTimeouts({ results, id, items, action }: Params) { const extra = items.length - Object.keys(results).length > 1 - ? i18n.translate('xpack.ml.models.transformService.allOtherRequestsCancelledDescription', { - defaultMessage: 'All other requests cancelled.', - }) + ? i18n.translate( + 'xpack.transform.models.transformService.allOtherRequestsCancelledDescription', + { + defaultMessage: 'All other requests cancelled.', + } + ) : ''; const error = { @@ -34,7 +41,7 @@ export function fillResultsWithTimeouts({ results, id, items, action }: Params) root_cause: [ { reason: i18n.translate( - 'xpack.ml.models.transformService.requestToActionTimedOutErrorMessage', + 'xpack.transform.models.transformService.requestToActionTimedOutErrorMessage', { defaultMessage: `Request to {action} '{id}' timed out. {extra}`, values: { @@ -50,7 +57,7 @@ export function fillResultsWithTimeouts({ results, id, items, action }: Params) }, }; - const newResults: DataFrameTransformEndpointResult = {}; + const newResults: TransformEndpointResult = {}; return items.reduce((accumResults, currentVal) => { if (results[currentVal.id] === undefined) { diff --git a/x-pack/legacy/plugins/transform/server/routes/api/register_routes.ts b/x-pack/legacy/plugins/transform/server/routes/api/register_routes.ts new file mode 100644 index 0000000000000..c01647c598d86 --- /dev/null +++ b/x-pack/legacy/plugins/transform/server/routes/api/register_routes.ts @@ -0,0 +1,14 @@ +/* + * 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 { Router } from '../../../../../server/lib/create_router'; +import { Plugins } from '../../shim'; +import { registerAppRoutes } from './app'; +import { registerTransformsRoutes } from './transforms'; + +export const registerRoutes = (router: Router, plugins: Plugins): void => { + registerAppRoutes(router, plugins); + registerTransformsRoutes(router, plugins); +}; diff --git a/x-pack/legacy/plugins/ml/server/models/data_frame/transform_audit_messages.ts b/x-pack/legacy/plugins/transform/server/routes/api/transform_audit_messages.ts similarity index 80% rename from x-pack/legacy/plugins/ml/server/models/data_frame/transform_audit_messages.ts rename to x-pack/legacy/plugins/transform/server/routes/api/transform_audit_messages.ts index 5a9839890e396..463474064bdee 100644 --- a/x-pack/legacy/plugins/ml/server/models/data_frame/transform_audit_messages.ts +++ b/x-pack/legacy/plugins/transform/server/routes/api/transform_audit_messages.ts @@ -4,26 +4,18 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ML_DF_NOTIFICATION_INDEX_PATTERN } from '../../../common/constants/index_patterns'; -import { callWithRequestType } from '../../../common/types/kibana'; -import { TransformMessage } from '../../../common/types/audit_message'; +import { CallCluster } from 'src/legacy/core_plugins/elasticsearch'; -const SIZE = 500; +import { AuditMessage } from '../../../common/types/messages'; -interface Message { - _index: string; - _type: string; - _id: string; - _score: null | number; - _source: TransformMessage; - sort?: any; -} +const ML_DF_NOTIFICATION_INDEX_PATTERN = '.data-frame-notifications-1'; +const SIZE = 500; interface BoolQuery { bool: { [key: string]: any }; } -export function transformAuditMessagesProvider(callWithRequest: callWithRequestType) { +export function transformAuditMessagesProvider(callWithRequest: CallCluster) { // search for audit messages, // transformId is optional. without it, all transforms will be listed. async function getTransformAuditMessages(transformId: string) { @@ -77,7 +69,7 @@ export function transformAuditMessagesProvider(callWithRequest: callWithRequestT let messages = []; if (resp.hits.total !== 0) { - messages = resp.hits.hits.map((hit: Message) => hit._source); + messages = resp.hits.hits.map((hit: AuditMessage) => hit._source); messages.reverse(); } return messages; diff --git a/x-pack/legacy/plugins/transform/server/routes/api/transforms.ts b/x-pack/legacy/plugins/transform/server/routes/api/transforms.ts new file mode 100644 index 0000000000000..6e833854a24c9 --- /dev/null +++ b/x-pack/legacy/plugins/transform/server/routes/api/transforms.ts @@ -0,0 +1,261 @@ +/* + * 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 { CallCluster } from 'src/legacy/core_plugins/elasticsearch'; +import { Router, RouterRouteHandler } from '../../../../../server/lib/create_router'; +import { wrapEsError } from '../../../../../server/lib/create_router/error_wrappers'; +import { Plugins } from '../../shim'; +import { TRANSFORM_STATE } from '../../../public/app/common'; +import { + TransformEndpointRequest, + TransformEndpointResult, +} from '../../../public/app/hooks/use_api_types'; +import { TransformId } from '../../../public/app/common/transform'; +import { isRequestTimeout, fillResultsWithTimeouts } from './error_utils'; +import { transformAuditMessagesProvider } from './transform_audit_messages'; + +enum TRANSFORM_ACTIONS { + STOP = 'stop', + START = 'start', + DELETE = 'delete', +} + +interface StartOptions { + transformId: TransformId; +} + +interface StopOptions { + transformId: TransformId; + force: boolean; + waitForCompletion?: boolean; +} + +export function registerTransformsRoutes(router: Router, plugins: Plugins) { + router.get('transforms', getTransformHandler); + router.get('transforms/{transformId}', getTransformHandler); + router.get('transforms/_stats', getTransformStatsHandler); + router.get('transforms/{transformId}/_stats', getTransformStatsHandler); + router.get('transforms/{transformId}/messages', getTransformMessagesHandler); + router.put('transforms/{transformId}', putTransformHandler); + router.post('delete_transforms', deleteTransformsHandler); + router.post('transforms/_preview', previewTransformHandler); + router.post('start_transforms', startTransformsHandler); + router.post('stop_transforms', stopTransformsHandler); + router.post('es_search', esSearchHandler); +} + +const getTransformHandler: RouterRouteHandler = async (req, callWithRequest) => { + const { transformId } = req.params; + const options = { + ...(transformId !== undefined ? { transformId } : {}), + }; + + try { + return await callWithRequest('transform.getTransforms', options); + } catch (e) { + return { error: wrapEsError(e) }; + } +}; + +const getTransformStatsHandler: RouterRouteHandler = async (req, callWithRequest) => { + const { transformId } = req.params; + const options = { + ...(transformId !== undefined ? { transformId } : {}), + }; + + try { + return await callWithRequest('transform.getTransformsStats', options); + } catch (e) { + return { error: wrapEsError(e) }; + } +}; + +const deleteTransformsHandler: RouterRouteHandler = async (req, callWithRequest) => { + const transformsInfo = req.payload as TransformEndpointRequest[]; + + try { + return await deleteTransforms(transformsInfo, callWithRequest); + } catch (e) { + return { error: wrapEsError(e) }; + } +}; + +const putTransformHandler: RouterRouteHandler = async (req, callWithRequest) => { + const { transformId } = req.params; + + const response: { + transformsCreated: Array<{ transform: string }>; + errors: any[]; + } = { + transformsCreated: [], + errors: [], + }; + + await callWithRequest('transform.createTransform', { body: req.payload, transformId }) + .then(() => response.transformsCreated.push({ transform: transformId })) + .catch(e => + response.errors.push({ + id: transformId, + error: wrapEsError(e), + }) + ); + + return response; +}; + +async function deleteTransforms( + transformsInfo: TransformEndpointRequest[], + callWithRequest: CallCluster +) { + const results: TransformEndpointResult = {}; + + for (const transformInfo of transformsInfo) { + const transformId = transformInfo.id; + try { + if (transformInfo.state === TRANSFORM_STATE.FAILED) { + try { + await callWithRequest('transform.stopTransform', { + transformId, + force: true, + waitForCompletion: true, + } as StopOptions); + } catch (e) { + if (isRequestTimeout(e)) { + return fillResultsWithTimeouts({ + results, + id: transformId, + items: transformsInfo, + action: TRANSFORM_ACTIONS.DELETE, + }); + } + } + } + + await callWithRequest('transform.deleteTransform', { transformId }); + results[transformId] = { success: true }; + } catch (e) { + if (isRequestTimeout(e)) { + return fillResultsWithTimeouts({ + results, + id: transformInfo.id, + items: transformsInfo, + action: TRANSFORM_ACTIONS.DELETE, + }); + } + results[transformId] = { success: false, error: JSON.stringify(e) }; + } + } + return results; +} + +const previewTransformHandler: RouterRouteHandler = async (req, callWithRequest) => { + try { + return await callWithRequest('transform.getTransformsPreview', { body: req.payload }); + } catch (e) { + return wrapEsError(e); + } +}; + +const startTransformsHandler: RouterRouteHandler = async (req, callWithRequest) => { + const { transformsInfo } = req.payload as { + transformsInfo: TransformEndpointRequest[]; + }; + + try { + return await startTransforms(transformsInfo, callWithRequest); + } catch (e) { + return wrapEsError(e); + } +}; + +async function startTransforms( + transformsInfo: TransformEndpointRequest[], + callWithRequest: CallCluster +) { + const results: TransformEndpointResult = {}; + + for (const transformInfo of transformsInfo) { + const transformId = transformInfo.id; + try { + await callWithRequest('transform.startTransform', { transformId } as StartOptions); + results[transformId] = { success: true }; + } catch (e) { + if (isRequestTimeout(e)) { + return fillResultsWithTimeouts({ + results, + id: transformId, + items: transformsInfo, + action: TRANSFORM_ACTIONS.START, + }); + } + results[transformId] = { success: false, error: JSON.stringify(e) }; + } + } + return results; +} + +const stopTransformsHandler: RouterRouteHandler = async (req, callWithRequest) => { + const { transformsInfo } = req.payload as { + transformsInfo: TransformEndpointRequest[]; + }; + + try { + return await stopTransforms(transformsInfo, callWithRequest); + } catch (e) { + return wrapEsError(e); + } +}; + +async function stopTransforms( + transformsInfo: TransformEndpointRequest[], + callWithRequest: CallCluster +) { + const results: TransformEndpointResult = {}; + + for (const transformInfo of transformsInfo) { + const transformId = transformInfo.id; + try { + await callWithRequest('transform.stopTransform', { + transformId, + force: + transformInfo.state !== undefined + ? transformInfo.state === TRANSFORM_STATE.FAILED + : false, + waitForCompletion: true, + } as StopOptions); + results[transformId] = { success: true }; + } catch (e) { + if (isRequestTimeout(e)) { + return fillResultsWithTimeouts({ + results, + id: transformId, + items: transformsInfo, + action: TRANSFORM_ACTIONS.STOP, + }); + } + results[transformId] = { success: false, error: JSON.stringify(e) }; + } + } + return results; +} + +const getTransformMessagesHandler: RouterRouteHandler = async (req, callWithRequest) => { + const { getTransformAuditMessages } = transformAuditMessagesProvider(callWithRequest); + const { transformId } = req.params; + + try { + return await getTransformAuditMessages(transformId); + } catch (e) { + return wrapEsError(e); + } +}; + +const esSearchHandler: RouterRouteHandler = async (req, callWithRequest) => { + try { + return await callWithRequest('search', req.payload); + } catch (e) { + return { error: wrapEsError(e) }; + } +}; diff --git a/x-pack/legacy/plugins/transform/server/shim.ts b/x-pack/legacy/plugins/transform/server/shim.ts new file mode 100644 index 0000000000000..83afa788682f1 --- /dev/null +++ b/x-pack/legacy/plugins/transform/server/shim.ts @@ -0,0 +1,58 @@ +/* + * 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 { get } from 'lodash'; +import { Legacy } from 'kibana'; +import { createRouter, Router } from '../../../server/lib/create_router'; +import { registerLicenseChecker } from '../../../server/lib/register_license_checker'; +import { elasticsearchJsPlugin } from './client/elasticsearch_transform'; + +export interface Core { + http: { + createRouter(basePath: string): Router; + }; +} + +export interface Plugins { + license: { + registerLicenseChecker: typeof registerLicenseChecker; + }; + cloud: { + config: { + isCloudEnabled: boolean; + }; + }; + xpack_main: any; + elasticsearch: any; +} + +export function createServerShim( + server: Legacy.Server, + pluginId: string +): { core: Core; plugins: Plugins } { + return { + core: { + http: { + createRouter: (basePath: string) => + createRouter(server, pluginId, basePath, { + plugins: [elasticsearchJsPlugin], + }), + }, + }, + plugins: { + license: { + registerLicenseChecker, + }, + cloud: { + config: { + isCloudEnabled: get(server.plugins, 'cloud.config.isCloudEnabled', false), + }, + }, + xpack_main: server.plugins.xpack_main, + elasticsearch: server.plugins.elasticsearch, + }, + }; +} diff --git a/x-pack/legacy/server/lib/mirror_plugin_status.js b/x-pack/legacy/server/lib/mirror_plugin_status.js index 7f04172c6cb77..0ec34e80d65d5 100644 --- a/x-pack/legacy/server/lib/mirror_plugin_status.js +++ b/x-pack/legacy/server/lib/mirror_plugin_status.js @@ -5,7 +5,7 @@ */ export function mirrorPluginStatus(upstreamPlugin, downstreamPlugin, ...statesToMirror) { - upstreamPlugin.status.setMaxListeners(20); // We need more than the default, which is 10 + upstreamPlugin.status.setMaxListeners(21); // We need more than the default, which is 10 function mirror(previousState, previousMsg, newState, newMsg) { if (newState) { diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index d75c730d5e25d..c18f43a37ce85 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -6044,132 +6044,6 @@ "xpack.ml.customUrlsEditor.timeRangeLabel": "時間範囲", "xpack.ml.customUrlsEditor.urlLabel": "URL", "xpack.ml.customUrlsList.invalidIntervalFormatErrorMessage": "無効な間隔のフォーマット", - "xpack.ml.dataframe.accessDenied.backToKibanaHomeButtonLabel": "Kibana ホームに戻る", - "xpack.ml.dataframe.accessDenied.retryButtonLabel": "再試行", - "xpack.ml.dataframe.accessDeniedTitle": "アクセスが拒否されました", - "xpack.ml.dataframe.agg.popoverForm.aggLabel": "集約", - "xpack.ml.dataframe.agg.popoverForm.aggNameAlreadyUsedError": "別の集約で既に同じ名前が使用されています。", - "xpack.ml.dataframe.agg.popoverForm.aggNameInvalidCharError": "無効な名前です。「[」、「]」「>」は使用できず、名前の始めと終わりにはスペースを使用できません。", - "xpack.ml.dataframe.agg.popoverForm.fieldLabel": "フィールド", - "xpack.ml.dataframe.agg.popoverForm.nameLabel": "集約名", - "xpack.ml.dataframe.agg.popoverForm.submitButtonLabel": "適用", - "xpack.ml.dataframe.aggLabelForm.deleteItemAriaLabel": "アイテムを削除", - "xpack.ml.dataframe.aggLabelForm.editAggAriaLabel": "集約を編集", - "xpack.ml.dataframe.stepDefineForm.aggExistsErrorMessage": "「{aggName}」という名前のアグリゲーション構成は既に存在します。", - "xpack.ml.dataframe.stepDefineForm.groupByExistsErrorMessage": "「{aggName}」という名前のgroup by構成は既に存在します。", - "xpack.ml.dataframe.stepDefineForm.nestedAggListConflictErrorMessage": "「{aggListName}」とネスティングの矛盾があるため、構成「{aggName}」を追加できませんでした。", - "xpack.ml.dataframe.stepDefineForm.nestedConflictErrorMessage": "「{aggNameCheck}」とネスティングの矛盾があるため、構成「{aggName}」を追加できませんでした。", - "xpack.ml.dataframe.stepDefineForm.nestedGroupByListConflictErrorMessage": "「{groupByListName}」とネスティングの矛盾があるため、構成「{aggName}」を追加できませんでした。", - "xpack.ml.dataframe.stepDefineForm.aggregationsLabel": "アグリゲーション(集計)", - "xpack.ml.dataframe.stepDefineForm.aggregationsPlaceholder": "集約を追加…", - "xpack.ml.dataframe.stepDefineForm.formHelp": "データフレーム変換は、ピボット用のスケーラブルで自動化されたプロセスです。開始するにはグループ分けの条件と集約を少なくとも 1 つ選んでください。", - "xpack.ml.dataframe.stepDefineForm.groupByLabel": "グループ分けの条件", - "xpack.ml.dataframe.stepDefineForm.groupByPlaceholder": "グループ分けの条件フィールドを追加…", - "xpack.ml.dataframe.stepDefineForm.indexPatternHelpText": "このインデックスパターンのオプションのクエリはサポートされていません。サポートされているインデックスフィールドの数は {maxIndexFields} で、このインデックスには {numIndexFields} 個のフィールドがあります。", - "xpack.ml.dataframe.stepDefineForm.indexPatternLabel": "インデックスパターン", - "xpack.ml.dataframe.stepDefineForm.queryHelpText": "クエリでソースデータをフィルタリングしてください (オプション)。", - "xpack.ml.dataframe.stepDefineForm.queryLabel": "クエリ", - "xpack.ml.dataframe.stepDefineForm.savedSearchLabel": "保存された検索", - "xpack.ml.dataframe.stepDefineSummary.aggregationsLabel": "アグリゲーション(集計)", - "xpack.ml.dataframe.stepDefineSummary.groupByLabel": "グループ分けの条件", - "xpack.ml.dataframe.stepDefineSummary.indexPatternLabel": "インデックスパターン", - "xpack.ml.dataframe.stepDefineSummary.queryLabel": "クエリ", - "xpack.ml.dataframe.groupby.popoverForm.aggLabel": "集約", - "xpack.ml.dataframe.groupBy.popoverForm.aggNameAlreadyUsedError": "別のグループ分けの構成が既にこの名前を使用しています。", - "xpack.ml.dataframe.groupBy.popoverForm.aggNameInvalidCharError": "無効な名前です。「[」、「]」「>」は使用できず、名前の始めと終わりにはスペースを使用できません。", - "xpack.ml.dataframe.groupBy.popoverForm.fieldLabel": "フィールド", - "xpack.ml.dataframe.groupBy.popoverForm.intervalError": "無効な間隔。", - "xpack.ml.dataframe.groupBy.popoverForm.intervalLabel": "間隔", - "xpack.ml.dataframe.groupBy.popoverForm.nameLabel": "グループ分け名", - "xpack.ml.dataframe.groupBy.popoverForm.submitButtonLabel": "適用", - "xpack.ml.dataframe.groupByLabelForm.deleteItemAriaLabel": "アイテムを削除", - "xpack.ml.dataframe.groupByLabelForm.editIntervalAriaLabel": "間隔を編集", - "xpack.ml.dataframe.stepCreateForm.copyTransformConfigToClipboardButton": "クリップボードにコピー", - "xpack.ml.dataframe.stepCreateForm.copyTransformConfigToClipboardDescription": "変換を作成する Kibana 開発コンソールのコマンドをクリップボードにコピーします。", - "xpack.ml.dataframe.stepCreateForm.createAndStartDataFrameButton": "作成して開始", - "xpack.ml.dataframe.stepCreateForm.createAndStartDataFrameDescription": "データフレーム変換を作成して開始します。データフレーム変換は、クラスターの検索とインデックスによる負荷を増やします。過剰な負荷が生じた場合は変換を停止してください。変換の開始後、データフレーム変換の閲覧を続けるオプションが提供されます。", - "xpack.ml.dataframe.stepCreateForm.createDataFrameButton": "作成", - "xpack.ml.dataframe.stepCreateForm.createDataFrameDescription": "データフレーム変換を開始せずに作成します。変換は後程データフレーム変換リストに戻って開始できます。", - "xpack.ml.dataframe.stepCreateForm.createIndexPatternErrorMessage": "Kibana インデックスパターン {indexPatternName} の作成中にエラーが発生しました: {error}", - "xpack.ml.dataframe.stepCreateForm.createIndexPatternLabel": "インデックスパターンを作成", - "xpack.ml.dataframe.stepCreateForm.createTransformErrorMessage": "データフレーム変換 {transformId} の作成中にエラーが発生しました: {error}", - "xpack.ml.dataframe.stepCreateForm.createTransformSuccessMessage": "データフレーム変換 {transformId} が作成されました", - "xpack.ml.dataframe.stepCreateForm.creatingIndexPatternMessage": "Kibana インデックスパターンを作成中…", - "xpack.ml.dataframe.stepCreateForm.discoverCardDescription": "ディスカバリでデータフレームピボットを閲覧します。", - "xpack.ml.dataframe.stepCreateForm.discoverCardTitle": "ディスカバー", - "xpack.ml.dataframe.stepCreateForm.transformListCardDescription": "データフレーム変換の管理ページに戻ります。", - "xpack.ml.dataframe.stepCreateForm.transformListCardTitle": "データフレーム変換", - "xpack.ml.dataframe.stepCreateForm.progressErrorMessage": "進捗パーセンテージの取得中にエラーが発生しました: {error}", - "xpack.ml.dataframe.stepCreateForm.progressTitle": "進捗", - "xpack.ml.dataframe.stepCreateForm.createIndexPatternSuccessMessage": "Kibana インデックスパターン {indexPatternName} が作成されました", - "xpack.ml.dataframe.stepCreateForm.startDataFrameButton": "開始", - "xpack.ml.dataframe.stepCreateForm.startDataFrameDescription": "データフレーム変換を開始します。データフレーム変換は、クラスターの検索とインデックスによる負荷を増やします。過剰な負荷が生じた場合は変換を停止してください。変換の開始後、データフレーム変換の閲覧を続けるオプションが提供されます。", - "xpack.ml.dataframe.stepCreateForm.startTransformErrorMessage": "データフレーム変換 {transformId} の開始中にエラーが発生しました: {error}", - "xpack.ml.dataframe.stepCreateForm.startTransformSuccessMessage": "データフレーム変換 {transformId} が正常に開始しました。", - "xpack.ml.dataframe.stepDetailsForm.errorGettingDataFrameIndexNames": "既存のインデックス名の取得中にエラーが発生しました:{error}", - "xpack.ml.dataframe.stepDetailsForm.errorGettingDataFrameTransformList": "既存のデータフレーム変換IDの取得中にエラーが発生しました:{error}", - "xpack.ml.dataframe.stepDetailsForm.errorGettingIndexPatternTitles": "既存のインデックスパターンのタイトルの取得中にエラーが発生しました: {error}", - "xpack.ml.dataframe.stepDetailsForm.indexPatternTitleError": "このタイトルのインデックスパターンが既に存在します。", - "xpack.ml.dataframe.stepDetailsForm.transformIdInputAriaLabel": "一意の変換 ID を選択してください。", - "xpack.ml.dataframe.stepDetailsForm.transformIdLabel": "変換 ID", - "xpack.ml.dataframe.stepDetailsSummary.createIndexPatternMessage": "この変換の Kibana インデックスパターンが作成されます。", - "xpack.ml.dataframe.stepDetailsSummary.transformIdLabel": "変換 ID", - "xpack.ml.dataframe.transformList.betaBadgeLabel": "ベータ", - "xpack.ml.dataframe.transformList.betaBadgeTooltipContent": "データフレームはベータ機能です。フィードバックをお待ちしています。", - "xpack.ml.dataframe.transformList.completeBatchTransformToolTip": "{transformId} は完了済みのバッチ変換で、再度開始できません。", - "xpack.ml.dataframe.transformList.createDataFrameButton": "変換の作成", - "xpack.ml.dataframe.transformList.dataFrameTitle": "データフレーム変換", - "xpack.ml.dataframe.transformList.deleteActionDisabledToolTipContent": "削除するにはデータフレーム変換を停止してください。", - "xpack.ml.dataframe.transformList.deleteActionName": "削除", - "xpack.ml.dataframe.transformList.deleteTransformSuccessMessage": "データフレーム変換 {transformId} が正常に削除されました。", - "xpack.ml.dataframe.transformList.deleteModalBody": "この変換を削除してよろしいですか?変換の送信先インデックスとオプションの Kibana インデックスパターンは削除されません。", - "xpack.ml.dataframe.transformList.deleteModalCancelButton": "キャンセル", - "xpack.ml.dataframe.transformList.deleteModalDeleteButton": "削除", - "xpack.ml.dataframe.transformList.deleteModalTitle": "{transformId} を削除", - "xpack.ml.dataframe.transformList.transformDetails.tabs.transformSettingsLabel": "変換詳細", - "xpack.ml.dataframe.transformList.rowCollapse": "{transformId} の詳細を非表示", - "xpack.ml.dataframe.transformList.rowExpand": "{transformId} の詳細を表示", - "xpack.ml.dataframe.transformList.startActionName": "開始", - "xpack.ml.dataframe.transformList.startTransformSuccessMessage": "データフレーム変換 {transformId} が正常に開始しました。", - "xpack.ml.dataframe.transformList.startModalCancelButton": "キャンセル", - "xpack.ml.dataframe.transformList.startModalStartButton": "開始", - "xpack.ml.dataframe.transformList.startModalTitle": "{transformId} を開始", - "xpack.ml.dataframe.transformList.stopActionName": "停止", - "xpack.ml.dataframe.transformList.stopTransformSuccessMessage": "データフレーム変換 {transformId} が正常に停止しました。", - "xpack.ml.dataframe.noGrantedPrivilegesDescription": "{kibanaUserParam} と {dataFrameUserParam} ロールの権限が必要です。{br}これらのロールはシステム管理者がユーザー管理ページで設定します。", - "xpack.ml.dataframe.noPermissionToAccessMLLabel": "データフレームへのアクセスにはパーミッションが必要です", - "xpack.ml.dataframe.pivotPreview.copyClipboardTooltip": "ピボットプレビューの開発コンソールステートメントをクリップボードにコピーします。", - "xpack.ml.dataframe.pivotPreview.dataFramePivotPreviewError": "ピボットプレビューの読み込み中にエラーが発生しました。", - "xpack.ml.dataframe.pivotPreview.dataFramePivotPreviewIncompleteConfigCalloutBody": "group-byフィールドとアグリゲーションを1つ以上選んでください。", - "xpack.ml.dataframe.pivotPreview.dataFramePivotPreviewNoDataCalloutBody": "プレビューリクエストはデータを返しませんでした。オプションのクエリがデータを返し、グループ分け基準により使用されるフィールドと集約フィールドに値が存在することを確認してください。", - "xpack.ml.dataframe.pivotPreview.dataFramePivotPreviewNoDataCalloutTitle": "ピボットプレビューを利用できません", - "xpack.ml.dataframe.pivotPreview.dataFramePivotPreviewTitle": "データフレームピボットプレビュー", - "xpack.ml.dataframe.pivotPreview.statusCodeLabel": "ステータスコード", - "xpack.ml.dataframe.progress": "進捗", - "xpack.ml.dataframe.sourceIndex": "ソースインデックス", - "xpack.ml.dataframe.sourceIndexPreview.copyClipboardTooltip": "ソースインデックスプレビューの開発コンソールステートメントをクリップボードにコピーします。", - "xpack.ml.dataframe.sourceIndexPreview.dataFrameSourceIndexNoDataCalloutBody": "ソースインデックスのクエリが結果を返しませんでした。インデックスにドキュメントが含まれていること、およびクエリ要件が妥当であることを確認してください。", - "xpack.ml.dataframe.sourceIndexPreview.dataFrameSourceIndexNoDataCalloutTitle": "空のソースインデックスクエリの結果。", - "xpack.ml.dataframe.sourceIndexPreview.fieldSelection": "{docFieldsCount, number} 件中 {selectedFieldsLength, number} 件の {docFieldsCount, plural, one {フィールド} other {フィールド}}を選択済み", - "xpack.ml.dataframe.sourceIndexPreview.rowCollapse": "縮小", - "xpack.ml.dataframe.sourceIndexPreview.rowExpand": "拡張", - "xpack.ml.dataframe.sourceIndexPreview.selectColumnsAriaLabel": "列を選択", - "xpack.ml.dataframe.sourceIndexPreview.selectFieldsPopoverTitle": "フィールドを選択", - "xpack.ml.dataframe.sourceIndexPreview.sourceIndexPatternError": "ソースインデックスデータの読み込み中にエラーが発生しました。", - "xpack.ml.dataframe.sourceIndexPreview.sourceIndexPatternTitle": "ソースインデックス {indexPatternTitle}", - "xpack.ml.dataframe.status": "ステータス", - "xpack.ml.dataframe.tableActionLabel": "アクション", - "xpack.ml.dataframe.transformsWizard.betaBadgeLabel": "ベータ", - "xpack.ml.dataframe.transformsWizard.betaBadgeTooltipContent": "データフレームはベータ機能です。フィードバックをお待ちしています。", - "xpack.ml.dataframe.transformsWizard.stepCreateTitle": "作成", - "xpack.ml.dataframe.transformsWizard.stepDefineTitle": "ピボットの定義", - "xpack.ml.dataframe.transformsWizard.stepDetailsTitle": "変換詳細", - "xpack.ml.dataframe.transformsWizard.newDataFrameTitle": "新規データフレーム", - "xpack.ml.dataframe.wizard.nextStepButton": "次へ", - "xpack.ml.dataframe.wizard.previousStepButton": "前へ", - "xpack.ml.dataFrameBreadcrumbs.dataFrameCreateLabel": "データフレームを作成", - "xpack.ml.dataFrameBreadcrumbs.dataFrameLabel": "変換", - "xpack.ml.dataFrameBreadcrumbs.selectIndexOrSearchLabel": "インデックスまたは検索を選択", "xpack.ml.datavisualizer.selector.dataVisualizerDescription": "機械学習データビジュアライザーツールは、ログファイルのメトリックとフィールド、または既存の Elasticsearch インデックスを分析し、データの理解を助けます。", "xpack.ml.datavisualizer.selector.dataVisualizerTitle": "データビジュアライザー", "xpack.ml.datavisualizer.selector.experimentalBadgeLabel": "実験的", @@ -6713,7 +6587,6 @@ "xpack.ml.models.jobValidation.validateJobObject.jobIsNotObjectErrorMessage": "無効な {invalidParamName}:オブジェクトでなければなりません。", "xpack.ml.models.jobValidation.validateJobObject.timeFieldIsNotStringErrorMessage": "無効な {invalidParamName}:文字列でなければなりません。", "xpack.ml.navMenu.anomalyExplorerTabLinkText": "異常エクスプローラー", - "xpack.ml.navMenu.dataFrameTabLinkText": "変換", "xpack.ml.navMenu.dataVisualizerTabLinkText": "データビジュアライザー", "xpack.ml.navMenu.jobManagementTabLinkText": "ジョブ管理", "xpack.ml.navMenu.settingsTabLinkText": "設定", @@ -7175,15 +7048,12 @@ "xpack.ml.newJob.wizard.jobType.useWizardTitle": "ウィザードを使用", "xpack.ml.privilege.licenseHasExpiredTooltip": "ご使用のライセンスは期限切れです。", "xpack.ml.privilege.noPermission.createCalendarsTooltip": "カレンダーを作成するパーミッションがありません。", - "xpack.ml.privilege.noPermission.createDataFrameTransformTooltip": "データフレーム変換を作成するパーミッションがありません。", "xpack.ml.privilege.noPermission.createMLJobsTooltip": "機械学習ジョブを作成するパーミッションがありません。", "xpack.ml.privilege.noPermission.deleteCalendarsTooltip": "カレンダーを削除するパーミッションがありません。", - "xpack.ml.privilege.noPermission.deleteDataFrameTransformTooltip": "データフレーム変換を削除するパーミッションがありません。", "xpack.ml.privilege.noPermission.deleteJobsTooltip": "ジョブを削除するパーミッションがありません。", "xpack.ml.privilege.noPermission.editJobsTooltip": "ジョブを編集するパーミッションがありません。", "xpack.ml.privilege.noPermission.runForecastsTooltip": "予測を実行するパーミッションがありません。", "xpack.ml.privilege.noPermission.startOrStopDatafeedsTooltip": "データフィードを開始・停止するパーミッションがありません。", - "xpack.ml.privilege.noPermission.startOrStopDataFrameTransformTooltip": "データフレーム変換を開始・停止するパーミッションがありません。", "xpack.ml.privilege.pleaseContactAdministratorTooltip": "{message} 管理者にお問い合わせください。", "xpack.ml.routes.annotations.annotationsFeatureUnavailableErrorMessage": "注釈機能に必要なインデックスとエイリアスが作成されていないか、現在のユーザーがアクセスできません。", "xpack.ml.ruleEditor.actionsSection.chooseActionsDescription": "ルールが異常と一致した際のアクションを選択します。", @@ -7490,180 +7360,6 @@ "xpack.ml.validateJob.modal.linkToJobTipsText.mlJobTipsLinkText": "機械学習ジョブのヒント", "xpack.ml.validateJob.modal.validateJobTitle": "ジョブ {title} の検証", "xpack.ml.validateJob.validateJobButtonLabel": "ジョブを検証", - "xpack.ml.dataframe.analytics.create.advancedEditor.codeEditorAriaLabel": "高度な分析ジョブエディター", - "xpack.ml.dataframe.analytics.create.advancedEditor.configRequestBody": "構成リクエスト本文", - "xpack.ml.dataframe.analytics.create.advancedEditor.jobIdExistsError": "この ID の分析ジョブが既に存在します。", - "xpack.ml.dataframe.analytics.create.advancedEditor.jobIdInputAriaLabel": "固有の分析ジョブ ID を選択してください。", - "xpack.ml.dataframe.analytics.create.advancedEditor.jobIdInvalidError": "小文字のアルファベットと数字 (a-z と 0-9)、ハイフンまたはアンダーラインのみ使用でき、最初と最後を英数字にする必要があります。", - "xpack.ml.dataframe.analytics.create.advancedEditor.jobIdLabel": "分析ジョブ ID", - "xpack.ml.dataframe.analytics.create.advancedEditorMessage.destinationIndexNameEmpty": "デスティネーションインデックス名は未入力のままにできません。", - "xpack.ml.dataframe.analytics.create.advancedEditorMessage.destinationIndexNameValid": "無効なデスティネーションインデックス名。", - "xpack.ml.dataframe.analytics.create.advancedEditorMessage.sourceIndexNameEmpty": "ソースインデックス名は未入力のままにできません。", - "xpack.ml.dataframe.analytics.create.advancedEditorMessage.sourceIndexNameValid": "無効なソースインデックス名。", - "xpack.ml.dataframe.analytics.create.createIndexPatternErrorMessage": "Kibana インデックスパターンの作成中にエラーが発生しました:", - "xpack.ml.dataframe.analytics.create.createIndexPatternLabel": "インデックスパターンを作成", - "xpack.ml.dataframe.analytics.create.createIndexPatternSuccessMessage": "Kibana インデックスパターン {indexPatternName} が作成されました。", - "xpack.ml.dataframe.analytics.create.destinationIndexHelpText": "この名前のインデックスが既に存在します。この分析ジョブを実行すると、デスティネーションインデックスが変更されます。", - "xpack.ml.dataframe.analytics.create.destinationIndexInputAriaLabel": "一意の宛先インデックス名を選択してください。", - "xpack.ml.dataframe.analytics.create.destinationIndexInvalidError": "無効なデスティネーションインデックス名。", - "xpack.ml.dataframe.analytics.create.destinationIndexLabel": "送信先インデックス", - "xpack.ml.dataframe.analytics.create.duplicateIndexPatternErrorMessage": "Kibana インデックスパターンの作成中にエラーが発生しました:", - "xpack.ml.dataframe.analytics.create.duplicateIndexPatternErrorMessageError": "インデックスパターン {indexPatternName} が既に存在します。", - "xpack.ml.dataframe.analytics.create.errorCreatingDataFrameAnalyticsJob": "データフレーム分析ジョブの作成中にエラーが発生しました:", - "xpack.ml.dataframe.analytics.create.errorGettingDataFrameAnalyticsList": "既存のデータフレーム分析ジョブ ID の取得中にエラーが発生しました:", - "xpack.ml.dataframe.analytics.create.errorGettingDataFrameIndexNames": "既存のインデックス名の取得中にエラーが発生しました:", - "xpack.ml.dataframe.analytics.create.errorGettingIndexPatternTitles": "既存のインデックスパターンのタイトルの取得中にエラーが発生しました:", - "xpack.ml.dataframe.analytics.create.errorStartingDataFrameAnalyticsJob": "データフレーム分析ジョブの開始中にエラーが発生しました:", - "xpack.ml.dataframe.analytics.create.indexPatternTitleError": "このタイトルのインデックスパターンが既に存在します。", - "xpack.ml.dataframe.analytics.create.jobIdExistsError": "この ID の分析ジョブが既に存在します。", - "xpack.ml.dataframe.analytics.create.jobIdInputAriaLabel": "固有の分析ジョブ ID を選択してください。", - "xpack.ml.dataframe.analytics.create.jobIdInvalidError": "小文字のアルファベットと数字 (a-z と 0-9)、ハイフンまたはアンダーラインのみ使用でき、最初と最後を英数字にする必要があります。", - "xpack.ml.dataframe.analytics.create.jobIdLabel": "ジョブ ID", - "xpack.ml.dataframe.analytics.create.jobIdPlaceholder": "ジョブ ID", - "xpack.ml.dataframe.analytics.create.jobTypeHelpText": "外れ値検出ジョブには表のようなデータストラクチャでマッピングされたソースインデックスが必要で、数字とブールフィールドのみ分析されます。モデルメモリー制限や分析タイプなどのカスタムオプションを適用するには、{advancedEditorButton} を使用してください。高度なエディターからこのフォームには戻れません。", - "xpack.ml.dataframe.analytics.create.jobTypeLabel": "ジョブタイプ", - "xpack.ml.dataframe.analytics.create.modalCancelButton": "キャンセル", - "xpack.ml.dataframe.analytics.create.modalCloseButton": "閉じる", - "xpack.ml.dataframe.analytics.create.modalCreateButton": "作成", - "xpack.ml.dataframe.analytics.create.modalHeaderTitle": "分析ジョブの作成", - "xpack.ml.dataframe.analytics.create.modalStartButton": "開始", - "xpack.ml.dataframe.analytics.create.outlierDetectionText": "外れ値検出", - "xpack.ml.dataframe.analytics.create.sourceIndexHelpText": "このインデックスパターンには数字タイプのフィールドが含まれていません。分析ジョブで外れ値が検出されない可能性があります。", - "xpack.ml.dataframe.analytics.create.sourceIndexInputAriaLabel": "ソースインデックスパターンまたは検索。", - "xpack.ml.dataframe.analytics.create.sourceIndexInvalidError": "無効なソースインデックス名。スペースや {characterList} を含めることはできません", - "xpack.ml.dataframe.analytics.create.sourceIndexLabel": "ソースインデックス", - "xpack.ml.dataframe.analytics.create.sourceIndexPlaceholder": "ソースインデックスパターンまたは保存された検索を選択してください。", - "xpack.ml.dataframe.analytics.create.startDataFrameAnalyticsSuccessMessage": "分析ジョブ {jobId} が開始しました。", - "xpack.ml.dataframe.analytics.create.switchToAdvancedEditorButton": "高度なエディター", - "xpack.ml.dataframe.analytics.exploration.experimentalBadgeLabel": "実験的", - "xpack.ml.dataframe.analytics.exploration.experimentalBadgeTooltipContent": "データフレーム分析は実験段階の機能です。フィードバックをお待ちしています。", - "xpack.ml.dataframe.analytics.exploration.fieldSelection": "{docFieldsCount, number} 件中 {selectedFieldsLength, number} 件の {docFieldsCount, plural, one {ふフィールド} other {フィールド}}を選択済み", - "xpack.ml.dataframe.analytics.exploration.indexArrayBadgeContent": "配列", - "xpack.ml.dataframe.analytics.exploration.indexArrayToolTipContent": "この配列ベースの列の完全なコンテンツは表示できません。", - "xpack.ml.dataframe.analytics.exploration.indexError": "インデックスデータの読み込み中にエラーが発生しました。", - "xpack.ml.dataframe.analytics.exploration.indexObjectBadgeContent": "オブジェクト", - "xpack.ml.dataframe.analytics.exploration.indexObjectToolTipContent": "このオブジェクトベースの列の完全なコンテンツは表示できません。", - "xpack.ml.dataframe.analytics.exploration.jobIdTitle": "ジョブ ID {jobId}", - "xpack.ml.dataframe.analytics.exploration.noDataCalloutBody": "インデックスのクエリが結果を返しませんでした。インデックスにドキュメントが含まれていること、およびクエリ要件が妥当であることを確認してください。", - "xpack.ml.dataframe.analytics.exploration.noDataCalloutTitle": "空のインデックスクエリ結果", - "xpack.ml.dataframe.analytics.exploration.selectColumnsAriaLabel": "列を選択", - "xpack.ml.dataframe.analytics.exploration.selectFieldsPopoverTitle": "フィールドを選択", - "xpack.ml.dataframe.analytics.exploration.title": "分析の探索", - "xpack.ml.dataframe.analyticsList.completeBatchAnalyticsToolTip": "{analyticsId} は完了済みの分析ジョブで、再度開始できません。", - "xpack.ml.dataframe.analyticsList.createDataFrameAnalyticsButton": "分析ジョブを作成", - "xpack.ml.dataframe.analyticsList.deleteActionDisabledToolTipContent": "削除するにはデータフレーム分析を停止してください。", - "xpack.ml.dataframe.analyticsList.deleteActionName": "削除", - "xpack.ml.dataframe.analyticsList.deleteAnalyticsErrorMessage": "データフレーム分析 {analyticsId} の削除中にエラーが発生しました: {error}", - "xpack.ml.dataframe.analyticsList.deleteAnalyticsSuccessMessage": "データフレーム分析 {analyticsId} の削除リクエストが受け付けられました。", - "xpack.ml.dataframe.analyticsList.deleteModalBody": "この分析ジョブを削除してよろしいですか?この分析ジョブのデスティネーションインデックスとオプションの Kibana インデックスパターンは削除されません。", - "xpack.ml.dataframe.analyticsList.deleteModalCancelButton": "キャンセル", - "xpack.ml.dataframe.analyticsList.deleteModalDeleteButton": "削除", - "xpack.ml.dataframe.analyticsList.deleteModalTitle": "{analyticsId} を削除", - "xpack.ml.dataframe.analyticsList.destinationIndex": "送信先インデックス", - "xpack.ml.dataFrame.analyticsList.emptyPromptButtonText": "最初のデータフレーム分析ジョブを作成", - "xpack.ml.dataFrame.analyticsList.emptyPromptTitle": "データフレーム分析ジョブが見つかりませんでした", - "xpack.ml.dataFrame.analyticsList.errorPromptTitle": "データフレーム分析リストの取得中にエラーが発生しました。", - "xpack.ml.dataframe.analyticsList.expandedRow.tabs.jobSettings.progress": "進捗", - "xpack.ml.dataframe.analyticsList.expandedRow.tabs.jobSettings.state": "ステータス", - "xpack.ml.dataframe.analyticsList.expandedRow.tabs.jobSettings.stats": "統計", - "xpack.ml.dataframe.analyticsList.expandedRow.tabs.jobSettingsLabel": "ジョブの詳細", - "xpack.ml.dataframe.analyticsList.experimentalBadgeLabel": "実験的", - "xpack.ml.dataframe.analyticsList.experimentalBadgeTooltipContent": "データフレーム分析は実験段階の機能です。フィードバックをお待ちしています。", - "xpack.ml.dataframe.analyticsList.progress": "進捗", - "xpack.ml.dataframe.analyticsList.refreshButtonLabel": "更新", - "xpack.ml.dataframe.analyticsList.rowCollapse": "{analyticsId} の詳細を非表示", - "xpack.ml.dataframe.analyticsList.rowExpand": "{analyticsId} の詳細を表示", - "xpack.ml.dataframe.analyticsList.sourceIndex": "ソースインデックス", - "xpack.ml.dataframe.analyticsList.startActionName": "開始", - "xpack.ml.dataframe.analyticsList.startAnalyticsErrorMessage": "データフレーム分析 {analyticsId} の開始中にエラーが発生しました: {error}", - "xpack.ml.dataframe.analyticsList.startAnalyticsSuccessMessage": "データフレーム分析 {analyticsId} の開始リクエストが受け付けられました。", - "xpack.ml.dataframe.analyticsList.startModalBody": "データフレーム分析ジョブは、クラスターの検索とインデックスによる負荷を増やします。過剰な負荷が生じた場合は分析ジョブを停止してください。この分析ジョブを開始してよろしいですか?", - "xpack.ml.dataframe.analyticsList.startModalCancelButton": "キャンセル", - "xpack.ml.dataframe.analyticsList.startModalStartButton": "開始", - "xpack.ml.dataframe.analyticsList.startModalTitle": "{analyticsId} を開始", - "xpack.ml.dataframe.analyticsList.status": "ステータス", - "xpack.ml.dataframe.analyticsList.statusFilter": "ステータス", - "xpack.ml.dataframe.analyticsList.stopActionName": "停止", - "xpack.ml.dataframe.analyticsList.stopAnalyticsErrorMessage": "データフレーム分析 {analyticsId} の停止中にエラーが発生しました: {error}", - "xpack.ml.dataframe.analyticsList.stopAnalyticsSuccessMessage": "データフレーム分析 {analyticsId} の停止リクエストが受け付けられました。", - "xpack.ml.dataframe.analyticsList.tableActionLabel": "アクション", - "xpack.ml.dataframe.analyticsList.title": "分析ジョブ", - "xpack.ml.dataframe.analyticsList.type": "タイプ", - "xpack.ml.dataframe.analyticsList.viewActionName": "表示", - "xpack.ml.dataframe.analyticsList.viewAriaLabel": "表示", - "xpack.ml.dataFrame.list.errorPromptTitle": "データフレーム変換リストの取得中にエラーが発生しました。", - "xpack.ml.dataframe.modeFilter": "モード", - "xpack.ml.dataframe.multiTransformActionsMenu.managementActionsAriaLabel": "管理アクション", - "xpack.ml.dataframe.multiTransformActionsMenu.transformsCount": "{count} 件の{count, plural, one {変換} other {変換}}を選択済み", - "xpack.ml.dataframe.sourceIndexPreview.dataFrameSourceIndexArrayBadgeContent": "配列", - "xpack.ml.dataframe.sourceIndexPreview.dataFrameSourceIndexObjectBadgeContent": "オブジェクト", - "xpack.ml.dataframe.sourceIndexPreview.dataFrameSourceIndexObjectToolTipContent": "このオブジェクトベースの列の完全な内容は、展開された行に表示されます。", - "xpack.ml.dataFrame.statsBar.batchTransformsLabel": "バッチ", - "xpack.ml.dataFrame.statsBar.continuousTransformsLabel": "連続", - "xpack.ml.dataFrame.statsBar.failedTransformsLabel": "失敗", - "xpack.ml.dataFrame.statsBar.startedTransformsLabel": "開始済み", - "xpack.ml.dataFrame.statsBar.totalTransformsLabel": "変換合計", - "xpack.ml.dataframe.statusFilter": "ステータス", - "xpack.ml.dataframe.stepCreateForm.continuousModeLabel": "連続モード", - "xpack.ml.dataframe.stepCreateForm.createDataFrameAnalyticsSuccessMessage": "分析ジョブ {jobId} が作成されました。", - "xpack.ml.dataframe.stepCreateForm.duplicateIndexPatternErrorMessage": "Kibana インデックスパターン {indexPatternName} の作成中にエラーが発生しました:インデックスパターンが既に存在します。", - "xpack.ml.dataframe.stepDefineForm.advancedEditorApplyButtonText": "変更を適用", - "xpack.ml.dataframe.stepDefineForm.advancedEditorAriaLabel": "高度なピボットエディター", - "xpack.ml.dataframe.stepDefineForm.advancedEditorHelpText": "詳細エディターでは、ピボットを編集できます", - "xpack.ml.dataframe.stepDefineForm.advancedEditorHelpTextLink": "使用可能なオプションの詳細を確認してください。", - "xpack.ml.dataframe.stepDefineForm.advancedEditorLabel": "ピボット構成オブジェクト", - "xpack.ml.dataframe.stepDefineForm.advancedEditorSourceConfigSwitchLabel": "高度なクエリエディター", - "xpack.ml.dataframe.stepDefineForm.advancedEditorSwitchLabel": "高度なピボットエディター", - "xpack.ml.dataframe.stepDefineForm.advancedEditorSwitchModalBodyText": "詳細エディターの変更は適用されませんでした詳細エディターを無効にすると、編集内容が失われます。", - "xpack.ml.dataframe.stepDefineForm.advancedEditorSwitchModalCancelButtonText": "キャンセル", - "xpack.ml.dataframe.stepDefineForm.advancedEditorSwitchModalConfirmButtonText": "詳細エディターを無効にする", - "xpack.ml.dataframe.stepDefineForm.advancedEditorSwitchModalTitle": "適用されていない変更", - "xpack.ml.dataframe.stepDefineForm.advancedSourceEditorApplyButtonText": "変更を適用", - "xpack.ml.dataframe.stepDefineForm.advancedSourceEditorAriaLabel": "高度なクエリエディター", - "xpack.ml.dataframe.stepDefineForm.advancedSourceEditorHelpText": "高度なエディターでは、データフレーム変換のソースクエリ句を編集できます。", - "xpack.ml.dataframe.stepDefineForm.advancedSourceEditorLabel": "ソースクエリ句", - "xpack.ml.dataframe.stepDefineForm.advancedSourceEditorSwitchModalBodyText": "KQL クエリバーに戻すと、編集内容が失われます。", - "xpack.ml.dataframe.stepDefineForm.advancedSourceEditorSwitchModalConfirmButtonText": "KQL に切り替える", - "xpack.ml.dataframe.stepDefineForm.advancedSourceEditorSwitchModalTitle": "編集内容は失われます", - "xpack.ml.dataframe.stepDefineForm.queryPlaceholder": "例: {example}.", - "xpack.ml.dataframe.stepDefineSummary.queryCodeBlockLabel": "クエリ", - "xpack.ml.dataframe.stepDefineSummary.savedSearchLabel": "保存された検索", - "xpack.ml.dataframe.stepDetailsForm.continuousModeAriaLabel": "遅延を選択してください。", - "xpack.ml.dataframe.stepDetailsForm.continuousModeDateFieldHelpText": "新しいドキュメントを特定するために使用できる日付フィールドを選択してください。", - "xpack.ml.dataframe.stepDetailsForm.continuousModeDateFieldLabel": "日付フィールド", - "xpack.ml.dataframe.stepDetailsForm.continuousModeDelayError": "無効な遅延フォーマット。", - "xpack.ml.dataframe.stepDetailsForm.continuousModeDelayHelpText": "現在の時刻と最新のインプットデータ時刻の間の遅延です。", - "xpack.ml.dataframe.stepDetailsForm.continuousModeDelayLabel": "遅延", - "xpack.ml.dataframe.stepDetailsForm.continuousModeError": "日付フィールドがないインデックスでは、連続モードを使用できません。", - "xpack.ml.dataframe.stepDetailsForm.destinationIndexHelpText": "この名前のインデックスが既に存在します。この変換を実行すると、デスティネーションインデックスが変更されます。", - "xpack.ml.dataframe.stepDetailsForm.destinationIndexInputAriaLabel": "一意の宛先インデックス名を選択してください。", - "xpack.ml.dataframe.stepDetailsForm.destinationIndexInvalidError": "無効なデスティネーションインデックス名。", - "xpack.ml.dataframe.stepDetailsForm.destinationIndexInvalidErrorLink": "インデックス名の制限に関する詳細。", - "xpack.ml.dataframe.stepDetailsForm.destinationIndexLabel": "送信先インデックス", - "xpack.ml.dataframe.stepDetailsForm.transformDescriptionHelpText": "オプションの説明テキストです。", - "xpack.ml.dataframe.stepDetailsForm.transformDescriptionInputAriaLabel": "任意の変換説明を選択してください。", - "xpack.ml.dataframe.stepDetailsForm.transformDescriptionLabel": "変換説明", - "xpack.ml.dataframe.stepDetailsForm.transformIdExistsError": "この ID の変換が既に存在します。", - "xpack.ml.dataframe.stepDetailsForm.transformIdInvalidError": "小文字のアルファベットと数字 (a-z と 0-9)、ハイフンまたはアンダーラインのみ使用でき、最初と最後を英数字にする必要があります。", - "xpack.ml.dataframe.stepDetailsSummary.continuousModeDateFieldLabel": "連続モード日付フィールド", - "xpack.ml.dataframe.stepDetailsSummary.destinationIndexLabel": "送信先インデックス", - "xpack.ml.dataframe.stepDetailsSummary.transformDescriptionLabel": "変換説明", - "xpack.ml.dataframe.transformList.bulkDeleteModalBody": "{count, plural, one {この} other {これらの}} {count} 件の{count, plural, one {変換} other {変換}}を削除してよろしいですか?変換の送信先インデックスとオプションの Kibana インデックスパターンは削除されません。", - "xpack.ml.dataframe.transformList.bulkDeleteModalTitle": "{count} 件の{count, plural, one {変換} other {変換}}を削除", - "xpack.ml.dataframe.transformList.bulkStartModalTitle": "{count} 件の{count, plural, one {変換} other {変換}}を開始", - "xpack.ml.dataframe.transformList.completeBatchTransformBulkActionToolTip": "選択されたデータフレーム変換のうちの 1 つまたは複数が完了済みのデータ変換で、再度開始することはできません。", - "xpack.ml.dataframe.transformList.deleteBulkActionDisabledToolTipContent": "削除するには、選択されたデータフレーム変換のうちの 1 つまたは複数を停止する必要があります。", - "xpack.ml.dataframe.transformList.deleteTransformErrorMessage": "データフレーム変換 {transformId} の削除中にエラーが発生しました", - "xpack.ml.dataframe.transformList.refreshButtonLabel": "更新", - "xpack.ml.dataframe.transformList.startedTransformBulkToolTip": "選択されたデータフレーム変換のうち 1 つまたは複数が既に開始済みです。", - "xpack.ml.dataframe.transformList.startedTransformToolTip": "{transformId} は既に開始済みです。", - "xpack.ml.dataframe.transformList.startModalBody": "データフレーム変換は、クラスターの検索とインデックスによる負荷を増やします。過剰な負荷が生じた場合は変換を停止してください。{count, plural, one {この} other {これら}} {count} 件の{count, plural, one {変換} other {変換}}を開始してよろしいですか?", - "xpack.ml.dataframe.transformList.startTransformErrorMessage": "データフレーム変換 {transformId} の開始中にエラーが発生しました", - "xpack.ml.dataframe.transformList.stoppedTransformBulkToolTip": "選択されたデータフレーム変換のうち 1 つまたは複数が既に停止済みです。", - "xpack.ml.dataframe.transformList.stoppedTransformToolTip": "{transformId} は既に停止済みです。", - "xpack.ml.dataframe.transformList.stopTransformErrorMessage": "データフレーム変換 {transformId} の停止中にエラーが発生しました", - "xpack.ml.dataframe.transformList.transformDetails.tabs.transformMessagesLabel": "メッセージ", - "xpack.ml.dataframe.transformList.transformDetails.tabs.transformPreviewLabel": "プレビュー", "xpack.ml.dataFrameAnalyticsBreadcrumbs.dataFrameLabel": "分析", "xpack.ml.datavisualizer.actionsPanel.advancedDescription": "より高度なユースケースでは、ジョブの作成にすべてのオプションを使用します", "xpack.ml.datavisualizer.actionsPanel.advancedTitle": "高度な設定", @@ -7692,11 +7388,6 @@ "xpack.ml.dfAnalyticsList.analyticsDetails.messagesPane.messageLabel": "メッセージ", "xpack.ml.dfAnalyticsList.analyticsDetails.messagesPane.nodeLabel": "ノード", "xpack.ml.dfAnalyticsList.analyticsDetails.messagesPane.timeLabel": "時間", - "xpack.ml.dfTransformList.stepDetails.previewPane.errorMessage": "プレビューを読み込めませんでした", - "xpack.ml.dfTransformList.transformDetails.messagesPane.errorMessage": "メッセージを読み込めませんでした", - "xpack.ml.dfTransformList.transformDetails.messagesPane.messageLabel": "メッセージ", - "xpack.ml.dfTransformList.transformDetails.messagesPane.nodeLabel": "ノード", - "xpack.ml.dfTransformList.transformDetails.messagesPane.timeLabel": "時間", "xpack.ml.fieldDataCard.cardBoolean.documentsCountDescription": "{count, plural, zero {# document} one {# document} other {# documents}} ({docsPercent}%)", "xpack.ml.fieldDataCard.cardDate.documentsCountDescription": "{count, plural, zero {# document} one {# document} other {# documents}} ({docsPercent}%)", "xpack.ml.fieldDataCard.cardDate.earliestDescription": "最も古い {earliestFormatted}", @@ -7739,8 +7430,6 @@ "xpack.ml.management.jobsListTitle": "ジョブリスト", "xpack.ml.management.mlTitle": "Machine Learning", "xpack.ml.messagebarService.errorTitle": "エラーが発生しました", - "xpack.ml.models.transformService.allOtherRequestsCancelledDescription": "他のすべてのリクエストはキャンセルされました。", - "xpack.ml.models.transformService.requestToActionTimedOutErrorMessage": "「{id}」を{action}するリクエストがタイムアウトしました。{extra}", "xpack.ml.navMenu.dataFrameAnalyticsTabLinkText": "分析", "xpack.ml.newJob.wizard.jobDetailsStep.additionalSection.calendarsSelection.description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.Ut enim ad minim veniam.", "xpack.ml.newJob.wizard.jobDetailsStep.additionalSection.calendarsSelection.title": "カレンダー", @@ -7831,6 +7520,116 @@ "xpack.ml.newJob.wizard.validateJob.jobNameAlreadyExists": "ジョブ ID が既に存在しますジョブ ID は既存のジョブやグループと同じにできません。", "xpack.ml.newJob.wizard.validateJob.modelMemoryLimitRangeInvalidErrorMessage": "モデルメモリー制限は最高値の {maxModelMemoryLimit} よりも高くできません", "xpack.ml.newJob.wizard.validateJob.modelMemoryLimitUnitsInvalidErrorMessage": "モデルメモリー制限のデータユニットが認識されません。{str} でなければなりません", + "xpack.transform.capability.noPermission.createTransformTooltip": "データフレーム変換を作成するパーミッションがありません。", + "xpack.transform.capability.noPermission.deleteTransformTooltip": "データフレーム変換を削除するパーミッションがありません。", + "xpack.transform.capability.noPermission.startOrStopTransformTooltip": "データフレーム変換を開始・停止するパーミッションがありません。", + "xpack.transform.models.transformService.allOtherRequestsCancelledDescription": "他のすべてのリクエストはキャンセルされました。", + "xpack.transform.models.transformService.requestToActionTimedOutErrorMessage": "「{id}」を{action}するリクエストがタイムアウトしました。{extra}", + "xpack.transform.transformList.stepDetails.previewPane.errorMessage": "プレビューを読み込めませんでした", + "xpack.transform.transformList.transformDetails.messagesPane.errorMessage": "メッセージを読み込めませんでした", + "xpack.transform.transformList.transformDetails.messagesPane.messageLabel": "メッセージ", + "xpack.transform.transformList.transformDetails.messagesPane.nodeLabel": "ノード", + "xpack.transform.transformList.transformDetails.messagesPane.timeLabel": "時間", + "xpack.transform.agg.popoverForm.aggLabel": "集約", + "xpack.transform.agg.popoverForm.aggNameAlreadyUsedError": "別の集約で既に同じ名前が使用されています。", + "xpack.transform.agg.popoverForm.aggNameInvalidCharError": "無効な名前です。「[」、「]」「>」は使用できず、名前の始めと終わりにはスペースを使用できません。", + "xpack.transform.agg.popoverForm.fieldLabel": "フィールド", + "xpack.transform.agg.popoverForm.nameLabel": "集約名", + "xpack.transform.agg.popoverForm.submitButtonLabel": "適用", + "xpack.transform.aggLabelForm.deleteItemAriaLabel": "アイテムを削除", + "xpack.transform.aggLabelForm.editAggAriaLabel": "集約を編集", + "xpack.transform.stepDefineForm.aggExistsErrorMessage": "「{aggName}」という名前のアグリゲーション構成は既に存在します。", + "xpack.transform.stepDefineForm.groupByExistsErrorMessage": "「{aggName}」という名前のgroup by構成は既に存在します。", + "xpack.transform.stepDefineForm.nestedAggListConflictErrorMessage": "「{aggListName}」とネスティングの矛盾があるため、構成「{aggName}」を追加できませんでした。", + "xpack.transform.stepDefineForm.nestedConflictErrorMessage": "「{aggNameCheck}」とネスティングの矛盾があるため、構成「{aggName}」を追加できませんでした。", + "xpack.transform.stepDefineForm.nestedGroupByListConflictErrorMessage": "「{groupByListName}」とネスティングの矛盾があるため、構成「{aggName}」を追加できませんでした。", + "xpack.transform.stepDefineForm.aggregationsLabel": "アグリゲーション(集計)", + "xpack.transform.stepDefineForm.aggregationsPlaceholder": "集約を追加…", + "xpack.transform.stepDefineForm.formHelp": "データフレーム変換は、ピボット用のスケーラブルで自動化されたプロセスです。開始するにはグループ分けの条件と集約を少なくとも 1 つ選んでください。", + "xpack.transform.stepDefineForm.groupByLabel": "グループ分けの条件", + "xpack.transform.stepDefineForm.groupByPlaceholder": "グループ分けの条件フィールドを追加…", + "xpack.transform.stepDefineForm.indexPatternHelpText": "このインデックスパターンのオプションのクエリはサポートされていません。サポートされているインデックスフィールドの数は {maxIndexFields} で、このインデックスには {numIndexFields} 個のフィールドがあります。", + "xpack.transform.stepDefineForm.indexPatternLabel": "インデックスパターン", + "xpack.transform.stepDefineForm.queryHelpText": "クエリ文字列でソースデータをフィルタリングしてください (オプション)。", + "xpack.transform.stepDefineForm.queryLabel": "クエリ", + "xpack.transform.stepDefineForm.savedSearchLabel": "保存された検索", + "xpack.transform.stepDefineSummary.aggregationsLabel": "アグリゲーション(集計)", + "xpack.transform.stepDefineSummary.groupByLabel": "グループ分けの条件", + "xpack.transform.stepDefineSummary.indexPatternLabel": "インデックスパターン", + "xpack.transform.stepDefineSummary.queryLabel": "クエリ", + "xpack.transform.groupby.popoverForm.aggLabel": "集約", + "xpack.transform.groupBy.popoverForm.aggNameAlreadyUsedError": "別のグループ分けの構成が既にこの名前を使用しています。", + "xpack.transform.groupBy.popoverForm.aggNameInvalidCharError": "無効な名前です。「[」、「]」「>」は使用できず、名前の始めと終わりにはスペースを使用できません。", + "xpack.transform.groupBy.popoverForm.fieldLabel": "フィールド", + "xpack.transform.groupBy.popoverForm.intervalError": "無効な間隔。", + "xpack.transform.groupBy.popoverForm.intervalLabel": "間隔", + "xpack.transform.groupBy.popoverForm.nameLabel": "グループ分け名", + "xpack.transform.groupBy.popoverForm.submitButtonLabel": "適用", + "xpack.transform.groupByLabelForm.deleteItemAriaLabel": "アイテムを削除", + "xpack.transform.groupByLabelForm.editIntervalAriaLabel": "間隔を編集", + "xpack.transform.stepCreateForm.copyTransformConfigToClipboardButton": "クリップボードにコピー", + "xpack.transform.stepCreateForm.copyTransformConfigToClipboardDescription": "ジョブを作成する Kibana 開発コンソールのコマンドをクリップボードにコピーします。", + "xpack.transform.stepCreateForm.createIndexPatternErrorMessage": "Kibana インデックスパターン {indexPatternName} の作成中にエラーが発生しました: {error}", + "xpack.transform.stepCreateForm.createIndexPatternLabel": "インデックスパターンを作成", + "xpack.transform.stepCreateForm.createTransformErrorMessage": "データフレームジョブ {transformId} の作成中にエラーが発生しました: {error}", + "xpack.transform.stepCreateForm.createTransformSuccessMessage": "データフレームジョブ {transformId} が作成されました", + "xpack.transform.stepCreateForm.creatingIndexPatternMessage": "Kibana インデックスパターンを作成中…", + "xpack.transform.stepCreateForm.discoverCardDescription": "ディスカバリでデータフレームピボットを閲覧します。", + "xpack.transform.stepCreateForm.discoverCardTitle": "ディスカバー", + "xpack.transform.stepCreateForm.transformListCardDescription": "データフレームジョブの管理ページに戻ります。", + "xpack.transform.stepCreateForm.transformListCardTitle": "データフレームジョブ", + "xpack.transform.stepCreateForm.progressErrorMessage": "進捗パーセンテージの取得中にエラーが発生しました: {error}", + "xpack.transform.stepCreateForm.progressTitle": "進捗", + "xpack.transform.stepCreateForm.createIndexPatternSuccessMessage": "Kibana インデックスパターン {indexPatternName} が作成されました", + "xpack.transform.stepCreateForm.startTransformErrorMessage": "データフレームジョブ {transformId} の開始中にエラーが発生しました: {error}", + "xpack.transform.stepCreateForm.startTransformSuccessMessage": "データフレームジョブ {transformId} が開始しました", + "xpack.transform.stepDetailsForm.errorGettingIndexPatternTitles": "既存のインデックスパターンのタイトルの取得中にエラーが発生しました: {error}", + "xpack.transform.stepDetailsForm.indexPatternTitleError": "このタイトルのインデックスパターンが既に存在します。", + "xpack.transform.stepDetailsForm.transformIdInputAriaLabel": "固有のジョブ ID を選択してください。", + "xpack.transform.stepDetailsForm.transformIdLabel": "ジョブ ID", + "xpack.transform.stepDetailsSummary.createIndexPatternMessage": "このジョブの Kibana インデックスパターンが作成されます。", + "xpack.transform.stepDetailsSummary.transformIdLabel": "ジョブ ID", + "xpack.transform.transformList.betaBadgeLabel": "ベータ", + "xpack.transform.transformList.betaBadgeTooltipContent": "データフレームはベータ機能です。フィードバックをお待ちしています。", + "xpack.transform.transformList.completeBatchTransformToolTip": "{transformId} は完了済みのバッチジョブで、再度開始できません。", + "xpack.transform.transformList.deleteActionDisabledToolTipContent": "削除するにはデータフレームジョブを停止してください。", + "xpack.transform.transformList.deleteActionName": "削除", + "xpack.transform.transformList.deleteTransformSuccessMessage": "データフレームジョブ {transformId} が削除されました", + "xpack.transform.transformList.deleteModalBody": "このジョブを削除してよろしいですか?ジョブの最大インデックスとオプションの Kibana インデックスパターンは削除されません。", + "xpack.transform.transformList.deleteModalCancelButton": "キャンセル", + "xpack.transform.transformList.deleteModalDeleteButton": "削除", + "xpack.transform.transformList.deleteModalTitle": "{transformId} を削除", + "xpack.transform.transformList.transformDetails.tabs.transformSettingsLabel": "ジョブの詳細", + "xpack.transform.transformList.rowCollapse": "{transformId} の詳細を非表示", + "xpack.transform.transformList.rowExpand": "{transformId} の詳細を表示", + "xpack.transform.transformList.startActionName": "開始", + "xpack.transform.transformList.startTransformSuccessMessage": "データフレームジョブ {transformId} が開始しました", + "xpack.transform.transformList.startModalCancelButton": "キャンセル", + "xpack.transform.transformList.startModalStartButton": "開始", + "xpack.transform.transformList.startModalTitle": "{transformId} を開始", + "xpack.transform.transformList.stopActionName": "停止", + "xpack.transform.transformList.stopTransformSuccessMessage": "データフレームジョブ {transformId} が停止しました", + "xpack.transform.pivotPreview.copyClipboardTooltip": "ピボットプレビューの開発コンソールステートメントをクリップボードにコピーします。", + "xpack.transform.pivotPreview.statusCodeLabel": "ステータスコード", + "xpack.transform.progress": "進捗", + "xpack.transform.sourceIndex": "ソースインデックス", + "xpack.transform.sourceIndexPreview.copyClipboardTooltip": "ソースインデックスプレビューの開発コンソールステートメントをクリップボードにコピーします。", + "xpack.transform.sourceIndexPreview.fieldSelection": "{docFieldsCount, number} 件中 showing {selectedFieldsLength, number} 件の{docFieldsCount, plural, one {フィールド} other {フィールド}}", + "xpack.transform.sourceIndexPreview.rowCollapse": "縮小", + "xpack.transform.sourceIndexPreview.rowExpand": "拡張", + "xpack.transform.sourceIndexPreview.selectColumnsAriaLabel": "列を選択", + "xpack.transform.sourceIndexPreview.selectFieldsPopoverTitle": "フィールドを選択", + "xpack.transform.sourceIndexPreview.sourceIndexPatternError": "ソースインデックスデータの読み込み中にエラーが発生しました。", + "xpack.transform.sourceIndexPreview.sourceIndexPatternTitle": "ソースインデックス {indexPatternTitle}", + "xpack.transform.status": "ステータス", + "xpack.transform.tableActionLabel": "アクション", + "xpack.transform.transformsWizard.betaBadgeLabel": "ベータ", + "xpack.transform.transformsWizard.betaBadgeTooltipContent": "データフレームはベータ機能です。フィードバックをお待ちしています。", + "xpack.transform.transformsWizard.stepCreateTitle": "作成", + "xpack.transform.transformsWizard.stepDefineTitle": "ピボットの定義", + "xpack.transform.transformsWizard.stepDetailsTitle": "ジョブの詳細", + "xpack.transform.wizard.nextStepButton": "次へ", + "xpack.transform.wizard.previousStepButton": "前へ", "xpack.monitoring.accessDenied.backToKibanaButtonLabel": "Kibana に戻る", "xpack.monitoring.accessDenied.clusterNotConfiguredDescription": "専用の監視クラスターへのアクセスを試みている場合、監視クラスターで構成されていないユーザーとしてログインしていることが原因である可能性があります。", "xpack.monitoring.accessDenied.notAuthorizedDescription": "監視アクセスが許可されていません。監視を利用するには、「{kibanaUser}」と「{monitoringUser}」の両方のロールからの権限が必要です。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 6e450431cc28e..f245547a97535 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -6047,131 +6047,6 @@ "xpack.ml.customUrlsEditor.timeRangeLabel": "时间范围", "xpack.ml.customUrlsEditor.urlLabel": "URL", "xpack.ml.customUrlsList.invalidIntervalFormatErrorMessage": "时间间隔格式无效", - "xpack.ml.dataframe.accessDenied.backToKibanaHomeButtonLabel": "返回 Kibana 主页", - "xpack.ml.dataframe.accessDenied.retryButtonLabel": "重试", - "xpack.ml.dataframe.accessDeniedTitle": "访问被拒绝", - "xpack.ml.dataframe.agg.popoverForm.aggLabel": "聚合", - "xpack.ml.dataframe.agg.popoverForm.aggNameAlreadyUsedError": "其他聚合已使用该名称。", - "xpack.ml.dataframe.agg.popoverForm.aggNameInvalidCharError": "名称无效。不允许使用字符“[”、“]” 和“>”且名称不得以空格字符开头或结束。", - "xpack.ml.dataframe.agg.popoverForm.fieldLabel": "字段", - "xpack.ml.dataframe.agg.popoverForm.nameLabel": "聚合名称", - "xpack.ml.dataframe.agg.popoverForm.submitButtonLabel": "应用", - "xpack.ml.dataframe.aggLabelForm.deleteItemAriaLabel": "删除项", - "xpack.ml.dataframe.aggLabelForm.editAggAriaLabel": "编辑聚合", - "xpack.ml.dataframe.stepDefineForm.aggExistsErrorMessage": "名称为“{aggName}”的聚合配置已存在。", - "xpack.ml.dataframe.stepDefineForm.groupByExistsErrorMessage": "名称为“{aggName}”的分组依据配置已存在。", - "xpack.ml.dataframe.stepDefineForm.nestedAggListConflictErrorMessage": "无法添加配置“{aggName}”,因为与“{aggListName}”有嵌套冲突。", - "xpack.ml.dataframe.stepDefineForm.nestedConflictErrorMessage": "无法添加配置“{aggName}”,因为与“{aggNameCheck}”有嵌套冲突。", - "xpack.ml.dataframe.stepDefineForm.nestedGroupByListConflictErrorMessage": "无法添加配置“{aggName}”,因为与“{groupByListName}”有嵌套冲突。", - "xpack.ml.dataframe.stepDefineForm.aggregationsLabel": "聚合", - "xpack.ml.dataframe.stepDefineForm.aggregationsPlaceholder": "添加聚合……", - "xpack.ml.dataframe.stepDefineForm.formHelp": "数据帧转换是用于数据透视的可伸缩和自动化流程。至少选择一个分组依据和聚合,才能开始。", - "xpack.ml.dataframe.stepDefineForm.groupByLabel": "分组依据", - "xpack.ml.dataframe.stepDefineForm.groupByPlaceholder": "添加分组依据字段……", - "xpack.ml.dataframe.stepDefineForm.indexPatternHelpText": "不支持此索引模式的可选查询。受支持索引字段数目为 {maxIndexFields},而此索引有 {numIndexFields} 个字段。", - "xpack.ml.dataframe.stepDefineForm.indexPatternLabel": "索引模式", - "xpack.ml.dataframe.stepDefineForm.queryHelpText": "使用查询筛选源数据(可选)。", - "xpack.ml.dataframe.stepDefineForm.queryLabel": "查询", - "xpack.ml.dataframe.stepDefineForm.savedSearchLabel": "已保存搜索", - "xpack.ml.dataframe.stepDefineSummary.aggregationsLabel": "聚合", - "xpack.ml.dataframe.stepDefineSummary.groupByLabel": "分组依据", - "xpack.ml.dataframe.stepDefineSummary.indexPatternLabel": "索引模式", - "xpack.ml.dataframe.stepDefineSummary.queryLabel": "查询", - "xpack.ml.dataframe.groupby.popoverForm.aggLabel": "聚合", - "xpack.ml.dataframe.groupBy.popoverForm.aggNameAlreadyUsedError": "其他分组依据配置已使用该名称。", - "xpack.ml.dataframe.groupBy.popoverForm.aggNameInvalidCharError": "名称无效。不允许使用字符“[”、“]” 和“>”且名称不得以空格字符开头或结束。", - "xpack.ml.dataframe.groupBy.popoverForm.fieldLabel": "字段", - "xpack.ml.dataframe.groupBy.popoverForm.intervalError": "时间间隔无效。", - "xpack.ml.dataframe.groupBy.popoverForm.intervalLabel": "时间间隔", - "xpack.ml.dataframe.groupBy.popoverForm.nameLabel": "分组依据名称", - "xpack.ml.dataframe.groupBy.popoverForm.submitButtonLabel": "应用", - "xpack.ml.dataframe.groupByLabelForm.deleteItemAriaLabel": "删除项", - "xpack.ml.dataframe.groupByLabelForm.editIntervalAriaLabel": "编辑时间间隔", - "xpack.ml.dataframe.stepCreateForm.copyTransformConfigToClipboardButton": "复制到剪贴板", - "xpack.ml.dataframe.stepCreateForm.copyTransformConfigToClipboardDescription": "将用于创建转换的 Kibana 开发控制台命令复制到剪贴板。", - "xpack.ml.dataframe.stepCreateForm.createAndStartDataFrameButton": "创建并启动", - "xpack.ml.dataframe.stepCreateForm.createAndStartDataFrameDescription": "创建并启动数据帧转换。数据帧转换将增加集群的搜索和索引负荷。如果负荷超载,请停止转换。转换启动后,系统将为您提供继续浏览数据帧转换的选项。", - "xpack.ml.dataframe.stepCreateForm.createDataFrameButton": "创建", - "xpack.ml.dataframe.stepCreateForm.createDataFrameDescription": "创建但不启动数据帧转换。您之后能够通过返回到数据帧转换列表,来启动转换。", - "xpack.ml.dataframe.stepCreateForm.createIndexPatternErrorMessage": "创建 Kibana 索引模式 {indexPatternName} 时发生错误:{error}", - "xpack.ml.dataframe.stepCreateForm.createIndexPatternLabel": "创建索引模式", - "xpack.ml.dataframe.stepCreateForm.createTransformErrorMessage": "创建数据帧转换 {transformId} 时发生错误:{error}", - "xpack.ml.dataframe.stepCreateForm.createTransformSuccessMessage": "数据帧转换 {transformId} 创建成功。", - "xpack.ml.dataframe.stepCreateForm.creatingIndexPatternMessage": "正在创建 Kibana 索引模式......", - "xpack.ml.dataframe.stepCreateForm.discoverCardDescription": "使用 Discover 浏览数据帧透视表。", - "xpack.ml.dataframe.stepCreateForm.discoverCardTitle": "Discover", - "xpack.ml.dataframe.stepCreateForm.transformListCardDescription": "返回数据帧转换管理页面。", - "xpack.ml.dataframe.stepCreateForm.transformListCardTitle": "数据帧转换", - "xpack.ml.dataframe.stepCreateForm.progressErrorMessage": "获取进度百分比时出错:{error}", - "xpack.ml.dataframe.stepCreateForm.progressTitle": "进度", - "xpack.ml.dataframe.stepCreateForm.createIndexPatternSuccessMessage": "Kibana 索引模式 {indexPatternName} 成功创建。", - "xpack.ml.dataframe.stepCreateForm.startDataFrameButton": "开始", - "xpack.ml.dataframe.stepCreateForm.startDataFrameDescription": "启动数据帧转换。数据帧转换将增加集群的搜索和索引负荷。如果负荷超载,请停止转换。转换启动后,系统将为您提供继续浏览数据帧转换的选项。", - "xpack.ml.dataframe.stepCreateForm.startTransformErrorMessage": "启动数据帧转换 {transformId} 时发生错误:{error}", - "xpack.ml.dataframe.stepCreateForm.startTransformSuccessMessage": "数据帧转换 {transformId} 启动成功。", - "xpack.ml.dataframe.stepDetailsForm.errorGettingDataFrameIndexNames": "获取现有索引名称时发生错误:{error}", - "xpack.ml.dataframe.stepDetailsForm.errorGettingDataFrameTransformList": "获取现有数据帧转换 ID 时发生错误:{error}", - "xpack.ml.dataframe.stepDetailsForm.errorGettingIndexPatternTitles": "获取现有索引名称时发生错误:{error}", - "xpack.ml.dataframe.stepDetailsForm.indexPatternTitleError": "具有此名称的索引模式已存在。", - "xpack.ml.dataframe.stepDetailsForm.transformIdInputAriaLabel": "选择唯一的转换 ID。", - "xpack.ml.dataframe.stepDetailsForm.transformIdLabel": "转换 ID", - "xpack.ml.dataframe.stepDetailsSummary.createIndexPatternMessage": "将为此转换创建 Kibana 索引模式。", - "xpack.ml.dataframe.stepDetailsSummary.transformIdLabel": "转换 ID", - "xpack.ml.dataframe.transformList.betaBadgeLabel": "公测版", - "xpack.ml.dataframe.transformList.betaBadgeTooltipContent": "数据帧是公测版功能。我们很乐意听取您的反馈意见。", - "xpack.ml.dataframe.transformList.completeBatchTransformToolTip": "{transformId} 为已完成的批量转换,无法重新启动。", - "xpack.ml.dataframe.transformList.createDataFrameButton": "创建转换", - "xpack.ml.dataframe.transformList.dataFrameTitle": "数据帧转换", - "xpack.ml.dataframe.transformList.deleteActionDisabledToolTipContent": "停止数据帧转换,以便将其删除。", - "xpack.ml.dataframe.transformList.deleteActionName": "删除", - "xpack.ml.dataframe.transformList.deleteTransformSuccessMessage": "数据帧转换 {transformId} 删除成功。", - "xpack.ml.dataframe.transformList.deleteModalBody": "是否确定要删除此转换?转换的目标索引和可选 Kibana 索引模式将不会删除。", - "xpack.ml.dataframe.transformList.deleteModalCancelButton": "取消", - "xpack.ml.dataframe.transformList.deleteModalDeleteButton": "删除", - "xpack.ml.dataframe.transformList.deleteModalTitle": "删除 {transformId}", - "xpack.ml.dataframe.transformList.transformDetails.tabs.transformSettingsLabel": "转换详情", - "xpack.ml.dataframe.transformList.rowCollapse": "隐藏 {transformId} 的详情", - "xpack.ml.dataframe.transformList.rowExpand": "显示 {transformId} 的详情", - "xpack.ml.dataframe.transformList.startActionName": "启动", - "xpack.ml.dataframe.transformList.startTransformSuccessMessage": "数据帧转换 {transformId} 启动成功。", - "xpack.ml.dataframe.transformList.startModalCancelButton": "取消", - "xpack.ml.dataframe.transformList.startModalStartButton": "启动", - "xpack.ml.dataframe.transformList.startModalTitle": "启动 {transformId}", - "xpack.ml.dataframe.transformList.stopActionName": "停止", - "xpack.ml.dataframe.transformList.stopTransformSuccessMessage": "数据帧转换 {transformId} 停止成功。", - "xpack.ml.dataframe.noGrantedPrivilegesDescription": "您必须具有 {kibanaUserParam} 和 {dataFrameUserParam} 角色授予的权限。{br}您的系统管理员可以在“管理用户”页面上设置这些角色。", - "xpack.ml.dataframe.noPermissionToAccessMLLabel": "您需要访问数据帧的权限", - "xpack.ml.dataframe.pivotPreview.copyClipboardTooltip": "将透视预览的开发控制台语句复制到剪贴板。", - "xpack.ml.dataframe.pivotPreview.dataFramePivotPreviewError": "加载透视预览时出错。", - "xpack.ml.dataframe.pivotPreview.dataFramePivotPreviewIncompleteConfigCalloutBody": "请至少选择一个分组依据字段和聚合。", - "xpack.ml.dataframe.pivotPreview.dataFramePivotPreviewNoDataCalloutBody": "预览请求未返回任何数据。请确保可选查询返回数据且存在分组依据和聚合字段使用的字段的值。", - "xpack.ml.dataframe.pivotPreview.dataFramePivotPreviewNoDataCalloutTitle": "透视预览不可用", - "xpack.ml.dataframe.pivotPreview.dataFramePivotPreviewTitle": "数据帧透视预览", - "xpack.ml.dataframe.pivotPreview.statusCodeLabel": "状态代码", - "xpack.ml.dataframe.progress": "进度", - "xpack.ml.dataframe.sourceIndex": "源索引", - "xpack.ml.dataframe.sourceIndexPreview.copyClipboardTooltip": "将源索引预览的开发控制台语句复制到剪贴板。", - "xpack.ml.dataframe.sourceIndexPreview.dataFrameSourceIndexNoDataCalloutBody": "源索引的查询未返回结果。请确保索引包含文档且您的查询限制不过于严格。", - "xpack.ml.dataframe.sourceIndexPreview.dataFrameSourceIndexNoDataCalloutTitle": "源索引查询结果为空。", - "xpack.ml.dataframe.sourceIndexPreview.fieldSelection": "已选择 {selectedFieldsLength, number} 个{docFieldsCount, plural, one {字段} other {字段}},共 {docFieldsCount, number} 个", - "xpack.ml.dataframe.sourceIndexPreview.rowCollapse": "折叠", - "xpack.ml.dataframe.sourceIndexPreview.rowExpand": "展开", - "xpack.ml.dataframe.sourceIndexPreview.selectColumnsAriaLabel": "选择列", - "xpack.ml.dataframe.sourceIndexPreview.selectFieldsPopoverTitle": "选择字段", - "xpack.ml.dataframe.sourceIndexPreview.sourceIndexPatternError": "加载源索引数据时出错。", - "xpack.ml.dataframe.sourceIndexPreview.sourceIndexPatternTitle": "源索引 {indexPatternTitle}", - "xpack.ml.dataframe.status": "状态", - "xpack.ml.dataframe.tableActionLabel": "操作", - "xpack.ml.dataframe.transformsWizard.betaBadgeLabel": "公测版", - "xpack.ml.dataframe.transformsWizard.stepCreateTitle": "创建", - "xpack.ml.dataframe.transformsWizard.stepDefineTitle": "定义透视", - "xpack.ml.dataframe.transformsWizard.stepDetailsTitle": "转换详情", - "xpack.ml.dataframe.transformsWizard.newDataFrameTitle": "新建数据帧", - "xpack.ml.dataframe.wizard.nextStepButton": "下一个", - "xpack.ml.dataframe.wizard.previousStepButton": "上一页", - "xpack.ml.dataFrameBreadcrumbs.dataFrameCreateLabel": "创建数据帧", - "xpack.ml.dataFrameBreadcrumbs.dataFrameLabel": "转换", - "xpack.ml.dataFrameBreadcrumbs.selectIndexOrSearchLabel": "选择索引或搜索", "xpack.ml.datavisualizer.selector.dataVisualizerDescription": "Machine Learning Data Visualizer 工具通过分析日志文件或现有 Elasticsearch 索引中的指标和字段,帮助您理解数据。", "xpack.ml.datavisualizer.selector.dataVisualizerTitle": "数据可视化工具", "xpack.ml.datavisualizer.selector.experimentalBadgeLabel": "实验性", @@ -6715,7 +6590,6 @@ "xpack.ml.models.jobValidation.validateJobObject.jobIsNotObjectErrorMessage": "无效的 {invalidParamName}:需要是对象。", "xpack.ml.models.jobValidation.validateJobObject.timeFieldIsNotStringErrorMessage": "无效的 {invalidParamName}:需要是字符串。", "xpack.ml.navMenu.anomalyExplorerTabLinkText": "Anomaly Explorer", - "xpack.ml.navMenu.dataFrameTabLinkText": "转换", "xpack.ml.navMenu.dataVisualizerTabLinkText": "数据可视化工具", "xpack.ml.navMenu.jobManagementTabLinkText": "作业管理", "xpack.ml.navMenu.settingsTabLinkText": "设置", @@ -7177,15 +7051,12 @@ "xpack.ml.newJob.wizard.jobType.useWizardTitle": "使用向导", "xpack.ml.privilege.licenseHasExpiredTooltip": "您的许可证已过期。", "xpack.ml.privilege.noPermission.createCalendarsTooltip": "您没有权限创建日历。", - "xpack.ml.privilege.noPermission.createDataFrameTransformTooltip": "您无权创建数据帧转换。", "xpack.ml.privilege.noPermission.createMLJobsTooltip": "您没有权限创建 Machine Learning 作业。", "xpack.ml.privilege.noPermission.deleteCalendarsTooltip": "您没有权限删除日历。", - "xpack.ml.privilege.noPermission.deleteDataFrameTransformTooltip": "您无权删除数据帧转换。", "xpack.ml.privilege.noPermission.deleteJobsTooltip": "您没有权限删除作业。", "xpack.ml.privilege.noPermission.editJobsTooltip": "您没有权限编辑作业。", "xpack.ml.privilege.noPermission.runForecastsTooltip": "您没有权限运行预测。", "xpack.ml.privilege.noPermission.startOrStopDatafeedsTooltip": "您没有权限开始或停止数据馈送。", - "xpack.ml.privilege.noPermission.startOrStopDataFrameTransformTooltip": "您无权启动或停止数据帧转换。", "xpack.ml.privilege.pleaseContactAdministratorTooltip": "{message}请联系您的管理员。", "xpack.ml.routes.annotations.annotationsFeatureUnavailableErrorMessage": "尚未创建或当前用户无法访问注释功能所需的索引和别名。", "xpack.ml.ruleEditor.actionsSection.chooseActionsDescription": "选择在规则匹配异常时要采取的操作。", @@ -7593,79 +7464,6 @@ "xpack.ml.dataframe.analyticsList.type": "类型", "xpack.ml.dataframe.analyticsList.viewActionName": "查看", "xpack.ml.dataframe.analyticsList.viewAriaLabel": "查看", - "xpack.ml.dataFrame.list.errorPromptTitle": "获取数据帧转换列表时发生错误。", - "xpack.ml.dataframe.modeFilter": "模式", - "xpack.ml.dataframe.multiTransformActionsMenu.managementActionsAriaLabel": "管理操作", - "xpack.ml.dataframe.multiTransformActionsMenu.transformsCount": "已选择 {count} 个{count, plural, one {转换} other {转换}}", - "xpack.ml.dataframe.sourceIndexPreview.dataFrameSourceIndexArrayBadgeContent": "数组", - "xpack.ml.dataframe.sourceIndexPreview.dataFrameSourceIndexObjectBadgeContent": "对象", - "xpack.ml.dataframe.sourceIndexPreview.dataFrameSourceIndexObjectToolTipContent": "此基于对象的列的完整内容在展开行中。", - "xpack.ml.dataFrame.statsBar.batchTransformsLabel": "批量", - "xpack.ml.dataFrame.statsBar.continuousTransformsLabel": "连续", - "xpack.ml.dataFrame.statsBar.failedTransformsLabel": "失败", - "xpack.ml.dataFrame.statsBar.startedTransformsLabel": "已开始", - "xpack.ml.dataFrame.statsBar.totalTransformsLabel": "转换总数", - "xpack.ml.dataframe.statusFilter": "状态", - "xpack.ml.dataframe.stepCreateForm.continuousModeLabel": "连续模式", - "xpack.ml.dataframe.stepCreateForm.createDataFrameAnalyticsSuccessMessage": "分析作业 {jobId} 已创建。", - "xpack.ml.dataframe.stepCreateForm.duplicateIndexPatternErrorMessage": "创建 Kibana 索引模式 {indexPatternName} 时发生错误:该索引模式已存在。", - "xpack.ml.dataframe.stepDefineForm.advancedEditorApplyButtonText": "应用更改", - "xpack.ml.dataframe.stepDefineForm.advancedEditorAriaLabel": "高级数据透视表编辑器", - "xpack.ml.dataframe.stepDefineForm.advancedEditorHelpText": "高级编辑器允许您编辑数据帧转换的数据透视表配置。", - "xpack.ml.dataframe.stepDefineForm.advancedEditorHelpTextLink": "详细了解可用选项。", - "xpack.ml.dataframe.stepDefineForm.advancedEditorLabel": "数据透视表配置对象", - "xpack.ml.dataframe.stepDefineForm.advancedEditorSourceConfigSwitchLabel": "高级查询编辑器", - "xpack.ml.dataframe.stepDefineForm.advancedEditorSwitchLabel": "高级数据透视表编辑器", - "xpack.ml.dataframe.stepDefineForm.advancedEditorSwitchModalBodyText": "高级编辑器中的更改尚未应用。禁用高级编辑器将会使您的编辑丢失。", - "xpack.ml.dataframe.stepDefineForm.advancedEditorSwitchModalCancelButtonText": "取消", - "xpack.ml.dataframe.stepDefineForm.advancedEditorSwitchModalConfirmButtonText": "禁用高级编辑器", - "xpack.ml.dataframe.stepDefineForm.advancedEditorSwitchModalTitle": "未应用的更改", - "xpack.ml.dataframe.stepDefineForm.advancedSourceEditorApplyButtonText": "应用更改", - "xpack.ml.dataframe.stepDefineForm.advancedSourceEditorAriaLabel": "高级查询编辑器", - "xpack.ml.dataframe.stepDefineForm.advancedSourceEditorHelpText": "高级编辑器允许您编辑数据帧转换的源查询子句。", - "xpack.ml.dataframe.stepDefineForm.advancedSourceEditorLabel": "源查询子句", - "xpack.ml.dataframe.stepDefineForm.advancedSourceEditorSwitchModalBodyText": "切换回到 KQL 查询栏,您将会丢失编辑。", - "xpack.ml.dataframe.stepDefineForm.advancedSourceEditorSwitchModalConfirmButtonText": "切换到 KQL", - "xpack.ml.dataframe.stepDefineForm.advancedSourceEditorSwitchModalTitle": "编辑将会丢失", - "xpack.ml.dataframe.stepDefineForm.queryPlaceholder": "例如,{example}", - "xpack.ml.dataframe.stepDefineSummary.queryCodeBlockLabel": "查询", - "xpack.ml.dataframe.stepDefineSummary.savedSearchLabel": "已保存搜索", - "xpack.ml.dataframe.stepDetailsForm.continuousModeAriaLabel": "选择延迟。", - "xpack.ml.dataframe.stepDetailsForm.continuousModeDateFieldHelpText": "选择可用于标识新文档的日期字段。", - "xpack.ml.dataframe.stepDetailsForm.continuousModeDateFieldLabel": "日期字段", - "xpack.ml.dataframe.stepDetailsForm.continuousModeDelayError": "延迟格式无效", - "xpack.ml.dataframe.stepDetailsForm.continuousModeDelayHelpText": "当前时间和最新输入数据时间之间的时间延迟。", - "xpack.ml.dataframe.stepDetailsForm.continuousModeDelayLabel": "延迟", - "xpack.ml.dataframe.stepDetailsForm.continuousModeError": "连续模式不可用于没有日期字段的索引。", - "xpack.ml.dataframe.stepDetailsForm.destinationIndexHelpText": "已存在具有此名称的索引。请注意,运行此转换将会修改此目标索引。", - "xpack.ml.dataframe.stepDetailsForm.destinationIndexInputAriaLabel": "选择唯一目标索引名称。", - "xpack.ml.dataframe.stepDetailsForm.destinationIndexInvalidError": "目标索引名称无效。", - "xpack.ml.dataframe.stepDetailsForm.destinationIndexInvalidErrorLink": "详细了解索引名称限制。", - "xpack.ml.dataframe.stepDetailsForm.destinationIndexLabel": "目标 IP", - "xpack.ml.dataframe.stepDetailsForm.transformDescriptionHelpText": "(可选)描述性文本。", - "xpack.ml.dataframe.stepDetailsForm.transformDescriptionInputAriaLabel": "选择可选的转换描述。", - "xpack.ml.dataframe.stepDetailsForm.transformDescriptionLabel": "转换描述", - "xpack.ml.dataframe.stepDetailsForm.transformIdExistsError": "已存在具有此 ID 的转换。", - "xpack.ml.dataframe.stepDetailsForm.transformIdInvalidError": "只能包含小写字母数字字符(a-z 和 0-9)、连字符和下划线,并且必须以字母数字字符开头和结尾。", - "xpack.ml.dataframe.stepDetailsSummary.continuousModeDateFieldLabel": "连续模式日期字段", - "xpack.ml.dataframe.stepDetailsSummary.destinationIndexLabel": "目标 IP", - "xpack.ml.dataframe.stepDetailsSummary.transformDescriptionLabel": "转换描述", - "xpack.ml.dataframe.transformList.bulkDeleteModalBody": "是否确定要删除{count, plural, one {这} other {这}} {count} 个 {count, plural, one {转换} other {转换}}?转换的目标索引和可选 Kibana 索引模式将不会删除。", - "xpack.ml.dataframe.transformList.bulkDeleteModalTitle": "删除 {count} 个 {count, plural, one {转换} other {转换}}?", - "xpack.ml.dataframe.transformList.bulkStartModalTitle": "启动 {count} 个 {count, plural, one {转换} other {转换}}?", - "xpack.ml.dataframe.transformList.completeBatchTransformBulkActionToolTip": "一个或多个选定数据帧转换是已完成的批量转换,无法重新启动。", - "xpack.ml.dataframe.transformList.deleteBulkActionDisabledToolTipContent": "一个或多个选定数据帧转换必须停止,才能删除。", - "xpack.ml.dataframe.transformList.deleteTransformErrorMessage": "删除数据帧转换 {transformId} 时发生错误", - "xpack.ml.dataframe.transformList.refreshButtonLabel": "刷新", - "xpack.ml.dataframe.transformList.startedTransformBulkToolTip": "一个或多个选定数据帧转换已启动。", - "xpack.ml.dataframe.transformList.startedTransformToolTip": "{transformId} 已启动。", - "xpack.ml.dataframe.transformList.startModalBody": "数据帧转换将增加集群的搜索和索引负荷。如果负荷超载,请停止转换。是否确定要启动{count, plural, one {这} other {这}} {count} 个 {count, plural, one {转换} other {转换}}?", - "xpack.ml.dataframe.transformList.startTransformErrorMessage": "启动数据帧转换 {transformId} 时发生错误", - "xpack.ml.dataframe.transformList.stoppedTransformBulkToolTip": "一个或多个选定数据帧转换已停止。", - "xpack.ml.dataframe.transformList.stoppedTransformToolTip": "{transformId} 已停止。", - "xpack.ml.dataframe.transformList.stopTransformErrorMessage": "停止数据帧转换 {transformId} 时发生错误", - "xpack.ml.dataframe.transformList.transformDetails.tabs.transformMessagesLabel": "消息", - "xpack.ml.dataframe.transformList.transformDetails.tabs.transformPreviewLabel": "预览", "xpack.ml.dataFrameAnalyticsBreadcrumbs.dataFrameLabel": "分析", "xpack.ml.datavisualizer.actionsPanel.advancedDescription": "使用全部选项为更高级的用例创建作业", "xpack.ml.datavisualizer.actionsPanel.advancedTitle": "高级", @@ -7694,11 +7492,6 @@ "xpack.ml.dfAnalyticsList.analyticsDetails.messagesPane.messageLabel": "消息", "xpack.ml.dfAnalyticsList.analyticsDetails.messagesPane.nodeLabel": "节点", "xpack.ml.dfAnalyticsList.analyticsDetails.messagesPane.timeLabel": "时间", - "xpack.ml.dfTransformList.stepDetails.previewPane.errorMessage": "无法加载预览", - "xpack.ml.dfTransformList.transformDetails.messagesPane.errorMessage": "无法加载消息", - "xpack.ml.dfTransformList.transformDetails.messagesPane.messageLabel": "消息", - "xpack.ml.dfTransformList.transformDetails.messagesPane.nodeLabel": "节点", - "xpack.ml.dfTransformList.transformDetails.messagesPane.timeLabel": "时间", "xpack.ml.fieldDataCard.cardBoolean.documentsCountDescription": "{count, plural, zero {# 个文档} one {# 个文档} other {# 个文档}} ({docsPercent}%)", "xpack.ml.fieldDataCard.cardDate.documentsCountDescription": "{count, plural, zero {# 个文档} one {# 个文档} other {# 个文档}} ({docsPercent}%)", "xpack.ml.fieldDataCard.cardDate.earliestDescription": "最早的 {earliestFormatted}", @@ -7741,8 +7534,6 @@ "xpack.ml.management.jobsListTitle": "作业列表", "xpack.ml.management.mlTitle": "Machine Learning", "xpack.ml.messagebarService.errorTitle": "发生了错误", - "xpack.ml.models.transformService.allOtherRequestsCancelledDescription": "所有其他请求已取消。", - "xpack.ml.models.transformService.requestToActionTimedOutErrorMessage": "对 {action}“{id}” 的请求超时。{extra}", "xpack.ml.navMenu.dataFrameAnalyticsTabLinkText": "分析", "xpack.ml.newJob.wizard.jobDetailsStep.additionalSection.calendarsSelection.description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.Ut enim ad minim veniam.", "xpack.ml.newJob.wizard.jobDetailsStep.additionalSection.calendarsSelection.title": "日历", @@ -7833,6 +7624,178 @@ "xpack.ml.newJob.wizard.validateJob.jobNameAlreadyExists": "作业 ID 已存在。作业 ID 不能与现有作业或组相同。", "xpack.ml.newJob.wizard.validateJob.modelMemoryLimitRangeInvalidErrorMessage": "模型内存限制不能高于最大值 {maxModelMemoryLimit}", "xpack.ml.newJob.wizard.validateJob.modelMemoryLimitUnitsInvalidErrorMessage": "无法识别模型内存限制数据单元。必须为 {str}", + "xpack.transform.capability.noPermission.createTransformTooltip": "您无权创建数据帧转换。", + "xpack.transform.capability.noPermission.deleteTransformTooltip": "您无权删除数据帧转换。", + "xpack.transform.models.transformService.allOtherRequestsCancelledDescription": "所有其他请求已取消。", + "xpack.transform.models.transformService.requestToActionTimedOutErrorMessage": "对 {action}“{id}” 的请求超时。{extra}", + "xpack.transform.list.errorPromptTitle": "获取数据帧转换列表时发生错误。", + "xpack.transform.modeFilter": "模式", + "xpack.transform.multiTransformActionsMenu.managementActionsAriaLabel": "管理操作", + "xpack.transform.multiTransformActionsMenu.transformsCount": "已选择 {count} 个{count, plural, one {转换} other {转换}}", + "xpack.transform.statsBar.batchTransformsLabel": "批量", + "xpack.transform.statsBar.continuousTransformsLabel": "连续", + "xpack.transform.statsBar.failedTransformsLabel": "失败", + "xpack.transform.statsBar.startedTransformsLabel": "已开始", + "xpack.transform.statsBar.totalTransformsLabel": "转换总数", + "xpack.transform.statusFilter": "状态", + "xpack.transform.stepCreateForm.continuousModeLabel": "连续模式", + "xpack.transform.stepCreateForm.duplicateIndexPatternErrorMessage": "创建 Kibana 索引模式 {indexPatternName} 时发生错误:该索引模式已存在。", + "xpack.transform.stepDefineForm.advancedEditorApplyButtonText": "应用更改", + "xpack.transform.stepDefineForm.advancedEditorAriaLabel": "高级数据透视表编辑器", + "xpack.transform.stepDefineForm.advancedEditorHelpText": "高级编辑器允许您编辑数据帧转换的数据透视表配置。", + "xpack.transform.stepDefineForm.advancedEditorHelpTextLink": "详细了解可用选项。", + "xpack.transform.stepDefineForm.advancedEditorLabel": "数据透视表配置对象", + "xpack.transform.stepDefineForm.advancedEditorSourceConfigSwitchLabel": "高级查询编辑器", + "xpack.transform.stepDefineForm.advancedEditorSwitchLabel": "高级数据透视表编辑器", + "xpack.transform.stepDefineForm.advancedEditorSwitchModalBodyText": "高级编辑器中的更改尚未应用。禁用高级编辑器将会使您的编辑丢失。", + "xpack.transform.stepDefineForm.advancedEditorSwitchModalCancelButtonText": "取消", + "xpack.transform.stepDefineForm.advancedEditorSwitchModalConfirmButtonText": "禁用高级编辑器", + "xpack.transform.stepDefineForm.advancedEditorSwitchModalTitle": "未应用的更改", + "xpack.transform.stepDefineForm.advancedSourceEditorApplyButtonText": "应用更改", + "xpack.transform.stepDefineForm.advancedSourceEditorAriaLabel": "高级查询编辑器", + "xpack.transform.stepDefineForm.advancedSourceEditorHelpText": "高级编辑器允许您编辑数据帧转换的源查询子句。", + "xpack.transform.stepDefineForm.advancedSourceEditorLabel": "源查询子句", + "xpack.transform.stepDefineForm.advancedSourceEditorSwitchModalBodyText": "切换回到 KQL 查询栏,您将会丢失编辑。", + "xpack.transform.stepDefineForm.advancedSourceEditorSwitchModalConfirmButtonText": "切换到 KQL", + "xpack.transform.stepDefineForm.advancedSourceEditorSwitchModalTitle": "编辑将会丢失", + "xpack.transform.stepDefineForm.queryPlaceholder": "例如,{example}", + "xpack.transform.stepDefineSummary.queryCodeBlockLabel": "查询", + "xpack.transform.stepDefineSummary.savedSearchLabel": "已保存搜索", + "xpack.transform.stepDetailsForm.continuousModeAriaLabel": "选择延迟。", + "xpack.transform.stepDetailsForm.continuousModeDateFieldHelpText": "选择可用于标识新文档的日期字段。", + "xpack.transform.stepDetailsForm.continuousModeDateFieldLabel": "日期字段", + "xpack.transform.stepDetailsForm.continuousModeDelayError": "延迟格式无效", + "xpack.transform.stepDetailsForm.continuousModeDelayHelpText": "当前时间和最新输入数据时间之间的时间延迟。", + "xpack.transform.stepDetailsForm.continuousModeDelayLabel": "延迟", + "xpack.transform.stepDetailsForm.continuousModeError": "连续模式不可用于没有日期字段的索引。", + "xpack.transform.stepDetailsForm.destinationIndexHelpText": "已存在具有此名称的索引。请注意,运行此转换将会修改此目标索引。", + "xpack.transform.stepDetailsForm.destinationIndexInputAriaLabel": "选择唯一目标索引名称。", + "xpack.transform.stepDetailsForm.destinationIndexInvalidError": "目标索引名称无效。", + "xpack.transform.stepDetailsForm.destinationIndexInvalidErrorLink": "详细了解索引名称限制。", + "xpack.transform.stepDetailsForm.destinationIndexLabel": "目标 IP", + "xpack.transform.stepDetailsForm.transformDescriptionHelpText": "(可选)描述性文本。", + "xpack.transform.stepDetailsForm.transformDescriptionInputAriaLabel": "选择可选的转换描述。", + "xpack.transform.stepDetailsForm.transformDescriptionLabel": "转换描述", + "xpack.transform.stepDetailsForm.transformIdExistsError": "已存在具有此 ID 的转换。", + "xpack.transform.stepDetailsForm.transformIdInvalidError": "只能包含小写字母数字字符(a-z 和 0-9)、连字符和下划线,并且必须以字母数字字符开头和结尾。", + "xpack.transform.stepDetailsSummary.continuousModeDateFieldLabel": "连续模式日期字段", + "xpack.transform.stepDetailsSummary.destinationIndexLabel": "目标 IP", + "xpack.transform.stepDetailsSummary.transformDescriptionLabel": "转换描述", + "xpack.transform.transformList.bulkDeleteModalBody": "是否确定要删除{count, plural, one {这} other {这}} {count} 个 {count, plural, one {转换} other {转换}}?转换的目标索引和可选 Kibana 索引模式将不会删除。", + "xpack.transform.transformList.bulkDeleteModalTitle": "删除 {count} 个 {count, plural, one {转换} other {转换}}?", + "xpack.transform.transformList.bulkStartModalTitle": "启动 {count} 个 {count, plural, one {转换} other {转换}}?", + "xpack.transform.transformList.completeBatchTransformBulkActionToolTip": "一个或多个选定数据帧转换是已完成的批量转换,无法重新启动。", + "xpack.transform.transformList.deleteBulkActionDisabledToolTipContent": "一个或多个选定数据帧转换必须停止,才能删除。", + "xpack.transform.transformList.deleteTransformErrorMessage": "删除数据帧转换 {transformId} 时发生错误", + "xpack.transform.transformList.refreshButtonLabel": "刷新", + "xpack.transform.transformList.startedTransformBulkToolTip": "一个或多个选定数据帧转换已启动。", + "xpack.transform.transformList.startedTransformToolTip": "{transformId} 已启动。", + "xpack.transform.transformList.startModalBody": "数据帧转换将增加集群的搜索和索引负荷。如果负荷超载,请停止转换。是否确定要启动{count, plural, one {这} other {这}} {count} 个 {count, plural, one {转换} other {转换}}?", + "xpack.transform.transformList.startTransformErrorMessage": "启动数据帧转换 {transformId} 时发生错误", + "xpack.transform.transformList.stoppedTransformBulkToolTip": "一个或多个选定数据帧转换已停止。", + "xpack.transform.transformList.stoppedTransformToolTip": "{transformId} 已停止。", + "xpack.transform.transformList.stopTransformErrorMessage": "停止数据帧转换 {transformId} 时发生错误", + "xpack.transform.transformList.transformDetails.tabs.transformMessagesLabel": "消息", + "xpack.transform.transformList.transformDetails.tabs.transformPreviewLabel": "预览", + "xpack.transform.agg.popoverForm.aggLabel": "聚合", + "xpack.transform.agg.popoverForm.aggNameAlreadyUsedError": "其他聚合已使用该名称。", + "xpack.transform.agg.popoverForm.aggNameInvalidCharError": "名称无效。不允许使用字符“[”、“]” 和“>”且名称不得以空格字符开头或结束。", + "xpack.transform.agg.popoverForm.fieldLabel": "字段", + "xpack.transform.agg.popoverForm.nameLabel": "聚合名称", + "xpack.transform.agg.popoverForm.submitButtonLabel": "应用", + "xpack.transform.aggLabelForm.deleteItemAriaLabel": "删除项", + "xpack.transform.aggLabelForm.editAggAriaLabel": "编辑聚合", + "xpack.transform.stepDefineForm.aggExistsErrorMessage": "名称为“{aggName}”的聚合配置已存在。", + "xpack.transform.stepDefineForm.groupByExistsErrorMessage": "名称为“{aggName}”的分组依据配置已存在。", + "xpack.transform.stepDefineForm.nestedAggListConflictErrorMessage": "无法添加配置“{aggName}”,因为与“{aggListName}”有嵌套冲突。", + "xpack.transform.stepDefineForm.nestedConflictErrorMessage": "无法添加配置“{aggName}”,因为与“{aggNameCheck}”有嵌套冲突。", + "xpack.transform.stepDefineForm.nestedGroupByListConflictErrorMessage": "无法添加配置“{aggName}”,因为与“{groupByListName}”有嵌套冲突。", + "xpack.transform.stepDefineForm.aggregationsLabel": "聚合", + "xpack.transform.stepDefineForm.aggregationsPlaceholder": "添加聚合……", + "xpack.transform.stepDefineForm.formHelp": "数据帧转换是用于数据透视的可伸缩和自动化流程。至少选择一个分组依据和聚合,才能开始。", + "xpack.transform.stepDefineForm.groupByLabel": "分组依据", + "xpack.transform.stepDefineForm.groupByPlaceholder": "添加分组依据字段……", + "xpack.transform.stepDefineForm.indexPatternHelpText": "不支持此索引模式的可选查询。受支持索引字段数目为 {maxIndexFields},而此索引有 {numIndexFields} 个字段。", + "xpack.transform.stepDefineForm.indexPatternLabel": "索引模式", + "xpack.transform.stepDefineForm.queryHelpText": "使用查询字符串筛选源数据(可选)。", + "xpack.transform.stepDefineForm.queryLabel": "查询", + "xpack.transform.stepDefineForm.savedSearchLabel": "已保存搜索", + "xpack.transform.stepDefineSummary.aggregationsLabel": "聚合", + "xpack.transform.stepDefineSummary.groupByLabel": "分组依据", + "xpack.transform.stepDefineSummary.indexPatternLabel": "索引模式", + "xpack.transform.stepDefineSummary.queryLabel": "查询", + "xpack.transform.groupby.popoverForm.aggLabel": "聚合", + "xpack.transform.groupBy.popoverForm.aggNameAlreadyUsedError": "其他分组依据配置已使用该名称。", + "xpack.transform.groupBy.popoverForm.aggNameInvalidCharError": "名称无效。不允许使用字符“[”、“]” 和“>”且名称不得以空格字符开头或结束。", + "xpack.transform.groupBy.popoverForm.fieldLabel": "字段", + "xpack.transform.groupBy.popoverForm.intervalError": "时间间隔无效。", + "xpack.transform.groupBy.popoverForm.intervalLabel": "时间间隔", + "xpack.transform.groupBy.popoverForm.nameLabel": "分组依据名称", + "xpack.transform.groupBy.popoverForm.submitButtonLabel": "应用", + "xpack.transform.groupByLabelForm.deleteItemAriaLabel": "删除项", + "xpack.transform.groupByLabelForm.editIntervalAriaLabel": "编辑时间间隔", + "xpack.transform.stepCreateForm.copyTransformConfigToClipboardButton": "复制到剪贴板", + "xpack.transform.stepCreateForm.copyTransformConfigToClipboardDescription": "将用于创建作业的 Kibana 开发控制台命令复制到剪贴板。", + "xpack.transform.stepCreateForm.createIndexPatternErrorMessage": "创建 Kibana 索引模式 {indexPatternName} 时发生错误:{error}", + "xpack.transform.stepCreateForm.createIndexPatternLabel": "创建索引模式", + "xpack.transform.stepCreateForm.createTransformErrorMessage": "创建数据帧作业 {transformId} 时发生错误:{error}", + "xpack.transform.stepCreateForm.createTransformSuccessMessage": "数据帧作业 {transformId} 创建成功。", + "xpack.transform.stepCreateForm.creatingIndexPatternMessage": "正在创建 Kibana 索引模式......", + "xpack.transform.stepCreateForm.discoverCardDescription": "使用 Discover 浏览数据帧透视表。", + "xpack.transform.stepCreateForm.discoverCardTitle": "Discover", + "xpack.transform.stepCreateForm.transformListCardDescription": "返回数据帧作业管理页面。", + "xpack.transform.stepCreateForm.transformListCardTitle": "数据帧作业", + "xpack.transform.stepCreateForm.progressErrorMessage": "获取进度百分比时出错:{error}", + "xpack.transform.stepCreateForm.progressTitle": "进度", + "xpack.transform.stepCreateForm.createIndexPatternSuccessMessage": "Kibana 索引模式 {indexPatternName} 成功创建。", + "xpack.transform.stepCreateForm.startTransformErrorMessage": "启动数据帧作业 {transformId} 时发生错误:{error}", + "xpack.transform.stepCreateForm.startTransformSuccessMessage": "数据帧作业 {transformId} 启动成功。", + "xpack.transform.stepDetailsForm.errorGettingIndexPatternTitles": "获取现有索引名称时发生错误:{error}", + "xpack.transform.stepDetailsForm.indexPatternTitleError": "具有此名称的索引模式已存在。", + "xpack.transform.stepDetailsForm.transformIdInputAriaLabel": "选择唯一的作业 ID。", + "xpack.transform.stepDetailsForm.transformIdLabel": "作业 ID", + "xpack.transform.stepDetailsSummary.createIndexPatternMessage": "将为此作业创建 Kibana 索引模式。", + "xpack.transform.stepDetailsSummary.transformIdLabel": "作业 ID", + "xpack.transform.transformList.betaBadgeLabel": "公测版", + "xpack.transform.transformList.betaBadgeTooltipContent": "数据帧是公测版功能。我们很乐意听取您的反馈意见。", + "xpack.transform.transformList.completeBatchTransformToolTip": "{transformId} 为已完成的批处理作业,无法重新启动。", + "xpack.transform.transformList.deleteActionDisabledToolTipContent": "停止数据帧作业,以便将其删除。", + "xpack.transform.transformList.deleteActionName": "删除", + "xpack.transform.transformList.deleteTransformSuccessMessage": "数据帧作业 {transformId} 删除成功。", + "xpack.transform.transformList.deleteModalBody": "是否确定要删除此作业?作业的目标索引和可选 Kibana 索引模式将不会删除。", + "xpack.transform.transformList.deleteModalCancelButton": "取消", + "xpack.transform.transformList.deleteModalDeleteButton": "删除", + "xpack.transform.transformList.deleteModalTitle": "删除 {transformId}", + "xpack.transform.transformList.transformDetails.tabs.transformSettingsLabel": "作业详情", + "xpack.transform.transformList.rowCollapse": "隐藏 {transformId} 的详情", + "xpack.transform.transformList.rowExpand": "显示 {transformId} 的详情", + "xpack.transform.transformList.startActionName": "开始", + "xpack.transform.transformList.startTransformSuccessMessage": "数据帧作业 {transformId} 启动成功。", + "xpack.transform.transformList.startModalCancelButton": "取消", + "xpack.transform.transformList.startModalStartButton": "开始", + "xpack.transform.transformList.startModalTitle": "启动 {transformId}", + "xpack.transform.transformList.stopActionName": "停止", + "xpack.transform.transformList.stopTransformSuccessMessage": "数据帧作业 {transformId} 停止成功。", + "xpack.transform.pivotPreview.copyClipboardTooltip": "将透视预览的开发控制台语句复制到剪贴板。", + "xpack.transform.pivotPreview.statusCodeLabel": "状态代码", + "xpack.transform.progress": "进度", + "xpack.transform.sourceIndex": "源索引", + "xpack.transform.sourceIndexPreview.copyClipboardTooltip": "将源索引预览的开发控制台语句复制到剪贴板。", + "xpack.transform.sourceIndexPreview.fieldSelection": "显示 {selectedFieldsLength, number} 个{docFieldsCount, plural, one {字段} other {字段}},共 {docFieldsCount, number} 个", + "xpack.transform.sourceIndexPreview.rowCollapse": "折叠", + "xpack.transform.sourceIndexPreview.rowExpand": "展开", + "xpack.transform.sourceIndexPreview.selectColumnsAriaLabel": "选择列", + "xpack.transform.sourceIndexPreview.selectFieldsPopoverTitle": "选择字段", + "xpack.transform.sourceIndexPreview.sourceIndexPatternError": "加载源索引数据时出错。", + "xpack.transform.sourceIndexPreview.sourceIndexPatternTitle": "源索引 {indexPatternTitle}", + "xpack.transform.status": "状态", + "xpack.transform.tableActionLabel": "操作", + "xpack.transform.transformsWizard.betaBadgeLabel": "公测版", + "xpack.transform.transformsWizard.stepCreateTitle": "创建", + "xpack.transform.transformsWizard.stepDefineTitle": "定义透视", + "xpack.transform.transformsWizard.stepDetailsTitle": "作业详情", + "xpack.transform.wizard.nextStepButton": "下一个", + "xpack.transform.wizard.previousStepButton": "上一页", "xpack.monitoring.accessDenied.backToKibanaButtonLabel": "返回 Kibana", "xpack.monitoring.accessDenied.clusterNotConfiguredDescription": "如果您尝试访问专用监测集群,则这可能是因为该监测集群上未配置您登录时所用的用户帐户。", "xpack.monitoring.accessDenied.notAuthorizedDescription": "您无权访问 Monitoring。要使用 Monitoring,您同时需要 `{kibanaUser}` 和 `{monitoringUser}` 角色授予的权限。", diff --git a/x-pack/test/functional/apps/machine_learning/anomaly_detection/multi_metric_job.ts b/x-pack/test/functional/apps/machine_learning/anomaly_detection/multi_metric_job.ts index 73f8c8cf29da4..c4e6459e10555 100644 --- a/x-pack/test/functional/apps/machine_learning/anomaly_detection/multi_metric_job.ts +++ b/x-pack/test/functional/apps/machine_learning/anomaly_detection/multi_metric_job.ts @@ -80,7 +80,6 @@ export default function({ getService }: FtrProviderContext) { after(async () => { await esArchiver.unload('ml/farequote'); await ml.api.cleanMlIndices(); - await ml.api.cleanDataframeIndices(); }); describe('job creation', function() { diff --git a/x-pack/test/functional/apps/machine_learning/anomaly_detection/population_job.ts b/x-pack/test/functional/apps/machine_learning/anomaly_detection/population_job.ts index fb5219a8885be..706a3c946a261 100644 --- a/x-pack/test/functional/apps/machine_learning/anomaly_detection/population_job.ts +++ b/x-pack/test/functional/apps/machine_learning/anomaly_detection/population_job.ts @@ -94,7 +94,6 @@ export default function({ getService }: FtrProviderContext) { after(async () => { await esArchiver.unload('ml/farequote'); await ml.api.cleanMlIndices(); - await ml.api.cleanDataframeIndices(); }); describe('job creation', function() { diff --git a/x-pack/test/functional/apps/machine_learning/anomaly_detection/saved_search_job.ts b/x-pack/test/functional/apps/machine_learning/anomaly_detection/saved_search_job.ts index a9b1187135271..9591cdd3ff561 100644 --- a/x-pack/test/functional/apps/machine_learning/anomaly_detection/saved_search_job.ts +++ b/x-pack/test/functional/apps/machine_learning/anomaly_detection/saved_search_job.ts @@ -280,7 +280,6 @@ export default function({ getService }: FtrProviderContext) { after(async () => { await esArchiver.unload('ml/farequote'); await ml.api.cleanMlIndices(); - await ml.api.cleanDataframeIndices(); }); for (const testData of testDataList) { diff --git a/x-pack/test/functional/apps/machine_learning/anomaly_detection/single_metric_job.ts b/x-pack/test/functional/apps/machine_learning/anomaly_detection/single_metric_job.ts index d52eed71b8e31..ebdcb67cf21cb 100644 --- a/x-pack/test/functional/apps/machine_learning/anomaly_detection/single_metric_job.ts +++ b/x-pack/test/functional/apps/machine_learning/anomaly_detection/single_metric_job.ts @@ -79,7 +79,6 @@ export default function({ getService }: FtrProviderContext) { after(async () => { await esArchiver.unload('ml/farequote'); await ml.api.cleanMlIndices(); - await ml.api.cleanDataframeIndices(); }); describe('job creation', function() { diff --git a/x-pack/test/functional/apps/machine_learning/pages.ts b/x-pack/test/functional/apps/machine_learning/pages.ts index 0c997c7389317..01d91bdfc3075 100644 --- a/x-pack/test/functional/apps/machine_learning/pages.ts +++ b/x-pack/test/functional/apps/machine_learning/pages.ts @@ -55,11 +55,6 @@ export default function({ getService }: FtrProviderContext) { await ml.settings.assertSettingsFilterlistLinkExists(); }); - it('loads the data frame page', async () => { - await ml.navigation.navigateToDataFrames(); - await ml.dataFrames.assertDataFrameEmptyListMessageExists(); - }); - it('loads the data frame analytics page', async () => { await ml.navigation.navigateToDataFrameAnalytics(); await ml.dataFrameAnalytics.assertEmptyListMessageExists(); diff --git a/x-pack/test/functional/services/machine_learning/api.ts b/x-pack/test/functional/services/machine_learning/api.ts index a82f37485dc4f..4ab59b5d847fe 100644 --- a/x-pack/test/functional/services/machine_learning/api.ts +++ b/x-pack/test/functional/services/machine_learning/api.ts @@ -39,9 +39,5 @@ export function MachineLearningAPIProvider({ getService }: FtrProviderContext) { async cleanMlIndices() { await this.deleteIndices('.ml-*'); }, - - async cleanDataframeIndices() { - await this.deleteIndices('.data-frame-*'); - }, }; } diff --git a/x-pack/test/functional/services/machine_learning/data_frames.ts b/x-pack/test/functional/services/machine_learning/data_frames.ts deleted file mode 100644 index c0fe7eab65f3e..0000000000000 --- a/x-pack/test/functional/services/machine_learning/data_frames.ts +++ /dev/null @@ -1,17 +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 { FtrProviderContext } from '../../ftr_provider_context'; - -export function MachineLearningDataFramesProvider({ getService }: FtrProviderContext) { - const testSubjects = getService('testSubjects'); - - return { - async assertDataFrameEmptyListMessageExists() { - await testSubjects.existOrFail('mlNoDataFrameTransformsFound'); - }, - }; -} diff --git a/x-pack/test/functional/services/machine_learning/index.ts b/x-pack/test/functional/services/machine_learning/index.ts index 9e2f70c1827ff..0dc588ffcc9e5 100644 --- a/x-pack/test/functional/services/machine_learning/index.ts +++ b/x-pack/test/functional/services/machine_learning/index.ts @@ -7,7 +7,6 @@ export { MachineLearningAnomalyExplorerProvider } from './anomaly_explorer'; export { MachineLearningAPIProvider } from './api'; export { MachineLearningDataFrameAnalyticsProvider } from './data_frame_analytics'; -export { MachineLearningDataFramesProvider } from './data_frames'; export { MachineLearningDataVisualizerProvider } from './data_visualizer'; export { MachineLearningJobManagementProvider } from './job_management'; export { MachineLearningJobSourceSelectionProvider } from './job_source_selection'; diff --git a/x-pack/test/functional/services/machine_learning/navigation.ts b/x-pack/test/functional/services/machine_learning/navigation.ts index 2d271c684e184..a55eae9122485 100644 --- a/x-pack/test/functional/services/machine_learning/navigation.ts +++ b/x-pack/test/functional/services/machine_learning/navigation.ts @@ -64,11 +64,6 @@ export function MachineLearningNavigationProvider({ ]); }, - async navigateToDataFrames() { - await this.navigateToArea('mlMainTab dataFrames', 'mlPageDataFrame'); - await this.assertTabsExist('mlSubTab', []); - }, - async navigateToDataFrameAnalytics() { await this.navigateToArea('mlMainTab dataFrameAnalytics', 'mlPageDataFrameAnalytics'); await this.assertTabsExist('mlSubTab', []); diff --git a/x-pack/test/functional/services/ml.ts b/x-pack/test/functional/services/ml.ts index 5b2f168301818..3feb45ae23bbc 100644 --- a/x-pack/test/functional/services/ml.ts +++ b/x-pack/test/functional/services/ml.ts @@ -10,7 +10,6 @@ import { MachineLearningAnomalyExplorerProvider, MachineLearningAPIProvider, MachineLearningDataFrameAnalyticsProvider, - MachineLearningDataFramesProvider, MachineLearningDataVisualizerProvider, MachineLearningJobManagementProvider, MachineLearningJobSourceSelectionProvider, @@ -28,7 +27,6 @@ export function MachineLearningProvider(context: FtrProviderContext) { const anomalyExplorer = MachineLearningAnomalyExplorerProvider(context); const api = MachineLearningAPIProvider(context); const dataFrameAnalytics = MachineLearningDataFrameAnalyticsProvider(context); - const dataFrames = MachineLearningDataFramesProvider(context); const dataVisualizer = MachineLearningDataVisualizerProvider(context); const jobManagement = MachineLearningJobManagementProvider(context); const jobSourceSelection = MachineLearningJobSourceSelectionProvider(context); @@ -45,7 +43,6 @@ export function MachineLearningProvider(context: FtrProviderContext) { anomalyExplorer, api, dataFrameAnalytics, - dataFrames, dataVisualizer, jobManagement, jobSourceSelection,