diff --git a/openmetadata-ui/src/main/resources/ui/src/axiosAPIs/elastic-index-API.ts b/openmetadata-ui/src/main/resources/ui/src/axiosAPIs/elastic-index-API.ts index b8110fa63cb..5cbceec2a84 100644 --- a/openmetadata-ui/src/main/resources/ui/src/axiosAPIs/elastic-index-API.ts +++ b/openmetadata-ui/src/main/resources/ui/src/axiosAPIs/elastic-index-API.ts @@ -31,12 +31,16 @@ export const reIndexByPublisher = async ({ runMode, entities = ['all'], recreateIndex = true, + batchSize, + flushIntervalInSec, }: CreateEventPublisherJob) => { const payload = { publisherType: PublisherType.ElasticSearch, runMode, recreateIndex, entities, + batchSize, + flushIntervalInSec, }; const res = await axiosClient.post('/indexResource/reindex', payload); diff --git a/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts b/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts index 9d3528a3a53..badbb4a5bd6 100644 --- a/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts +++ b/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts @@ -258,6 +258,7 @@ export const SOCKET_EVENTS = { ACTIVITY_FEED: 'activityFeed', TASK_CHANNEL: 'taskChannel', MENTION_CHANNEL: 'mentionChannel', + JOB_STATUS: 'jobStatus', }; export const IN_PAGE_SEARCH_ROUTES: Record> = { diff --git a/openmetadata-ui/src/main/resources/ui/src/constants/elasticsearch.constant.ts b/openmetadata-ui/src/main/resources/ui/src/constants/elasticsearch.constant.ts index 461b8027997..46ab97fb474 100644 --- a/openmetadata-ui/src/main/resources/ui/src/constants/elasticsearch.constant.ts +++ b/openmetadata-ui/src/main/resources/ui/src/constants/elasticsearch.constant.ts @@ -49,3 +49,32 @@ export const ELASTIC_SEARCH_INDEX_ENTITIES = [ label: 'Tag', }, ]; + +export const ELASTIC_SEARCH_INITIAL_VALUES = { + entities: [ + 'table', + 'topic', + 'dashboard', + 'pipeline', + 'mlmodel', + 'bot', + 'user', + 'team', + 'glossaryTerm', + 'tag', + ], + batchSize: 100, + flushIntervalInSec: 30, + recreateIndex: false, +}; + +export const RECREATE_INDEX_OPTIONS = [ + { + label: 'Yes', + value: true, + }, + { + label: 'No', + value: false, + }, +]; diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/ElasticSearchIndexPage/elastic-re-index-modal.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/ElasticSearchIndexPage/elastic-re-index-modal.component.tsx new file mode 100644 index 00000000000..108c3840b58 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/pages/ElasticSearchIndexPage/elastic-re-index-modal.component.tsx @@ -0,0 +1,102 @@ +/* + * Copyright 2022 Collate + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Checkbox, Col, Form, Input, Modal, Row, Select } from 'antd'; +import React, { useState } from 'react'; +import { + ELASTIC_SEARCH_INDEX_ENTITIES, + ELASTIC_SEARCH_INITIAL_VALUES, + RECREATE_INDEX_OPTIONS, +} from '../../constants/elasticsearch.constant'; +import { CreateEventPublisherJob } from '../../generated/api/createEventPublisherJob'; + +interface ReIndexAllModalInterface { + visible: boolean; + onCancel: () => void; + onSave?: (data: CreateEventPublisherJob) => void; + confirmLoading: boolean; +} + +const ReIndexAllModal = ({ + visible, + onCancel, + onSave, + confirmLoading, +}: ReIndexAllModalInterface) => { + const [entities, setEntities] = useState( + ELASTIC_SEARCH_INITIAL_VALUES.entities + ); + + return ( + +
+ + + + + + + +
+
+ ); +}; + +export default ReIndexAllModal; diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/ElasticSearchIndexPage/elastic-search-index.page.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/ElasticSearchIndexPage/elastic-search-index.page.tsx index ab2d2b12364..a2e5aa0ec4d 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/ElasticSearchIndexPage/elastic-search-index.page.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/ElasticSearchIndexPage/elastic-search-index.page.tsx @@ -11,20 +11,8 @@ * limitations under the License. */ -import { QuestionCircleOutlined, ReloadOutlined } from '@ant-design/icons'; -import { - Badge, - Button, - Card, - Checkbox, - Col, - Row, - Skeleton, - Space, - Switch, - Tooltip, - Typography, -} from 'antd'; +import { ReloadOutlined } from '@ant-design/icons'; +import { Badge, Button, Card, Col, Divider, Row, Space } from 'antd'; import { AxiosError } from 'axios'; import { isEmpty, startCase } from 'lodash'; import React, { useEffect, useState } from 'react'; @@ -33,10 +21,11 @@ import { reIndexByPublisher, } from '../../axiosAPIs/elastic-index-API'; import RichTextEditorPreviewer from '../../components/common/rich-text-editor/RichTextEditorPreviewer'; -import { ELASTIC_SEARCH_INDEX_ENTITIES } from '../../constants/elasticsearch.constant'; +import { useWebSocketConnector } from '../../components/web-scoket/web-scoket.provider'; +import { SOCKET_EVENTS } from '../../constants/constants'; +import { CreateEventPublisherJob } from '../../generated/api/createEventPublisherJob'; import { EventPublisherJob, - PublisherType, RunMode, } from '../../generated/settings/eventPublisherJob'; import { useAuth } from '../../hooks/authHooks'; @@ -48,6 +37,7 @@ import { import SVGIcons from '../../utils/SvgUtils'; import { getDateTimeByTimeStampWithZone } from '../../utils/TimeUtils'; import { showErrorToast, showSuccessToast } from '../../utils/ToastUtils'; +import ReIndexAllModal from './elastic-re-index-modal.component'; import './elastic-search-index.style.less'; const ElasticSearchIndexPage = () => { @@ -57,19 +47,11 @@ const ElasticSearchIndexPage = () => { const { isAdminUser } = useAuth(); const [batchLoading, setBatchLoading] = useState(false); const [streamLoading, setStreamLoading] = useState(false); - const [recreateIndex, setRecreateIndex] = useState(false); - const [entities, setEntities] = useState([ - 'table', - 'topic', - 'dashboard', - 'pipeline', - 'mlmodel', - 'bot', - 'user', - 'team', - 'glossaryTerm', - 'tag', - ]); + const [confirmLoading, setConfirmLoading] = useState(false); + + const [isModalOpen, setModalOpen] = useState(false); + + const { socket } = useWebSocketConnector(); const fetchBatchReIndexedData = async () => { try { @@ -97,14 +79,13 @@ const ElasticSearchIndexPage = () => { } }; - const performReIndexAll = async (mode: RunMode) => { + const performReIndexAll = async (data: CreateEventPublisherJob) => { try { + setConfirmLoading(true); await reIndexByPublisher({ - runMode: mode, - entities, - recreateIndex, - publisherType: PublisherType.ElasticSearch, - }); + ...data, + runMode: RunMode.Batch, + } as CreateEventPublisherJob); showSuccessToast(jsonData['api-success-messages']['fetch-re-index-all']); } catch (err) { @@ -112,6 +93,9 @@ const ElasticSearchIndexPage = () => { err as AxiosError, jsonData['api-error-messages']['update-re-index-all'] ); + } finally { + setModalOpen(false); + setConfirmLoading(false); } }; @@ -120,6 +104,25 @@ const ElasticSearchIndexPage = () => { fetchStreamReIndexedData(); }; + useEffect(() => { + if (socket) { + socket.on(SOCKET_EVENTS.JOB_STATUS, (newActivity) => { + if (newActivity) { + const activity = JSON.parse(newActivity) as EventPublisherJob; + if (activity.runMode === RunMode.Batch) { + setBatchJobData(activity); + } else { + setStreamJobData(activity); + } + } + }); + } + + return () => { + socket && socket.off(SOCKET_EVENTS.JOB_STATUS); + }; + }, [socket]); + useEffect(() => { fetchData(); }, []); @@ -128,277 +131,216 @@ const ElasticSearchIndexPage = () => {
- - - -
-
- - - ElasticSearch - - -
- Mode : - - {startCase(batchJobData?.runMode) || '--'} - -
-
- Status : - - - {batchJobData?.status && ( - - )} - - {getEventPublisherStatusText( - batchJobData?.status - ) || '--'} - - - -
- -
- - Index stats - {' '} - : - - {!isEmpty(batchJobData) ? ( - - - - - - - - ) : ( - '--' - )} - -
- -
- - Last Updated - {' '} - : - - {batchJobData?.timestamp - ? getDateTimeByTimeStampWithZone( - batchJobData?.timestamp - ) - : '--'} - -
-
- -
- - Last Failed At: - -

- {batchJobData?.failureDetails?.lastFailedAt - ? getDateTimeByTimeStampWithZone( - batchJobData?.failureDetails?.lastFailedAt - ) - : '--'} -

-
-
- - Last error: - - - {batchJobData?.failureDetails?.lastFailedReason ? ( - - ) : ( - '--' - )} - -
-
-
+ + + + } + loading={batchLoading} + size="small" + title="ElasticSearch"> + + + +
+ Mode : + + {startCase(batchJobData?.runMode) || '--'} +
- - - - - - Recreate indexes  - - - - - -
- - Entities - - setEntities(values as string[])}> - - {ELASTIC_SEARCH_INDEX_ENTITIES.map((option) => ( - - - {option.label} - - - ))} - - -
- - - - -
-
- - - - -
- ElasticSearch - -
- - -
- Mode : - - {startCase(streamJobData?.runMode) || '--'} - -
-
- Status : - + +
+ Status : + + + {batchJobData?.status && ( + + )} + + {getEventPublisherStatusText(batchJobData?.status) || + '--'} + + + +
+ +
+ Index stats : + + {!isEmpty(batchJobData) ? ( - {streamJobData?.status && ( - - )} - - {getEventPublisherStatusText( - streamJobData?.status - ) || '--'} - - - -
+ -
- Last Updated : - - {streamJobData?.timestamp - ? getDateTimeByTimeStampWithZone( - streamJobData?.timestamp - ) - : '--'} - -
- -
- -
- - Last Failed At: - -

- {streamJobData?.failureDetails?.lastFailedAt - ? getDateTimeByTimeStampWithZone( - streamJobData?.failureDetails?.lastFailedAt - ) - : '--'} -

-
-
- Last error : - - {streamJobData?.failureDetails?.lastFailedReason ? ( - - ) : ( - '--' - )} - -
-
+ + + + + ) : ( + '--' + )} +
- - - - + +
+ Last Updated : + + {batchJobData?.timestamp + ? getDateTimeByTimeStampWithZone( + batchJobData?.timestamp + ) + : '--'} + +
+ +
+ Last Failed At: +

+ {batchJobData?.failureDetails?.lastFailedAt + ? getDateTimeByTimeStampWithZone( + batchJobData?.failureDetails?.lastFailedAt + ) + : '--'} +

+
+ + + + + Last error: + + {batchJobData?.failureDetails?.lastFailedReason ? ( + + ) : ( + '--' + )} + + + + + + + } + size="small" + title="Refresh log" + onClick={fetchStreamReIndexedData} + /> + } + loading={streamLoading} + size="small" + title="ElasticSearch"> + +
+ Mode : + + {startCase(streamJobData?.runMode) || '--'} + +
+
+ Status : + + + {streamJobData?.status && ( + + )} + + {getEventPublisherStatusText(streamJobData?.status) || + '--'} + + + +
+ +
+ Last Updated : + + {streamJobData?.timestamp + ? getDateTimeByTimeStampWithZone(streamJobData?.timestamp) + : '--'} + +
+
+ Last Failed At: +

+ {streamJobData?.failureDetails?.lastFailedAt + ? getDateTimeByTimeStampWithZone( + streamJobData?.failureDetails?.lastFailedAt + ) + : '--'} +

+
+
+
+ Last error : + + {streamJobData?.failureDetails?.lastFailedReason ? ( + + ) : ( + '--' + )} + +
+
+ setModalOpen(false)} + onSave={performReIndexAll} + />
); }; diff --git a/openmetadata-ui/src/main/resources/ui/src/styles/antd-master.less b/openmetadata-ui/src/main/resources/ui/src/styles/antd-master.less index 357827d5c36..b9103456d4b 100644 --- a/openmetadata-ui/src/main/resources/ui/src/styles/antd-master.less +++ b/openmetadata-ui/src/main/resources/ui/src/styles/antd-master.less @@ -18,3 +18,4 @@ @import url('./components/table.less'); @import url('./components/toggle-switch.less'); @import url('./components/button.less'); +@import url('./components/card.less'); diff --git a/openmetadata-ui/src/main/resources/ui/src/styles/components/card.less b/openmetadata-ui/src/main/resources/ui/src/styles/components/card.less new file mode 100644 index 00000000000..a6f7323d79a --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/styles/components/card.less @@ -0,0 +1,4 @@ +.ant-card { + box-shadow: @card-shadow; + border: 1px #dde3ea solid; +} diff --git a/openmetadata-ui/src/main/resources/ui/src/styles/x-master.css b/openmetadata-ui/src/main/resources/ui/src/styles/x-master.css index 06143674b2b..d125b1d673a 100644 --- a/openmetadata-ui/src/main/resources/ui/src/styles/x-master.css +++ b/openmetadata-ui/src/main/resources/ui/src/styles/x-master.css @@ -1060,14 +1060,6 @@ code { background-color: #dbd1f9; } -.ant-select-single:not(.ant-select-customize-input) .ant-select-selector { - padding: 0px 4px; -} - -.ant-select-single .ant-select-selector .ant-select-selection-search { - left: 4px; -} - @media only screen and (max-width: 1440px) { #left-panel { width: 284px;