diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/details.tsx b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/details.tsx new file mode 100644 index 0000000000000..2fa13b5da43e2 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/details.tsx @@ -0,0 +1,130 @@ +/* + * 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, { FunctionComponent } from 'react'; +import { i18n } from '@kbn/i18n'; +import { + EuiFlyout, + EuiFlyoutHeader, + EuiFlyoutBody, + EuiTitle, + EuiDescriptionList, + EuiSpacer, + EuiFlyoutFooter, + EuiFlexGroup, + EuiFlexItem, + EuiButtonEmpty, +} from '@elastic/eui'; +import { Pipeline } from '../../../../common/types'; + +import { PipelineDetailsJsonBlock } from './details_json_block'; + +export interface Props { + pipeline: Pipeline; + onEditClick: () => void; + onDeleteClick: () => void; + onClose: () => void; +} + +export const PipelineDetails: FunctionComponent = ({ + pipeline, + onClose, + onEditClick, + onDeleteClick, +}) => { + const descriptionListItems = [ + { + title: i18n.translate('xpack.ingestPipelines.list.pipelineDetails.descriptionTitle', { + defaultMessage: 'Description', + }), + description: pipeline.description ?? '', + }, + ]; + + if (pipeline.version) { + descriptionListItems.push({ + title: i18n.translate('xpack.ingestPipelines.list.pipelineDetails.versionTitle', { + defaultMessage: 'Version', + }), + description: String(pipeline.version), + }); + } + + return ( + + + +

{pipeline.name}

+
+
+ + + + + + + + + {/* On Failure Processor JSON */} + {pipeline.onFailure?.length && ( + <> + + + + )} + {/* End On Failure Processor JSON */} + + + + + + + {i18n.translate('xpack.ingestPipelines.list.pipelineDetails.closeButtonLabel', { + defaultMessage: 'Close', + })} + + + + + + {i18n.translate('xpack.ingestPipelines.list.pipelineDetails.editButtonLabel', { + defaultMessage: 'Edit', + })} + + + + + {i18n.translate('xpack.ingestPipelines.list.pipelineDetails.deleteButtonLabel', { + defaultMessage: 'Delete', + })} + + + + + +
+ ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/details_json_block.tsx b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/details_json_block.tsx new file mode 100644 index 0000000000000..b648d2445b271 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/details_json_block.tsx @@ -0,0 +1,27 @@ +/* + * 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, { FunctionComponent } from 'react'; +import { EuiCodeBlock, EuiText } from '@elastic/eui'; + +export interface Props { + htmlForId: string; + label: string; + json: Record; +} + +export const PipelineDetailsJsonBlock: FunctionComponent = ({ label, htmlForId, json }) => ( + <> + + + + + {JSON.stringify(json, null, 2)} + + +); diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/empty_list.tsx b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/empty_list.tsx new file mode 100644 index 0000000000000..c109334168da9 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/empty_list.tsx @@ -0,0 +1,32 @@ +/* + * 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, { FunctionComponent } from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiButton, EuiEmptyPrompt } from '@elastic/eui'; + +interface Props { + onClick: () => void; +} + +export const EmptyList: FunctionComponent = ({ onClick }) => ( + + {i18n.translate('xpack.ingestPipelines.list.table.emptyPromptTitle', { + defaultMessage: 'Create your first pipeline', + })} + + } + actions={ + + {i18n.translate('xpack.ingestPipelines.list.table.emptyPrompt.createButtonLabel', { + defaultMessage: 'Create pipeline', + })} + + } + /> +); diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/index.ts b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/index.ts index d750aaba177ba..a541e3bb85fd0 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/index.ts +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { PipelinesList } from './pipelines_list'; +export { PipelinesList } from './main'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/main.tsx b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/main.tsx new file mode 100644 index 0000000000000..5cd63a61123f3 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/main.tsx @@ -0,0 +1,132 @@ +/* + * 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 } from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { + EuiPageBody, + EuiPageContent, + EuiTitle, + EuiFlexGroup, + EuiFlexItem, + EuiButtonEmpty, + EuiCallOut, +} from '@elastic/eui'; + +import { EuiSpacer, EuiText } from '@elastic/eui'; + +import { Pipeline } from '../../../../common/types'; +import { useKibana, SectionLoading } from '../../../shared_imports'; +import { UIM_PIPELINES_LIST_LOAD } from '../../constants'; + +import { EmptyList } from './empty_list'; +import { PipelineTable } from './table'; +import { PipelineDetails } from './details'; + +export const PipelinesList: React.FunctionComponent = () => { + const { services } = useKibana(); + + const [selectedPipeline, setSelectedPipeline] = useState(undefined); + + // Track component loaded + useEffect(() => { + services.metric.trackUiMetric(UIM_PIPELINES_LIST_LOAD); + }, [services.metric]); + + const { data, isLoading, error, sendRequest } = services.api.useLoadPipelines(); + + let content: React.ReactNode; + + if (isLoading) { + content = ( + + + + ); + } else if (data?.length) { + content = ( + { + sendRequest(); + }} + onEditPipelineClick={() => {}} + onDeletePipelineClick={() => {}} + onViewPipelineClick={setSelectedPipeline} + pipelines={data} + /> + ); + } else { + content = {}} />; + } + + return ( + <> + + + + + +

+ +

+
+ + + + + +
+
+ + + + + + + + {/* Error call out or pipeline table */} + {error ? ( + + ) : ( + content + )} +
+
+ {selectedPipeline && ( + setSelectedPipeline(undefined)} + onDeleteClick={() => {}} + onEditClick={() => {}} + /> + )} + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/pipelines_list.tsx b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/pipelines_list.tsx deleted file mode 100644 index d2ea0f77ebcf3..0000000000000 --- a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/pipelines_list.tsx +++ /dev/null @@ -1,73 +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, { useEffect } from 'react'; - -import { - EuiPageBody, - EuiPageContent, - EuiTitle, - EuiFlexGroup, - EuiFlexItem, - EuiButtonEmpty, -} from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiSpacer, EuiText } from '@elastic/eui'; - -import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; - -import { UIM_PIPELINES_LIST_LOAD } from '../../constants'; - -export const PipelinesList: React.FunctionComponent = () => { - const { services } = useKibana(); - - // Track component loaded - useEffect(() => { - services.metric.trackUiMetric(UIM_PIPELINES_LIST_LOAD); - }, [services.metric]); - - return ( - - - - - -

- -

-
- - - - - -
-
- - - - - - - - -
-
- ); -}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/table.tsx b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/table.tsx new file mode 100644 index 0000000000000..fb79c062c7722 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/table.tsx @@ -0,0 +1,91 @@ +/* + * 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, { FunctionComponent } from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiInMemoryTable, EuiLink, EuiButton } from '@elastic/eui'; + +import { Pipeline } from '../../../../common/types'; + +export interface Props { + pipelines: Pipeline[]; + onReloadClick: () => void; + onEditPipelineClick: (pipeline: Pipeline) => void; + onDeletePipelineClick: (pipeline: Pipeline) => void; + onViewPipelineClick: (pipeline: Pipeline) => void; +} + +export const PipelineTable: FunctionComponent = ({ + pipelines, + onReloadClick, + onEditPipelineClick, + onDeletePipelineClick, + onViewPipelineClick, +}) => { + return ( + + {i18n.translate('xpack.ingestPipelines.list.table.reloadButtonLabel', { + defaultMessage: 'Reload', + })} + + ), + box: { + incremental: true, + }, + }} + pagination={{ + initialPageSize: 10, + pageSizeOptions: [10, 20, 50], + }} + columns={[ + { + field: 'name', + name: i18n.translate('xpack.ingestPipelines.list.table.nameColumnTitle', { + defaultMessage: 'Name', + }), + render: (name: any, pipeline) => ( + onViewPipelineClick(pipeline)}>{name} + ), + }, + { + name: i18n.translate('xpack.ingestPipelines.list.table.actionColumnTitle', { + defaultMessage: 'Actions', + }), + actions: [ + { + name: i18n.translate('xpack.ingestPipelines.list.table.editActionLabel', { + defaultMessage: 'Edit', + }), + description: i18n.translate( + 'xpack.ingestPipelines.list.table.editActionDescription', + { defaultMessage: 'Edit this pipeline' } + ), + type: 'icon', + icon: 'pencil', + onClick: onEditPipelineClick, + }, + { + name: i18n.translate('xpack.ingestPipelines.list.table.deleteActionLabel', { + defaultMessage: 'Delete', + }), + description: i18n.translate( + 'xpack.ingestPipelines.list.table.deleteActionDescription', + { defaultMessage: 'Delete this pipeline' } + ), + type: 'icon', + icon: 'trash', + color: 'danger', + onClick: onDeletePipelineClick, + }, + ], + }, + ]} + items={pipelines ?? []} + /> + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/services/api.ts b/x-pack/plugins/ingest_pipelines/public/application/services/api.ts index 71ebb4b25d829..98d5c0db7b867 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/services/api.ts +++ b/x-pack/plugins/ingest_pipelines/public/application/services/api.ts @@ -6,6 +6,7 @@ import { HttpSetup } from 'src/core/public'; import { API_BASE_PATH } from '../../../common/constants'; +import { Pipeline } from '../../../common/types'; import { UseRequestConfig, sendRequest as _sendRequest, @@ -15,11 +16,11 @@ import { export class ApiService { private client: HttpSetup | undefined; - private useRequest(config: UseRequestConfig) { + private useRequest(config: UseRequestConfig) { if (!this.client) { throw new Error('Api service has not be initialized.'); } - return _useRequest(this.client, config); + return _useRequest(this.client, config); } public setup(httpClient: HttpSetup): void { @@ -27,7 +28,7 @@ export class ApiService { } public useLoadPipelines() { - return this.useRequest({ + return this.useRequest({ path: API_BASE_PATH, method: 'get', }); diff --git a/x-pack/plugins/ingest_pipelines/public/shared_imports.ts b/x-pack/plugins/ingest_pipelines/public/shared_imports.ts index 1a278a04adedf..7bcba3a638a97 100644 --- a/x-pack/plugins/ingest_pipelines/public/shared_imports.ts +++ b/x-pack/plugins/ingest_pipelines/public/shared_imports.ts @@ -3,6 +3,8 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { useKibana as _useKibana } from '../../../../src/plugins/kibana_react/public'; +import { AppServices } from './application'; export { SendRequestConfig, @@ -11,3 +13,7 @@ export { sendRequest, useRequest, } from '../../../../src/plugins/es_ui_shared/public/request/np_ready_request'; + +export { SectionLoading } from '../../../../src/plugins/es_ui_shared/public'; + +export const useKibana = () => _useKibana();