160 lines
4.4 KiB
TypeScript
160 lines
4.4 KiB
TypeScript
import React from 'react';
|
|
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
|
|
|
|
import Button from 'react-bootstrap/Button';
|
|
import ListGroup from 'react-bootstrap/ListGroup';
|
|
import Modal from 'react-bootstrap/Modal';
|
|
import Stack from 'react-bootstrap/Stack';
|
|
|
|
import { BsFileEarmarkText, BsHourglassSplit, BsCheckCircle } from 'react-icons/bs';
|
|
import { AiOutlineDelete } from 'react-icons/ai';
|
|
|
|
import fileSizePretty from './fileSizePretty';
|
|
|
|
interface Props {
|
|
client: S3Client;
|
|
bucket: string;
|
|
prefix: string;
|
|
onUploadComplete: () => void;
|
|
}
|
|
|
|
type State = {
|
|
iFile: number;
|
|
show: boolean;
|
|
files: File[];
|
|
processing: boolean;
|
|
canceled: boolean;
|
|
progressEach: number[];
|
|
};
|
|
|
|
class UploadFiles extends React.Component<Props, State> {
|
|
file_input: HTMLInputElement | null = null;
|
|
|
|
state = {
|
|
iFile: 0,
|
|
show: true,
|
|
files: [],
|
|
processing: false,
|
|
canceled: false,
|
|
progressEach: [],
|
|
};
|
|
|
|
async componentDidMount() {
|
|
this.addFile();
|
|
}
|
|
|
|
handleClose() {
|
|
this.setState({show: false});
|
|
}
|
|
|
|
handleFileChange() {
|
|
let infiles = this.file_input!.files || [];
|
|
let files: File[] = this.state.files;
|
|
|
|
for (var i = 0; i < infiles.length; i++) {
|
|
files.push(infiles[i]);
|
|
}
|
|
|
|
this.setState({show: (files.length > 0), files: files, iFile: this.state.iFile + 1});
|
|
}
|
|
|
|
addFile() {
|
|
this.file_input!.click();
|
|
}
|
|
|
|
removeFile(i: number) {
|
|
let files: File[] = this.state.files;
|
|
files.splice(i, 1);
|
|
this.setState({files: files});
|
|
}
|
|
|
|
async processUpload() {
|
|
var i: number;
|
|
|
|
this.setState({canceled: false});
|
|
|
|
let progressEach: number[] = [];
|
|
for (i = 0; i < this.state.files.length; i++) {
|
|
progressEach.push(0);
|
|
}
|
|
this.setState({canceled: false, processing: true, progressEach: progressEach});
|
|
|
|
for (i = 0; i < this.state.files.length; i++) {
|
|
let file: File = this.state.files[i];
|
|
let req = new PutObjectCommand({
|
|
Bucket: this.props.bucket,
|
|
Key: this.props.prefix + file.name,
|
|
ContentType: file.type,
|
|
ContentLength: file.size,
|
|
Body: file,
|
|
});
|
|
await this.props.client.send(req);
|
|
progressEach[i] = 100;
|
|
this.setState({progressEach: progressEach});
|
|
}
|
|
|
|
this.setState({show: false});
|
|
this.props.onUploadComplete();
|
|
}
|
|
|
|
render() {
|
|
return <>
|
|
<Modal show={this.state.show} onHide={() => this.handleClose()}>
|
|
<Modal.Header closeButton>
|
|
<Modal.Title>
|
|
Upload files
|
|
</Modal.Title>
|
|
</Modal.Header>
|
|
<Modal.Body>
|
|
<input
|
|
key={ "file" + this.state.iFile }
|
|
type="file" id="file_input"
|
|
ref={input => this.file_input = input}
|
|
onChange={() => this.handleFileChange()}
|
|
multiple
|
|
hidden />
|
|
{ this.state.files.length === 0 ? <p>No files added yet, click "add file" below.</p> : <></> }
|
|
<ListGroup>
|
|
{ this.state.files.map((f: File, i: number) =>
|
|
<ListGroup.Item>
|
|
<Stack direction="horizontal">
|
|
<div className="mt-1">
|
|
<BsFileEarmarkText /> { f.name }
|
|
</div>
|
|
<div className="ms-auto">
|
|
{ this.state.processing ?
|
|
(this.state.progressEach[i] === 100 ? <BsCheckCircle />
|
|
: this.state.progressEach[i] > 0 ? this.state.progressEach[i] + "%"
|
|
: <BsHourglassSplit /> )
|
|
:
|
|
<Button variant="danger" size="sm" onClick={() => this.removeFile(i)}>
|
|
<AiOutlineDelete />
|
|
</Button>
|
|
}
|
|
</div>
|
|
</Stack>
|
|
<Stack direction="horizontal">
|
|
<div className="px-2"> </div>
|
|
<div className="text-muted small">
|
|
{ fileSizePretty(f.size) } - { f.type }
|
|
</div>
|
|
</Stack>
|
|
</ListGroup.Item>
|
|
)}
|
|
</ListGroup>
|
|
</Modal.Body>
|
|
<Modal.Footer>
|
|
<Button variant="success" onClick={() => this.addFile()}>
|
|
Add file
|
|
</Button>
|
|
<Button variant="primary" onClick={() => this.processUpload()} disabled={this.state.files.length === 0}>
|
|
Upload
|
|
</Button>
|
|
</Modal.Footer>
|
|
</Modal>
|
|
</>;
|
|
}
|
|
};
|
|
|
|
export default UploadFiles;
|