From 79a7d02e08568b24c425000b977dcde78a0997f1 Mon Sep 17 00:00:00 2001 From: Arpit Bandejiya Date: Wed, 26 Apr 2023 17:11:43 +0530 Subject: [PATCH 1/4] Edit page Signed-off-by: Arpit Bandejiya --- packages/osd-opensearch/package.json | 2 +- .../public/components/breadcrumbs.ts | 46 +- .../public/components/pit_edit/edit_page.tsx | 147 ++ .../public/components/pit_edit/index.ts | 6 + .../public/components/pit_table/pit_table.tsx | 1347 +++++++++-------- .../public/components/utils.ts | 319 ++-- .../mount_management_section.tsx | 102 +- .../public/services.ts | 86 +- .../server/saved_objects/pit_saved_object.ts | 77 +- yarn.lock | 16 - 10 files changed, 1160 insertions(+), 988 deletions(-) create mode 100644 src/plugins/point_in_time_management/public/components/pit_edit/edit_page.tsx create mode 100644 src/plugins/point_in_time_management/public/components/pit_edit/index.ts diff --git a/packages/osd-opensearch/package.json b/packages/osd-opensearch/package.json index 02fcddb36e6f..44404a9ae5a3 100644 --- a/packages/osd-opensearch/package.json +++ b/packages/osd-opensearch/package.json @@ -12,7 +12,7 @@ "osd:watch": "../../scripts/use_node scripts/build --watch" }, "dependencies": { - "@opensearch-project/opensearch": "^2.1.0", + "@opensearch-project/opensearch": "^2.2.0", "@osd/dev-utils": "1.0.0", "abort-controller": "^3.0.0", "chalk": "^4.1.0", diff --git a/src/plugins/point_in_time_management/public/components/breadcrumbs.ts b/src/plugins/point_in_time_management/public/components/breadcrumbs.ts index c20af07652b9..b5bd41852f88 100644 --- a/src/plugins/point_in_time_management/public/components/breadcrumbs.ts +++ b/src/plugins/point_in_time_management/public/components/breadcrumbs.ts @@ -1,17 +1,29 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { i18n } from '@osd/i18n'; - -export function getListBreadcrumbs() { - return [ - { - text: i18n.translate('pitManagement.listBreadcrumb', { - defaultMessage: 'Point in time', - }), - href: `/`, - }, - ]; -} +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { i18n } from '@osd/i18n'; + +export function getListBreadcrumbs() { + return [ + { + text: i18n.translate('pitManagement.listBreadcrumb', { + defaultMessage: 'Point in time', + }), + href: `/`, + }, + ]; +} + +export function getEditBreadcrumbs() { + return [ + ...getListBreadcrumbs(), + { + text: i18n.translate('dataSourcesManagement.dataSources.createBreadcrumb', { + defaultMessage: 'Edit', + }), + href: `/edit`, + }, + ]; +} diff --git a/src/plugins/point_in_time_management/public/components/pit_edit/edit_page.tsx b/src/plugins/point_in_time_management/public/components/pit_edit/edit_page.tsx new file mode 100644 index 000000000000..cfbe92240f93 --- /dev/null +++ b/src/plugins/point_in_time_management/public/components/pit_edit/edit_page.tsx @@ -0,0 +1,147 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useState } from 'react'; +import { RouteComponentProps, withRouter } from 'react-router-dom'; +import { useMount } from 'react-use'; +import { i18n } from '@osd/i18n'; +import { + EuiCheckbox, + EuiDescribedFormGroup, + EuiFieldNumber, + EuiFieldText, + EuiFlexGroup, + EuiFlexItem, + EuiForm, + EuiFormRow, + EuiPageContent, + EuiPageHeader, + EuiPageHeaderSection, + EuiSpacer, + EuiTitle, +} from '@elastic/eui'; +import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; +import { PointInTimeManagementContext } from '../../types'; +import { getEditBreadcrumbs } from '../breadcrumbs'; + +export const PITEdit: React.FunctionComponent> = ( + props: RouteComponentProps<{ id: string }> +) => { + const { setBreadcrumbs } = useOpenSearchDashboards().services; + const PitID: string = props.match.params.id; + useMount(() => { + console.log(PitID); + setBreadcrumbs(getEditBreadcrumbs()); + }); + const [checked, setChecked] = useState(false); + const onChange = (e) => { + setChecked(e.target.checked); + }; + + return ( + <> + + + + +

Time Configurations

+
+
+
+ + + Add time} + description={ +

+ The keep_alive time is the amount of time the PIT is kept active. The time entered + will also be the amount of time a PIT is extended by when it is queried. A PITs time + can not be extended by an amount less than the one entered. The keep alive time can + not exceed a maximum of X hours. +

+ } + > + + + + + + + + + + +
+
+
+ + + + + +

Dashboard PIT configurations

+
+
+
+ + + PIT name} + description={

Choose a name for a PIT that is available in OpenSearch Dashboards.

} + > + + + +
+ Post-expiration actions} + description={ +

+ PIT data is lost once it expires you have the option to keep the PIT metadata after + after expiration. expiration. expiration. expiration. expiration. You can also + choose to keep the Dashboard Object expiration. This object will be converted to an + Index Pattern and Pattern and it will reference data. +

+ } + > + + <> + onChange(e)} + /> + onChange(e)} + disabled={true} + /> + + +
+
+
+ + ); +}; + +export const PITEditWithRouter = withRouter(PITEdit); diff --git a/src/plugins/point_in_time_management/public/components/pit_edit/index.ts b/src/plugins/point_in_time_management/public/components/pit_edit/index.ts new file mode 100644 index 000000000000..7a6f6aca2ee3 --- /dev/null +++ b/src/plugins/point_in_time_management/public/components/pit_edit/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { PITEditWithRouter } from './edit_page'; diff --git a/src/plugins/point_in_time_management/public/components/pit_table/pit_table.tsx b/src/plugins/point_in_time_management/public/components/pit_table/pit_table.tsx index 44aba9f682fb..62bbf61514d5 100644 --- a/src/plugins/point_in_time_management/public/components/pit_table/pit_table.tsx +++ b/src/plugins/point_in_time_management/public/components/pit_table/pit_table.tsx @@ -1,667 +1,680 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useEffect, useState } from 'react'; -import { RouteComponentProps, withRouter } from 'react-router-dom'; -import { useEffectOnce, useMount } from 'react-use'; -import { - EuiButton, - EuiInMemoryTable, - EuiPageContent, - EuiPageContentBody, - EuiSpacer, - EuiSearchBarProps, - Query, - EuiPageContentHeader, - EuiPageContentHeaderSection, - EuiTitle, - EuiText, - EuiFlexGroup, - EuiFlexItem, - EuiBadge, - EuiSelect, - EuiConfirmModal, - EuiFormRow, - EuiFieldText, -} from '@elastic/eui'; -import { i18n } from '@osd/i18n'; -import { FormattedMessage } from '@osd/i18n/react'; -import moment, { now } from 'moment'; -import { SavedObjectReference } from 'src/core/public'; -import { getListBreadcrumbs } from '../breadcrumbs'; -import { PointInTimeManagementContext } from '../../types'; -import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; -import { - getDataSources, - PointInTime, - createSavedObject, - getSavedPits, -} from '../utils'; -import { EmptyState, NoDataSourceState } from './empty_state'; -// import { PageHeader } from './page_header'; -import { getServices, Services } from '../../services'; -// import { dataSource } from 'src/plugins/data_source/server/saved_objects'; - -export interface DataSourceItem { - id: string; - name: string; - title: string; - sort: string; -} - -export interface DashboardPitItem { - id: string; - name: string; - creation_time: number; - keep_alive: number; -} - -export interface PitItem { - pit_id: string; - name: string; - creation_time: number; - keep_alive: number; - dataSource: string; - expiry: number; -} - -const PITTable = ({ history }: RouteComponentProps) => { - const { - setBreadcrumbs, - savedObjects, - notifications: { toasts }, - http, - } = useOpenSearchDashboards().services; - - useMount(() => { - setBreadcrumbs(getListBreadcrumbs()); - }); - - const services: Services = getServices(http); - - // TODO: update this for cases when some data source name is default - const defaultDataSource: DataSourceItem = { id: '', title: '', sort: '0', name: 'default' }; - - // TODO: use APIs to fetch PITs and update the table and message - const [loading, setLoading] = useState(false); - const [pits, setPits] = useState([]); - const [pitsToDelete, setPitsToDelete] = useState([]); - const [selectedPits, setSelectedPits] = useState([]); - // const [dashboardPits, setDashboardPits] = useState([]); - const [message, setMessage] = useState(); - - const [dataSources, setDataSources] = useState([defaultDataSource]); - const [dataSource, setDataSource] = useState(''); - const [isModalVisible, setIsModalVisible] = useState(false); - - useEffectOnce(() => { - fetchDataSources(); - }); - - useEffect(() => { - getPits(dataSource); - }, [dataSource]); - - const fetchDataSources = () => { - getDataSources(savedObjects.client) - .then((fetchedDataSources) => { - if (fetchedDataSources?.length) { - setDataSources( - fetchedDataSources - .concat([defaultDataSource]) - .sort((a, b) => a.sort.localeCompare(b.sort)) - ); - } - }) - .catch(() => { - toasts.addDanger( - i18n.translate('pitManagement.pitTable.fetchDataSourceError', { - defaultMessage: 'Unable to find existing data sources', - }) - ); - }); - }; - - const getPits = (dataSourceId?: string) => { - // setMessage(<>Loading PITs...); - setLoading(true); - console.log(dataSourceId); - // let dataSourceId: string | undefined; - const dataSourceName = dataSourceId; - if (dataSourceId === '') { - dataSourceId = undefined; - } else if (dataSourceId === 'noDataSource') { - // setMessage(); - setLoading(false); - setPits([]); - return; - } else { - const dataSource = dataSources.filter((x) => x.title === dataSourceId); - if (dataSource.length === 0) { - toasts.addDanger( - i18n.translate('pitManagement.pitTable.fetchDataSourceError', { - defaultMessage: 'Unable to find data source', - }) - ); - setMessage(); - setPits([]); - return; - } else { - dataSourceId = dataSource[0].id; - } - } - setMessage(); - console.log(dataSourceId); - - services - .getAllPits(dataSourceId) - .then((fetchedPits) => { - getSavedPits(savedObjects.client) - .then((fetchedDashboardPits) => { - // if (fetchedDataSources?.length) { - // setDashboardPits(fetchedDataSources); - // } - - setLoading(false); - if (fetchedPits?.resp?.pits) { - let expiredPits: DashboardPitItem[] = []; - if (dataSourceId === undefined) { - expiredPits = fetchedDashboardPits.filter( - (x) => !fetchedPits?.resp?.pits.some((x2) => x.attributes.id === x2.pit_id) - ); - } - console.log('expired', expiredPits); - setPits( - fetchedPits?.resp?.pits - .map((val) => { - const date = moment(val.creation_time); - let formattedDate = date.format('MMM D @ HH:mm:ss'); - const expiry = val.creation_time + val.keep_alive; - const dashboardPit = fetchedDashboardPits.filter( - (x) => x.attributes.id === val.pit_id - ); - console.log(dashboardPit); - if (dashboardPit.length > 0) { - formattedDate = dashboardPit[0].attributes.name; - } - - return { - pit_id: val.pit_id, - name: formattedDate, - creation_time: val.creation_time, - keep_alive: val.keep_alive, - dataSource: dataSourceName, - expiry, - }; - }) - .concat( - expiredPits.map((x) => ({ - pit_id: x.attributes.id, - name: x.attributes.name, - creation_time: x.attributes.creation_time, - keep_alive: x.attributes.keepAlive, - dataSource: dataSourceName, - expiry: x.attributes.creation_time + x.attributes.keepAlive, - })) - ) - ); - } - - console.log(fetchedPits?.resp?.pits as PitItem[]); - console.log(pits.length); - }) - .catch(() => { - toasts.addDanger( - i18n.translate('pitManagement.pitTable.fetchPitError', { - defaultMessage: 'Unable to load existing dashboard PITs', - }) - ); - }); - }) - .catch(() => { - setLoading(false); - toasts.addDanger( - i18n.translate('pitManagement.pitTable.fetchDataSourceError', { - defaultMessage: 'Unable to fetch point in time objects.', - }) - ); - }); - }; - - const createPointInTime = () => { - // setIsFlyoutVisible(false); - const pit: PointInTime = { - id: - 'o463QQEKbXktaW5kZXgtMRZtN2RWMHdaRlNILThIMUVWWDJJMVBRABZxMlNNZVdPZVRGbVR6MUxPc1RZYkx3AAAAAAAAAAAjFmhZdDNoTk9hUlBlVng2RVNIMUNhelEBFm03ZFYwd1pGU0gtOEgxRVZYMkkxUFEAAA==', - keepAlive: 600000, - creation_time: 1681386155468, - name: 'PIT-my-index-2', // Todo create pit and fill the pit id - }; - - const reference: SavedObjectReference = { - id: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f', - type: 'index-pattern', - name: 'opensearch_dashboards_sample_data_ecommerce', - }; - createSavedObject(pit, savedObjects.client, reference); - }; - - const getBackendPits = () => { - getSavedPits(savedObjects.client).then((fetchedDashboardPits) => { - console.log(fetchedDashboardPits); - }); - }; - - const deletePit = (pit) => { - let dataSourceId: string | undefined = ''; - if (dataSource === '') { - dataSourceId = undefined; - } else { - const dataSourceObj = dataSources.filter((x) => x.title === dataSource); - if (dataSourceObj.length === 0) { - toasts.addDanger( - i18n.translate('pitManagement.pitTable.fetchDataSourceError', { - defaultMessage: 'Unable to find data source', - }) - ); - setMessage(); - setPits([]); - return; - } else { - dataSourceId = dataSourceObj[0].id; - } - } - services.deletePits([pit.pit_id], dataSourceId).then((deletedPits) => { - console.log(deletedPits); - getPits(dataSource); - }); - }; - - const DeleteModal = ({}) => { - const closeModal = () => { - setIsModalVisible(false); - }; - - const [value, setValue] = useState(''); - const onChange = (e) => { - setValue(e.target.value); - console.log(pitsToDelete[0]); - }; - - let modal; - - if (isModalVisible) { - const expired = moment(pitsToDelete[0].expiry).isBefore(now()); - if (expired) { - modal = ( - { - closeModal(); - deletePit(pitsToDelete[0]); - setPitsToDelete([]); - }} - confirmButtonText="Delete PIT" - cancelButtonText="Cancel" - buttonColor="danger" - > - The PIT will be permanently deleted. This action is irreversible. - - - ); - } else { - modal = ( - { - closeModal(); - deletePit(pitsToDelete[0]); - setPitsToDelete([]); - }} - confirmButtonText="Delete PIT" - cancelButtonText="Cancel" - buttonColor="danger" - confirmButtonDisabled={value !== pitsToDelete[0].name} - > - - This is an active PIT. Deleting it will permanently remove data and may cause - unexpected behavior in saved objects that use this PIT. This action is irreversible. - - - - - - - ); - } - } - - return
{modal}
; - }; - - const displayDelete = (pit) => { - setPitsToDelete([pit]); - setIsModalVisible(true); - }; - - const actions = [ - { - name: 'Add Time', - description: 'Add Time', - icon: 'clock', - type: 'icon', - onClick: fetchDataSources, - }, - { - name: 'Configure PIT', - description: 'Configure PIT', - icon: 'pencil', - type: 'icon', - onClick: fetchDataSources, - }, - { - name: 'Delete', - description: 'Delete PIT', - icon: 'trash', - type: 'icon', - color: 'danger', - onClick: displayDelete, - }, - ]; - - const Timer = ({ endTime }) => { - const getTime = () => - moment(endTime).isBefore(now()) ? 'Expired' : '~ ' + moment(endTime).fromNow(true); - - const getBadgeColor = () => { - const timeLeft = endTime - moment.now().valueOf(); - if (timeLeft < 0) { - return 'hollow'; - } else if (timeLeft < 10 * 60 * 1000) { - return 'danger'; - } else { - return 'default'; - } - }; - - const [time, setTime] = useState(() => getTime()); - const [badge, setBadge] = useState(() => getBadgeColor()); - - const updateTime = () => { - setInterval(() => { - setTime(() => getTime()); - setBadge(() => getBadgeColor()); - }, 30000); - }; - - useEffectOnce(updateTime); - - return {time}; - }; - - const columns = [ - { - field: 'name', - name: i18n.translate('pitManagement.pitTable.nameColumnName', { - defaultMessage: 'Name', - }), - }, - { - field: 'expiry', - name: i18n.translate('pitManagement.pitTable.expiresColumnName', { - defaultMessage: 'Expires', - }), - render: (t: number) => { - // return prettyDuration(moment(t).format('YYYY-MM-DDTHH:mm:ss'),'now',[], 'MMMM Do YYYY, HH:mm:ss.SSS') - return ; - }, - sortable: true, - }, - { - field: 'dataSource', - name: i18n.translate('pitManagement.pitTable.dataSourceColumnName', { - defaultMessage: 'Data Source', - }), - render: (t: string) => { - // return prettyDuration(moment(t).format('YYYY-MM-DDTHH:mm:ss'),'now',[], 'MMMM Do YYYY, HH:mm:ss.SSS') - return t === '' ? 'default' : t; - }, - }, - { - field: 'creation_time', - name: i18n.translate('pitManagement.pitTable.createdColumnName', { - defaultMessage: 'Created', - }), - render: (t: number) => { - const date = moment(t); - const formattedDate = date.format('MMM D, YYYY HH:mm:ss'); - return formattedDate; - }, - sortable: true, - }, - { - name: i18n.translate('pitManagement.pitTable.actionsColumnName', { - defaultMessage: 'Actions', - }), - actions, - }, - ]; - - const handleDeletePit = () => { - let dataSourceId: string | undefined = ''; - if (dataSource === '') { - dataSourceId = undefined; - } else { - const dataSourceObj = dataSources.filter((x) => x.title === dataSource); - if (dataSourceObj.length === 0) { - toasts.addDanger( - i18n.translate('pitManagement.pitTable.fetchDataSourceError', { - defaultMessage: 'Unable to find data source', - }) - ); - setMessage(); - setPits([]); - return; - } else { - dataSourceId = dataSourceObj[0].id; - } - } - - services - .deletePits( - selectedPits.map((x) => x.pit_id), - dataSourceId - ) - .then((deletedPits) => { - console.log(deletedPits); - getPits(dataSource); - }); - }; - - const renderToolsRight = () => { - return [ - - - , - ]; - }; - - const renderToolsLeft = () => { - return [ - ({ - value: source.title, - text: source.name, - }))} - value={dataSource} - onChange={(e) => setDataSource(e.target.value)} - />, - ]; - }; - - // function onQueryChange({ query }: { query: Query }) { - // if (query.ast.getFieldClauses('dataSource')) { - // const selectedDataSource = query.ast.getFieldClauses('dataSource')[0].value as string; - // setDataSource(selectedDataSource); - // } else { - // setMessage(); - // setDataSource('noDataSource'); - // } - // } - - const search: EuiSearchBarProps = { - toolsLeft: renderToolsLeft(), - toolsRight: renderToolsRight(), - // defaultQuery: 'dataSource:""', - // onChange: onQueryChange, - box: { - incremental: true, - schema: true, - disabled: pits.length === 0, - }, - // filters: [ - // { - // type: 'field_value_selection', - // searchThreshold: 5, - // field: 'dataSource', - // name: i18n.translate('pitManagement.pitTable.dataSourceFilterName', { - // defaultMessage: 'Data Source', - // }), - // multiSelect: false, - // options: dataSources.map((source) => ({ - // value: source.title, - // name: source.name, - // view: `${source.title}`, - // })), - // }, - // ], - }; - - const onSelectionChange = (selected: PitItem[]) => { - setSelectedPits(selected); - }; - - const selection = { - onSelectionChange, - }; - - const pagination = { - initialPageSize: 10, - pageSizeOptions: [5, 10, 25, 50], - }; - - const PageHeader = () => { - const [refreshTime, setRefreshTime] = useState(moment.now()); - const [timeSinceRefresh, setTimeSinceRefresh] = useState( - moment(refreshTime).fromNow(true) - ); - - const handleClick = () => { - getPits(dataSource); - setRefreshTime(moment.now()); - }; - - const updateTimeSinceRefresh = () => { - setInterval(() => { - setTimeSinceRefresh(moment(refreshTime).fromNow(true)); - }, 30000); - }; - - useEffectOnce(updateTimeSinceRefresh); - - return ( - <> - - - -

- -

-
-
- - - Last updated {timeSinceRefresh} ago - - - - - - - - - - - - -
- -

- -

-
- - ); - }; - - return ( - <> - - - - - - - - - {/* Create PIT - Get PITs */} - - ); -}; - -export const PITTableWithRouter = withRouter(PITTable); +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useEffect, useState } from 'react'; +import { RouteComponentProps, withRouter } from 'react-router-dom'; +import { useEffectOnce, useMount } from 'react-use'; +import { + EuiButton, + EuiInMemoryTable, + EuiPageContent, + EuiPageContentBody, + EuiSpacer, + EuiSearchBarProps, + Query, + EuiPageContentHeader, + EuiPageContentHeaderSection, + EuiTitle, + EuiText, + EuiFlexGroup, + EuiFlexItem, + EuiBadge, + EuiSelect, + EuiConfirmModal, + EuiFormRow, + EuiFieldText, +} from '@elastic/eui'; +import { i18n } from '@osd/i18n'; +import { FormattedMessage } from '@osd/i18n/react'; +import moment, { now } from 'moment'; +import { SavedObjectReference } from 'src/core/public'; +import { getListBreadcrumbs } from '../breadcrumbs'; +import { PointInTimeManagementContext } from '../../types'; +import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; +import { getDataSources, PointInTime, createSavedObject, getSavedPits } from '../utils'; +import { EmptyState, NoDataSourceState } from './empty_state'; +// import { PageHeader } from './page_header'; +import { getServices, Services } from '../../services'; +// import { dataSource } from 'src/plugins/data_source/server/saved_objects'; + +export interface DataSourceItem { + id: string; + name: string; + title: string; + sort: string; +} + +export interface DashboardPitItem { + id: string; + name: string; + creation_time: number; + keep_alive: number; +} + +export interface PitItem { + pit_id: string; + name: string; + creation_time: number; + keep_alive: number; + dataSource: string; + expiry: number; +} + +const PITTable = ({ history }: RouteComponentProps) => { + const { + setBreadcrumbs, + savedObjects, + notifications: { toasts }, + http, + } = useOpenSearchDashboards().services; + + useMount(() => { + setBreadcrumbs(getListBreadcrumbs()); + }); + + const services: Services = getServices(http); + + // TODO: update this for cases when some data source name is default + const defaultDataSource: DataSourceItem = { id: '', title: '', sort: '0', name: 'default' }; + + // TODO: use APIs to fetch PITs and update the table and message + const [loading, setLoading] = useState(false); + const [pits, setPits] = useState([]); + const [pitsToDelete, setPitsToDelete] = useState([]); + const [selectedPits, setSelectedPits] = useState([]); + // const [dashboardPits, setDashboardPits] = useState([]); + const [message, setMessage] = useState(); + + const [dataSources, setDataSources] = useState([defaultDataSource]); + const [dataSource, setDataSource] = useState(''); + const [isModalVisible, setIsModalVisible] = useState(false); + + useEffectOnce(() => { + fetchDataSources(); + }); + + useEffect(() => { + getPits(dataSource); + }, [dataSource]); + + const fetchDataSources = () => { + getDataSources(savedObjects.client) + .then((fetchedDataSources) => { + if (fetchedDataSources?.length) { + setDataSources( + fetchedDataSources + .concat([defaultDataSource]) + .sort((a, b) => a.sort.localeCompare(b.sort)) + ); + } + }) + .catch(() => { + toasts.addDanger( + i18n.translate('pitManagement.pitTable.fetchDataSourceError', { + defaultMessage: 'Unable to find existing data sources', + }) + ); + }); + }; + + const navigateEdit = (pit) => { + console.log(pit); + history.push(`${pit.id}`); + }; + + const getPits = (dataSourceId?: string) => { + // setMessage(<>Loading PITs...); + setLoading(true); + console.log(dataSourceId); + // let dataSourceId: string | undefined; + const dataSourceName = dataSourceId; + if (dataSourceId === '') { + dataSourceId = undefined; + } else if (dataSourceId === 'noDataSource') { + // setMessage(); + setLoading(false); + setPits([]); + return; + } else { + const dataSource = dataSources.filter((x) => x.title === dataSourceId); + if (dataSource.length === 0) { + toasts.addDanger( + i18n.translate('pitManagement.pitTable.fetchDataSourceError', { + defaultMessage: 'Unable to find data source', + }) + ); + setMessage(); + setPits([]); + return; + } else { + dataSourceId = dataSource[0].id; + } + } + setMessage(); + console.log(dataSourceId); + + services + .getAllPits(dataSourceId) + .then((fetchedPits) => { + getSavedPits(savedObjects.client) + .then((fetchedDashboardPits) => { + // if (fetchedDataSources?.length) { + // setDashboardPits(fetchedDataSources); + // } + + setLoading(false); + if (fetchedPits?.resp?.pits) { + let expiredPits: DashboardPitItem[] = []; + if (dataSourceId === undefined) { + expiredPits = fetchedDashboardPits.filter( + (x) => !fetchedPits?.resp?.pits.some((x2) => x.attributes.id === x2.pit_id) + ); + } + console.log('expired', expiredPits); + setPits( + fetchedPits?.resp?.pits + .map((val) => { + const date = moment(val.creation_time); + let formattedDate = date.format('MMM D @ HH:mm:ss'); + const expiry = val.creation_time + val.keep_alive; + const dashboardPit = fetchedDashboardPits.filter( + (x) => x.attributes.pit_id === val.pit_id + ); + let isSavedObject = false; + if (dashboardPit.length > 0) { + isSavedObject = true; + return { + pit_id: val.pit_id, + id: dashboardPit[0].id, + name: dashboardPit[0].attributes.name, + creation_time: val.creation_time, + keep_alive: val.keep_alive, + dataSource: dataSourceName, + isSavedObject, + expiry, + }; + } + return { + pit_id: val.pit_id, + id: val.id, + name: formattedDate, + creation_time: val.creation_time, + keep_alive: val.keep_alive, + dataSource: dataSourceName, + isSavedObject, + expiry, + }; + }) + .concat( + expiredPits.map((x) => ({ + pit_id: x.attributes.pit_id, + name: x.attributes.name, + id: x.id, + creation_time: x.attributes.creation_time, + keep_alive: x.attributes.keepAlive, + dataSource: dataSourceName, + isSavedObject: true, + expiry: x.attributes.creation_time + x.attributes.keepAlive, + })) + ) + ); + } + + console.log(fetchedPits?.resp?.pits as PitItem[]); + console.log(pits.length); + }) + .catch(() => { + toasts.addDanger( + i18n.translate('pitManagement.pitTable.fetchPitError', { + defaultMessage: 'Unable to load existing dashboard PITs', + }) + ); + }); + }) + .catch(() => { + setLoading(false); + toasts.addDanger( + i18n.translate('pitManagement.pitTable.fetchDataSourceError', { + defaultMessage: 'Unable to fetch point in time objects.', + }) + ); + }); + }; + + const createPointInTime = () => { + // setIsFlyoutVisible(false); + const pit: PointInTime = { + pit_id: + 'o463QQEKbXktaW5kZXgtMRZtN2RWMHdaRlNILThIMUVWWDJJMVBRABZxMlNNZVdPZVRGbVR6MUxPc1RZYkx3AAAAAAAAAAAjFmhZdDNoTk9hUlBlVng2RVNIMUNhelEBFm03ZFYwd1pGU0gtOEgxRVZYMkkxUFEAAA==12', + keepAlive: 600000, + creation_time: 1681386155468, + name: 'PIT-my-index-2-3', // Todo create pit and fill the pit id + }; + + const reference: SavedObjectReference = { + id: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f', + type: 'index-pattern', + name: 'opensearch_dashboards_sample_data_ecommerce', + }; + createSavedObject(pit, savedObjects.client, reference); + }; + + const getBackendPits = () => { + getSavedPits(savedObjects.client).then((fetchedDashboardPits) => { + console.log(fetchedDashboardPits); + }); + }; + + const deletePit = (pit) => { + let dataSourceId: string | undefined = ''; + if (dataSource === '') { + dataSourceId = undefined; + } else { + const dataSourceObj = dataSources.filter((x) => x.title === dataSource); + if (dataSourceObj.length === 0) { + toasts.addDanger( + i18n.translate('pitManagement.pitTable.fetchDataSourceError', { + defaultMessage: 'Unable to find data source', + }) + ); + setMessage(); + setPits([]); + return; + } else { + dataSourceId = dataSourceObj[0].id; + } + } + services.deletePits([pit.pit_id], dataSourceId).then((deletedPits) => { + console.log(deletedPits); + getPits(dataSource); + }); + }; + + const DeleteModal = ({}) => { + const closeModal = () => { + setIsModalVisible(false); + }; + + const [value, setValue] = useState(''); + const onChange = (e) => { + setValue(e.target.value); + console.log(pitsToDelete[0]); + }; + + let modal; + + if (isModalVisible) { + const expired = moment(pitsToDelete[0].expiry).isBefore(now()); + if (expired) { + modal = ( + { + closeModal(); + deletePit(pitsToDelete[0]); + setPitsToDelete([]); + }} + confirmButtonText="Delete PIT" + cancelButtonText="Cancel" + buttonColor="danger" + > + The PIT will be permanently deleted. This action is irreversible. + + + ); + } else { + modal = ( + { + closeModal(); + deletePit(pitsToDelete[0]); + setPitsToDelete([]); + }} + confirmButtonText="Delete PIT" + cancelButtonText="Cancel" + buttonColor="danger" + confirmButtonDisabled={value !== pitsToDelete[0].name} + > + + This is an active PIT. Deleting it will permanently remove data and may cause + unexpected behavior in saved objects that use this PIT. This action is irreversible. + + + + + + + ); + } + } + + return
{modal}
; + }; + + const displayDelete = (pit) => { + setPitsToDelete([pit]); + setIsModalVisible(true); + }; + + const actions = [ + { + name: 'Add Time', + description: 'Add Time', + icon: 'clock', + type: 'icon', + onClick: fetchDataSources, + }, + { + name: 'Configure PIT', + description: 'Configure PIT', + icon: 'pencil', + type: 'icon', + onClick: navigateEdit, // route it to edit page --> create a route page + }, + { + name: 'Delete', + description: 'Delete PIT', + icon: 'trash', + type: 'icon', + color: 'danger', + onClick: displayDelete, + }, + ]; + + const Timer = ({ endTime }) => { + const getTime = () => + moment(endTime).isBefore(now()) ? 'Expired' : '~ ' + moment(endTime).fromNow(true); + + const getBadgeColor = () => { + const timeLeft = endTime - moment.now().valueOf(); + if (timeLeft < 0) { + return 'hollow'; + } else if (timeLeft < 10 * 60 * 1000) { + return 'danger'; + } else { + return 'default'; + } + }; + + const [time, setTime] = useState(() => getTime()); + const [badge, setBadge] = useState(() => getBadgeColor()); + + const updateTime = () => { + setInterval(() => { + setTime(() => getTime()); + setBadge(() => getBadgeColor()); + }, 30000); + }; + + useEffectOnce(updateTime); + + return {time}; + }; + + const columns = [ + { + field: 'name', + name: i18n.translate('pitManagement.pitTable.nameColumnName', { + defaultMessage: 'Name', + }), + }, + { + field: 'expiry', + name: i18n.translate('pitManagement.pitTable.expiresColumnName', { + defaultMessage: 'Expires', + }), + render: (t: number) => { + // return prettyDuration(moment(t).format('YYYY-MM-DDTHH:mm:ss'),'now',[], 'MMMM Do YYYY, HH:mm:ss.SSS') + return ; + }, + sortable: true, + }, + { + field: 'dataSource', + name: i18n.translate('pitManagement.pitTable.dataSourceColumnName', { + defaultMessage: 'Data Source', + }), + render: (t: string) => { + // return prettyDuration(moment(t).format('YYYY-MM-DDTHH:mm:ss'),'now',[], 'MMMM Do YYYY, HH:mm:ss.SSS') + return t === '' ? 'default' : t; + }, + }, + { + field: 'creation_time', + name: i18n.translate('pitManagement.pitTable.createdColumnName', { + defaultMessage: 'Created', + }), + render: (t: number) => { + const date = moment(t); + const formattedDate = date.format('MMM D, YYYY HH:mm:ss'); + return formattedDate; + }, + sortable: true, + }, + { + name: i18n.translate('pitManagement.pitTable.actionsColumnName', { + defaultMessage: 'Actions', + }), + actions, + }, + ]; + + const handleDeletePit = () => { + let dataSourceId: string | undefined = ''; + if (dataSource === '') { + dataSourceId = undefined; + } else { + const dataSourceObj = dataSources.filter((x) => x.title === dataSource); + if (dataSourceObj.length === 0) { + toasts.addDanger( + i18n.translate('pitManagement.pitTable.fetchDataSourceError', { + defaultMessage: 'Unable to find data source', + }) + ); + setMessage(); + setPits([]); + return; + } else { + dataSourceId = dataSourceObj[0].id; + } + } + + services + .deletePits( + selectedPits.map((x) => x.pit_id), + dataSourceId + ) + .then((deletedPits) => { + console.log(deletedPits); + getPits(dataSource); + }); + }; + + const renderToolsRight = () => { + return [ + + + , + ]; + }; + + const renderToolsLeft = () => { + return [ + ({ + value: source.title, + text: source.name, + }))} + value={dataSource} + onChange={(e) => setDataSource(e.target.value)} + />, + ]; + }; + + // function onQueryChange({ query }: { query: Query }) { + // if (query.ast.getFieldClauses('dataSource')) { + // const selectedDataSource = query.ast.getFieldClauses('dataSource')[0].value as string; + // setDataSource(selectedDataSource); + // } else { + // setMessage(); + // setDataSource('noDataSource'); + // } + // } + + const search: EuiSearchBarProps = { + toolsLeft: renderToolsLeft(), + toolsRight: renderToolsRight(), + // defaultQuery: 'dataSource:""', + // onChange: onQueryChange, + box: { + incremental: true, + schema: true, + disabled: pits.length === 0, + }, + // filters: [ + // { + // type: 'field_value_selection', + // searchThreshold: 5, + // field: 'dataSource', + // name: i18n.translate('pitManagement.pitTable.dataSourceFilterName', { + // defaultMessage: 'Data Source', + // }), + // multiSelect: false, + // options: dataSources.map((source) => ({ + // value: source.title, + // name: source.name, + // view: `${source.title}`, + // })), + // }, + // ], + }; + + const onSelectionChange = (selected: PitItem[]) => { + setSelectedPits(selected); + }; + + const selection = { + onSelectionChange, + }; + + const pagination = { + initialPageSize: 10, + pageSizeOptions: [5, 10, 25, 50], + }; + + const PageHeader = () => { + const [refreshTime, setRefreshTime] = useState(moment.now()); + const [timeSinceRefresh, setTimeSinceRefresh] = useState( + moment(refreshTime).fromNow(true) + ); + + const handleClick = () => { + getPits(dataSource); + setRefreshTime(moment.now()); + }; + + const updateTimeSinceRefresh = () => { + setInterval(() => { + setTimeSinceRefresh(moment(refreshTime).fromNow(true)); + }, 30000); + }; + + useEffectOnce(updateTimeSinceRefresh); + + return ( + <> + + + +

+ +

+
+
+ + + Last updated {timeSinceRefresh} ago + + + + + + + + + + + + +
+ +

+ +

+
+ + ); + }; + + return ( + <> + + + + + + + + + Create PIT + Get PITs + + ); +}; + +export const PITTableWithRouter = withRouter(PITTable); diff --git a/src/plugins/point_in_time_management/public/components/utils.ts b/src/plugins/point_in_time_management/public/components/utils.ts index 5e6a0b054c68..6e5ef6ac9b69 100644 --- a/src/plugins/point_in_time_management/public/components/utils.ts +++ b/src/plugins/point_in_time_management/public/components/utils.ts @@ -1,158 +1,161 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { SavedObjectReference, SavedObjectsClientContract } from 'src/core/public'; -import { DataSourceAttributes } from 'src/plugins/data_source/common/data_sources'; - -export async function getDataSources(savedObjectsClient: SavedObjectsClientContract) { - return savedObjectsClient - .find({ - type: 'data-source', - fields: ['title', 'id'], - perPage: 10000, - }) - .then((response) => { - return ( - response.savedObjects.map((dataSource) => { - const id = dataSource.id; - const title = dataSource.get('title'); - - return { - id, - title, - name: title, - sort: `${title}`, - }; - }) || [] - ); - }); -} - -// export async function getDashboardPits(savedObjectsClient: SavedObjectsClientContract) { -// return savedObjectsClient -// .find({ -// type: 'data-source', -// fields: ['title', 'id'], -// perPage: 10000, -// }) -// .then((response) => { -// return [ -// { -// name: 'PIT-my-index-1', -// id: -// 'o463QQEKbXktaW5kZXgtMRZtN2RWMHdaRlNILThIMUVWWDJJMVBRABZxMlNNZVdPZVRGbVR6MUxPc1RZYkx3AAAAAAAAAAAiFmhZdDNoTk9hUlBlVng2RVNIMUNhelEBFm03ZFYwd1pGU0gtOEgxRVZYMkkxUFEAAA==', -// creation_time: 1681386155468, -// keep_alive: 600000, -// }, -// { -// name: 'PIT-my-index-2', -// id: -// 'o463QQEKbXktaW5kZXgtMRZtN2RWMHdaRlNILThIMUVWWDJJMVBRABZxMlNNZVdPZVRGbVR6MUxPc1RZYkx3AAAAAAAAAAAjFmhZdDNoTk9hUlBlVng2RVNIMUNhelEBFm03ZFYwd1pGU0gtOEgxRVZYMkkxUFEAAA==', -// creation_time: 1681386155468, -// keep_alive: 600000, -// }, -// ]; -// }); -// } - -export interface PointInTime { - name: string; - keepAlive: number; - id: string; - creation_time: number; -} - -export async function getIndexPatterns(savedObjectsClient: SavedObjectsClientContract) { - return ( - savedObjectsClient - .find({ - type: 'index-pattern', - fields: ['title', 'type'], - perPage: 10000, - }) - .then((response) => - response.savedObjects - .map((pattern) => { - const id = pattern.id; - const title = pattern.get('title'); - - return { - id, - title, - // the prepending of 0 at the default pattern takes care of prioritization - // so the sorting will but the default index on top - // or on bottom of a the table - sort: `${title}`, - }; - }) - .sort((a, b) => { - if (a.sort < b.sort) { - return -1; - } else if (a.sort > b.sort) { - return 1; - } else { - return 0; - } - }) - ) || [] - ); -} - -export async function getSavedPits(client: SavedObjectsClientContract) { - const savedObjects = await client.find({ - type: 'point-in-time', - perPage: 1000, - fields: ['id', 'creation_time', 'keepAlive', 'name'], - }); - - return savedObjects.savedObjects; -} - -export async function findById(client: SavedObjectsClientContract, id: string) { - if (id) { - console.log(id); - const savedObjects = await client.find({ - type: 'point-in-time', - perPage: 1000, - // search: `${id}`, - // searchFields: ['id'], - fields: ['id'], - }); - console.log(savedObjects.savedObjects); - return savedObjects.savedObjects.find( - (obj) => obj.attributes.id.toLowerCase() === id.toLowerCase() - ); - } -} - -export async function createSavedObject( - pointintime: PointInTime, - client: SavedObjectsClientContract, - reference: SavedObjectReference -) { - const dupe = await findById(client, pointintime.id); - console.log(dupe); - if (dupe) { - throw new Error(`Duplicate Point in time: ${pointintime.id}`); - } - // if (dupe) { - // if (override) { - // await this.delete(dupe.id); - // } else { - // throw new DuplicateIndexPatternError(`Duplicate index pattern: ${indexPattern.title}`); - // } - // } - - const body = pointintime; - const references = [{ ...reference }]; - const savedObjectType = 'point-in-time'; - const response = await client.create(savedObjectType, body, { - id: pointintime.id, - references, - }); - console.log(response); - pointintime.id = response.id; - return pointintime; -} +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedObjectReference, SavedObjectsClientContract } from 'src/core/public'; +import { DataSourceAttributes } from 'src/plugins/data_source/common/data_sources'; + +export async function getDataSources(savedObjectsClient: SavedObjectsClientContract) { + return savedObjectsClient + .find({ + type: 'data-source', + fields: ['title', 'id'], + perPage: 10000, + }) + .then((response) => { + return ( + response.savedObjects.map((dataSource) => { + const id = dataSource.id; + const title = dataSource.get('title'); + + return { + id, + title, + name: title, + sort: `${title}`, + }; + }) || [] + ); + }); +} + +// export async function getDashboardPits(savedObjectsClient: SavedObjectsClientContract) { +// return savedObjectsClient +// .find({ +// type: 'data-source', +// fields: ['title', 'id'], +// perPage: 10000, +// }) +// .then((response) => { +// return [ +// { +// name: 'PIT-my-index-1', +// id: +// 'o463QQEKbXktaW5kZXgtMRZtN2RWMHdaRlNILThIMUVWWDJJMVBRABZxMlNNZVdPZVRGbVR6MUxPc1RZYkx3AAAAAAAAAAAiFmhZdDNoTk9hUlBlVng2RVNIMUNhelEBFm03ZFYwd1pGU0gtOEgxRVZYMkkxUFEAAA==', +// creation_time: 1681386155468, +// keep_alive: 600000, +// }, +// { +// name: 'PIT-my-index-2', +// id: +// 'o463QQEKbXktaW5kZXgtMRZtN2RWMHdaRlNILThIMUVWWDJJMVBRABZxMlNNZVdPZVRGbVR6MUxPc1RZYkx3AAAAAAAAAAAjFmhZdDNoTk9hUlBlVng2RVNIMUNhelEBFm03ZFYwd1pGU0gtOEgxRVZYMkkxUFEAAA==', +// creation_time: 1681386155468, +// keep_alive: 600000, +// }, +// ]; +// }); +// } + +export interface PointInTime { + name: string; + keepAlive: number; + pit_id: string; + creation_time: number; + id?: string; +} + +export async function getIndexPatterns(savedObjectsClient: SavedObjectsClientContract) { + return ( + savedObjectsClient + .find({ + type: 'index-pattern', + fields: ['title', 'type'], + perPage: 10000, + }) + .then((response) => + response.savedObjects + .map((pattern) => { + const id = pattern.id; + const title = pattern.get('title'); + + return { + id, + title, + // the prepending of 0 at the default pattern takes care of prioritization + // so the sorting will but the default index on top + // or on bottom of a the table + sort: `${title}`, + }; + }) + .sort((a, b) => { + if (a.sort < b.sort) { + return -1; + } else if (a.sort > b.sort) { + return 1; + } else { + return 0; + } + }) + ) || [] + ); +} + +export async function getSavedPits(client: SavedObjectsClientContract) { + const savedObjects = await client.find({ + type: 'point-in-time', + perPage: 1000, + fields: ['id', 'creation_time', 'keepAlive', 'name', 'pit_id'], + }); + + return savedObjects.savedObjects; +} + +export async function findById(client: SavedObjectsClientContract, id: string) { + if (id) { + console.log(id); + const savedObjects = await client.find({ + type: 'point-in-time', + perPage: 1000, + // search: `${id}`, + // searchFields: ['id'], + fields: ['id'], + }); + console.log(savedObjects.savedObjects); + return savedObjects.savedObjects.find( + (obj) => obj.attributes.pit_id.toLowerCase() === id.toLowerCase() + ); + } +} + +export async function createSavedObject( + pointintime: PointInTime, + client: SavedObjectsClientContract, + reference: SavedObjectReference +) { + const dupe = await findById(client, pointintime.pit_id); + console.log("This is dupe output") + console.log(dupe); + if (dupe) { + throw new Error(`Duplicate Point in time: ${pointintime.pit_id}`); + } + // if (dupe) { + // if (override) { + // await this.delete(dupe.id); + // } else { + // throw new DuplicateIndexPatternError(`Duplicate index pattern: ${indexPattern.title}`); + // } + // } + + const body = pointintime; + const references = [{ ...reference }]; + const savedObjectType = 'point-in-time'; + const response = await client.create(savedObjectType, body, { + references, + }); + console.log("This is the response"); + console.log(response); + pointintime.id = response.id; + console.log(pointintime); + return pointintime; +} diff --git a/src/plugins/point_in_time_management/public/management_app/mount_management_section.tsx b/src/plugins/point_in_time_management/public/management_app/mount_management_section.tsx index 10aad5d5a7b7..2408313ef732 100644 --- a/src/plugins/point_in_time_management/public/management_app/mount_management_section.tsx +++ b/src/plugins/point_in_time_management/public/management_app/mount_management_section.tsx @@ -1,49 +1,53 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import ReactDOM from 'react-dom'; -import { I18nProvider } from '@osd/i18n/react'; -import { Route, Router, Switch } from 'react-router-dom'; -import { ManagementAppMountParams } from '../../../management/public'; -import { PointInTimeManagementStartDependencies } from '../plugin'; -import { StartServicesAccessor } from '../../../../core/public'; -import { PointInTimeManagementContext } from '../types'; -import { OpenSearchDashboardsContextProvider } from '../../../opensearch_dashboards_react/public'; -import { PITTableWithRouter } from '../components'; - -export async function mountManagementSection( - getStartServices: StartServicesAccessor, - params: ManagementAppMountParams -) { - const [{ chrome, application, savedObjects, notifications, http }] = await getStartServices(); - const deps: PointInTimeManagementContext = { - chrome, - application, - notifications, - savedObjects, - http, - setBreadcrumbs: params.setBreadcrumbs, - }; - ReactDOM.render( - - - - - - - - - - - , - params.element - ); - - return () => { - chrome.docTitle.reset(); - ReactDOM.unmountComponentAtNode(params.element); - }; -} +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import ReactDOM from 'react-dom'; +import { I18nProvider } from '@osd/i18n/react'; +import { Route, Router, Switch } from 'react-router-dom'; +import { ManagementAppMountParams } from '../../../management/public'; +import { PointInTimeManagementStartDependencies } from '../plugin'; +import { StartServicesAccessor } from '../../../../core/public'; +import { PointInTimeManagementContext } from '../types'; +import { OpenSearchDashboardsContextProvider } from '../../../opensearch_dashboards_react/public'; +import { PITTableWithRouter } from '../components'; +import {PITEditWithRouter} from "../components/pit_edit"; + +export async function mountManagementSection( + getStartServices: StartServicesAccessor, + params: ManagementAppMountParams +) { + const [{ chrome, application, savedObjects, notifications, http }] = await getStartServices(); + const deps: PointInTimeManagementContext = { + chrome, + application, + notifications, + savedObjects, + http, + setBreadcrumbs: params.setBreadcrumbs, + }; + ReactDOM.render( + + + + + + + + + + + + + + , + params.element + ); + + return () => { + chrome.docTitle.reset(); + ReactDOM.unmountComponentAtNode(params.element); + }; +} diff --git a/src/plugins/point_in_time_management/public/services.ts b/src/plugins/point_in_time_management/public/services.ts index a0eef6967e32..ac313b110b3f 100644 --- a/src/plugins/point_in_time_management/public/services.ts +++ b/src/plugins/point_in_time_management/public/services.ts @@ -1,42 +1,44 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { CoreStart, HttpFetchError } from 'opensearch-dashboards/public'; - -export interface Services { - getAllPits: (dataSourceId?: string) => Promise; - deletePits: (pits: string[], dataSourceId?: string) => any; -} - -export function getServices(http: CoreStart['http']): Services { - return { - getAllPits: async (dataSourceId?: string) => { - try { - const response = await http.post('/api/pit/all', { - body: JSON.stringify({ - dataSourceId: dataSourceId ? dataSourceId : '', - }), - }); - return response; - } catch (e) { - return e; - } - }, - - deletePits: async (pits: string[], dataSourceId?: string) => { - try { - const response = await http.post('/api/pit/delete', { - body: JSON.stringify({ - dataSourceId: dataSourceId ? dataSourceId : '', - pit_id: pits, - }), - }); - return response; - } catch (e) { - return e; - } - }, - }; -} +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { CoreStart, HttpFetchError } from 'opensearch-dashboards/public'; + +export interface Services { + getAllPits: (dataSourceId?: string) => Promise; + deletePits: (pits: string[], dataSourceId?: string) => any; +} + +export function getServices(http: CoreStart['http']): Services { + return { + getAllPits: async (dataSourceId?: string) => { + try { + const response = await http.post('/api/pit/all', { + body: JSON.stringify({ + dataSourceId: dataSourceId ? dataSourceId : '', + }), + }); + console.log("These are backend PITs"); + console.log(response); + return response; + } catch (e) { + return e; + } + }, + + deletePits: async (pits: string[], dataSourceId?: string) => { + try { + const response = await http.post('/api/pit/delete', { + body: JSON.stringify({ + dataSourceId: dataSourceId ? dataSourceId : '', + pit_id: pits, + }), + }); + return response; + } catch (e) { + return e; + } + }, + }; +} diff --git a/src/plugins/point_in_time_management/server/saved_objects/pit_saved_object.ts b/src/plugins/point_in_time_management/server/saved_objects/pit_saved_object.ts index 25dc287a5dab..3df8a167e86c 100644 --- a/src/plugins/point_in_time_management/server/saved_objects/pit_saved_object.ts +++ b/src/plugins/point_in_time_management/server/saved_objects/pit_saved_object.ts @@ -1,38 +1,39 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { SavedObjectsType } from 'opensearch-dashboards/server'; - -export const pointInTimeSavedObject: SavedObjectsType = { - name: 'point-in-time', - namespaceType: 'agnostic', - hidden: false, - management: { - icon: 'apps', // todo: pending ux #2034 - defaultSearchField: 'id', - importableAndExportable: true, - getTitle(obj) { - return obj.attributes.name; - }, - // getEditUrl(obj) { - // return `/management/opensearch-dashboards/dataSources/${encodeURIComponent(obj.id)}`; - // }, - // getInAppUrl(obj) { - // return { - // path: `/app/management/opensearch-dashboards/dataSources/${encodeURIComponent(obj.id)}`, - // uiCapabilitiesPath: 'management.opensearchDashboards.dataSources', - // }; - // }, - }, - mappings: { - dynamic: false, - properties: { - title: { type: 'text' }, - creation_time: { type: 'double' }, - keepAlive: { type: 'integer' }, - name: { type: 'text' }, - }, - }, -}; +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedObjectsType } from 'opensearch-dashboards/server'; + +export const pointInTimeSavedObject: SavedObjectsType = { + name: 'point-in-time', + namespaceType: 'agnostic', + hidden: false, + management: { + icon: 'apps', // todo: pending ux #2034 + defaultSearchField: 'id', + importableAndExportable: true, + getTitle(obj) { + return obj.attributes.name; + }, + // getEditUrl(obj) { + // return `/management/opensearch-dashboards/dataSources/${encodeURIComponent(obj.id)}`; + // }, + // getInAppUrl(obj) { + // return { + // path: `/app/management/opensearch-dashboards/dataSources/${encodeURIComponent(obj.id)}`, + // uiCapabilitiesPath: 'management.opensearchDashboards.dataSources', + // }; + // }, + }, + mappings: { + dynamic: false, + properties: { + title: { type: 'text' }, + creation_time: { type: 'double' }, + keepAlive: { type: 'integer' }, + name: { type: 'text' }, + pit_id: { type: 'text' }, + }, + }, +}; diff --git a/yarn.lock b/yarn.lock index 1a037f5af282..029599c4af0f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2338,17 +2338,6 @@ mkdirp "^1.0.4" rimraf "^3.0.2" -"@opensearch-project/opensearch@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@opensearch-project/opensearch/-/opensearch-2.1.0.tgz#d79ab4ae643493512099673e117faffe40b4fe56" - integrity sha512-iM2u63j2IlUOuMSbcw1TZFpRqjK6qMwVhb3jLLa/x4aATxdKOiO1i17mgzfkeepqj85efNzXBZzN+jkq1/EXhQ== - dependencies: - aws4 "^1.11.0" - debug "^4.3.1" - hpagent "^0.1.1" - ms "^2.1.3" - secure-json-parse "^2.4.0" - "@opensearch-project/opensearch@^2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@opensearch-project/opensearch/-/opensearch-2.2.0.tgz#2a31a67242bf3bacedc9644a0c68893eb5fb9420" @@ -9641,11 +9630,6 @@ hosted-git-info@^4.0.1: dependencies: lru-cache "^6.0.0" -hpagent@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/hpagent/-/hpagent-0.1.2.tgz#cab39c66d4df2d4377dbd212295d878deb9bdaa9" - integrity sha512-ePqFXHtSQWAFXYmj+JtOTHr84iNrII4/QRlAAPPE+zqnKy4xJo7Ie1Y4kC7AdB+LxLxSTTzBMASsEcy0q8YyvQ== - hpagent@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/hpagent/-/hpagent-1.2.0.tgz#0ae417895430eb3770c03443456b8d90ca464903" From 118874d5dd2181697551ce49428569fac6b66283 Mon Sep 17 00:00:00 2001 From: Arpit Bandejiya Date: Wed, 17 May 2023 23:56:46 +0530 Subject: [PATCH 2/4] more changes in the edit page Signed-off-by: Arpit Bandejiya --- .../public/components/pit_edit/edit_page.tsx | 177 ++++----- .../components/pit_edit/edit_pit_form.tsx | 341 +++++++++++++++++ .../public/components/pit_table/pit_table.tsx | 7 +- .../public/components/utils.ts | 26 +- .../public/services.ts | 18 +- .../point_in_time_management/public/types.ts | 22 +- .../server/routes/opensearch.ts | 345 ++++++++++-------- .../server/saved_objects/pit_saved_object.ts | 1 + 8 files changed, 667 insertions(+), 270 deletions(-) create mode 100644 src/plugins/point_in_time_management/public/components/pit_edit/edit_pit_form.tsx diff --git a/src/plugins/point_in_time_management/public/components/pit_edit/edit_page.tsx b/src/plugins/point_in_time_management/public/components/pit_edit/edit_page.tsx index cfbe92240f93..b6539e00392c 100644 --- a/src/plugins/point_in_time_management/public/components/pit_edit/edit_page.tsx +++ b/src/plugins/point_in_time_management/public/components/pit_edit/edit_page.tsx @@ -3,11 +3,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useState } from 'react'; +import React, {useEffect, useState} from 'react'; import { RouteComponentProps, withRouter } from 'react-router-dom'; -import { useMount } from 'react-use'; +import {useEffectOnce, useMount} from 'react-use'; import { i18n } from '@osd/i18n'; import { + EuiBottomBar, + EuiButton, + EuiButtonEmpty, EuiCheckbox, EuiDescribedFormGroup, EuiFieldNumber, @@ -23,123 +26,85 @@ import { EuiTitle, } from '@elastic/eui'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; -import { PointInTimeManagementContext } from '../../types'; +import { PointInTimeAttributes, PointInTimeManagementContext} from '../../types'; import { getEditBreadcrumbs } from '../breadcrumbs'; +import { EditPitForm } from './edit_pit_form'; +import {findById, findPointInTimeSavedObject, updatePointInTimeById, updatePointInTimeKeepAlive} from '../utils'; +import {ToastMessageItem} from "../../../../data_source_management/public/types"; +import {getServices, Services} from "../../services"; + +const defaultPitSavedObject: PointInTimeAttributes = { + pit_id: '', + creation_time: 0, + id: '', + keepAlive: 0, + name: '', + addtime: 0, +}; export const PITEdit: React.FunctionComponent> = ( props: RouteComponentProps<{ id: string }> ) => { - const { setBreadcrumbs } = useOpenSearchDashboards().services; + const { setBreadcrumbs, savedObjects, notifications: { toasts }, http } = useOpenSearchDashboards< + PointInTimeManagementContext + >().services; const PitID: string = props.match.params.id; - useMount(() => { + const [pitSavedObject, setPitSavedObject] = useState(defaultPitSavedObject); + const [isLoading, setIsLoading] = useState(false); + const [newProp, setNewProp] = useState(false); + const services: Services = getServices(http); + useEffectOnce(() => { console.log(PitID); setBreadcrumbs(getEditBreadcrumbs()); + setIsLoading(true); + (async function () { + await fetchPitSavedObject(); + })(); }); - const [checked, setChecked] = useState(false); - const onChange = (e) => { - setChecked(e.target.checked); + + const fetchPitSavedObject = async () => { + const tempPitSavedObject = await findById(savedObjects.client, PitID); + setNewProp(true); + const pointInTimeAttributes: PointInTimeAttributes = { + creation_time: tempPitSavedObject.attributes.creation_time, + name: tempPitSavedObject.attributes.name, + keepAlive: tempPitSavedObject.attributes.keepAlive, + pit_id: tempPitSavedObject.attributes.pit_id, + id: tempPitSavedObject.id, + addtime: 0, + }; + console.log('This is teh attributes'); + console.log(pointInTimeAttributes); + setPitSavedObject(pointInTimeAttributes); + setIsLoading(false); + } + + const handleSubmit = async (attributes: PointInTimeAttributes) => { + console.log('These are the attributes', attributes); + const new_keep_alive_proposal = attributes.addtime.toString() + "m"; + console.log(attributes.pit_id, new_keep_alive_proposal); + await services.addPitTime(attributes.pit_id, new_keep_alive_proposal); + await updatePointInTimeById(savedObjects.client, attributes.id, attributes); + }; + + const handleDisplayToastMessage = ({ id, defaultMessage, success }: ToastMessageItem) => { + if (success) { + toasts.addSuccess(i18n.translate(id, { defaultMessage })); + } else { + toasts.addWarning(i18n.translate(id, { defaultMessage })); + } }; return ( <> - - - - -

