diff --git a/public/components/datasources/components/__tests__/acceleration_action_overlay.test.tsx b/public/components/datasources/components/__tests__/acceleration_action_overlay.test.tsx
new file mode 100644
index 0000000000..e72d6c94ad
--- /dev/null
+++ b/public/components/datasources/components/__tests__/acceleration_action_overlay.test.tsx
@@ -0,0 +1,71 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { mount, configure } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import { EuiOverlayMask, EuiConfirmModal, EuiFieldText } from '@elastic/eui';
+import {
+ AccelerationActionOverlay,
+ AccelerationActionOverlayProps,
+} from '../manage/accelerations/acceleration_action_overlay';
+import { skippingIndexAcceleration } from '../../../../../test/datasources';
+import { act } from 'react-dom/test-utils';
+
+configure({ adapter: new Adapter() });
+
+describe('AccelerationActionOverlay Component Tests', () => {
+ let props: AccelerationActionOverlayProps;
+
+ beforeEach(() => {
+ props = {
+ isVisible: true,
+ actionType: 'delete',
+ acceleration: skippingIndexAcceleration,
+ dataSourceName: 'test-datasource',
+ onCancel: jest.fn(),
+ onConfirm: jest.fn(),
+ };
+ });
+
+ it('renders correctly', () => {
+ const wrapper = mount();
+ expect(wrapper.find(EuiOverlayMask).exists()).toBe(true);
+ expect(wrapper.find(EuiConfirmModal).exists()).toBe(true);
+ expect(wrapper.text()).toContain('Delete acceleration');
+ });
+
+ it('calls onConfirm when confirm button is clicked and confirm is enabled', async () => {
+ const wrapper = mount();
+
+ if (props.actionType === 'vacuum') {
+ await act(async () => {
+ const onChange = wrapper.find(EuiFieldText).first().prop('onChange');
+ if (typeof onChange === 'function') {
+ onChange({
+ target: { value: props.acceleration!.indexName },
+ } as any);
+ }
+ });
+ wrapper.update();
+ }
+ wrapper
+ .find('button')
+ .filterWhere((button) => button.text().includes('Delete'))
+ .simulate('click');
+ expect(props.onConfirm).toHaveBeenCalled();
+ });
+
+ it('calls onCancel when cancel button is clicked', () => {
+ const wrapper = mount();
+
+ wrapper
+ .find('button')
+ .filterWhere((button) => button.text() === 'Cancel')
+ .simulate('click');
+
+ expect(props.onCancel).toHaveBeenCalled();
+ });
+});
diff --git a/public/components/datasources/components/__tests__/acceleration_operation.test.tsx b/public/components/datasources/components/__tests__/acceleration_operation.test.tsx
new file mode 100644
index 0000000000..8b22c08d38
--- /dev/null
+++ b/public/components/datasources/components/__tests__/acceleration_operation.test.tsx
@@ -0,0 +1,52 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { renderHook, act } from '@testing-library/react-hooks';
+import { useAccelerationOperation } from '../manage/accelerations/acceleration_operation';
+import * as useDirectQueryModule from '../../../../framework/datasources/direct_query_hook';
+import * as useToastModule from '../../../common/toast';
+import { DirectQueryLoadingStatus } from '../../../../../common/types/explorer';
+import { skippingIndexAcceleration } from '../../../../../test/datasources';
+
+jest.mock('../../../../framework/datasources/direct_query_hook', () => ({
+ useDirectQuery: jest.fn(),
+}));
+
+jest.mock('../../../common/toast', () => ({
+ useToast: jest.fn(),
+}));
+
+describe('useAccelerationOperation', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+
+ (useDirectQueryModule.useDirectQuery as jest.Mock).mockReturnValue({
+ startLoading: jest.fn(),
+ stopLoading: jest.fn(),
+ loadStatus: DirectQueryLoadingStatus.INITIAL,
+ });
+
+ (useToastModule.useToast as jest.Mock).mockReturnValue({
+ setToast: jest.fn(),
+ });
+ });
+
+ it('performs acceleration operation and handles success', async () => {
+ (useDirectQueryModule.useDirectQuery as jest.Mock).mockReturnValue({
+ startLoading: jest.fn(),
+ stopLoading: jest.fn(),
+ loadStatus: DirectQueryLoadingStatus.SUCCESS,
+ });
+
+ const { result } = renderHook(() => useAccelerationOperation('test-datasource'));
+
+ act(() => {
+ result.current.performOperation(skippingIndexAcceleration, 'delete');
+ });
+
+ expect((useDirectQueryModule.useDirectQuery as jest.Mock).mock.calls.length).toBeGreaterThan(0);
+ expect((useToastModule.useToast as jest.Mock).mock.calls.length).toBeGreaterThan(0);
+ });
+});
diff --git a/public/components/datasources/components/__tests__/acceleration_table.test.tsx b/public/components/datasources/components/__tests__/acceleration_table.test.tsx
index 8c8ef6eabc..c149e7722a 100644
--- a/public/components/datasources/components/__tests__/acceleration_table.test.tsx
+++ b/public/components/datasources/components/__tests__/acceleration_table.test.tsx
@@ -177,6 +177,10 @@ describe('AccelerationTable Component', () => {
});
wrapper!.update();
- expect(wrapper!.text()).toContain(accelerationCache.lastUpdated);
+ const expectedLocalizedTime = accelerationCache.lastUpdated
+ ? new Date(accelerationCache.lastUpdated).toLocaleString()
+ : '';
+
+ expect(wrapper!.text()).toContain(expectedLocalizedTime);
});
});
diff --git a/public/components/datasources/components/__tests__/associated_objects_flyout.test.tsx b/public/components/datasources/components/__tests__/associated_objects_flyout.test.tsx
index a561452557..4e9abae123 100644
--- a/public/components/datasources/components/__tests__/associated_objects_flyout.test.tsx
+++ b/public/components/datasources/components/__tests__/associated_objects_flyout.test.tsx
@@ -82,7 +82,7 @@ describe('AssociatedObjectsDetailsFlyout Integration Tests', () => {
wrapper.update();
});
- const accName = getAccelerationName(mockTableDetail.accelerations[0], 'flint_s3');
+ const accName = getAccelerationName(mockTableDetail.accelerations[0]);
const accLink = wrapper
.find('EuiLink')
.findWhere((node) => node.text() === accName)
diff --git a/public/components/datasources/components/manage/accelerations/acceleration_action_overlay.tsx b/public/components/datasources/components/manage/accelerations/acceleration_action_overlay.tsx
new file mode 100644
index 0000000000..ce5cff4367
--- /dev/null
+++ b/public/components/datasources/components/manage/accelerations/acceleration_action_overlay.tsx
@@ -0,0 +1,93 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useState } from 'react';
+import { EuiOverlayMask, EuiConfirmModal, EuiFormRow, EuiFieldText } from '@elastic/eui';
+import { CachedAcceleration } from '../../../../../../common/types/data_connections';
+import {
+ ACC_DELETE_MSG,
+ ACC_VACUUM_MSG,
+ ACC_SYNC_MSG,
+ AccelerationActionType,
+ getAccelerationName,
+ getAccelerationFullPath,
+} from './utils/acceleration_utils';
+
+export interface AccelerationActionOverlayProps {
+ isVisible: boolean;
+ actionType: AccelerationActionType;
+ acceleration: CachedAcceleration | null;
+ dataSourceName: string;
+ onCancel: () => void;
+ onConfirm: () => void;
+}
+
+export const AccelerationActionOverlay: React.FC = ({
+ isVisible,
+ actionType,
+ acceleration,
+ dataSourceName,
+ onCancel,
+ onConfirm,
+}) => {
+ const [confirmationInput, setConfirmationInput] = useState('');
+
+ if (!isVisible || !acceleration) {
+ return null;
+ }
+
+ const displayIndexName = getAccelerationName(acceleration);
+ const displayFullPath = getAccelerationFullPath(acceleration, dataSourceName);
+
+ let title = '';
+ let description = '';
+ let confirmButtonText = 'Confirm';
+ let confirmEnabled = true;
+
+ switch (actionType) {
+ case 'vacuum':
+ title = `Vacuum acceleration ${displayIndexName} on ${displayFullPath}?`;
+ description = ACC_VACUUM_MSG;
+ confirmButtonText = 'Vacuum';
+ confirmEnabled = confirmationInput === displayIndexName;
+ break;
+ case 'delete':
+ title = `Delete acceleration ${displayIndexName} on ${displayFullPath}?`;
+ description = ACC_DELETE_MSG;
+ confirmButtonText = 'Delete';
+ break;
+ case 'sync':
+ title = 'Manual sync data?';
+ description = ACC_SYNC_MSG;
+ confirmButtonText = 'Sync';
+ break;
+ }
+
+ return (
+
+ onConfirm()}
+ cancelButtonText="Cancel"
+ confirmButtonText={confirmButtonText}
+ buttonColor="danger"
+ defaultFocusedButton="confirm"
+ confirmButtonDisabled={!confirmEnabled}
+ >
+ {description}
+ {actionType === 'vacuum' && (
+
+ setConfirmationInput(e.target.value)}
+ />
+
+ )}
+
+
+ );
+};
diff --git a/public/components/datasources/components/manage/accelerations/acceleration_details_flyout.tsx b/public/components/datasources/components/manage/accelerations/acceleration_details_flyout.tsx
index 108af38b91..76294a209a 100644
--- a/public/components/datasources/components/manage/accelerations/acceleration_details_flyout.tsx
+++ b/public/components/datasources/components/manage/accelerations/acceleration_details_flyout.tsx
@@ -18,22 +18,22 @@ import {
import React, { useEffect, useState } from 'react';
import { AccelerationDetailsTab } from './flyout_modules/acceleration_details_tab';
import { AccelerationSchemaTab } from './flyout_modules/accelerations_schema_tab';
-import { AccelerationSqlTab } from './flyout_modules/acceleration_sql_tab';
import {
- getRefreshButtonIcon,
- onRefreshButtonClick,
- onDiscoverButtonClick,
- onDeleteButtonClick,
+ onDiscoverIconClick,
+ AccelerationActionType,
+ getAccelerationName,
} from './utils/acceleration_utils';
import { coreRefs } from '../../../../../framework/core_refs';
import { OpenSearchDashboardsResponse } from '../../../../../../../../src/core/server/http/router';
import { CachedAcceleration } from '../../../../../../common/types/data_connections';
+import { useAccelerationOperation } from './acceleration_operation';
+import { AccelerationActionOverlay } from './acceleration_action_overlay';
export interface AccelerationDetailsFlyoutProps {
- index: string;
acceleration: CachedAcceleration;
dataSourceName: string;
resetFlyout: () => void;
+ handleRefresh?: () => void;
}
const getMappings = (index: string): Promise | undefined => {
@@ -58,15 +58,42 @@ const handleDetailsFetchingPromise = (
};
export const AccelerationDetailsFlyout = (props: AccelerationDetailsFlyoutProps) => {
- const { index, dataSourceName, acceleration, resetFlyout } = props;
- console.log(index, acceleration, dataSourceName);
+ const { dataSourceName, acceleration, resetFlyout, handleRefresh } = props;
const { flintIndexName } = acceleration;
const [selectedTab, setSelectedTab] = useState('details');
const tabsMap: { [key: string]: any } = {
details: AccelerationDetailsTab,
schema: AccelerationSchemaTab,
- sql_definition: AccelerationSqlTab,
};
+ const [operationType, setOperationType] = useState(null);
+ const [showConfirmationOverlay, setShowConfirmationOverlay] = useState(false);
+
+ const { performOperation, operationSuccess } = useAccelerationOperation(props.dataSourceName);
+
+ const displayedIndex = getAccelerationName(acceleration);
+
+ const onConfirmOperation = () => {
+ if (operationType && props.acceleration) {
+ performOperation(props.acceleration, operationType);
+ setShowConfirmationOverlay(false);
+ }
+ };
+
+ const onSyncIconClickHandler = () => {
+ setOperationType('sync');
+ setShowConfirmationOverlay(true);
+ };
+
+ const onDeleteIconClickHandler = () => {
+ setOperationType('delete');
+ setShowConfirmationOverlay(true);
+ };
+
+ const onVacuumIconClickHandler = () => {
+ setOperationType('vacuum');
+ setShowConfirmationOverlay(true);
+ };
+
const [settings, setSettings] = useState