2024-06-13 09:12:10 +02:00
|
|
|
import { css } from '@emotion/css';
|
2024-06-25 12:43:47 +01:00
|
|
|
import { useMemo } from 'react';
|
2024-06-13 09:12:10 +02:00
|
|
|
|
|
|
|
|
import { GrafanaTheme2 } from '@grafana/data/';
|
|
|
|
|
import { Button, useStyles2 } from '@grafana/ui';
|
2024-06-17 11:15:37 +01:00
|
|
|
import { GENERAL_FOLDER_UID } from 'app/features/search/constants';
|
2024-06-13 09:12:10 +02:00
|
|
|
|
|
|
|
|
import appEvents from '../../../core/app_events';
|
|
|
|
|
import { Trans } from '../../../core/internationalization';
|
|
|
|
|
import { useDispatch } from '../../../types';
|
|
|
|
|
import { ShowModalReactEvent } from '../../../types/events';
|
2024-06-20 18:18:11 +02:00
|
|
|
import { useHardDeleteDashboardMutation, useRestoreDashboardMutation } from '../api/browseDashboardsAPI';
|
2024-06-14 15:25:19 +01:00
|
|
|
import { useRecentlyDeletedStateManager } from '../api/useRecentlyDeletedStateManager';
|
2024-06-20 18:18:11 +02:00
|
|
|
import { clearFolders, setAllSelection, useActionSelectionState } from '../state';
|
|
|
|
|
|
|
|
|
|
import { PermanentlyDeleteModal } from './PermanentlyDeleteModal';
|
|
|
|
|
import { RestoreModal } from './RestoreModal';
|
2024-06-13 09:12:10 +02:00
|
|
|
|
|
|
|
|
export function RecentlyDeletedActions() {
|
|
|
|
|
const styles = useStyles2(getStyles);
|
|
|
|
|
|
|
|
|
|
const dispatch = useDispatch();
|
2024-06-14 14:30:05 +02:00
|
|
|
const selectedItemsState = useActionSelectionState();
|
2024-06-13 09:12:10 +02:00
|
|
|
const [, stateManager] = useRecentlyDeletedStateManager();
|
|
|
|
|
|
|
|
|
|
const [restoreDashboard, { isLoading: isRestoreLoading }] = useRestoreDashboardMutation();
|
2024-06-20 18:18:11 +02:00
|
|
|
const [deleteDashboard, { isLoading: isDeleteLoading }] = useHardDeleteDashboardMutation();
|
2024-06-13 09:12:10 +02:00
|
|
|
|
2024-06-14 14:30:05 +02:00
|
|
|
const selectedDashboards = useMemo(() => {
|
|
|
|
|
return Object.entries(selectedItemsState.dashboard)
|
|
|
|
|
.filter(([_, selected]) => selected)
|
|
|
|
|
.map(([uid]) => uid);
|
|
|
|
|
}, [selectedItemsState.dashboard]);
|
|
|
|
|
|
2024-06-13 09:12:10 +02:00
|
|
|
const onActionComplete = () => {
|
|
|
|
|
dispatch(setAllSelection({ isSelected: false, folderUID: undefined }));
|
|
|
|
|
|
|
|
|
|
stateManager.doSearchWithDebounce();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onRestore = async () => {
|
2024-06-17 11:15:37 +01:00
|
|
|
const resultsView = stateManager.state.result?.view.toArray();
|
|
|
|
|
if (!resultsView) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const promises = selectedDashboards.map((uid) => {
|
|
|
|
|
return restoreDashboard({ dashboardUID: uid });
|
|
|
|
|
});
|
2024-06-14 14:30:05 +02:00
|
|
|
|
2024-06-13 09:12:10 +02:00
|
|
|
await Promise.all(promises);
|
2024-06-17 11:15:37 +01:00
|
|
|
|
|
|
|
|
const parentUIDs = new Set<string | undefined>();
|
|
|
|
|
for (const uid of selectedDashboards) {
|
|
|
|
|
const foundItem = resultsView.find((v) => v.uid === uid);
|
|
|
|
|
if (!foundItem) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Search API returns items with no parent with a location of 'general', so we
|
|
|
|
|
// need to convert that back to undefined
|
|
|
|
|
const folderUID = foundItem.location === GENERAL_FOLDER_UID ? undefined : foundItem.location;
|
|
|
|
|
parentUIDs.add(folderUID);
|
|
|
|
|
}
|
|
|
|
|
dispatch(clearFolders(Array.from(parentUIDs)));
|
|
|
|
|
|
2024-06-13 09:12:10 +02:00
|
|
|
onActionComplete();
|
|
|
|
|
};
|
|
|
|
|
|
2024-06-20 18:18:11 +02:00
|
|
|
const onDelete = async () => {
|
|
|
|
|
const promises = selectedDashboards.map((uid) => deleteDashboard({ dashboardUID: uid }));
|
|
|
|
|
|
|
|
|
|
await Promise.all(promises);
|
|
|
|
|
onActionComplete();
|
|
|
|
|
};
|
|
|
|
|
|
2024-06-13 09:12:10 +02:00
|
|
|
const showRestoreModal = () => {
|
|
|
|
|
appEvents.publish(
|
|
|
|
|
new ShowModalReactEvent({
|
|
|
|
|
component: RestoreModal,
|
|
|
|
|
props: {
|
2024-06-14 14:30:05 +02:00
|
|
|
selectedDashboards,
|
2024-06-13 09:12:10 +02:00
|
|
|
onConfirm: onRestore,
|
|
|
|
|
isLoading: isRestoreLoading,
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2024-06-20 18:18:11 +02:00
|
|
|
const showDeleteModal = () => {
|
|
|
|
|
appEvents.publish(
|
|
|
|
|
new ShowModalReactEvent({
|
|
|
|
|
component: PermanentlyDeleteModal,
|
|
|
|
|
props: {
|
|
|
|
|
selectedDashboards,
|
|
|
|
|
onConfirm: onDelete,
|
|
|
|
|
isLoading: isDeleteLoading,
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2024-06-13 09:12:10 +02:00
|
|
|
return (
|
|
|
|
|
<div className={styles.row}>
|
|
|
|
|
<Button onClick={showRestoreModal} variant="secondary">
|
|
|
|
|
<Trans i18nKey="recently-deleted.buttons.restore">Restore</Trans>
|
|
|
|
|
</Button>
|
2024-06-20 18:18:11 +02:00
|
|
|
<Button onClick={showDeleteModal} variant="destructive">
|
|
|
|
|
<Trans i18nKey="recently-deleted.buttons.delete">Delete permanently</Trans>
|
|
|
|
|
</Button>
|
2024-06-13 09:12:10 +02:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getStyles = (theme: GrafanaTheme2) => ({
|
|
|
|
|
row: css({
|
2024-06-20 18:18:11 +02:00
|
|
|
display: 'flex',
|
|
|
|
|
flexDirection: 'row',
|
|
|
|
|
gap: theme.spacing(1),
|
2024-06-27 14:00:12 +02:00
|
|
|
margin: theme.spacing(2, 0),
|
|
|
|
|
|
|
|
|
|
[theme.breakpoints.up('md')]: {
|
|
|
|
|
marginTop: 0,
|
|
|
|
|
},
|
2024-06-13 09:12:10 +02:00
|
|
|
}),
|
|
|
|
|
});
|