refactor: Upload file to storage, and then pass attachmentId to collections.import
This avoids having large file uploads going directly to the server and allows us to fetch it async into a worker process
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
// @flow
|
||||
import invariant from "invariant";
|
||||
import { observer } from "mobx-react";
|
||||
import { CollectionIcon } from "outline-icons";
|
||||
import * as React from "react";
|
||||
@@ -14,6 +15,7 @@ import PageTitle from "components/PageTitle";
|
||||
import useCurrentUser from "hooks/useCurrentUser";
|
||||
import useStores from "hooks/useStores";
|
||||
import getDataTransferFiles from "utils/getDataTransferFiles";
|
||||
import { uploadFile } from "utils/uploadFile";
|
||||
|
||||
function ImportExport() {
|
||||
const { t } = useTranslation();
|
||||
@@ -23,7 +25,7 @@ function ImportExport() {
|
||||
const { showToast } = ui;
|
||||
const [isLoading, setLoading] = React.useState(false);
|
||||
const [isImporting, setImporting] = React.useState(false);
|
||||
const [importedDetails, setImported] = React.useState(false);
|
||||
const [isImported, setImported] = React.useState(false);
|
||||
const [isExporting, setExporting] = React.useState(false);
|
||||
const [file, setFile] = React.useState();
|
||||
const [importDetails, setImportDetails] = React.useState();
|
||||
@@ -34,11 +36,13 @@ function ImportExport() {
|
||||
setImporting(true);
|
||||
|
||||
try {
|
||||
const { documentCount, collectionCount } = await collections.import(
|
||||
file
|
||||
);
|
||||
showToast(t("Import completed"));
|
||||
setImported({ documentCount, collectionCount });
|
||||
invariant(file, "File must exist to upload");
|
||||
const attachment = await uploadFile(file, {
|
||||
name: file.name,
|
||||
});
|
||||
await collections.import(attachment.id);
|
||||
showToast(t("Import started"));
|
||||
setImported(true);
|
||||
} catch (err) {
|
||||
showToast(err.message);
|
||||
} finally {
|
||||
@@ -121,14 +125,11 @@ function ImportExport() {
|
||||
accept="application/zip"
|
||||
/>
|
||||
</VisuallyHidden>
|
||||
{importedDetails && (
|
||||
{isImported && (
|
||||
<Notice>
|
||||
<Trans
|
||||
count={importedDetails.documentCount}
|
||||
i18nKey="importSuccessful"
|
||||
>
|
||||
Import successful, {{ count: importedDetails.documentCount }}{" "}
|
||||
documents were imported to your knowledge base.
|
||||
<Trans>
|
||||
Your file has been uploaded and the import is being processed, you
|
||||
can safely leave this page.
|
||||
</Trans>
|
||||
</Notice>
|
||||
)}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// @flow
|
||||
import invariant from "invariant";
|
||||
import { concat, filter, last } from "lodash";
|
||||
import { computed, action } from "mobx";
|
||||
import naturalSort from "shared/utils/naturalSort";
|
||||
@@ -89,18 +88,11 @@ export default class CollectionsStore extends BaseStore<Collection> {
|
||||
}
|
||||
|
||||
@action
|
||||
import = async (file: File) => {
|
||||
const formData = new FormData();
|
||||
formData.append("type", "outline");
|
||||
formData.append("file", file);
|
||||
|
||||
const res = await client.post("/collections.import", formData);
|
||||
invariant(res && res.data, "Data should be available");
|
||||
|
||||
this.addPolicies(res.policies);
|
||||
res.data.collections.forEach(this.add);
|
||||
|
||||
return res.data;
|
||||
import = async (attachmentId: string) => {
|
||||
await client.post("/collections.import", {
|
||||
type: "outline",
|
||||
attachmentId,
|
||||
});
|
||||
};
|
||||
|
||||
async update(params: Object): Promise<Collection> {
|
||||
|
||||
@@ -39,11 +39,13 @@ export const uploadFile = async (
|
||||
formData.append("file", file);
|
||||
}
|
||||
|
||||
await fetch(data.uploadUrl, {
|
||||
const uploadResponse = await fetch(data.uploadUrl, {
|
||||
method: "post",
|
||||
body: formData,
|
||||
});
|
||||
|
||||
invariant(uploadResponse.ok, "Upload failed, try again?");
|
||||
|
||||
return attachment;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user