Skip to content

Commit 2f91285

Browse files
committed
Add support for copying files.
1 parent 5f59210 commit 2f91285

File tree

5 files changed

+55
-10
lines changed

5 files changed

+55
-10
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import http from '@/api/http';
2+
3+
export default (uuid: string, location: string): Promise<void> => {
4+
return new Promise((resolve, reject) => {
5+
http.post(`/api/client/servers/${uuid}/files/copy`, { location })
6+
.then(() => resolve())
7+
.catch(reject);
8+
});
9+
};

resources/scripts/components/elements/SpinnerOverlay.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@ import classNames from 'classnames';
33
import { CSSTransition } from 'react-transition-group';
44
import Spinner from '@/components/elements/Spinner';
55

6-
export default ({ large, visible }: { visible: boolean; large?: boolean }) => (
6+
export default ({ large, fixed, visible }: { visible: boolean; fixed?: boolean; large?: boolean }) => (
77
<CSSTransition timeout={150} classNames={'fade'} in={visible} unmountOnExit={true}>
88
<div
9-
className={classNames('absolute pin-t pin-l flex items-center justify-center w-full h-full rounded')}
9+
className={classNames('z-50 pin-t pin-l flex items-center justify-center w-full h-full rounded', {
10+
absolute: !fixed,
11+
fixed: fixed,
12+
})}
1013
style={{ background: 'rgba(0, 0, 0, 0.45)' }}
1114
>
1215
<Spinner large={large}/>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import React, { useEffect } from 'react';
2+
import { FileObject } from '@/api/server/files/loadDirectory';
3+
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
4+
import { ServerContext } from '@/state/server';
5+
import copyFile from '@/api/server/files/copyFile';
6+
import { join } from 'path';
7+
import { httpErrorToHuman } from '@/api/http';
8+
9+
// This component copies the given file on mount, so only mount it when
10+
// you actually want to copy the file...
11+
export default ({ file, onCopyComplete }: { file: FileObject; onCopyComplete: () => void }) => {
12+
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
13+
const directory = ServerContext.useStoreState(state => state.files.directory);
14+
const getDirectoryContents = ServerContext.useStoreActions(actions => actions.files.getDirectoryContents);
15+
16+
useEffect(() => {
17+
copyFile(uuid, join(directory, file.name))
18+
.then(() => getDirectoryContents(directory))
19+
.catch(error => {
20+
console.error('Error while attempting to copy file.', error);
21+
alert(httpErrorToHuman(error));
22+
});
23+
}, []);
24+
25+
return (
26+
<SpinnerOverlay visible={true} large={true} fixed={true}/>
27+
);
28+
};

resources/scripts/components/server/files/FileDropdownMenu.tsx

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ import { faCopy } from '@fortawesome/free-solid-svg-icons/faCopy';
99
import { faLevelUpAlt } from '@fortawesome/free-solid-svg-icons/faLevelUpAlt';
1010
import RenameFileModal from '@/components/server/files/RenameFileModal';
1111
import { ServerContext } from '@/state/server';
12+
import CopyFileModal from '@/components/server/files/CopyFileModal';
1213

13-
type ModalType = 'rename' | 'move';
14+
type ModalType = 'rename' | 'move' | 'copy' | 'download' | 'delete';
1415

1516
export default ({ uuid }: { uuid: string }) => {
1617
const menu = createRef<HTMLDivElement>();
@@ -54,7 +55,7 @@ export default ({ uuid }: { uuid: string }) => {
5455
}, []);
5556

5657
return (
57-
<div>
58+
<div key={`dropdown:${file.uuid}`}>
5859
<div
5960
className={'p-3 hover:text-white'}
6061
onClick={e => {
@@ -70,18 +71,19 @@ export default ({ uuid }: { uuid: string }) => {
7071
<FontAwesomeIcon icon={faEllipsisH}/>
7172
</div>
7273
{visible &&
73-
<React.Fragment>
74-
<RenameFileModal file={file} visible={modal === 'rename'} onDismissed={() => setModal(null)}/>
75-
</React.Fragment>
74+
<React.Fragment>
75+
<RenameFileModal file={file} visible={modal === 'rename'} onDismissed={() => setModal(null)}/>
76+
{modal === 'copy' && <CopyFileModal file={file} onCopyComplete={() => setModal(null)}/>}
77+
</React.Fragment>
7678
}
7779
<CSSTransition timeout={250} in={visible} unmountOnExit={true} classNames={'fade'}>
7880
<div
7981
className={'absolute bg-white p-2 rounded border border-neutral-700 shadow-lg text-neutral-500 min-w-48'}
8082
ref={menu}
8183
>
8284
<div
83-
className={'hover:text-neutral-700 p-2 flex items-center hover:bg-neutral-100 rounded'}
8485
onClick={() => setModal('rename')}
86+
className={'hover:text-neutral-700 p-2 flex items-center hover:bg-neutral-100 rounded'}
8587
>
8688
<FontAwesomeIcon icon={faPencilAlt} className={'text-xs'}/>
8789
<span className={'ml-2'}>Rename</span>
@@ -90,7 +92,10 @@ export default ({ uuid }: { uuid: string }) => {
9092
<FontAwesomeIcon icon={faLevelUpAlt} className={'text-xs'}/>
9193
<span className={'ml-2'}>Move</span>
9294
</div>
93-
<div className={'hover:text-neutral-700 p-2 flex items-center hover:bg-neutral-100 rounded'}>
95+
<div
96+
onClick={() => setModal('copy')}
97+
className={'hover:text-neutral-700 p-2 flex items-center hover:bg-neutral-100 rounded'}
98+
>
9499
<FontAwesomeIcon icon={faCopy} className={'text-xs'}/>
95100
<span className={'ml-2'}>Copy</span>
96101
</div>

resources/scripts/components/server/files/FileManagerContainer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export default () => {
8484
<div>
8585
{
8686
files.map(file => (
87-
<FileObjectRow key={file.name} file={file}/>
87+
<FileObjectRow key={file.uuid} file={file}/>
8888
))
8989
}
9090
</div>

0 commit comments

Comments
 (0)