diff --git a/app/scenes/Settings/Import.tsx b/app/scenes/Settings/Import.tsx
index 0d5d60dff..9819c19b0 100644
--- a/app/scenes/Settings/Import.tsx
+++ b/app/scenes/Settings/Import.tsx
@@ -83,7 +83,7 @@ function Import() {
subtitle={t("Import pages from a Confluence instance")}
actions={
}
/>
diff --git a/app/scenes/Settings/components/FileOperationListItem.tsx b/app/scenes/Settings/components/FileOperationListItem.tsx
index 012143b19..0f2e475fb 100644
--- a/app/scenes/Settings/components/FileOperationListItem.tsx
+++ b/app/scenes/Settings/components/FileOperationListItem.tsx
@@ -21,6 +21,7 @@ const FileOperationListItem = ({ fileOperation, handleDelete }: Props) => {
const user = useCurrentUser();
const theme = useTheme();
const stateMapping = {
+ complete: t("Completed"),
creating: t("Processing"),
expired: t("Expired"),
uploading: t("Processing"),
@@ -46,9 +47,7 @@ const FileOperationListItem = ({ fileOperation, handleDelete }: Props) => {
image={iconMapping[fileOperation.state]}
subtitle={
<>
- {fileOperation.state !== "complete" && (
- <>{stateMapping[fileOperation.state]} • >
- )}
+ {stateMapping[fileOperation.state]} •
{fileOperation.error && <>{fileOperation.error} • >}
{t(`{{userName}} requested`, {
userName:
diff --git a/server/commands/documentCreator.ts b/server/commands/documentCreator.ts
index bc0fbbaa2..935ffe327 100644
--- a/server/commands/documentCreator.ts
+++ b/server/commands/documentCreator.ts
@@ -9,6 +9,7 @@ export default async function documentCreator({
collectionId,
parentDocumentId,
templateDocument,
+ importId,
createdAt,
// allows override for import
updatedAt,
@@ -26,6 +27,7 @@ export default async function documentCreator({
publish?: boolean;
collectionId: string;
parentDocumentId?: string;
+ importId?: string;
templateDocument?: Document | null;
publishedAt?: Date;
template?: boolean;
@@ -54,6 +56,7 @@ export default async function documentCreator({
template,
templateId,
publishedAt,
+ importId,
title: templateDocument ? templateDocument.title : title,
text: templateDocument ? templateDocument.text : text,
},
diff --git a/server/migrations/20221112152649-import-document-relationship.js b/server/migrations/20221112152649-import-document-relationship.js
new file mode 100644
index 000000000..fffde7621
--- /dev/null
+++ b/server/migrations/20221112152649-import-document-relationship.js
@@ -0,0 +1,48 @@
+"use strict";
+
+module.exports = {
+ async up(queryInterface, Sequelize) {
+ await queryInterface.sequelize.transaction(async (transaction) => {
+ await queryInterface.addColumn("documents", "importId", {
+ type: Sequelize.UUID,
+ allowNull: true,
+ references: {
+ model: "file_operations",
+ },
+ transaction,
+ });
+ await queryInterface.addColumn("collections", "importId", {
+ type: Sequelize.UUID,
+ allowNull: true,
+ references: {
+ model: "file_operations",
+ },
+ transaction,
+ });
+ await queryInterface.addIndex("documents", ["importId"], {
+ transaction
+ });
+ await queryInterface.addIndex("collections", ["importId"], {
+ transaction
+ });
+ });
+
+ },
+
+ async down(queryInterface) {
+ await queryInterface.sequelize.transaction(async (transaction) => {
+ await queryInterface.removeIndex("collections", ["importId"], {
+ transaction
+ });
+ await queryInterface.removeIndex("documents", ["importId"], {
+ transaction
+ });
+ await queryInterface.removeColumn("collections", "importId", {
+ transaction
+ });
+ await queryInterface.removeColumn("documents", "importId", {
+ transaction
+ });
+ });
+ }
+};
diff --git a/server/models/Collection.ts b/server/models/Collection.ts
index 1426540e3..1660defa1 100644
--- a/server/models/Collection.ts
+++ b/server/models/Collection.ts
@@ -30,6 +30,7 @@ import type { NavigationNode, CollectionSort } from "~/types";
import CollectionGroup from "./CollectionGroup";
import CollectionUser from "./CollectionUser";
import Document from "./Document";
+import FileOperation from "./FileOperation";
import Group from "./Group";
import GroupUser from "./GroupUser";
import Team from "./Team";
@@ -272,6 +273,13 @@ class Collection extends ParanoidModel {
// associations
+ @BelongsTo(() => FileOperation, "importId")
+ import: FileOperation | null;
+
+ @ForeignKey(() => FileOperation)
+ @Column(DataType.UUID)
+ importId: string | null;
+
@HasMany(() => Document, "collectionId")
documents: Document[];
diff --git a/server/models/Document.ts b/server/models/Document.ts
index 84b4e9ee3..6cd0c794e 100644
--- a/server/models/Document.ts
+++ b/server/models/Document.ts
@@ -39,6 +39,7 @@ import { DocumentValidation } from "@shared/validations";
import slugify from "@server/utils/slugify";
import Backlink from "./Backlink";
import Collection from "./Collection";
+import FileOperation from "./FileOperation";
import Revision from "./Revision";
import Star from "./Star";
import Team from "./Team";
@@ -342,6 +343,13 @@ class Document extends ParanoidModel {
// associations
+ @BelongsTo(() => FileOperation, "importId")
+ import: FileOperation | null;
+
+ @ForeignKey(() => FileOperation)
+ @Column(DataType.UUID)
+ importId: string | null;
+
@BelongsTo(() => Document, "parentDocumentId")
parentDocument: Document | null;
diff --git a/server/presenters/fileOperation.ts b/server/presenters/fileOperation.ts
index 3e9438bc1..13f568d4f 100644
--- a/server/presenters/fileOperation.ts
+++ b/server/presenters/fileOperation.ts
@@ -6,6 +6,7 @@ export default function present(data: FileOperation) {
return {
id: data.id,
type: data.type,
+ format: data.format,
name: data.collection?.name || path.basename(data.key || ""),
state: data.state,
error: data.error,
diff --git a/server/queues/tasks/ImportTask.ts b/server/queues/tasks/ImportTask.ts
index cb0dc30af..2155200c5 100644
--- a/server/queues/tasks/ImportTask.ts
+++ b/server/queues/tasks/ImportTask.ts
@@ -274,6 +274,7 @@ export default abstract class ImportTask extends BaseTask {
}),
createdById: fileOperation.userId,
permission: CollectionPermission.ReadWrite,
+ importId: fileOperation.id,
},
transaction,
});
@@ -294,6 +295,7 @@ export default abstract class ImportTask extends BaseTask {
createdById: fileOperation.userId,
name,
permission: CollectionPermission.ReadWrite,
+ importId: fileOperation.id,
},
{ transaction }
);
@@ -357,6 +359,7 @@ export default abstract class ImportTask extends BaseTask {
updatedAt: item.updatedAt ?? item.createdAt,
publishedAt: item.updatedAt ?? item.createdAt ?? new Date(),
parentDocumentId: item.parentDocumentId,
+ importId: fileOperation.id,
user,
ip,
transaction,
diff --git a/server/routes/api/fileOperations.ts b/server/routes/api/fileOperations.ts
index 5d0ca697c..f0483de75 100644
--- a/server/routes/api/fileOperations.ts
+++ b/server/routes/api/fileOperations.ts
@@ -51,13 +51,13 @@ router.post(
authorize(user, "manage", team);
const [exports, total] = await Promise.all([
- await FileOperation.findAll({
+ FileOperation.findAll({
where,
order: [[sort, direction]],
offset: ctx.state.pagination.offset,
limit: ctx.state.pagination.limit,
}),
- await FileOperation.count({
+ FileOperation.count({
where,
}),
]);
diff --git a/shared/i18n/locales/en_US/translation.json b/shared/i18n/locales/en_US/translation.json
index 54bb2f1b0..51aa05cf0 100644
--- a/shared/i18n/locales/en_US/translation.json
+++ b/shared/i18n/locales/en_US/translation.json
@@ -586,6 +586,7 @@
"Please choose a single file to import": "Please choose a single file to import",
"Your import is being processed, you can safely leave this page": "Your import is being processed, you can safely leave this page",
"File not supported – please upload a valid ZIP file": "File not supported – please upload a valid ZIP file",
+ "Completed": "Completed",
"Processing": "Processing",
"Expired": "Expired",
"Failed": "Failed",
@@ -673,7 +674,7 @@
"Import data": "Import data",
"Import pages exported from Notion": "Import pages exported from Notion",
"Import pages from a Confluence instance": "Import pages from a Confluence instance",
- "Coming soon": "Coming soon",
+ "Enterprise": "Enterprise",
"Recent imports": "Recent imports",
"Everyone that has signed into Outline appears here. It’s possible that there are other users who have access through {team.signinMethods} but haven’t signed in yet.": "Everyone that has signed into Outline appears here. It’s possible that there are other users who have access through {team.signinMethods} but haven’t signed in yet.",
"Filter": "Filter",