diff --git a/src/plugins/data/common/search/search_source/fetch/get_search_params.ts b/src/plugins/data/common/search/search_source/fetch/get_search_params.ts index a25d6e530bad..19917e543ea1 100644 --- a/src/plugins/data/common/search/search_source/fetch/get_search_params.ts +++ b/src/plugins/data/common/search/search_source/fetch/get_search_params.ts @@ -59,6 +59,13 @@ export function getSearchParamsFromRequest( const { getConfig } = dependencies; const searchParams = getSearchParams(getConfig); + if (searchRequest.body.pit) { + delete searchParams.preference; + return { + body: searchRequest.body, + ...searchParams, + }; + } return { index: searchRequest.index.title || searchRequest.index, body: searchRequest.body, diff --git a/src/plugins/data/server/search/opensearch_search/get_default_search_params.ts b/src/plugins/data/server/search/opensearch_search/get_default_search_params.ts index d7cbd48a6507..fc85d23a8068 100644 --- a/src/plugins/data/server/search/opensearch_search/get_default_search_params.ts +++ b/src/plugins/data/server/search/opensearch_search/get_default_search_params.ts @@ -49,7 +49,7 @@ export async function getDefaultSearchParams(uiSettingsClient: IUiSettingsClient maxConcurrentShardRequests: maxConcurrentShardRequests > 0 ? maxConcurrentShardRequests : undefined, ignoreThrottled, - ignoreUnavailable: true, // Don't fail if the index/indices don't exist + ignoreUnavailable: false, // Don't fail if the index/indices don't exist trackTotalHits: true, }; } diff --git a/src/plugins/data/server/search/opensearch_search/opensearch_search_strategy.ts b/src/plugins/data/server/search/opensearch_search/opensearch_search_strategy.ts index ba50740e6baf..83aee77856e9 100644 --- a/src/plugins/data/server/search/opensearch_search/opensearch_search_strategy.ts +++ b/src/plugins/data/server/search/opensearch_search/opensearch_search_strategy.ts @@ -72,6 +72,11 @@ export const opensearchSearchStrategyProvider = ( ...request.params, }); + console.log('This is the params', params); + + if (params.body.pit) { + delete params.ignore_unavailable; + } try { const client = await decideClient(context, request); const promise = shimAbortSignal(client.search(params), options?.abortSignal); diff --git a/src/plugins/discover/public/application/angular/discover.js b/src/plugins/discover/public/application/angular/discover.js index de244e3c44b6..a81d9bb07202 100644 --- a/src/plugins/discover/public/application/angular/discover.js +++ b/src/plugins/discover/public/application/angular/discover.js @@ -77,6 +77,7 @@ const { toastNotifications, uiSettings: config, visualizations, + savedObjectsClient, } = getServices(); import { getRootBreadcrumbs, getSavedSearchBreadcrumbs } from '../helpers/breadcrumbs'; @@ -102,6 +103,33 @@ const fetchStatuses = { const app = getAngularModule(); +export async function getpits(savedObjectsClient) { + return ( + savedObjectsClient + .find({ + type: 'point-in-time', + perPage: 10000, + }) + .then((response) => + response.savedObjects + .map((pattern) => { + return { + ...pattern, + }; + }) + .sort((a, b) => { + if (a.sort < b.sort) { + return -1; + } else if (a.sort > b.sort) { + return 1; + } else { + return 0; + } + }) + ) || [] + ); +} + app.config(($routeProvider) => { const defaults = { requireDefaultIndex: true, @@ -129,14 +157,14 @@ app.config(($routeProvider) => { template: indexTemplateLegacy, reloadOnSearch: false, resolve: { - savedObjects: function ($route, Promise) { + savedObjects: async function ($route, Promise) { const history = getHistory(); const savedSearchId = $route.current.params.id; - return data.indexPatterns.ensureDefaultIndexPattern(history).then(() => { + return await data.indexPatterns.ensureDefaultIndexPattern(history).then(async () => { const { appStateContainer } = getState({ history }); - const { index } = appStateContainer.getState(); - return Promise.props({ - ip: indexPatterns.getCache().then((indexPatternList) => { + const { index, pitid } = appStateContainer.getState(); + return await Promise.props({ + ip: await indexPatterns.getCache().then(async (indexPatternList) => { /** * In making the indexPattern modifiable it was placed in appState. Unfortunately, * the load order of AppState conflicts with the load order of many other things @@ -154,6 +182,10 @@ app.config(($routeProvider) => { stateValFound: !!index && id === index, }); }), + pit: await Promise.props({ + list: await getpits(savedObjectsClient, history), + pitid: pitid, + }), savedSearch: getServices() .getSavedSearchById(savedSearchId) .then((savedSearch) => { @@ -209,6 +241,7 @@ function discoverController($element, $route, $scope, $timeout, $window, Promise const savedSearch = $route.current.locals.savedObjects.savedSearch; $scope.searchSource = savedSearch.searchSource; $scope.indexPattern = resolveIndexPatternLoading(); + $scope.selectedPointInTime = $route.current.locals.savedObjects.pit.pitid || undefined; //used for functional testing $scope.fetchCounter = 0; @@ -239,7 +272,7 @@ function discoverController($element, $route, $scope, $timeout, $window, Promise setAppState({ index: $scope.indexPattern.id }); } $scope.state = { ...appStateContainer.getState() }; - + console.log("state is", $scope.state); // syncs `_g` portion of url with query services const { stop: stopSyncingGlobalStateWithUrl } = syncQueryStateWithUrl( data.query, @@ -294,20 +327,52 @@ function discoverController($element, $route, $scope, $timeout, $window, Promise }); $scope.setIndexPattern = async (id) => { - const nextIndexPattern = await indexPatterns.get(id); - if (nextIndexPattern) { - const nextAppState = getSwitchIndexPatternAppState( - $scope.indexPattern, - nextIndexPattern, - $scope.state.columns, - $scope.state.sort, - config.get(MODIFY_COLUMNS_ON_SWITCH) - ); - await replaceUrlAppState(nextAppState); - $route.reload(); + try { + const nextIndexPattern = await indexPatterns.get(id); + if (nextIndexPattern) { + const nextAppState = getSwitchIndexPatternAppState( + $scope.indexPattern, + nextIndexPattern, + $scope.state.columns, + $scope.state.sort, + config.get(MODIFY_COLUMNS_ON_SWITCH) + ); + await replaceUrlAppState(nextAppState); + $route.reload(); + } + } catch (e) { + const nextIndexPattern = await indexPatterns.get(id); + if (nextIndexPattern) { + const nextAppState = getSwitchIndexPatternAppState( + $scope.indexPattern, + nextIndexPattern, + $scope.state.columns, + $scope.state.sort, + config.get(MODIFY_COLUMNS_ON_SWITCH) + ); + await replaceUrlAppState(nextAppState); + $route.reload(); + } } }; + $scope.setPointInTime = async (id) => { + console.log('This is the pit list', $route.current.locals.savedObjects.pit.list, id); + const pitList = await $route.current.locals.savedObjects.pit.list; + const nextPit = pitList.find((pit) => pit.attributes.pit_id === id); + console.log(nextPit); + const nextAppState = getSwitchIndexPatternAppState( + $scope.indexPattern, + nextPit, + $scope.state.columns, + $scope.state.sort, + config.get(MODIFY_COLUMNS_ON_SWITCH) + ); + await replaceUrlAppState(nextAppState); + await $route.reload(); + }; + + // update data source when filters update subscriptions.add( subscribeWithScope( @@ -627,6 +692,7 @@ function discoverController($element, $route, $scope, $timeout, $window, Promise timefield: getTimeField(), savedSearch: savedSearch, indexPatternList: $route.current.locals.savedObjects.ip.list, + pointInTimeList: $route.current.locals.savedObjects.pit.list, config: config, fixedScroll: createFixedScroll($scope, $timeout), setHeaderActionMenu: getHeaderActionMenuMounter(), @@ -805,26 +871,55 @@ function discoverController($element, $route, $scope, $timeout, $window, Promise if (abortController) abortController.abort(); abortController = new AbortController(); - $scope - .updateDataSource() - .then(setupVisualization) - .then(function () { - $scope.fetchStatus = fetchStatuses.LOADING; - logInspectorRequest(); - return $scope.searchSource.fetch({ - abortSignal: abortController.signal, - }); + if ($scope.selectedPointInTime != null) { + $scope.updateDataSource().then(setupVisualization). + then(async function () { + $scope.fetchStatus = fetchStatuses.LOADING; + logInspectorRequest(); + const search_source_local = _.cloneDeep($scope.searchSource); + console.log("this is local search source"); + const point_in_time_object = $scope.opts.pointInTimeList.find((object) => object.id === $scope.selectedPointInTime); + const pit_object = { + pit: { + id: point_in_time_object.attributes.pit_id, + keep_alive: '1m', + }, + }; + const pit_json = JSON.parse(JSON.stringify(pit_object)); + search_source_local.fields = { ...search_source_local.fields, ...pit_json}; + delete search_source_local.fields.index; + return await search_source_local.fetch({ + abortSignal: abortController.signal, + }); }) - .then(onResults) - .catch((error) => { - // If the request was aborted then no need to surface this error in the UI - if (error instanceof Error && error.name === 'AbortError') return; + .then(onResults).catch((error) => { + if (error instanceof Error && error.name === 'AbortError') return; + $scope.fetchStatus = fetchStatuses.NO_RESULTS; + $scope.rows = []; + data.search.showError(error); + }); + } else { + $scope + .updateDataSource() + .then(setupVisualization) + .then(function () { + $scope.fetchStatus = fetchStatuses.LOADING; + logInspectorRequest(); + return $scope.searchSource.fetch({ + abortSignal: abortController.signal, + }); + }) + .then(onResults) + .catch((error) => { + // If the request was aborted then no need to surface this error in the UI + if (error instanceof Error && error.name === 'AbortError') return; - $scope.fetchStatus = fetchStatuses.NO_RESULTS; - $scope.rows = []; + $scope.fetchStatus = fetchStatuses.NO_RESULTS; + $scope.rows = []; - data.search.showError(error); - }); + data.search.showError(error); + }); + } }; $scope.handleRefresh = function (_payload, isUpdate) { @@ -876,6 +971,7 @@ function discoverController($element, $route, $scope, $timeout, $window, Promise } function onResults(resp) { + console.log('response after fetching the results', resp); inspectorRequest.stats(getResponseInspectorStats(resp, $scope.searchSource)).ok({ json: resp }); if (getTimeField()) { @@ -891,6 +987,10 @@ function discoverController($element, $route, $scope, $timeout, $window, Promise $scope.hits = resp.hits.total; $scope.rows = resp.hits.hits; + // debugger; + // console.log($scope.hits); + // console.log($scope.rows); + // if we haven't counted yet, reset the counts const counts = ($scope.fieldCounts = $scope.fieldCounts || {}); diff --git a/src/plugins/discover/public/application/angular/discover_legacy.html b/src/plugins/discover/public/application/angular/discover_legacy.html index 8582f71c0cb8..afbbf5570322 100644 --- a/src/plugins/discover/public/application/angular/discover_legacy.html +++ b/src/plugins/discover/public/application/angular/discover_legacy.html @@ -23,6 +23,8 @@ saved-search="savedSearch" search-source="searchSource" set-index-pattern="setIndexPattern" + set-point-in-time="setPointInTime" + selected-point-in-time="selectedPointInTime" show-save-query="showSaveQuery" state="state" time-filter-update-handler="timefilterUpdateHandler" diff --git a/src/plugins/discover/public/application/components/create_discover_legacy_directive.ts b/src/plugins/discover/public/application/components/create_discover_legacy_directive.ts index 09cc33964862..2b4b6e6e66a6 100644 --- a/src/plugins/discover/public/application/components/create_discover_legacy_directive.ts +++ b/src/plugins/discover/public/application/components/create_discover_legacy_directive.ts @@ -55,6 +55,8 @@ export function createDiscoverLegacyDirective(reactDirective: any) { ['savedSearch', { watchDepth: 'reference' }], ['searchSource', { watchDepth: 'reference' }], ['setIndexPattern', { watchDepth: 'reference' }], + ['setPointInTime', { watchDepth: 'reference' }], + ['selectedPointInTime', { watchDepth: 'reference' }], ['showSaveQuery', { watchDepth: 'reference' }], ['state', { watchDepth: 'reference' }], ['timefilterUpdateHandler', { watchDepth: 'reference' }], diff --git a/src/plugins/discover/public/application/components/discover_legacy.tsx b/src/plugins/discover/public/application/components/discover_legacy.tsx index 3e6e96fc6124..a6c94aff49a7 100644 --- a/src/plugins/discover/public/application/components/discover_legacy.tsx +++ b/src/plugins/discover/public/application/components/discover_legacy.tsx @@ -81,6 +81,7 @@ export interface DiscoverLegacyProps { savedSearch: SavedSearch; config: IUiSettingsClient; indexPatternList: Array>; + pointInTimeList: any; timefield: string; sampleSize: number; fixedScroll: (el: HTMLElement) => void; @@ -99,6 +100,8 @@ export interface DiscoverLegacyProps { updateQuery: (payload: { dateRange: TimeRange; query?: Query }, isUpdate?: boolean) => void; updateSavedQueryId: (savedQueryId?: string) => void; vis?: Vis; + selectedPointInTime: any; + setPointInTime: (id: string) => void; } export function DiscoverLegacy({ @@ -130,10 +133,12 @@ export function DiscoverLegacy({ updateQuery, updateSavedQueryId, vis, + selectedPointInTime, + setPointInTime, }: DiscoverLegacyProps) { const [isSidebarClosed, setIsSidebarClosed] = useState(false); const { TopNavMenu } = getServices().navigation.ui; - const { savedSearch, indexPatternList } = opts; + const { savedSearch, indexPatternList, pointInTimeList } = opts; const bucketAggConfig = vis?.data?.aggs?.aggs[1]; const bucketInterval = bucketAggConfig && search.aggs.isDateHistogramBucketAggConfig(bucketAggConfig) @@ -141,6 +146,13 @@ export function DiscoverLegacy({ : undefined; const [fixedScrollEl, setFixedScrollEl] = useState(); + // The selected Point in time here is the id of the saved object, We will be passing the complete object later + if (selectedPointInTime != null) { + selectedPointInTime = pointInTimeList.find( + (pattern) => pattern.id === selectedPointInTime + ); + } + useEffect(() => (fixedScrollEl ? opts.fixedScroll(fixedScrollEl) : undefined), [ fixedScrollEl, opts, @@ -195,11 +207,14 @@ export function DiscoverLegacy({ fieldCounts={fieldCounts} hits={rows} indexPatternList={indexPatternList} + pointInTimeList={pointInTimeList} onAddField={addColumn} onAddFilter={onAddFilter} onRemoveField={onRemoveColumn} selectedIndexPattern={searchSource && searchSource.getField('index')} setIndexPattern={setIndexPattern} + selectedPointInTime={selectedPointInTime} // currently search source do not support pit hence passing it in props + setPointInTime={setPointInTime} // here we have the complete object /> )} diff --git a/src/plugins/discover/public/application/components/sidebar/change_indexpattern.tsx b/src/plugins/discover/public/application/components/sidebar/change_indexpattern.tsx index 553031f06721..2d301fa8c4c8 100644 --- a/src/plugins/discover/public/application/components/sidebar/change_indexpattern.tsx +++ b/src/plugins/discover/public/application/components/sidebar/change_indexpattern.tsx @@ -29,16 +29,21 @@ */ import { i18n } from '@osd/i18n'; -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { EuiButtonEmpty, EuiPopover, EuiPopoverTitle, EuiSelectable, EuiButtonEmptyProps, + EuiSpacer, + EuiFlexGroup, + EuiFlexItem, + EuiSelectableOption, } from '@elastic/eui'; import { EuiSelectableProps } from '@elastic/eui/src/components/selectable/selectable'; -import { IndexPatternRef } from './types'; +import { IndexPatternRef, PointInTimeRef } from './types'; +import { ChangePatternFilter } from './change_pattern_filter'; export type ChangeIndexPatternTriggerProps = EuiButtonEmptyProps & { label: string; @@ -47,20 +52,25 @@ export type ChangeIndexPatternTriggerProps = EuiButtonEmptyProps & { export function ChangeIndexPattern({ indexPatternRefs, + pointInTimeRefs, indexPatternId, - onChangeIndexPattern, + onChangePattern, trigger, selectableProps, }: { trigger: ChangeIndexPatternTriggerProps; indexPatternRefs: IndexPatternRef[]; - onChangeIndexPattern: (newId: string) => void; + pointInTimeRefs: PointInTimeRef[]; + onChangePattern: (newId: string) => void; indexPatternId?: string; selectableProps?: EuiSelectableProps; }) { const [isPopoverOpen, setPopoverIsOpen] = useState(false); + const [isIndexPatternSelected, setIndexPatternIsSelected] = useState(true); + const [isPointInTimeSelected, setPointInTimeIsSelected] = useState(true); const createTrigger = function () { + const { label, title, ...rest } = trigger; return ( { + return isSelected + ? [ + // { + // label: 'index-pattern', + // isGroupLabel: true, + // }, + ...indexPatternRefs.map( + ({ title, id }): EuiSelectableOption => ({ + label: title, + key: id, + searchableLabel: title, + value: id, + checked: id === indexPatternId ? 'on' : undefined, + }) + ), + ] + : []; + }; + + const pointInTimeOptions = (isSelected: boolean) => { + return isSelected + ? [ + // { + // label: 'point-in-time', + // isGroupLabel: true, + // }, + ...pointInTimeRefs.map( + ({ title, id, references }): EuiSelectableOption => ({ + label: "PIT-" + title , + key: title, + searchableLabel: title, + value: id, + references, + checked: id === indexPatternId ? 'on' : undefined, + }) + ), + ] + : []; + }; + + const [options, setOptions] = useState>>([ + ...indexPatternOptions(isIndexPatternSelected), + ...pointInTimeOptions(isPointInTimeSelected), + ]); + + useEffect(() => { + setOptions([ + ...indexPatternOptions(isIndexPatternSelected), + ...pointInTimeOptions(isPointInTimeSelected), + ]); + }, [isIndexPatternSelected, isPointInTimeSelected]); + return ( -
+
{i18n.translate('discover.fieldChooser.indexPattern.changeIndexPatternTitle', { defaultMessage: 'Change index pattern', })} + ({ - label: title, - key: id, - value: id, - checked: id === indexPatternId ? 'on' : undefined, - }))} - onChange={(choices) => { + options={options} + onChange={(choices: Array>) => { const choice = (choices.find(({ checked }) => checked) as unknown) as { value: string; }; - onChangeIndexPattern(choice.value); + onChangePattern(choice.value); setPopoverIsOpen(false); }} searchProps={{ @@ -120,7 +184,14 @@ export function ChangeIndexPattern({ > {(list, search) => ( <> - {search} + + {search} + + + {list} )} diff --git a/src/plugins/discover/public/application/components/sidebar/change_pattern_filter.tsx b/src/plugins/discover/public/application/components/sidebar/change_pattern_filter.tsx new file mode 100644 index 000000000000..1c3732681273 --- /dev/null +++ b/src/plugins/discover/public/application/components/sidebar/change_pattern_filter.tsx @@ -0,0 +1,80 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiButton, + EuiFlexItem, + EuiPopover, + EuiSelectable, + EuiSelectableOption, +} from '@elastic/eui'; +import React, { useState } from 'react'; + +interface ChangePatternDeps { + setIndexPatternIsSelected: (value: boolean) => void; + setPointInTimeIsSelected: (value: boolean) => void; +} + +export function ChangePatternFilter({ + setIndexPatternIsSelected, + setPointInTimeIsSelected, +}: ChangePatternDeps) { + const [options, setOptions] = useState([ + { label: 'point-in-time', checked: 'on' }, + { label: 'index-pattern', checked: 'on' }, + ]); + + const [isPopoverOpen, setPopoverIsOpen] = useState(false); + + return ( + + setPopoverIsOpen(!isPopoverOpen)} + size="s" + > + Filter + + } + isOpen={isPopoverOpen} + closePopover={() => setPopoverIsOpen(false)} + > + { + choices.find((option) => { + if (option.label == 'point-in-time') { + if (option.checked) { + setPointInTimeIsSelected(true); + } else { + setPointInTimeIsSelected(false); + } + } + + if (option.label == 'index-pattern') { + if (option.checked) { + setIndexPatternIsSelected(true); + } else { + setIndexPatternIsSelected(false); + } + } + }); + setOptions(choices); + }} + > + {(list) =>
{list}
} +
+
+
+ ); +} diff --git a/src/plugins/discover/public/application/components/sidebar/discover_index_pattern.tsx b/src/plugins/discover/public/application/components/sidebar/discover_index_pattern.tsx index 95154bec1939..2f7bdcd5c3f5 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_index_pattern.tsx +++ b/src/plugins/discover/public/application/components/sidebar/discover_index_pattern.tsx @@ -33,21 +33,26 @@ import { SavedObject } from 'opensearch-dashboards/public'; import { IIndexPattern, IndexPatternAttributes } from 'src/plugins/data/public'; import { I18nProvider } from '@osd/i18n/react'; -import { IndexPatternRef } from './types'; +import { IndexPatternRef, PointInTimeRef } from './types'; import { ChangeIndexPattern } from './change_indexpattern'; +import {PointInTimeAttributes} from "../../../../../point_in_time_management/public/types"; + export interface DiscoverIndexPatternProps { /** * list of available index patterns, if length > 1, component offers a "change" link */ indexPatternList: Array>; + pointInTimeList: Array>; /** * currently selected index pattern, due to angular issues it's undefined at first rendering */ + selectedPointInTime: any; selectedIndexPattern: IIndexPattern; /** * triggered when user selects a new index pattern */ setIndexPattern: (id: string) => void; + setPointInTime: (id: string) => void; } /** @@ -55,25 +60,44 @@ export interface DiscoverIndexPatternProps { */ export function DiscoverIndexPattern({ indexPatternList, + pointInTimeList, selectedIndexPattern, + selectedPointInTime, setIndexPattern, + setPointInTime, }: DiscoverIndexPatternProps) { const options: IndexPatternRef[] = (indexPatternList || []).map((entity) => ({ id: entity.id, title: entity.attributes!.title, + type: entity.type, + })); + + const point_in_time_options: PointInTimeRef[] = (pointInTimeList || []).map((entity) => ({ + id: entity.id, + title: entity.attributes!.name, + type: entity.type, + references: entity.references, + pit_id: entity.attributes.pit_id, })); - const { id: selectedId, title: selectedTitle } = selectedIndexPattern || {}; + console.log('this is the selected point in time object'); + console.log(selectedPointInTime); + // TODO: will have a title attribute in the saved object of Point in time + if (selectedPointInTime) { + + selectedPointInTime = { ...selectedPointInTime, title: selectedPointInTime?.attributes?.name }; + } + const selectedPattern = selectedPointInTime || selectedIndexPattern || {}; + const { id: selectedId, title: selectedTitle } = selectedPattern; const [selected, setSelected] = useState({ id: selectedId, title: selectedTitle || '', }); useEffect(() => { - const { id, title } = selectedIndexPattern; - const indexPattern = indexPatternList.find((pattern) => pattern.id === id); - const titleToDisplay = indexPattern ? indexPattern.attributes!.title : title; - setSelected({ id, title: titleToDisplay }); - }, [indexPatternList, selectedIndexPattern]); + const { id, title } = selectedPattern; + debugger; + setSelected({ id, title }); + }, []); if (!selectedId) { return null; } @@ -90,12 +114,21 @@ export function DiscoverIndexPattern({ }} indexPatternId={selected.id} indexPatternRefs={options} - onChangeIndexPattern={(id) => { + pointInTimeRefs={point_in_time_options} + onChangePattern={(id) => { const indexPattern = options.find((pattern) => pattern.id === id); if (indexPattern) { setIndexPattern(id); setSelected(indexPattern); } + const pointInTime = point_in_time_options.find((pattern) => pattern.id === id); + if (pointInTime) { + console.log("this is the PIT selected", pointInTime); + setPointInTime(pointInTime.pit_id); + const PitId = pointInTimeList[0].attributes.pit_id; + const title = pointInTimeList[0].attributes.name; + setSelected({ id: PitId, title }); + } }} /> diff --git a/src/plugins/discover/public/application/components/sidebar/discover_sidebar.tsx b/src/plugins/discover/public/application/components/sidebar/discover_sidebar.tsx index 865aff590286..fccec17ccb05 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_sidebar.tsx +++ b/src/plugins/discover/public/application/components/sidebar/discover_sidebar.tsx @@ -46,6 +46,7 @@ import { getDetails } from './lib/get_details'; import { getDefaultFieldFilter, setFieldFilterProp } from './lib/field_filter'; import { getIndexPatternFieldList } from './lib/get_index_pattern_field_list'; import { getServices } from '../../../opensearch_dashboards_services'; +import { PointInTimeAttributes } from '../../../../../point_in_time_management/public/types'; export interface DiscoverSidebarProps { /** @@ -64,6 +65,7 @@ export interface DiscoverSidebarProps { * List of available index patterns */ indexPatternList: Array>; + pointInTimeList: Array>; /** * Callback function when selecting a field */ @@ -85,6 +87,8 @@ export interface DiscoverSidebarProps { * Callback function to select another index pattern */ setIndexPattern: (id: string) => void; + selectedPointInTime: any; + setPointInTime: (id: string) => void; } export function DiscoverSidebar({ @@ -92,11 +96,14 @@ export function DiscoverSidebar({ fieldCounts, hits, indexPatternList, + pointInTimeList, onAddField, onAddFilter, onRemoveField, selectedIndexPattern, setIndexPattern, + setPointInTime, + selectedPointInTime, }: DiscoverSidebarProps) { const [showFields, setShowFields] = useState(false); const [fields, setFields] = useState(null); @@ -164,6 +171,9 @@ export function DiscoverSidebar({ selectedIndexPattern={selectedIndexPattern} setIndexPattern={setIndexPattern} indexPatternList={sortBy(indexPatternList, (o) => o.attributes.title)} + pointInTimeList={pointInTimeList} + setPointInTime={setPointInTime} + selectedPointInTime={selectedPointInTime} />
diff --git a/src/plugins/discover/public/application/components/sidebar/types.ts b/src/plugins/discover/public/application/components/sidebar/types.ts index a43120b28e96..b9899e8d12de 100644 --- a/src/plugins/discover/public/application/components/sidebar/types.ts +++ b/src/plugins/discover/public/application/components/sidebar/types.ts @@ -33,6 +33,14 @@ export interface IndexPatternRef { title: string; } +export interface PointInTimeRef { + id: string; + title: string; + type: string; + references?: any; + pit_id: string; +} + export interface FieldDetails { error: string; exists: number; diff --git a/src/plugins/discover/public/application/helpers/get_switch_index_pattern_app_state.ts b/src/plugins/discover/public/application/helpers/get_switch_index_pattern_app_state.ts index 51835910a402..9aedb07fd95b 100644 --- a/src/plugins/discover/public/application/helpers/get_switch_index_pattern_app_state.ts +++ b/src/plugins/discover/public/application/helpers/get_switch_index_pattern_app_state.ts @@ -36,23 +36,38 @@ import { IndexPattern } from '../../opensearch_dashboards_services'; * Helper function to remove or adapt the currently selected columns/sort to be valid with the next * index pattern, returns a new state object */ + +export interface PointInTime { + attributes: any; + id: string; +} + export function getSwitchIndexPatternAppState( - currentIndexPattern: IndexPattern, - nextIndexPattern: IndexPattern, + currentIndexPattern: IndexPattern | PointInTime, + nextIndexPattern: IndexPattern | PointInTime, currentColumns: string[], currentSort: SortPairArr[], modifyColumns: boolean = true ) { - const nextColumns = modifyColumns - ? currentColumns.filter( - (column) => - nextIndexPattern.fields.getByName(column) || !currentIndexPattern.fields.getByName(column) - ) - : currentColumns; - const nextSort = getSortArray(currentSort, nextIndexPattern); - return { - index: nextIndexPattern.id, - columns: nextColumns.length ? nextColumns : ['_source'], - sort: nextSort, - }; + if(nextIndexPattern.attributes) { + return { + pitid: nextIndexPattern.id, + index: null, + }; + } else { + const nextColumns = modifyColumns + ? currentColumns.filter( + (column) => + nextIndexPattern.fields.getByName(column) || + !currentIndexPattern.fields.getByName(column) + ) + : currentColumns; + const nextSort = getSortArray(currentSort, nextIndexPattern); + return { + index: nextIndexPattern.id, + pitid: null, + columns: nextColumns.length ? nextColumns : ['_source'], + sort: nextSort, + }; + } } diff --git a/src/plugins/discover/public/build_services.ts b/src/plugins/discover/public/build_services.ts index 3fdafcff0c40..7ca5044502c7 100644 --- a/src/plugins/discover/public/build_services.ts +++ b/src/plugins/discover/public/build_services.ts @@ -38,6 +38,7 @@ import { ToastsStart, IUiSettingsClient, PluginInitializerContext, + SavedObjectsClientContract, } from 'opensearch-dashboards/public'; import { FilterManager, @@ -82,6 +83,7 @@ export interface DiscoverServices { getEmbeddableInjector: any; uiSettings: IUiSettingsClient; visualizations: VisualizationsStart; + savedObjectsClient: SavedObjectsClientContract; } export async function buildServices( @@ -125,5 +127,6 @@ export async function buildServices( toastNotifications: core.notifications.toasts, uiSettings: core.uiSettings, visualizations: plugins.visualizations, + savedObjectsClient: core.savedObjects.client, }; } diff --git a/src/plugins/point_in_time_management/public/components/create_button/create_button.tsx b/src/plugins/point_in_time_management/public/components/create_button/create_button.tsx index 29d57ce8c06b..bc05b5485c1d 100644 --- a/src/plugins/point_in_time_management/public/components/create_button/create_button.tsx +++ b/src/plugins/point_in_time_management/public/components/create_button/create_button.tsx @@ -22,10 +22,7 @@ export const CreateButton = ({ history, isEmptyState, dataTestSubj }: Props) => fill={isEmptyState ? false : true} onClick={() => history.push('/create')} > - + ); }; diff --git a/src/plugins/point_in_time_management/public/components/create_pit/create_pit.tsx b/src/plugins/point_in_time_management/public/components/create_pit/create_pit.tsx index 44515d0ed89c..bf2a88ad5dfa 100644 --- a/src/plugins/point_in_time_management/public/components/create_pit/create_pit.tsx +++ b/src/plugins/point_in_time_management/public/components/create_pit/create_pit.tsx @@ -1,601 +1,583 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + import React, { useEffect, useState } from 'react'; import { - EuiButton, - EuiText, - EuiTitle, - EuiFormRow, - EuiSelect, - EuiFlexGroup, - EuiFlexItem, - EuiSpacer, - EuiFieldText, - EuiPageContent, - EuiCheckbox, - EuiRadioGroup, - EuiFieldNumber, - EuiHorizontalRule, - EuiSwitch, - EuiComboBox, + EuiButton, + EuiText, + EuiTitle, + EuiFormRow, + EuiSelect, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiFieldText, + EuiPageContent, + EuiCheckbox, + EuiRadioGroup, + EuiFieldNumber, + EuiHorizontalRule, + EuiSwitch, + EuiComboBox, } from '@elastic/eui'; import { FormattedMessage } from '@osd/i18n/react'; -import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; -import { ChromeStart, ApplicationStart, SavedObjectsStart, NotificationsStart, OverlayStart, HttpSetup, DocLinksStart } from 'opensearch-dashboards/public'; +import { + ChromeStart, + ApplicationStart, + SavedObjectsStart, + NotificationsStart, + OverlayStart, + HttpSetup, + DocLinksStart, +} from 'opensearch-dashboards/public'; import { IUiSettingsClient } from 'opensearch-dashboards/server'; import { DataPublicPluginStart } from 'src/plugins/data/public'; import { ManagementAppMountParams } from 'src/plugins/management/public'; -import { DataSourceItem } from '../pit_table/pit_table'; import { useEffectOnce } from 'react-use'; -import { createPit, getDataSources, getIndicesViaResolve } from '../utils'; import { withRouter } from 'react-router-dom'; import { i18n } from '@osd/i18n'; +import { createPit, getDataSources, getIndicesViaResolve } from '../utils'; +import { DataSourceItem } from '../pit_table/pit_table'; +import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; import { getCreateBreadcrumbs } from '../breadcrumbs'; - export interface PointInTimeFlyoutItem { - id: string; - title: string; - sort: string; -}; + id: string; + title: string; + sort: string; +} export interface IndexPatternManagmentContext { - chrome: ChromeStart; - application: ApplicationStart; - savedObjects: SavedObjectsStart; - uiSettings: IUiSettingsClient; - notifications: NotificationsStart; - overlays: OverlayStart; - http: HttpSetup; - docLinks: DocLinksStart; - data: DataPublicPluginStart; - setBreadcrumbs: ManagementAppMountParams['setBreadcrumbs']; -}; + chrome: ChromeStart; + application: ApplicationStart; + savedObjects: SavedObjectsStart; + uiSettings: IUiSettingsClient; + notifications: NotificationsStart; + overlays: OverlayStart; + http: HttpSetup; + docLinks: DocLinksStart; + data: DataPublicPluginStart; + setBreadcrumbs: ManagementAppMountParams['setBreadcrumbs']; +} export interface PointInTimeFlyoutItem { - id: string; - title: string; - sort: string; -}; + id: string; + title: string; + sort: string; +} export interface SavedObjectReference { - name?: string; - id: string; - type: string; + name?: string; + id: string; + type: string; } export async function getPits(client, title: string) { - if (title) { - const savedObjects = await client.find({ - type: 'point-in-time', - perPage: 1000, - fields: ['id'] - }); - - return savedObjects.savedObjects; - } + if (title) { + const savedObjects = await client.find({ + type: 'point-in-time', + perPage: 1000, + fields: ['id'], + }); + + return savedObjects.savedObjects; + } } export async function findByTitle(client, title: string) { - if (title) { - const savedObjects = await client.find({ - type: 'point-in-time', - perPage: 1000, - fields: [] - }); - - return savedObjects.savedObjects.find((obj) => obj && obj.attributes && obj.attributes.name && obj.attributes.name.toLowerCase() === title.toLowerCase()); - } -} + if (title) { + const savedObjects = await client.find({ + type: 'point-in-time', + perPage: 1000, + fields: [], + }); -export async function getIndexPatterns(savedObjectsClient) { - return ( - savedObjectsClient - .find({ - type: 'index-pattern', - perPage: 10000, - }) - .then((response) => - response.savedObjects - .map((pattern) => { - const id = pattern.id; - const title = pattern.get('title'); - const references = pattern.references - let datasource = '' - if (references.length > 0) { - if (references.some((ref) => ref.type === 'data-source')) { - datasource = references.find(ref => ref.type === "data-source").id - } - } - - return { - id, - title, - references, - // 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}`, - datasource: datasource - - }; - }) - .sort((a, b) => { - if (a.sort < b.sort) { - return -1; - } else if (a.sort > b.sort) { - return 1; - } else { - return 0; - } - }) - ) || [] + return savedObjects.savedObjects.find( + (obj) => + obj && + obj.attributes && + obj.attributes.name && + obj.attributes.name.toLowerCase() === title.toLowerCase() ); + } } -export const PointInTimeCreateForm = ({ history }) => { - const [isFlyoutVisible, setIsFlyoutVisible] = useState(false); - const [showErrors, setShowErrors] = useState(false); - const [keepAliveTime, setKeepAliveTime] = useState('2'); - const [keepAliveUnit, setKeepAliveUnit] = useState('h'); - const [makedashboardschecked, setMakedashboardschecked] = useState(false); - const [partialfailurechecked, setPartialfailurechecked] = useState(false); - const [loading, setLoading] = useState(true); - - const [indexPatterns, setIndexPatterns] = useState([] as PointInTimeFlyoutItem[]); - const [selectedIndexPattern, setSelectedIndexPattern] = useState(``); - const [pitName, setPitName] = useState(""); - - const [deletepitchecked, setDeletepitchecked] = useState(false) - const [deletepitdashboardchecked, setDeletepitdashboardchecked] = useState(false) - const [radioIdSelected, setRadioIdSelected] = useState(``); - const [showIndices, setShowIndices] = useState(false) - const [showIndexPatterns, setShowIndexPatterns] = useState(false) - const [selectedIndexOptions, setSelectedIndexOptions] = useState([]); - - // TODO: update this for cases when some data source name is default - const defaultDataSource: DataSourceItem = { id: '', title: '', sort: '0', name: 'default' }; - - const [dataSources, setDataSources] = useState([defaultDataSource]); - const [dataSource, setDataSource] = useState(''); - - const [indices, setIndices] = useState([]) - - const { - setBreadcrumbs, - savedObjects, - notifications: { toasts }, - http, - data, - } = useOpenSearchDashboards().services; - - const onChange = (e) => { - setKeepAliveTime(e.target.value); - }; - - useEffectOnce(() => { - fetchDataSources(); - - }); +export async function getIndexPatterns(savedObjectsClient) { + return ( + savedObjectsClient + .find({ + type: 'index-pattern', + perPage: 10000, + }) + .then((response) => + response.savedObjects + .map((pattern) => { + const id = pattern.id; + const title = pattern.get('title'); + const references = pattern.references; + let datasource = ''; + if (references.length > 0) { + if (references.some((ref) => ref.type === 'data-source')) { + datasource = references.find((ref) => ref.type === 'data-source').id; + } + } - useEffect(() => { - (async function () { - const gettedIndexPatterns = await getIndexPatterns( - savedObjects.client - ); - // filter the index pattern w.r.t data source selected - const dsIndexPatterns = gettedIndexPatterns.filter(x => x.datasource == dataSource) - setIndexPatterns(dsIndexPatterns); - if (dsIndexPatterns.length > 0) { - setSelectedIndexPattern(dsIndexPatterns[0].id) + return { + id, + title, + references, + // 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}`, + datasource, + }; + }) + .sort((a, b) => { + if (a.sort < b.sort) { + return -1; + } else if (a.sort > b.sort) { + return 1; } else { - setSelectedIndexPattern(''); + return 0; } - console.log(gettedIndexPatterns) - const gettedIndices = await getIndicesViaResolve( - http, - "*", - false, - dataSource - ); - setIndices(gettedIndices); - setBreadcrumbs(getCreateBreadcrumbs()); - setLoading(false); - })(); - }, [ - savedObjects.client, 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 createPointInTime = async () => { - - const keepAlive = keepAliveTime + keepAliveUnit; - try { - if (makedashboardschecked) { - const dupe = await findByTitle(savedObjects.client, pitName); - if (dupe) { - throw new Error(`Duplicate Point in time: ${pitName}`); - } - } - await createPit(selectedIndexOptions, selectedIndexPattern, indexPatterns, dataSource, data, - http, keepAlive, makedashboardschecked, pitName, savedObjects, deletepitchecked); - - history.push(''); - toasts.addSuccess("Point in time created successfully"); - } catch (e) { - toasts.addDanger( - e.message - ); - } - //setIsFlyoutVisible(false); - - } - + }) + ) || [] + ); +} - const createOptions = [ - { - id: `index-pattern-option`, - label: 'Create from index pattern', - }, - { - id: `index-option`, - label: 'Create from indices', - }, - ]; - - const onRadioChange = (optionId) => { - setRadioIdSelected(optionId); - if (optionId == "index-pattern-option") { - setShowIndexPatterns(true) - setShowIndices(false) - setSelectedIndexOptions([]) - } else if (optionId == "index-option") { - setShowIndices(true) - setShowIndexPatterns(false) +export const PointInTimeCreateForm = ({ history }) => { + const [isFlyoutVisible, setIsFlyoutVisible] = useState(false); + const [showErrors, setShowErrors] = useState(false); + const [keepAliveTime, setKeepAliveTime] = useState('2'); + const [keepAliveUnit, setKeepAliveUnit] = useState('h'); + const [makedashboardschecked, setMakedashboardschecked] = useState(false); + const [partialfailurechecked, setPartialfailurechecked] = useState(false); + const [loading, setLoading] = useState(true); + + const [indexPatterns, setIndexPatterns] = useState([] as PointInTimeFlyoutItem[]); + const [selectedIndexPattern, setSelectedIndexPattern] = useState(``); + const [pitName, setPitName] = useState(''); + + const [deletepitchecked, setDeletepitchecked] = useState(false); + const [deletepitdashboardchecked, setDeletepitdashboardchecked] = useState(false); + const [radioIdSelected, setRadioIdSelected] = useState(``); + const [showIndices, setShowIndices] = useState(false); + const [showIndexPatterns, setShowIndexPatterns] = useState(false); + const [selectedIndexOptions, setSelectedIndexOptions] = useState([]); + + // TODO: update this for cases when some data source name is default + const defaultDataSource: DataSourceItem = { id: '', title: '', sort: '0', name: 'default' }; + + const [dataSources, setDataSources] = useState([defaultDataSource]); + const [dataSource, setDataSource] = useState(''); + + const [indices, setIndices] = useState([]); + + const { + setBreadcrumbs, + savedObjects, + notifications: { toasts }, + http, + data, + } = useOpenSearchDashboards().services; + + const onChange = (e) => { + setKeepAliveTime(e.target.value); + }; + + useEffectOnce(() => { + fetchDataSources(); + }); + + useEffect(() => { + (async function () { + const gettedIndexPatterns = await getIndexPatterns(savedObjects.client); + // filter the index pattern w.r.t data source selected + const dsIndexPatterns = gettedIndexPatterns.filter((x) => x.datasource == dataSource); + setIndexPatterns(dsIndexPatterns); + if (dsIndexPatterns.length > 0) { + setSelectedIndexPattern(dsIndexPatterns[0].id); + } else { + setSelectedIndexPattern(''); + } + console.log(gettedIndexPatterns); + const gettedIndices = await getIndicesViaResolve(http, '*', false, dataSource); + setIndices(gettedIndices); + setBreadcrumbs(getCreateBreadcrumbs()); + setLoading(false); + })(); + }, [savedObjects.client, 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 createPointInTime = async () => { + const keepAlive = keepAliveTime + keepAliveUnit; + try { + if (makedashboardschecked) { + const dupe = await findByTitle(savedObjects.client, pitName); + if (dupe) { + throw new Error(`Duplicate Point in time: ${pitName}`); } - }; + } + await createPit( + selectedIndexOptions, + selectedIndexPattern, + indexPatterns, + dataSource, + data, + http, + keepAlive, + makedashboardschecked, + pitName, + savedObjects, + deletepitchecked + ); - const onExpirationComboChange = (e) => { - setKeepAliveUnit(e.target.value); + history.push(''); + toasts.addSuccess('Point in time created successfully'); + } catch (e) { + toasts.addDanger(e.message); } - - const onPartialFailureCheckChange = (e) => { - setPartialfailurechecked(e.target.checked); + // setIsFlyoutVisible(false); + }; + + const createOptions = [ + { + id: `index-pattern-option`, + label: 'Create from index pattern', + }, + { + id: `index-option`, + label: 'Create from indices', + }, + ]; + + const onRadioChange = (optionId) => { + setRadioIdSelected(optionId); + if (optionId == 'index-pattern-option') { + setShowIndexPatterns(true); + setShowIndices(false); + setSelectedIndexOptions([]); + } else if (optionId == 'index-option') { + setShowIndices(true); + setShowIndexPatterns(false); } + }; - const oDashboardSwitchChange = (e) => { - setMakedashboardschecked(e.target.checked); - }; - - const onDeletePitCheckboxChange = (e) => { - setDeletepitchecked(e.target.checked); - }; + const onExpirationComboChange = (e) => { + setKeepAliveUnit(e.target.value); + }; - const onDeletePitDashboardCheckboxChange = (e) => { - setDeletepitdashboardchecked(e.target.checked); - }; + const onPartialFailureCheckChange = (e) => { + setPartialfailurechecked(e.target.checked); + }; - console.log("index patterns : " + showIndexPatterns) - console.log("indices : " + showIndices) + const oDashboardSwitchChange = (e) => { + setMakedashboardschecked(e.target.checked); + }; - let renderDataSource; - const formatFieldsToComboBox = (fields) => { - if (!fields) return []; + const onDeletePitCheckboxChange = (e) => { + setDeletepitchecked(e.target.checked); + }; - return fields?.map((field) => { - return { - label: field.name, - }; - }); - } - const handleIndexOnChange = (selectedOptions) => { - setSelectedIndexOptions(selectedOptions); - }; - - const onNameChange = (e) => { - setPitName(e.target.value); - } - if (showIndices) { - // Basically check if the pattern or selection of indices string match with existing index patterns - // Also lets create index pattern only at the end - // if selection of indices match index pattern, don't create index pattern - // otherwise create index pattern - renderDataSource = - + const onDeletePitDashboardCheckboxChange = (e) => { + setDeletepitdashboardchecked(e.target.checked); + }; - - } - if (showIndexPatterns) { - renderDataSource = - ({ - value: source.id, - text: source.title, - }))} - value={selectedIndexPattern} - onChange={(e) => setSelectedIndexPattern(e.target.value)} - /> + console.log('index patterns : ' + showIndexPatterns); + console.log('indices : ' + showIndices); - - } + let renderDataSource; + const formatFieldsToComboBox = (fields) => { + if (!fields) return []; + return fields?.map((field) => { + return { + label: field.name, + }; + }); + }; + const handleIndexOnChange = (selectedOptions) => { + setSelectedIndexOptions(selectedOptions); + }; + + const onNameChange = (e) => { + setPitName(e.target.value); + }; + if (showIndices) { + // Basically check if the pattern or selection of indices string match with existing index patterns + // Also lets create index pattern only at the end + // if selection of indices match index pattern, don't create index pattern + // otherwise create index pattern + renderDataSource = ( + + + + ); + } + if (showIndexPatterns) { + renderDataSource = ( + + ({ + value: source.id, + text: source.title, + }))} + value={selectedIndexPattern} + onChange={(e) => setSelectedIndexPattern(e.target.value)} + /> + + ); + } - const header = - -
- -

- { - - } -

-
- - -

- -
-

-
-
-
+ const header = ( + + +
+ +

+ {} +

+
+ + +

+ +
+

+
+
+
- - const datasource = - -

- { - - } -

-
- - - {/* Title */} - - ({ - value: source.id, - text: source.name, - }))} - value={dataSource} - onChange={(e) => setDataSource(e.target.value)} - /> - - - onRadioChange(id)} - name="radio group" - /> - - {renderDataSource} -
- - const expiration = - -

- { - - } -

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +

+ {} +

+
+ + + {/* Title */} + + ({ + value: source.id, + text: source.name, + }))} + value={dataSource} + onChange={(e) => setDataSource(e.target.value)} /> - + + onRadioChange(id)} + name="radio group" /> + + {renderDataSource}
- - const details = - -

- { - - } -

-
- - - - - + +

+ {} +

+
+ + + + + + + + + - - - {makedashboardschecked && - - - - - - - - - - - - - } -
- - const additional_config = - -

+ + + + + - } -

-
- - - - - - - + + + + + + + +
+ + + + + + + - - const buttons = - - - history.push('')} - > - Cancel - - - - - Create PIT - - + ); + + const details = ( + + +

+ {} +

+
+ + + + + + + + {makedashboardschecked && ( + + + + + + + + + + + + )} +
+ ); - let formgroup; - if (true) { - formgroup = ( -
- {header} - - {datasource} - - {expiration} - - {details} - - {additional_config} - - {buttons} -
- ) - } + const additional_config = ( + + +

+ {} +

+
- return ( -
- {formgroup} -
+ + + + + +
+ ); + + const buttons = ( + + + history.push('')}>Cancel + + + + Create PIT + + + + ); + + let formgroup; + if (true) { + formgroup = ( +
+ {header} + + {datasource} + + {expiration} + + {details} + + {additional_config} + + {buttons} +
); -} + } -function useGeneratedHtmlId(arg0: { prefix: string; }) { - throw new Error('Function not implemented.'); + return
{formgroup}
; +}; + +function useGeneratedHtmlId(arg0: { prefix: string }) { + throw new Error('Function not implemented.'); } export const CreatePitWithRouter = withRouter(PointInTimeCreateForm); - diff --git a/src/plugins/point_in_time_management/public/components/create_pit/index.ts b/src/plugins/point_in_time_management/public/components/create_pit/index.ts index afdf0ce3cef1..c5671f26d5c9 100644 --- a/src/plugins/point_in_time_management/public/components/create_pit/index.ts +++ b/src/plugins/point_in_time_management/public/components/create_pit/index.ts @@ -1 +1,6 @@ -export {PointInTimeCreateForm} from './create_pit'; \ No newline at end of file +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { PointInTimeCreateForm } from './create_pit'; 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 6fdcd3fef75d..19b76b5e5a89 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 @@ -7,29 +7,13 @@ import React, { useEffect, useState } from 'react'; import { RouteComponentProps, withRouter } from 'react-router-dom'; import { useEffectOnce, useMount } from 'react-use'; import { i18n } from '@osd/i18n'; -import { - EuiBottomBar, - EuiButton, - EuiButtonEmpty, - EuiCheckbox, - EuiDescribedFormGroup, - EuiFieldNumber, - EuiFieldText, - EuiFlexGroup, - EuiFlexItem, - EuiForm, - EuiFormRow, - EuiPageContent, - EuiPageHeader, - EuiPageHeaderSection, - EuiSpacer, - EuiTitle, -} from '@elastic/eui'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; import { PointInTimeAttributes, PointInTimeManagementContext } from '../../types'; import { getEditBreadcrumbs } from '../breadcrumbs'; import { EditPitForm } from './edit_pit_form'; import { + createPit, + createPitSavedObjectWithIndexPatttern, findById, findPointInTimeSavedObject, updatePointInTimeById, @@ -46,20 +30,21 @@ const defaultPitSavedObject: PointInTimeAttributes = { name: '', addtime: 0, delete_on_expiry: false, + isSavedObject: true, }; -export const PITEdit = ( - props -) => { +export const PITEdit = (props) => { const { setBreadcrumbs, savedObjects, notifications: { toasts }, http, + data, } = useOpenSearchDashboards().services; const PitID: string = props.match.params.id; const pit = props.location && props.location.state; console.log(pit); + console.log(props.location.state); debugger; const [pitSavedObject, setPitSavedObject] = useState( defaultPitSavedObject @@ -77,29 +62,96 @@ export const PITEdit = ( }); 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, - delete_on_expiry: tempPitSavedObject.attributes.delete_on_expiry, - }; - console.log('This is teh attributes'); - console.log(pointInTimeAttributes); - setPitSavedObject(pointInTimeAttributes); - setIsLoading(false); + if (pit.isSavedObject) { + 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, + delete_on_expiry: tempPitSavedObject.attributes.delete_on_expiry, + isSavedObject: true, + }; + console.log('This is teh attributes'); + console.log(pointInTimeAttributes); + setPitSavedObject(pointInTimeAttributes); + setIsLoading(false); + } else { + const pointInTimeAttributes: PointInTimeAttributes = { + creation_time: pit.creation_time, + name: '', + keepAlive: pit.keep_alive, + pit_id: pit.pit_id, + addtime: 0, + delete_on_expiry: false, + isSavedObject: false, + }; + console.log('For a local PIT these are the variables'); + 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); + if (attributes.isSavedObject) { + 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, pit.dataSourceId); + await updatePointInTimeById(savedObjects.client, attributes.id, attributes); + props.history.push('/'); + } else { + console.log('This is not saved object', attributes); + if (attributes.addtime > 0) { + console.log('time updated'); + // update pit time + const new_keep_alive_proposal = attributes.addtime.toString() + 'm'; + await services.addPitTime(attributes.pit_id, new_keep_alive_proposal, pit.dataSourceId); + } + + if (attributes.name !== '') { + console.log('name updated'); + + // createsavedobject + + services.getAllPits(pit.dataSourceId).then((fetchedPits) => { + const backendPit = fetchedPits.resp.pits.filter((x) => x.pit_id === attributes.pit_id)[0]; + createPitSavedObjectWithIndexPatttern( + { + creation_time: backendPit.creation_time, + dataSource: pit.dataSourceId ? pit.dataSourceId : '', + delete_on_expiry: false, + keepAlive: backendPit.keep_alive, + name: attributes.name, + pit_id: backendPit.pit_id, + id: '', + }, + savedObjects.client, + data, + backendPit.indices, + pit.dataSourceId + ).catch(() => { + toasts.addDanger( + i18n.translate('pitManagement.edit.createSavedObjectError', { + defaultMessage: 'Error while creating saved object.', + }) + ); + }); + }); + } + + // TODO:: Need to call the create PIT ID here. + // TODO:: Add indices and data source in the PIT object and call createPit + // await createPit( + // ['opensearch_dashboards_sample_data_ecommerce'], + // 'opensearch_dashboards_sample_data_ecommerce', indexPatterns, dataSource, data, + // http, keepAlive, makedashboardschecked, pitName, savedObjects, deletepitchecked) + props.history.push('/'); + } }; const handleDisplayToastMessage = ({ id, defaultMessage, success }: ToastMessageItem) => { @@ -112,7 +164,7 @@ export const PITEdit = ( return ( <> - {!isLoading ? ( + {pitSavedObject.creation_time !== 0 ? ( { @@ -61,13 +65,16 @@ export class EditPitForm extends React.Component { AddTimeHr: 0, AddTimeMin: 0, addTime: 0, + isSavedObject: true, + makedashboardschecked: false, + creation_time: 0, }; } componentDidMount() { this.setFormValuesForEditMode(); console.log('These are the props in mount'); - console.log(this.props); + console.log('here', this.props); } resetFormValues = () => { @@ -77,13 +84,23 @@ export class EditPitForm extends React.Component { setFormValuesForEditMode() { if (this.props.existingPointInTime) { - const { keepAlive, name, pit_id, id, addtime } = this.props.existingPointInTime; - this.setState({ + const { + creation_time, keepAlive, name, pit_id, id, addtime, + isSavedObject, + } = this.props.existingPointInTime; + this.setState({ + keepAlive, + name, + pit_id, + id, + addTime: addtime, + isSavedObject, + creation_time, }); } } @@ -103,14 +120,16 @@ export class EditPitForm extends React.Component { onClickUpdatePit = async () => { if (this.isFormValid()) { + console.log(this.state, 'State'); const formValues: PointInTimeAttributes = { name: this.state.name, keepAlive: this.state.keepAlive, - creation_time: this.state.keepAlive, + creation_time: this.state.creation_time, id: this.state.id, pit_id: this.state.pit_id, addtime: this.state.addTime, delete_on_expiry: this.state.checked, + isSavedObject: this.state.isSavedObject, }; this.setState({ isLoading: true }); @@ -229,6 +248,96 @@ export class EditPitForm extends React.Component { ); }; + configurationForm = (isSavedObject: boolean) => { + return isSavedObject ? ( + 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)} + disabled={true} + /> + + +
+
+ ) : ( + this.onChangeFormValues()} + data-test-subj="pit-edit-2" + > + Dashboard availability} + description={ +

To use this PIT in OpenSearch Dashboards, make it available to Dashboards.

+ } + > + + + this.setState({ ...this.state, makedashboardschecked: e.target.checked }) + } + /> + + + {this.state.makedashboardschecked && ( + + + + + + + + + + + + + )} +
+
+ ); + }; render() { return ( <> @@ -292,55 +401,11 @@ export class EditPitForm extends React.Component { - 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)} - disabled={true} - /> - - -
-
- {this.state.showUpdateOptions ? this.renderBottomBar() : null} + {this.state.isSavedObject + ? this.configurationForm(this.state.isSavedObject) + : this.configurationForm(this.state.isSavedObject)} + {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 ae6641e6d951..aa3f4eba5026 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 @@ -40,6 +40,7 @@ import { getSavedPits, deletePointInTimeById, updatePointInTimeSavedObject, + getPitSavedPitsByDataSource, } from '../utils'; import { EmptyState, NoDataSourceState } from './empty_state'; // import { PageHeader } from './page_header'; @@ -86,7 +87,6 @@ const PITTable = ({ history }: RouteComponentProps) => { const createButton = ; - const services: Services = getServices(http); // TODO: update this for cases when some data source name is default @@ -133,8 +133,18 @@ const PITTable = ({ history }: RouteComponentProps) => { }; const navigateEdit = (pit) => { - console.log(pit); - const id = pit.id ? pit.id : "edit"; + console.log('editing', pit); + const id = pit.id ? pit.id : 'edit'; + let dataSourceId; + if (pit.dataSource === '') { + dataSourceId = undefined; + } else { + const dataSource = dataSources.filter((x) => x.title === pit.dataSource); + dataSourceId = dataSource[0].id; + } + + pit.dataSourceId = dataSourceId; + history.push(`${id}`, pit); }; @@ -172,7 +182,7 @@ const PITTable = ({ history }: RouteComponentProps) => { services .getAllPits(dataSourceId) .then((fetchedPits) => { - getSavedPits(savedObjects.client) + getPitSavedPitsByDataSource(savedObjects.client, dataSourceId ? dataSourceId : '') .then((fetchedDashboardPits) => { // if (fetchedDataSources?.length) { // setDashboardPits(fetchedDataSources); @@ -295,9 +305,9 @@ const PITTable = ({ history }: RouteComponentProps) => { }; const reference: SavedObjectReference = { - id: '5586e600-f57b-11ed-90e3-a75eeb2a18a5', + id: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f', type: 'index-pattern', - name: 'my*', + name: 'opensearch_dashboards_sample_data_ecommerce', }; createSavedObject(pit, savedObjects.client, reference); }; @@ -329,7 +339,13 @@ const PITTable = ({ history }: RouteComponentProps) => { } services.deletePits([pit.pit_id], dataSourceId).then((deletedPits) => { console.log(deletedPits); - getPits(dataSource); + if (pit.isSavedObject) { + deletePointInTimeById(savedObjects.client, pit.id).then(() => { + getPits(dataSource); + }); + } else { + getPits(dataSource); + } }); }; @@ -534,6 +550,12 @@ const PITTable = ({ history }: RouteComponentProps) => { console.log(deletedPits); getPits(dataSource); }); + + selectedPits.forEach((x) => { + if (x.isSavedObject) { + deletePointInTimeById(savedObjects.client, x.id); + } + }); }; const renderToolsRight = () => { @@ -663,9 +685,7 @@ const PITTable = ({ history }: RouteComponentProps) => { /> - - {createButton} - + {createButton}
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 39655cd7b7f0..145dccf70c19 100644 --- a/src/plugins/point_in_time_management/public/components/utils.ts +++ b/src/plugins/point_in_time_management/public/components/utils.ts @@ -3,14 +3,18 @@ * SPDX-License-Identifier: Apache-2.0 */ - - -import { HttpSetup, HttpStart, SavedObjectReference, SavedObjectsClientContract, SavedObjectsStart } from 'src/core/public'; +import { + HttpSetup, + HttpStart, + SavedObjectReference, + SavedObjectsClientContract, + SavedObjectsStart, +} from 'src/core/public'; import { DataSourceAttributes } from 'src/plugins/data_source/common/data_sources'; -import { PointInTimeAttributes } from '../types'; import { ResolveIndexResponse } from 'src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/types'; -import { getServices } from '../services'; import { DataPublicPluginStart } from 'src/plugins/data/public'; +import { PointInTimeAttributes } from '../types'; +import { getServices } from '../services'; import { PointInTimeFlyoutItem } from './create_pit/create_pit'; export async function getDataSources(savedObjectsClient: SavedObjectsClientContract) { @@ -44,6 +48,7 @@ export interface PointInTime { creation_time: number; id?: string; delete_on_expiry: boolean; + dataSource: string; } export async function getIndexPatterns(savedObjectsClient: SavedObjectsClientContract) { @@ -86,12 +91,41 @@ 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', 'delete_on_expiry'], + fields: [ + 'id', + 'creation_time', + 'keepAlive', + 'name', + 'pit_id', + 'delete_on_expiry', + 'dataSource', + ], }); return savedObjects.savedObjects; } +export async function getPitSavedPitsByDataSource( + client: SavedObjectsClientContract, + dataSource: string +) { + const savedObjects = await client.find({ + type: 'point-in-time', + perPage: 1000, + fields: [ + 'id', + 'creation_time', + 'keepAlive', + 'name', + 'pit_id', + 'delete_on_expiry', + 'dataSource', + ], + }); + + return savedObjects.savedObjects.filter((x) => x.attributes.dataSource == dataSource); +} + export async function findById(client: SavedObjectsClientContract, id: string) { if (id) { console.log(id); @@ -132,7 +166,7 @@ export async function updatePointInTimeKeepAlive( savedObjectsClient: SavedObjectsClientContract, id: string, addTime: number -) { } +) {} export async function createSavedObject( pointintime: PointInTime, @@ -160,7 +194,7 @@ export async function createSavedObject( } export async function getIndicesViaResolve( http: HttpStart, - //getIndexTags: IndexPatternCreationConfig['getIndexTags'], + // getIndexTags: IndexPatternCreationConfig['getIndexTags'], pattern: string, showAllIndices: boolean, dataSourceId?: string @@ -184,7 +218,6 @@ export async function getIndicesViaResolve( const source: any[] | PromiseLike = []; (response.indices || []).forEach((index) => { - source.push({ name: index.name, item: index, @@ -193,27 +226,34 @@ export async function getIndicesViaResolve( return source; } }); -}; - -export async function getFieldsForWildcard(indexPattern: string, capabilities: any, indexPatternsService: any) { +} +export async function getFieldsForWildcard( + indexPattern: string, + capabilities: any, + indexPatternsService: any +) { return await indexPatternsService!.getFieldsForWildcard({ pattern: indexPattern, fieldCapsOptions: { allowNoIndices: true }, }); } -export async function createIndexPattern(indexPatternTitle: string, indexPatternsService: any, dataSourceRef: any) { +export async function createIndexPattern( + indexPatternTitle: string, + indexPatternsService: any, + dataSourceRef: any +) { try { return await indexPatternsService.createAndSave({ title: indexPatternTitle, - id: "", + id: '', dataSourceRef, }); } catch (err) { throw err; } -}; +} export async function createPitSavedObject(pointintime, client, reference) { const body = pointintime; @@ -221,49 +261,91 @@ export async function createPitSavedObject(pointintime, client, reference) { body.title = pointintime.name; body.name = pointintime.name; const references = [{ ...reference }]; - const savedObjectType = "point-in-time"; + const savedObjectType = 'point-in-time'; return await client.create(savedObjectType, body, { references, }); } -export async function createPit(selectedIndexOptions, selectedIndexPattern, indexPatterns: PointInTimeFlyoutItem[], - dataSource: string, data: DataPublicPluginStart, http: HttpSetup, keepAlive: string, - makedashboardschecked: boolean, pitName: string, savedObjects: SavedObjectsStart, deletepitchecked: boolean, pit:any=null) { - let indexPatternObj; +export async function createPit( + selectedIndexOptions, + selectedIndexPattern, + indexPatterns: PointInTimeFlyoutItem[], + dataSource: string, + data: DataPublicPluginStart, + http: HttpSetup, + keepAlive: string, + makedashboardschecked: boolean, + pitName: string, + savedObjects: SavedObjectsStart, + deletepitchecked: boolean, + pit: any = null +) { + let indexPatternObj; if (selectedIndexOptions.length > 0) { - const indices = selectedIndexOptions.flatMap(a => a.label).join(","); - indexPatternObj = indexPatterns.find(x => x.title == indices); - const ds = { - id: dataSource, - type: "data-source", - name: "DataSource", - }; - if (!indexPatternObj) { - indexPatternObj = await createIndexPattern(indices, data.indexPatterns, ds); - } + const indices = selectedIndexOptions.flatMap((a) => a.label).join(','); + indexPatternObj = indexPatterns.find((x) => x.title == indices); + const ds = { + id: dataSource, + type: 'data-source', + name: 'DataSource', + }; + if (!indexPatternObj) { + indexPatternObj = await createIndexPattern(indices, data.indexPatterns, ds); + } } else { - indexPatternObj = indexPatterns.find(x => x.id == selectedIndexPattern); + indexPatternObj = indexPatterns.find((x) => x.id == selectedIndexPattern); } const reference: SavedObjectReference = { - id: indexPatternObj.id, - type: 'index-pattern', - name: indexPatternObj.title + id: indexPatternObj.id, + type: 'index-pattern', + name: indexPatternObj.title, }; const service = getServices(http); - const createdPit = pit == null ? await service.createPit(indexPatternObj.title, keepAlive, true, dataSource) : pit; + const createdPit = + pit == null ? await service.createPit(indexPatternObj.title, keepAlive, true, dataSource) : pit; if (makedashboardschecked) { - const pit: PointInTime = { - name: pitName, - keepAlive: createdPit.keep_alive, - pit_id: createdPit.pit_id, - creation_time: createdPit.creation_time, - delete_on_expiry: deletepitchecked, - id: '', - }; - await createSavedObject(pit, savedObjects.client, reference); + const pit: PointInTime = { + name: pitName, + keepAlive: createdPit.keep_alive, + pit_id: createdPit.pit_id, + creation_time: createdPit.creation_time, + delete_on_expiry: deletepitchecked, + id: '', + dataSource, + }; + await createSavedObject(pit, savedObjects.client, reference); } } +export async function createPitSavedObjectWithIndexPatttern( + pointintime: PointInTime, + client: SavedObjectsClientContract, + data: DataPublicPluginStart, + indices: string[], + dataSourceId: string +) { + let indexPatternObj; + const index = indices.join(','); + const gettedIndexPatterns = await getIndexPatterns(client); + console.log('fetched index patterns', gettedIndexPatterns); + const dsIndexPatterns = gettedIndexPatterns.filter((x) => x.datasource == dataSourceId); + indexPatternObj = dsIndexPatterns.find((x) => x.title == index); + if (!indexPatternObj) { + const ds = { + id: dataSourceId, + type: 'data-source', + name: 'DataSource', + }; + indexPatternObj = await createIndexPattern(index, data.indexPatterns, ds); + } + const reference: SavedObjectReference = { + id: indexPatternObj.id, + type: 'index-pattern', + name: indexPatternObj.title, + }; + + await createSavedObject(pointintime, client, reference); +} 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 1a0478091054..f088d8d548b8 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 @@ -20,7 +20,10 @@ export async function mountManagementSection( getStartServices: StartServicesAccessor, params: ManagementAppMountParams ) { - const [{ chrome, application, savedObjects, notifications, http }, {data}] = await getStartServices(); + const [ + { chrome, application, savedObjects, notifications, http }, + { data }, + ] = await getStartServices(); const deps: PointInTimeManagementContext = { chrome, application, @@ -35,8 +38,8 @@ export async function mountManagementSection( - - + + diff --git a/src/plugins/point_in_time_management/public/services.ts b/src/plugins/point_in_time_management/public/services.ts index d956efa22995..7a2176d03874 100644 --- a/src/plugins/point_in_time_management/public/services.ts +++ b/src/plugins/point_in_time_management/public/services.ts @@ -8,7 +8,12 @@ import { CoreStart, HttpFetchError } from 'opensearch-dashboards/public'; export interface Services { getAllPits: (dataSourceId?: string) => Promise; deletePits: (pits: string[], dataSourceId?: string) => any; - createPit: (index: string, keepAlive: string, allowPartialCreation: boolean, dataSourceId?: string) => any; + createPit: ( + index: string, + keepAlive: string, + allowPartialCreation: boolean, + dataSourceId?: string + ) => any; addPitTime: (pit_id: string, keepAlive: string, dataSourceId?: string) => any; } @@ -33,7 +38,7 @@ export function getServices(http: CoreStart['http']): Services { console.log(pit_id, keepAlive, dataSourceId); const response = await http.post('/api/pit/addTime', { body: JSON.stringify({ - dataSourceId: dataSourceId ? dataSourceId : 'default', + dataSourceId: dataSourceId ? dataSourceId : '', pit_id, keepAlive, }), @@ -59,20 +64,25 @@ export function getServices(http: CoreStart['http']): Services { } }, - createPit: async (index: string, keepAlive: string, allowPartialCreation: boolean, dataSourceId?: string) => { + createPit: async ( + index: string, + keepAlive: string, + allowPartialCreation: boolean, + dataSourceId?: string + ) => { try { - console.log("create pit : " + dataSourceId) - const response = await http.post('/api/pit/create/'+index, { + console.log('create pit : ' + dataSourceId); + const response = await http.post('/api/pit/create/' + index, { body: JSON.stringify({ dataSourceId: dataSourceId ? dataSourceId : '', }), query: { - keepAlive: keepAlive, - allowPartialFailures : allowPartialCreation - } + keepAlive, + allowPartialFailures: allowPartialCreation, + }, }); - console.log("create pit response") - console.log(response) + console.log('create pit response'); + console.log(response); return response; } catch (e) { return e; diff --git a/src/plugins/point_in_time_management/public/types.ts b/src/plugins/point_in_time_management/public/types.ts index 8a2238cafebc..7ed1d668ba1f 100644 --- a/src/plugins/point_in_time_management/public/types.ts +++ b/src/plugins/point_in_time_management/public/types.ts @@ -10,10 +10,10 @@ import { SavedObjectAttributes, } from 'opensearch-dashboards/public'; import { NotificationsStart, SavedObjectsStart } from 'src/core/public'; +import { DataPublicPluginStart } from 'src/plugins/data/public'; import { NavigationPublicPluginStart } from '../../navigation/public'; import { ManagementAppMountParams } from '../../management/public'; import { ManagementSetup } from '../../management/public'; -import { DataPublicPluginStart } from 'src/plugins/data/public'; export interface PointInTimeAttributes extends SavedObjectAttributes { creation_time?: number; @@ -23,6 +23,7 @@ export interface PointInTimeAttributes extends SavedObjectAttributes { id?: string; addtime: number; delete_on_expiry: boolean; + isSavedObject?: boolean; } export interface ToastMessageItem { @@ -37,7 +38,7 @@ export interface PointInTimeManagementContext { notifications: NotificationsStart; savedObjects: SavedObjectsStart; http: HttpSetup; - data: DataPublicPluginStart, + data: DataPublicPluginStart; setBreadcrumbs: ManagementAppMountParams['setBreadcrumbs']; } 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 d64754fce7f9..fd1062e81c2c 100644 --- a/src/plugins/point_in_time_management/server/routes/opensearch.ts +++ b/src/plugins/point_in_time_management/server/routes/opensearch.ts @@ -120,12 +120,10 @@ export function registerPitRoutes(router: IRouter) { params: schema.object({ index: schema.string(), }), - query: schema.object( - { - allowPartialFailures: schema.boolean({ defaultValue: true }), - keepAlive: schema.string() - }, - ), + query: schema.object({ + allowPartialFailures: schema.boolean({ defaultValue: true }), + keepAlive: schema.string(), + }), body: schema.object({ dataSourceId: schema.string(), }), @@ -135,17 +133,18 @@ export function registerPitRoutes(router: IRouter) { console.log('This is the request for create point in time path'); console.log(request); const { index } = request.params; - const {keepAlive, allowPartialFailures} = request.query + const { keepAlive, allowPartialFailures } = request.query; console.log(index); console.log(context); // eslint-disable-next-line @typescript-eslint/naming-convention debugger; const client: OpenSearchClient = await getClient(request, context); - - const response_local = await client.createPit({ + + const response_local = await client.createPit( + { index, keep_alive: keepAlive, - allow_partial_pit_creation: allowPartialFailures + allow_partial_pit_creation: allowPartialFailures, }, {} ); 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 fddb2c1500a3..800cde6842d2 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 @@ -29,6 +29,7 @@ export const pointInTimeSavedObject: SavedObjectsType = { mappings: { dynamic: false, properties: { + dataSource: { type: 'text' }, title: { type: 'text' }, creation_time: { type: 'double' }, keepAlive: { type: 'integer' },