Time Configurations

-
-
-
- - - Add time} - description={ -

- The keep_alive time is the amount of time the PIT is kept active. The time entered - will also be the amount of time a PIT is extended by when it is queried. A PITs time - can not be extended by an amount less than the one entered. The keep alive time can - not exceed a maximum of X hours. -

- } - > - - - - - - - - - - -
-
-
- - - - - -

Dashboard PIT configurations

-
-
-
- - - PIT name} - description={

Choose a name for a PIT that is available in OpenSearch Dashboards.

} - > - - - -
- Post-expiration actions} - description={ -

- PIT data is lost once it expires you have the option to keep the PIT metadata after - after expiration. expiration. expiration. expiration. expiration. You can also - choose to keep the Dashboard Object expiration. This object will be converted to an - Index Pattern and Pattern and it will reference data. -

- } - > - - <> - onChange(e)} - /> - onChange(e)} - disabled={true} - /> - - -
-
-
+ {!isLoading ? ( + + ) : null} ); }; diff --git a/src/plugins/point_in_time_management/public/components/pit_edit/edit_pit_form.tsx b/src/plugins/point_in_time_management/public/components/pit_edit/edit_pit_form.tsx new file mode 100644 index 000000000000..8b788cb2a388 --- /dev/null +++ b/src/plugins/point_in_time_management/public/components/pit_edit/edit_pit_form.tsx @@ -0,0 +1,341 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import React from 'react'; +import { + EuiBottomBar, + EuiButton, + EuiButtonEmpty, + EuiCheckbox, + EuiDescribedFormGroup, + EuiFieldNumber, + EuiFieldText, + EuiFlexGroup, + EuiFlexItem, + EuiForm, + EuiFormRow, + EuiPageContent, + EuiPageHeader, + EuiPageHeaderSection, + EuiSpacer, + EuiTitle, +} from '@elastic/eui'; +import { i18n } from '@osd/i18n'; +import { PointInTimeAttributes, ToastMessageItem } from '../../types'; +import { findById } from '../utils'; + +export interface EditPitProps { + existingPointInTime: PointInTimeAttributes; + handleSubmit: (formValues: PointInTimeAttributes) => void; + displayToastMessage: (info: ToastMessageItem) => void; + newProp: boolean; +} + +export interface EditPitState { + keepAlive: number; + name: string; + pit_id?: string; + id?: string; + delete_pit: boolean; + showUpdateOptions: boolean; + isLoading: boolean; + checked: boolean; + AddTimeHr: any; + AddTimeMin: any; + addTime: any; +} + +export class EditPitForm extends React.Component { + constructor(props: EditPitProps, context: EditPitState) { + super(props, context); + this.state = { + keepAlive: 0, + name: '', + pit_id: '', + id: '', + delete_pit: false, + showUpdateOptions: false, + isLoading: false, + checked: false, + AddTimeHr: 0, + AddTimeMin: 0, + addTime: 0, + }; + } + + componentDidMount() { + this.setFormValuesForEditMode(); + console.log('These are the props in mount'); + console.log(this.props); + } + + resetFormValues = () => { + this.setFormValuesForEditMode(); + this.setState({ showUpdateOptions: false }); + }; + + setFormValuesForEditMode() { + if (this.props.existingPointInTime) { + const { keepAlive, name, pit_id, id, addtime } = this.props.existingPointInTime; + this.setState({ + keepAlive: keepAlive, + name: name, + pit_id: pit_id, + id: id, + addtime: addtime, + }); + } + } + + onChangeName = (e: { target: { value: any } }) => { + this.setState({ name: e.target.value }); + }; + + onChangeKeepAlive = (e: { target: { value: any } }) => { + this.setState({ name: e.target.value }); + }; + + isFormValid = (): boolean => { + console.log('This is the form validation'); + return true; + }; + + onClickUpdatePit = async () => { + if (this.isFormValid()) { + const formValues: PointInTimeAttributes = { + name: this.state.name, + keepAlive: this.state.keepAlive, + creation_time: this.state.keepAlive, + id: this.state.id, + pit_id: this.state.pit_id, + addtime: this.state.addTime, + }; + this.setState({ isLoading: true }); + + try { + console.log("OnClickUpdate", formValues); + await this.props.handleSubmit(formValues); + this.setState({ showUpdateOptions: false }); + this.setFormValuesForEditMode(); + } catch (e) { + this.props.displayToastMessage({ + id: 'PointInTimeManagement.editPointInTime.editPointInTimeFailMsg', + defaultMessage: 'Updating the Point in time failed with some errors.', + }); + } finally { + this.setState({ isLoading: false }); + } + } + }; + + onChange = (e) => { + this.setState({ checked: e.target.checked }); + }; + + didFormValuesChange = () => { + const formValues: PointInTimeAttributes = { + name: this.state.name, + pit_id: this.state.pit_id, + keepAlive: this.state.keepAlive, + id: this.state.id, + addtime: this.state.addTime, + }; + + const { keepAlive, name, pit_id, id } = this.props.existingPointInTime; + + const isNameChanged: boolean = formValues.name !== name; + const isAddTimeChanged: boolean = formValues.addtime > 0; + if (isNameChanged || isAddTimeChanged) { + this.setState({ showUpdateOptions: true }); + } else { + this.setState({ showUpdateOptions: false }); + } + }; + + onChangeFormValues = () => { + setTimeout(() => { + this.didFormValuesChange(); + }, 0); + }; + + + + onChangeTimeHr = (e: { target: { value: any } }) => { + this.setState({ + AddTimeHr: parseInt(e.target.value), + addTime: 60 * parseInt(e.target.value) + this.state.AddTimeMin, + }); + console.log(this.state); + }; + + onChangeTimeMin = (e: { target: { value: any } }) => { + this.setState({ + AddTimeMin: parseInt(e.target.value), + addTime: 60 * this.state.AddTimeHr + parseInt(e.target.value), + }); + console.log(this.state); + }; + + onChangePitName = (e: { target: { value: any } }) => { + this.setState({ name: e.target.value }); + console.log(e.target.value); + }; + + renderBottomBar = () => { + return ( + + + + + + this.resetFormValues()} + aria-describedby="aria-describedby.countOfUnsavedSettings" + data-test-subj="pit-edit-cancelButton" + > + Discard changes + + + + + Save changes + + + + + ); + }; + + render() { + return ( + <> + + + + +

Time Configurations

+
+
+
+ + this.onChangeFormValues()} + data-test-subj="pit-edit" + > + Add time} + description={ +

+ The keep_alive time is the amount of time the PIT is kept active. The time entered + will also be the amount of time a PIT is extended by when it is queried. A PITs + time can not be extended by an amount less than the one entered. The keep alive + time can not exceed a maximum of X hours. +

+ } + > + + + + + + + + + + +
+
+
+ + + + + +

