diff --git a/changelogs/fragments/6756.yml b/changelogs/fragments/6756.yml
new file mode 100644
index 000000000000..9cad7bffc99d
--- /dev/null
+++ b/changelogs/fragments/6756.yml
@@ -0,0 +1,2 @@
+fix:
+- Show error toast when fail to delete saved objects ([#6756](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6756))
\ No newline at end of file
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap
index fdff7b9d913b..6c56eed79fe4 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap
@@ -74,6 +74,146 @@ exports[`SavedObjectsTable delete should show a confirm modal 1`] = `
`;
+exports[`SavedObjectsTable delete should show error toast when failing to delete saved objects 1`] = `
+
+ }
+ confirmButtonText={
+
+ }
+ defaultFocusedButton="confirm"
+ onCancel={[Function]}
+ onConfirm={[Function]}
+ title={
+
+ }
+>
+
+
+
+
+
+`;
+
+exports[`SavedObjectsTable delete should show error toast when failing to delete saved objects 2`] = `
+
+ }
+ confirmButtonText={
+
+ }
+ defaultFocusedButton="confirm"
+ onCancel={[Function]}
+ onConfirm={[Function]}
+ title={
+
+ }
+>
+
+
+
+
+
+`;
+
exports[`SavedObjectsTable export should allow the user to choose when exporting all 1`] = `
{
// Set some as selected
component.instance().onSelectionChanged(mockSelectedSavedObjects);
+ await component.instance().onDelete();
+ component.update();
+ expect(component.state('isShowingDeleteConfirmModal')).toBe(true);
await component.instance().delete();
@@ -612,6 +615,53 @@ describe('SavedObjectsTable', () => {
{ force: true }
);
expect(component.state('selectedSavedObjects').length).toBe(0);
+ expect(notifications.toasts.addDanger).not.toHaveBeenCalled();
+ expect(component.state('isDeleting')).toBe(false);
+ expect(component.state('isShowingDeleteConfirmModal')).toBe(false);
+ });
+
+ it('should show error toast when failing to delete saved objects', async () => {
+ const mockSelectedSavedObjects = [
+ { id: '1', type: 'index-pattern' },
+ ] as SavedObjectWithMetadata[];
+
+ const mockSavedObjects = mockSelectedSavedObjects.map((obj) => ({
+ id: obj.id,
+ type: obj.type,
+ source: {},
+ }));
+
+ const mockSavedObjectsClient = {
+ ...defaultProps.savedObjectsClient,
+ bulkGet: jest.fn().mockImplementation(() => ({
+ savedObjects: mockSavedObjects,
+ })),
+ delete: jest.fn().mockImplementation(() => {
+ throw new Error('Unable to delete saved objects');
+ }),
+ };
+
+ const component = shallowRender({ savedObjectsClient: mockSavedObjectsClient });
+
+ // Ensure all promises resolve
+ await new Promise((resolve) => process.nextTick(resolve));
+ // Ensure the state changes are reflected
+ component.update();
+
+ // Set some as selected
+ component.instance().onSelectionChanged(mockSelectedSavedObjects);
+ await component.instance().onDelete();
+ component.update();
+ expect(component.state('isShowingDeleteConfirmModal')).toBe(true);
+ expect(component.find('EuiConfirmModal')).toMatchSnapshot();
+
+ await component.instance().delete();
+ component.update();
+ expect(notifications.toasts.addDanger).toHaveBeenCalled();
+ // If user fail to delete the saved objects, the delete modal will continue to display
+ expect(component.state('isShowingDeleteConfirmModal')).toBe(true);
+ expect(component.find('EuiConfirmModal')).toMatchSnapshot();
+ expect(component.state('isDeleting')).toBe(false);
});
});
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx
index 56e7950efeea..04d7a46d24d2 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx
@@ -589,7 +589,7 @@ export class SavedObjectsTable extends Component {
- const { savedObjectsClient } = this.props;
+ const { savedObjectsClient, notifications } = this.props;
const { selectedSavedObjects, isDeleting } = this.state;
if (isDeleting) {
@@ -599,30 +599,38 @@ export class SavedObjectsTable extends Component object.type === 'index-pattern');
- if (indexPatterns.length) {
- await this.props.indexPatterns.clearCache();
- }
-
- const objects = await savedObjectsClient.bulkGet(selectedSavedObjects);
- const deletes = objects.savedObjects.map((object) =>
- savedObjectsClient.delete(object.type, object.id, { force: true })
- );
- await Promise.all(deletes);
- // Unset this
- this.setState({
- selectedSavedObjects: [],
- });
+ try {
+ if (indexPatterns.length) {
+ await this.props.indexPatterns.clearCache();
+ }
+ const objects = await savedObjectsClient.bulkGet(selectedSavedObjects);
+ const deletes = objects.savedObjects.map((object) =>
+ savedObjectsClient.delete(object.type, object.id, { force: true })
+ );
+ await Promise.all(deletes);
+ // Unset this
+ this.setState({
+ selectedSavedObjects: [],
+ });
+ // Fetching all data
+ await this.fetchSavedObjects();
+ await this.fetchCounts();
- // Fetching all data
- await this.fetchSavedObjects();
- await this.fetchCounts();
+ // Allow the user to interact with the table once the saved objects have been re-fetched.
+ // If the user fails to delete the saved objects, the delete modal will continue to display.
+ this.setState({ isShowingDeleteConfirmModal: false });
+ } catch (error) {
+ notifications.toasts.addDanger({
+ title: i18n.translate(
+ 'savedObjectsManagement.objectsTable.unableDeleteSavedObjectsNotificationMessage',
+ { defaultMessage: 'Unable to delete saved objects' }
+ ),
+ text: `${error}`,
+ });
+ }
- // Allow the user to interact with the table once the saved objects have been re-fetched.
- this.setState({
- isShowingDeleteConfirmModal: false,
- isDeleting: false,
- });
+ this.setState({ isDeleting: false });
};
getRelationships = async (type: string, id: string) => {