frontend/app/multistep/projecttemplate/TemplateUploadComponent.jsx (245 lines of code) (raw):
import React from "react";
import ReactDOM from "react-dom";
import PropTypes from "prop-types";
import axios from "axios";
import CommonMultistepComponent from "../common/CommonMultistepComponent.jsx";
import ErrorViewComponent from "../common/ErrorViewComponent.jsx";
import UploadingThrobber from "../common/UploadingThrobber.jsx";
import FileEntryView from "../../EntryViews/FileEntryView.jsx";
import StorageSelector from "../../Selectors/StorageSelector.jsx";
import UploadNewVersionComponent from "./UploadNewVersionComponent.jsx";
class TemplateUploadComponent extends CommonMultistepComponent {
static propTypes = {
storages: PropTypes.array.isRequired,
valueWasSet: PropTypes.func.isRequired,
existingFileId: PropTypes.number,
};
constructor(props) {
super(props);
const firstStorage = this.props.storages[0]
? this.props.storages[0].id
: null;
this.state = {
loading: false,
error: null,
hasFiles: false,
selectedStorage: firstStorage,
fileId: null,
uploading: false,
// Use non-strict equality check to check for both undefined and null.
useExisting: props.existingFileId != null,
uploadFileVersion: 1,
uploadFileName: null,
fileInputKey: 0, //we use this to clear the file input component by forcing it to re-render when the value is changed
};
this.fileChange = this.fileChange.bind(this);
this.fileInput = React.createRef();
}
componentDidUpdate() {
//override the super-class implementation as we don't want it here
}
doUpload() {
const data = this.fileInput.current.files[0];
console.log("doUpload: file name is ", data.name);
axios({
method: "PUT",
url: "/api/file/" + this.state.fileId + "/content",
data: data,
headers: { "Content-Type": "application/octet-stream" },
})
.then((response) => {
this.setState({ uploading: false, hasFiles: true }, () => {
this.props.valueWasSet(this.state.fileId);
});
})
.catch((error) => {
this.setState({ uploading: false, error: error });
});
}
createFile() {
return new Promise((resolve, reject) => {
if (this.state.uploadFileName === null) {
reject("uploadFileName not set");
} else {
this.setState({ uploading: true, error: null }, () => {
const nowtime = new Date().toISOString();
axios({
method: "PUT",
url: "/api/file",
data: {
storage: parseInt(this.state.selectedStorage),
filepath: this.state.uploadFileName,
version: this.state.uploadFileVersion,
user: "",
ctime: nowtime,
mtime: nowtime,
atime: nowtime,
hasContent: false,
hasLink: false,
},
})
.then((response) => {
this.setState({ fileId: response.data.id }, () =>
resolve(response.data)
);
})
.catch((error) => {
console.log(error);
console.log(error.response.data);
console.log(
error.response.data.hasOwnProperty("nextAvailableVersion")
);
if (error.response.data.hasOwnProperty("nextAvailableVersion")) {
console.log(
"can create object at version ",
error.response.data.nextAvailableVersion
);
this.setState(
{
error: error,
uploading: false,
uploadFileVersion: error.response.data.nextAvailableVersion,
},
() => reject(error)
);
} else {
this.setState({ error: error, uploading: false }, () =>
reject(error)
);
}
});
});
}
});
}
fileChange(event) {
/*called when the user changes the file selector*/
const files = event.target.files || event.dataTransfer.files;
if (!files.length) {
console.log("No files present");
return;
}
this.setState({ uploadFileName: files[0].name }, () =>
this.createFile().then(() => this.doUpload())
);
}
labelForStorage(strg) {
const remotePart =
strg.hasOwnProperty("user") && strg.hasOwnProperty("host")
? strg.user.toString + "@" + strg.host.toString
: "(no credentials)";
const pathPart = strg.hasOwnProperty("rootpath")
? strg.rootpath.toString()
: "/";
if (strg.storageType === "Local") {
return strg.storageType + " (" + pathPart + ")";
} else {
return strg.storageType + " " + remotePart + " (" + pathPart + ")";
}
}
storageSupportsVersions() {
const matchingStorageList = this.props.storages.filter(
(value, idx, arry) => value === this.state.selectedStorage
);
if (matchingStorageList.length === 0) return false;
console.log(
"storageSupportsVersions: ",
matchingStorageList[0].supportsVersions
);
}
render() {
return (
<div>
<h3>Template upload</h3>
<p className="information">
Please upload the file that you want to serve as a template
</p>
<input
type="radio"
name="uploadOrUseExisting"
id="useExisting"
checked={this.state.useExisting}
disabled={this.props.existingFileId === null}
onChange={(event) =>
this.setState({ useExisting: !this.state.useExisting })
}
/>
<span style={{ marginLeft: "1em" }}>
Use existing template file:
<FileEntryView
entryId={this.props.existingFileId}
hide={!this.props.existingFileId}
/>
</span>
<br />
<input
type="radio"
name="uploadOrUseExisting"
id="uploadNew"
checked={!this.state.useExisting}
onChange={(event) =>
this.setState({ useExisting: !this.state.useExisting })
}
/>
<span style={{ marginLeft: "1em" }}>Upload new file</span>
<table style={{ display: this.state.useExisting ? "none" : "inherit" }}>
<tbody>
<tr>
<td>Storage</td>
<td>
<StorageSelector
selectedStorage={this.state.selectedStorage}
selectionUpdated={(newValue) =>
this.setState({ selectedStorage: newValue })
}
storageList={this.props.storages}
showLabel={true}
enabled={true}
/>
</td>
</tr>
<tr>
<td>File to upload</td>
<td>
<input
onChange={this.fileChange}
type="file"
id="template-upload-fileselector"
key={this.state.fileInputKey}
ref={this.fileInput}
/>
</td>
<td>
<UploadingThrobber loading={this.state.uploading} />
{this.state.hasFiles ? (
<p style={{ color: "green" }}>
File uploaded to version {this.state.uploadFileVersion},
please click "Next"
</p>
) : (
<p />
)}
</td>
</tr>
</tbody>
</table>
{this.state.error && <ErrorViewComponent error={this.state.error} />}
{this.state.uploadFileVersion === 1 || this.state.hasFiles ? (
<p />
) : (
<UploadNewVersionComponent
newVersionCb={() => this.createFile().then(() => this.doUpload())}
cancelCb={() =>
this.setState({
fileInputKey: this.state.fileInputKey + 1,
uploadFileVersion: 1,
error: null,
})
}
/>
)}
</div>
);
}
}
export default TemplateUploadComponent;