misc_pterodactyl-panel/resources/scripts/components/server/files/MassActionsBar.tsx

114 lines
4.8 KiB
TypeScript
Raw Normal View History

2022-11-25 20:25:03 +00:00
import { useEffect, useState } from 'react';
import compressFiles from '@/api/server/files/compressFiles';
import deleteFiles from '@/api/server/files/deleteFiles';
import { Button } from '@/components/elements/button';
import { Dialog } from '@/components/elements/dialog';
import Portal from '@/components/elements/Portal';
2020-07-11 22:37:59 +00:00
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
2022-11-25 20:25:03 +00:00
import RenameFileModal from '@/components/server/files/RenameFileModal';
2020-07-11 22:37:59 +00:00
import useFileManagerSwr from '@/plugins/useFileManagerSwr';
import useFlash from '@/plugins/useFlash';
import { ServerContext } from '@/state/server';
2022-11-25 20:25:03 +00:00
import FadeTransition from '@/components/elements/transitions/FadeTransition';
2020-07-11 22:37:59 +00:00
const MassActionsBar = () => {
2022-11-25 20:25:03 +00:00
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
2020-08-26 04:39:00 +00:00
2020-07-11 22:37:59 +00:00
const { mutate } = useFileManagerSwr();
const { clearFlashes, clearAndAddHttpError } = useFlash();
const [loading, setLoading] = useState(false);
const [loadingMessage, setLoadingMessage] = useState('');
const [showConfirm, setShowConfirm] = useState(false);
const [showMove, setShowMove] = useState(false);
2022-11-25 20:25:03 +00:00
const directory = ServerContext.useStoreState(state => state.files.directory);
2020-07-11 22:37:59 +00:00
2022-11-25 20:25:03 +00:00
const selectedFiles = ServerContext.useStoreState(state => state.files.selectedFiles);
const setSelectedFiles = ServerContext.useStoreActions(actions => actions.files.setSelectedFiles);
useEffect(() => {
if (!loading) setLoadingMessage('');
}, [loading]);
2020-07-11 22:37:59 +00:00
const onClickCompress = () => {
setLoading(true);
clearFlashes('files');
setLoadingMessage('Archiving files...');
2020-07-11 22:37:59 +00:00
compressFiles(uuid, directory, selectedFiles)
2020-07-11 22:37:59 +00:00
.then(() => mutate())
.then(() => setSelectedFiles([]))
2022-11-25 20:25:03 +00:00
.catch(error => clearAndAddHttpError({ key: 'files', error }))
2020-07-11 22:37:59 +00:00
.then(() => setLoading(false));
};
const onClickConfirmDeletion = () => {
setLoading(true);
setShowConfirm(false);
clearFlashes('files');
setLoadingMessage('Deleting files...');
2020-07-11 22:37:59 +00:00
deleteFiles(uuid, directory, selectedFiles)
2022-11-25 20:25:03 +00:00
.then(async () => {
await mutate(files => files!.filter(f => selectedFiles.indexOf(f.name) < 0), false);
setSelectedFiles([]);
2020-07-11 22:37:59 +00:00
})
2022-11-25 20:25:03 +00:00
.catch(async error => {
await mutate();
2020-07-11 22:37:59 +00:00
clearAndAddHttpError({ key: 'files', error });
})
.then(() => setLoading(false));
};
return (
2022-06-20 18:16:42 +00:00
<>
2023-01-12 19:31:47 +00:00
<div className="pointer-events-none fixed bottom-0 left-0 right-0 z-20 flex justify-center">
<SpinnerOverlay visible={loading} size={'large'} fixed>
{loadingMessage}
</SpinnerOverlay>
2022-06-20 18:16:42 +00:00
<Dialog.Confirm
title={'Delete Files'}
open={showConfirm}
confirm={'Delete'}
onClose={() => setShowConfirm(false)}
2020-07-11 22:37:59 +00:00
onConfirmed={onClickConfirmDeletion}
>
2022-11-25 20:25:03 +00:00
<p className="mb-2">
2022-06-20 18:16:42 +00:00
Are you sure you want to delete&nbsp;
<span className="font-semibold text-slate-50">{selectedFiles.length} files</span>? This is a
permanent action and the files cannot be recovered.
2022-06-20 18:16:42 +00:00
</p>
2022-11-25 20:25:03 +00:00
{selectedFiles.slice(0, 15).map(file => (
<li key={file}>{file}</li>
))}
{selectedFiles.length > 15 && <li>and {selectedFiles.length - 15} others</li>}
2022-06-20 18:16:42 +00:00
</Dialog.Confirm>
{showMove && (
2022-06-20 18:16:42 +00:00
<RenameFileModal
files={selectedFiles}
visible
appear
useMoveTerminology
onDismissed={() => setShowMove(false)}
/>
)}
2022-06-20 18:16:42 +00:00
<Portal>
2023-01-12 19:31:47 +00:00
<div className="fixed bottom-0 z-50 mb-6 flex w-full justify-center">
2022-11-25 20:25:03 +00:00
<FadeTransition duration="duration-75" show={selectedFiles.length > 0} appear unmount>
2023-01-12 19:31:47 +00:00
<div className="pointer-events-auto flex items-center space-x-4 rounded bg-black/50 p-4">
2022-06-20 18:16:42 +00:00
<Button onClick={() => setShowMove(true)}>Move</Button>
<Button onClick={onClickCompress}>Archive</Button>
<Button.Danger variant={Button.Variants.Secondary} onClick={() => setShowConfirm(true)}>
Delete
</Button.Danger>
</div>
2022-11-25 20:25:03 +00:00
</FadeTransition>
2022-06-20 18:16:42 +00:00
</div>
</Portal>
2020-07-11 22:37:59 +00:00
</div>
2022-06-20 18:16:42 +00:00
</>
2020-07-11 22:37:59 +00:00
);
};
export default MassActionsBar;