Dashboard PIT configurations

+
+
+
+ + this.onChangeFormValues()} + data-test-subj="pit-edit-2" + > + PIT name} + description={ +

Choose a name for a PIT that is available in OpenSearch Dashboards.

+ } + > + + + +
+ Post-expiration actions} + description={ +

+ PIT data is lost once it expires you have the option to keep the PIT metadata + after after expiration. expiration. expiration. expiration. expiration. You can + also choose to keep the Dashboard Object expiration. This object will be converted + to an Index Pattern and Pattern and it will reference data. +

+ } + > + + <> + this.onChange(e)} + /> + this.onChange(e)} + disabled={true} + /> + + +
+
+ {this.state.showUpdateOptions ? this.renderBottomBar() : null} +
+ + ); + } +} diff --git a/src/plugins/point_in_time_management/public/components/pit_table/pit_table.tsx b/src/plugins/point_in_time_management/public/components/pit_table/pit_table.tsx index 62bbf61514d5..a70d58936e7e 100644 --- a/src/plugins/point_in_time_management/public/components/pit_table/pit_table.tsx +++ b/src/plugins/point_in_time_management/public/components/pit_table/pit_table.tsx @@ -247,10 +247,11 @@ const PITTable = ({ history }: RouteComponentProps) => { // setIsFlyoutVisible(false); const pit: PointInTime = { pit_id: - 'o463QQEKbXktaW5kZXgtMRZtN2RWMHdaRlNILThIMUVWWDJJMVBRABZxMlNNZVdPZVRGbVR6MUxPc1RZYkx3AAAAAAAAAAAjFmhZdDNoTk9hUlBlVng2RVNIMUNhelEBFm03ZFYwd1pGU0gtOEgxRVZYMkkxUFEAAA==12', - keepAlive: 600000, + 'o463QQIHdGVzdC0wMRZCaEJjeGcxUFRxdWlqR1VucTE0dkpnARZNLXdhOWdoRFJJeXFRRWp1RkdqZ05nAAAAAAAAAF09FlRNaE5OQy1LUzdTS0h5NThWY1oySkEHdGVzdC0wMRZCaEJjeGcxUFRxdWlqR1VucTE0dkpnABZNLXdhOWdoRFJJeXFRRWp1RkdqZ05nAAAAAAAAAF08FlRNaE5OQy1LUzdTS0h5NThWY1oySkEBFkJoQmN4ZzFQVHF1aWpHVW5xMTR2SmcAAA==', + keepAlive: 300000, creation_time: 1681386155468, - name: 'PIT-my-index-2-3', // Todo create pit and fill the pit id + name: 'PIT-my-index-2-3-new', // Todo create pit and fill the pit id + delete_on_expiry: false, }; const reference: SavedObjectReference = { diff --git a/src/plugins/point_in_time_management/public/components/utils.ts b/src/plugins/point_in_time_management/public/components/utils.ts index 6e5ef6ac9b69..fd90ad645460 100644 --- a/src/plugins/point_in_time_management/public/components/utils.ts +++ b/src/plugins/point_in_time_management/public/components/utils.ts @@ -5,6 +5,7 @@ import { SavedObjectReference, SavedObjectsClientContract } from 'src/core/public'; import { DataSourceAttributes } from 'src/plugins/data_source/common/data_sources'; +import {PointInTimeAttributes} from "../types"; export async function getDataSources(savedObjectsClient: SavedObjectsClientContract) { return savedObjectsClient @@ -63,6 +64,7 @@ export interface PointInTime { pit_id: string; creation_time: number; id?: string; + delete_on_expiry: boolean; } export async function getIndexPatterns(savedObjectsClient: SavedObjectsClientContract) { @@ -117,17 +119,27 @@ export async function findById(client: SavedObjectsClientContract, id: string) { const savedObjects = await client.find({ type: 'point-in-time', perPage: 1000, - // search: `${id}`, - // searchFields: ['id'], - fields: ['id'], + fields: [], }); - console.log(savedObjects.savedObjects); - return savedObjects.savedObjects.find( - (obj) => obj.attributes.pit_id.toLowerCase() === id.toLowerCase() - ); + return savedObjects.savedObjects.find((obj) => obj.id === id); } } +export async function updatePointInTimeById( + savedObjectsClient: SavedObjectsClientContract, + id: string, + attributes: PointInTimeAttributes +) { + return savedObjectsClient.update('point-in-time', id, attributes); +} + +export async function updatePointInTimeKeepAlive( + savedObjectsClient: SavedObjectsClientContract, + id: string, + addTime: number +) { + +} export async function createSavedObject( pointintime: PointInTime, client: SavedObjectsClientContract, diff --git a/src/plugins/point_in_time_management/public/services.ts b/src/plugins/point_in_time_management/public/services.ts index ac313b110b3f..e95247f8dd7a 100644 --- a/src/plugins/point_in_time_management/public/services.ts +++ b/src/plugins/point_in_time_management/public/services.ts @@ -8,6 +8,7 @@ import { CoreStart, HttpFetchError } from 'opensearch-dashboards/public'; export interface Services { getAllPits: (dataSourceId?: string) => Promise; deletePits: (pits: string[], dataSourceId?: string) => any; + addPitTime: (pit_id: string, keepAlive: string, dataSourceId?: string) => any; } export function getServices(http: CoreStart['http']): Services { @@ -26,7 +27,22 @@ export function getServices(http: CoreStart['http']): Services { return e; } }, - + addPitTime: async (pit_id: string, keepAlive: string, dataSourceId?: string) => { + try { + console.log(pit_id, keepAlive, dataSourceId); + const response = await http.post('/api/pit/addTime', { + body: JSON.stringify({ + dataSourceId: dataSourceId ? dataSourceId : 'default', + pit_id: pit_id, + keepAlive: keepAlive, + }), + }); + console.log("Updated the PIT KeepAlive"); + console.log(response); + } catch (e) { + return e; + } + }, deletePits: async (pits: string[], dataSourceId?: string) => { try { const response = await http.post('/api/pit/delete', { diff --git a/src/plugins/point_in_time_management/public/types.ts b/src/plugins/point_in_time_management/public/types.ts index c4625e843080..78d15aad6605 100644 --- a/src/plugins/point_in_time_management/public/types.ts +++ b/src/plugins/point_in_time_management/public/types.ts @@ -3,12 +3,32 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { ApplicationStart, ChromeStart, HttpSetup } from 'opensearch-dashboards/public'; +import { + ApplicationStart, + ChromeStart, + HttpSetup, + SavedObjectAttributes, +} from 'opensearch-dashboards/public'; import { NotificationsStart, SavedObjectsStart } from 'src/core/public'; import { NavigationPublicPluginStart } from '../../navigation/public'; import { ManagementAppMountParams } from '../../management/public'; import { ManagementSetup } from '../../management/public'; +export interface PointInTimeAttributes extends SavedObjectAttributes { + creation_time?: number; + keepAlive: number; + name: string; + pit_id?: string; + id?: string; + addtime: number; +} + +export interface ToastMessageItem { + id: string; + defaultMessage: string; + success?: boolean; +} + export interface PointInTimeManagementContext { chrome: ChromeStart; application: ApplicationStart; diff --git a/src/plugins/point_in_time_management/server/routes/opensearch.ts b/src/plugins/point_in_time_management/server/routes/opensearch.ts index 69165e7b26f8..100e24736c98 100644 --- a/src/plugins/point_in_time_management/server/routes/opensearch.ts +++ b/src/plugins/point_in_time_management/server/routes/opensearch.ts @@ -1,152 +1,193 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { schema } from '@osd/config-schema'; -import { - IRouter, - OpenSearchClient, - OpenSearchDashboardsRequest, - RequestHandlerContext, -} from 'opensearch-dashboards/server'; - -export function registerPitRoutes(router: IRouter) { - router.post( - { - path: '/api/pit/all', - validate: { - body: schema.object({ - dataSourceId: schema.string(), - }), - }, - }, - async (context, req, res) => { - const client: OpenSearchClient = await getClient(req, context); - try { - const pits = await client.getAllPits({}); - return res.ok({ - body: { - ok: true, - resp: pits.body, - }, - }); - } catch (err: any) { - return res.ok({ - body: { - ok: false, - resp: err.message, - }, - }); - } - } - ); - - router.post( - { - path: '/api/pit/delete', - validate: { - body: schema.object({ - dataSourceId: schema.string(), - pit_id: schema.arrayOf(schema.string()), - }), - }, - }, - async (context, req, res) => { - const client: OpenSearchClient = await getClient(req, context); - try { - const pits = await client.deletePit({ body: { pit_id: req.body.pit_id } }); - return res.ok({ - body: { - ok: true, - resp: pits.body, - }, - }); - } catch (err: any) { - return res.ok({ - body: { - ok: false, - resp: err.message, - }, - }); - } - } - ); - - // router.post( - // { - // path: '/api/geospatial/_search', - // validate: { - // body: schema.object({ - // index: schema.string(), - // }), - // }, - // }, - // async (context, req, res) => { - // const client = context.core.opensearch.client.asCurrentUser; - // try { - // const { index } = req.body; - // const params = { index, body: {} }; - // const results = await client.search(params); - // return res.ok({ - // body: { - // ok: true, - // resp: results.body, - // }, - // }); - // } catch (err: any) { - // return res.ok({ - // body: { - // ok: false, - // resp: err.message, - // }, - // }); - // } - // } - // ); - - // router.post( - // { - // path: '/api/geospatial/_mappings', - // validate: { - // body: schema.object({ - // index: schema.string(), - // }), - // }, - // }, - // async (context, req, res) => { - // const client = context.core.opensearch.client.asCurrentUser; - // try { - // const { index } = req.body; - // const mappings = await client.indices.getMapping({ index }); - // return res.ok({ - // body: { - // ok: true, - // resp: mappings.body, - // }, - // }); - // } catch (err: any) { - // return res.ok({ - // body: { - // ok: false, - // resp: err.message, - // }, - // }); - // } - // } - // ); -} - -async function getClient( - req: OpenSearchDashboardsRequest< - unknown, - unknown, - Readonly<{} & { dataSourceId: string }>, - 'post' - >, - context: RequestHandlerContext -): Promise { - return req.body.dataSourceId && req.body.dataSourceId !== 'default' && context.dataSource - ? await context.dataSource.opensearch.getClient(req.body.dataSourceId) - : context.core.opensearch.client.asCurrentUser; -} +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { schema } from '@osd/config-schema'; +import { + IRouter, + OpenSearchClient, + OpenSearchDashboardsRequest, + RequestHandlerContext, +} from 'opensearch-dashboards/server'; + +export function registerPitRoutes(router: IRouter) { + router.post( + { + path: '/api/pit/all', + validate: { + body: schema.object({ + dataSourceId: schema.string(), + }), + }, + }, + async (context, req, res) => { + const client: OpenSearchClient = await getClient(req, context); + try { + const pits = await client.getAllPits({}); + return res.ok({ + body: { + ok: true, + resp: pits.body, + }, + }); + } catch (err: any) { + return res.ok({ + body: { + ok: false, + resp: err.message, + }, + }); + } + } + ); + + router.post( + { + path: '/api/pit/addTime', + validate: { + body: schema.object({ + dataSourceId: schema.string(), + pit_id: schema.string(), + keepAlive: schema.string(), + }), + }, + }, + async (context, req, res) => { + const client: OpenSearchClient = await getClient(req, context); + console.log(req.body); + try { + const response = await client.search({ + body: { + size: 0, + pit: { + id: req.body.pit_id, + keep_alive: req.body.keepAlive, + }, + }, + }); + return res.ok({ + body: { + ok: true, + resp: response.body, + }, + }); + } catch (err: any) { + return res.ok({ + body: { + ok: false, + resp: err.message, + }, + }); + } + } + ); + + router.post( + { + path: '/api/pit/delete', + validate: { + body: schema.object({ + dataSourceId: schema.string(), + pit_id: schema.arrayOf(schema.string()), + }), + }, + }, + async (context, req, res) => { + const client: OpenSearchClient = await getClient(req, context); + try { + const pits = await client.deletePit({ body: { pit_id: req.body.pit_id } }); + return res.ok({ + body: { + ok: true, + resp: pits.body, + }, + }); + } catch (err: any) { + return res.ok({ + body: { + ok: false, + resp: err.message, + }, + }); + } + } + ); + + // router.post( + // { + // path: '/api/geospatial/_search', + // validate: { + // body: schema.object({ + // index: schema.string(), + // }), + // }, + // }, + // async (context, req, res) => { + // const client = context.core.opensearch.client.asCurrentUser; + // try { + // const { index } = req.body; + // const params = { index, body: {} }; + // const results = await client.search(params); + // return res.ok({ + // body: { + // ok: true, + // resp: results.body, + // }, + // }); + // } catch (err: any) { + // return res.ok({ + // body: { + // ok: false, + // resp: err.message, + // }, + // }); + // } + // } + // ); + + // router.post( + // { + // path: '/api/geospatial/_mappings', + // validate: { + // body: schema.object({ + // index: schema.string(), + // }), + // }, + // }, + // async (context, req, res) => { + // const client = context.core.opensearch.client.asCurrentUser; + // try { + // const { index } = req.body; + // const mappings = await client.indices.getMapping({ index }); + // return res.ok({ + // body: { + // ok: true, + // resp: mappings.body, + // }, + // }); + // } catch (err: any) { + // return res.ok({ + // body: { + // ok: false, + // resp: err.message, + // }, + // }); + // } + // } + // ); +} + +async function getClient( + req: OpenSearchDashboardsRequest< + unknown, + unknown, + Readonly<{} & { dataSourceId: string }>, + 'post' + >, + context: RequestHandlerContext +): Promise { + return req.body.dataSourceId && req.body.dataSourceId !== 'default' && context.dataSource + ? await context.dataSource.opensearch.getClient(req.body.dataSourceId) + : context.core.opensearch.client.asCurrentUser; +} diff --git a/src/plugins/point_in_time_management/server/saved_objects/pit_saved_object.ts b/src/plugins/point_in_time_management/server/saved_objects/pit_saved_object.ts index 3df8a167e86c..e06345ac2f42 100644 --- a/src/plugins/point_in_time_management/server/saved_objects/pit_saved_object.ts +++ b/src/plugins/point_in_time_management/server/saved_objects/pit_saved_object.ts @@ -34,6 +34,7 @@ export const pointInTimeSavedObject: SavedObjectsType = { keepAlive: { type: 'integer' }, name: { type: 'text' }, pit_id: { type: 'text' }, + delete_on_expiry: { type: 'boolean' }, }, }, }; From ab59bf3aa9365c0614b35e26f54bf075379a56c3 Mon Sep 17 00:00:00 2001 From: Arpit Bandejiya Date: Thu, 18 May 2023 16:21:43 +0530 Subject: [PATCH 3/4] Add expiry param Signed-off-by: Arpit Bandejiya --- .../public/components/pit_edit/edit_page.tsx | 2 ++ .../public/components/pit_edit/edit_pit_form.tsx | 14 +++++++++++--- .../public/components/utils.ts | 2 +- .../point_in_time_management/public/types.ts | 1 + 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/plugins/point_in_time_management/public/components/pit_edit/edit_page.tsx b/src/plugins/point_in_time_management/public/components/pit_edit/edit_page.tsx index b6539e00392c..6dc4d4bac8d9 100644 --- a/src/plugins/point_in_time_management/public/components/pit_edit/edit_page.tsx +++ b/src/plugins/point_in_time_management/public/components/pit_edit/edit_page.tsx @@ -40,6 +40,7 @@ const defaultPitSavedObject: PointInTimeAttributes = { keepAlive: 0, name: '', addtime: 0, + delete_on_expiry: false, }; export const PITEdit: React.FunctionComponent> = ( @@ -72,6 +73,7 @@ export const PITEdit: React.FunctionComponent { id: this.state.id, pit_id: this.state.pit_id, addtime: this.state.addTime, + delete_on_expiry: this.state.checked, }; this.setState({ isLoading: true }); @@ -140,13 +141,15 @@ export class EditPitForm extends React.Component { keepAlive: this.state.keepAlive, id: this.state.id, addtime: this.state.addTime, + delete_on_expiry: this.state.checked, }; - const { keepAlive, name, pit_id, id } = this.props.existingPointInTime; + const { keepAlive, name, pit_id, id, delete_on_expiry } = this.props.existingPointInTime; const isNameChanged: boolean = formValues.name !== name; const isAddTimeChanged: boolean = formValues.addtime > 0; - if (isNameChanged || isAddTimeChanged) { + const isDeleteOnExpirtChanged: boolean = formValues.delete_on_expiry !== delete_on_expiry; + if (isNameChanged || isAddTimeChanged || isDeleteOnExpirtChanged) { this.setState({ showUpdateOptions: true }); } else { this.setState({ showUpdateOptions: false }); @@ -182,6 +185,11 @@ export class EditPitForm extends React.Component { console.log(e.target.value); }; + onChangeDeleteObject = (e) => { + this.setState({ checked: e.target.checked }); + console.log(this.state.checked); + }; + renderBottomBar = () => { return ( @@ -321,7 +329,7 @@ export class EditPitForm extends React.Component { id="pit-id" label="Delete this PIT at expiration" checked={this.state.checked} - onChange={(e) => this.onChange(e)} + onChange={this.onChangeDeleteObject} /> Date: Thu, 18 May 2023 19:42:07 +0530 Subject: [PATCH 4/4] update and delete pit saved objects --- .../public/components/pit_edit/edit_page.tsx | 34 ++++++---- .../components/pit_edit/edit_pit_form.tsx | 18 +++-- .../public/components/pit_table/pit_table.tsx | 68 ++++++++++++++----- .../public/components/utils.ts | 25 +++++-- .../mount_management_section.tsx | 2 +- .../public/services.ts | 8 +-- 6 files changed, 106 insertions(+), 49 deletions(-) diff --git a/src/plugins/point_in_time_management/public/components/pit_edit/edit_page.tsx b/src/plugins/point_in_time_management/public/components/pit_edit/edit_page.tsx index 6dc4d4bac8d9..f4cdcae867cd 100644 --- a/src/plugins/point_in_time_management/public/components/pit_edit/edit_page.tsx +++ b/src/plugins/point_in_time_management/public/components/pit_edit/edit_page.tsx @@ -3,9 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, {useEffect, useState} from 'react'; +import React, { useEffect, useState } from 'react'; import { RouteComponentProps, withRouter } from 'react-router-dom'; -import {useEffectOnce, useMount} from 'react-use'; +import { useEffectOnce, useMount } from 'react-use'; import { i18n } from '@osd/i18n'; import { EuiBottomBar, @@ -26,12 +26,17 @@ import { EuiTitle, } from '@elastic/eui'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; -import { PointInTimeAttributes, PointInTimeManagementContext} from '../../types'; +import { PointInTimeAttributes, PointInTimeManagementContext } from '../../types'; import { getEditBreadcrumbs } from '../breadcrumbs'; import { EditPitForm } from './edit_pit_form'; -import {findById, findPointInTimeSavedObject, updatePointInTimeById, updatePointInTimeKeepAlive} from '../utils'; -import {ToastMessageItem} from "../../../../data_source_management/public/types"; -import {getServices, Services} from "../../services"; +import { + findById, + findPointInTimeSavedObject, + updatePointInTimeById, + updatePointInTimeKeepAlive, +} from '../utils'; +import { ToastMessageItem } from '../../../../data_source_management/public/types'; +import { getServices, Services } from '../../services'; const defaultPitSavedObject: PointInTimeAttributes = { pit_id: '', @@ -46,11 +51,16 @@ const defaultPitSavedObject: PointInTimeAttributes = { export const PITEdit: React.FunctionComponent> = ( props: RouteComponentProps<{ id: string }> ) => { - const { setBreadcrumbs, savedObjects, notifications: { toasts }, http } = useOpenSearchDashboards< - PointInTimeManagementContext - >().services; + const { + setBreadcrumbs, + savedObjects, + notifications: { toasts }, + http, + } = useOpenSearchDashboards().services; const PitID: string = props.match.params.id; - const [pitSavedObject, setPitSavedObject] = useState(defaultPitSavedObject); + const [pitSavedObject, setPitSavedObject] = useState( + defaultPitSavedObject + ); const [isLoading, setIsLoading] = useState(false); const [newProp, setNewProp] = useState(false); const services: Services = getServices(http); @@ -79,11 +89,11 @@ export const PITEdit: React.FunctionComponent { console.log('These are the attributes', attributes); - const new_keep_alive_proposal = attributes.addtime.toString() + "m"; + const new_keep_alive_proposal = attributes.addtime.toString() + 'm'; console.log(attributes.pit_id, new_keep_alive_proposal); await services.addPitTime(attributes.pit_id, new_keep_alive_proposal); await updatePointInTimeById(savedObjects.client, attributes.id, attributes); diff --git a/src/plugins/point_in_time_management/public/components/pit_edit/edit_pit_form.tsx b/src/plugins/point_in_time_management/public/components/pit_edit/edit_pit_form.tsx index 78dacfc908f7..58d8f5bb0364 100644 --- a/src/plugins/point_in_time_management/public/components/pit_edit/edit_pit_form.tsx +++ b/src/plugins/point_in_time_management/public/components/pit_edit/edit_pit_form.tsx @@ -79,11 +79,11 @@ export class EditPitForm extends React.Component { if (this.props.existingPointInTime) { const { keepAlive, name, pit_id, id, addtime } = this.props.existingPointInTime; this.setState({ - keepAlive: keepAlive, - name: name, - pit_id: pit_id, - id: id, - addtime: addtime, + keepAlive, + name, + pit_id, + id, + addtime, }); } } @@ -115,7 +115,7 @@ export class EditPitForm extends React.Component { this.setState({ isLoading: true }); try { - console.log("OnClickUpdate", formValues); + console.log('OnClickUpdate', formValues); await this.props.handleSubmit(formValues); this.setState({ showUpdateOptions: false }); this.setFormValuesForEditMode(); @@ -162,8 +162,6 @@ export class EditPitForm extends React.Component { }, 0); }; - - onChangeTimeHr = (e: { target: { value: any } }) => { this.setState({ AddTimeHr: parseInt(e.target.value), @@ -268,10 +266,10 @@ export class EditPitForm extends React.Component { - + - + diff --git a/src/plugins/point_in_time_management/public/components/pit_table/pit_table.tsx b/src/plugins/point_in_time_management/public/components/pit_table/pit_table.tsx index a70d58936e7e..c21cd91cfa19 100644 --- a/src/plugins/point_in_time_management/public/components/pit_table/pit_table.tsx +++ b/src/plugins/point_in_time_management/public/components/pit_table/pit_table.tsx @@ -33,7 +33,14 @@ import { SavedObjectReference } from 'src/core/public'; import { getListBreadcrumbs } from '../breadcrumbs'; import { PointInTimeManagementContext } from '../../types'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; -import { getDataSources, PointInTime, createSavedObject, getSavedPits } from '../utils'; +import { + getDataSources, + PointInTime, + createSavedObject, + getSavedPits, + deletePointInTimeById, + updatePointInTimeSavedObject, +} from '../utils'; import { EmptyState, NoDataSourceState } from './empty_state'; // import { PageHeader } from './page_header'; import { getServices, Services } from '../../services'; @@ -51,6 +58,7 @@ export interface DashboardPitItem { name: string; creation_time: number; keep_alive: number; + delete_on_expiry: boolean; } export interface PitItem { @@ -163,28 +171,54 @@ const PITTable = ({ history }: RouteComponentProps) => { // if (fetchedDataSources?.length) { // setDashboardPits(fetchedDataSources); // } - + console.log('dashboard pits', fetchedDashboardPits); setLoading(false); if (fetchedPits?.resp?.pits) { - let expiredPits: DashboardPitItem[] = []; + const expiredPits: DashboardPitItem[] = []; + // if (dataSourceId === undefined) { + // expiredPits = fetchedDashboardPits.filter( + // (x) => !fetchedPits?.resp?.pits.some((x2) => x.attributes.id === x2.pit_id) + // ); + // } + // console.log('expired', expiredPits); + // expiredPits.filter(x=>x.attributes.delete_on_expiry).forEach(x=> { + // console.log('deleting ', x) + // deletePointInTimeById(savedObjects.client, x.id); + // }) + if (dataSourceId === undefined) { - expiredPits = fetchedDashboardPits.filter( - (x) => !fetchedPits?.resp?.pits.some((x2) => x.attributes.id === x2.pit_id) - ); + fetchedDashboardPits.forEach((x) => { + if (!fetchedPits?.resp?.pits.some((x2) => x.attributes.pit_id === x2.pit_id)) { + if (x.attributes.delete_on_expiry) { + console.log('deleting ', x); + deletePointInTimeById(savedObjects.client, x.id); + } else { + expiredPits.push(x); + } + } + }); } console.log('expired', expiredPits); + setPits( fetchedPits?.resp?.pits .map((val) => { const date = moment(val.creation_time); - let formattedDate = date.format('MMM D @ HH:mm:ss'); + const formattedDate = date.format('MMM D @ HH:mm:ss'); const expiry = val.creation_time + val.keep_alive; const dashboardPit = fetchedDashboardPits.filter( (x) => x.attributes.pit_id === val.pit_id ); - let isSavedObject = false; if (dashboardPit.length > 0) { - isSavedObject = true; + console.log(dashboardPit); + dashboardPit[0].attributes.keepAlive = val.keep_alive; + console.log('updating', dashboardPit); + updatePointInTimeSavedObject( + savedObjects.client, + dashboardPit[0].id, + dashboardPit[0].attributes, + dashboardPit[0].references + ); return { pit_id: val.pit_id, id: dashboardPit[0].id, @@ -192,7 +226,7 @@ const PITTable = ({ history }: RouteComponentProps) => { creation_time: val.creation_time, keep_alive: val.keep_alive, dataSource: dataSourceName, - isSavedObject, + isSavedObject: true, expiry, }; } @@ -203,7 +237,7 @@ const PITTable = ({ history }: RouteComponentProps) => { creation_time: val.creation_time, keep_alive: val.keep_alive, dataSource: dataSourceName, - isSavedObject, + isSavedObject: false, expiry, }; }) @@ -247,17 +281,17 @@ const PITTable = ({ history }: RouteComponentProps) => { // setIsFlyoutVisible(false); const pit: PointInTime = { pit_id: - 'o463QQIHdGVzdC0wMRZCaEJjeGcxUFRxdWlqR1VucTE0dkpnARZNLXdhOWdoRFJJeXFRRWp1RkdqZ05nAAAAAAAAAF09FlRNaE5OQy1LUzdTS0h5NThWY1oySkEHdGVzdC0wMRZCaEJjeGcxUFRxdWlqR1VucTE0dkpnABZNLXdhOWdoRFJJeXFRRWp1RkdqZ05nAAAAAAAAAF08FlRNaE5OQy1LUzdTS0h5NThWY1oySkEBFkJoQmN4ZzFQVHF1aWpHVW5xMTR2SmcAAA==', - keepAlive: 300000, - creation_time: 1681386155468, - name: 'PIT-my-index-2-3-new', // Todo create pit and fill the pit id + 'o463QQEKbXktaW5kZXgtMRZqUlZFU2lSaFE1eUx0cHdiSjNLWjRRABZtWjNCdk1ZdFRZbS1JbnltaVlBTWdBAAAAAAAAAACGFlJXLVVNYXVQVFctQVIxVmh1OUJuSlEBFmpSVkVTaVJoUTV5THRwd2JKM0taNFEAAA==', + keepAlive: 30000000, + creation_time: 1684418768188, + name: 'PIT-my-index-1223', // Todo create pit and fill the pit id delete_on_expiry: false, }; const reference: SavedObjectReference = { - id: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f', + id: '5586e600-f57b-11ed-90e3-a75eeb2a18a5', type: 'index-pattern', - name: 'opensearch_dashboards_sample_data_ecommerce', + name: 'my*', }; createSavedObject(pit, savedObjects.client, reference); }; diff --git a/src/plugins/point_in_time_management/public/components/utils.ts b/src/plugins/point_in_time_management/public/components/utils.ts index 41a0f90fcc35..9e4c3e6ca88c 100644 --- a/src/plugins/point_in_time_management/public/components/utils.ts +++ b/src/plugins/point_in_time_management/public/components/utils.ts @@ -5,7 +5,7 @@ import { SavedObjectReference, SavedObjectsClientContract } from 'src/core/public'; import { DataSourceAttributes } from 'src/plugins/data_source/common/data_sources'; -import {PointInTimeAttributes} from "../types"; +import { PointInTimeAttributes } from '../types'; export async function getDataSources(savedObjectsClient: SavedObjectsClientContract) { return savedObjectsClient @@ -133,20 +133,35 @@ export async function updatePointInTimeById( return savedObjectsClient.update('point-in-time', id, attributes); } -export async function updatePointInTimeKeepAlive( +export async function updatePointInTimeSavedObject( savedObjectsClient: SavedObjectsClientContract, id: string, - addTime: number + attributes: PointInTimeAttributes, + reference: SavedObjectReference[] ) { + return savedObjectsClient.update('point-in-time', id, attributes, { references: reference }); +} +export async function deletePointInTimeById( + savedObjectsClient: SavedObjectsClientContract, + id: string +) { + return savedObjectsClient.delete('point-in-time', id); } + +export async function updatePointInTimeKeepAlive( + savedObjectsClient: SavedObjectsClientContract, + id: string, + addTime: number +) {} + export async function createSavedObject( pointintime: PointInTime, client: SavedObjectsClientContract, reference: SavedObjectReference ) { const dupe = await findById(client, pointintime.pit_id); - console.log("This is dupe output") + console.log('This is dupe output'); console.log(dupe); if (dupe) { throw new Error(`Duplicate Point in time: ${pointintime.pit_id}`); @@ -165,7 +180,7 @@ export async function createSavedObject( const response = await client.create(savedObjectType, body, { references, }); - console.log("This is the response"); + console.log('This is the response'); console.log(response); pointintime.id = response.id; console.log(pointintime); diff --git a/src/plugins/point_in_time_management/public/management_app/mount_management_section.tsx b/src/plugins/point_in_time_management/public/management_app/mount_management_section.tsx index 2408313ef732..707d601fc399 100644 --- a/src/plugins/point_in_time_management/public/management_app/mount_management_section.tsx +++ b/src/plugins/point_in_time_management/public/management_app/mount_management_section.tsx @@ -13,7 +13,7 @@ import { StartServicesAccessor } from '../../../../core/public'; import { PointInTimeManagementContext } from '../types'; import { OpenSearchDashboardsContextProvider } from '../../../opensearch_dashboards_react/public'; import { PITTableWithRouter } from '../components'; -import {PITEditWithRouter} from "../components/pit_edit"; +import { PITEditWithRouter } from '../components/pit_edit'; export async function mountManagementSection( getStartServices: StartServicesAccessor, diff --git a/src/plugins/point_in_time_management/public/services.ts b/src/plugins/point_in_time_management/public/services.ts index e95247f8dd7a..180b6787f7fc 100644 --- a/src/plugins/point_in_time_management/public/services.ts +++ b/src/plugins/point_in_time_management/public/services.ts @@ -20,7 +20,7 @@ export function getServices(http: CoreStart['http']): Services { dataSourceId: dataSourceId ? dataSourceId : '', }), }); - console.log("These are backend PITs"); + console.log('These are backend PITs'); console.log(response); return response; } catch (e) { @@ -33,11 +33,11 @@ export function getServices(http: CoreStart['http']): Services { const response = await http.post('/api/pit/addTime', { body: JSON.stringify({ dataSourceId: dataSourceId ? dataSourceId : 'default', - pit_id: pit_id, - keepAlive: keepAlive, + pit_id, + keepAlive, }), }); - console.log("Updated the PIT KeepAlive"); + console.log('Updated the PIT KeepAlive'); console.log(response); } catch (e) { return e;