fix: Don't trigger email and slack notifications when mass importing
feat: Show success message after import
This commit is contained in:
@ -23,17 +23,22 @@ function ImportExport() {
|
|||||||
const { showToast } = ui;
|
const { showToast } = ui;
|
||||||
const [isLoading, setLoading] = React.useState(false);
|
const [isLoading, setLoading] = React.useState(false);
|
||||||
const [isImporting, setImporting] = React.useState(false);
|
const [isImporting, setImporting] = React.useState(false);
|
||||||
|
const [importedDetails, setImported] = React.useState(false);
|
||||||
const [isExporting, setExporting] = React.useState(false);
|
const [isExporting, setExporting] = React.useState(false);
|
||||||
const [file, setFile] = React.useState();
|
const [file, setFile] = React.useState();
|
||||||
const [importDetails, setImportDetails] = React.useState();
|
const [importDetails, setImportDetails] = React.useState();
|
||||||
|
|
||||||
const handleImport = React.useCallback(
|
const handleImport = React.useCallback(
|
||||||
async (ev) => {
|
async (ev) => {
|
||||||
|
setImported(undefined);
|
||||||
setImporting(true);
|
setImporting(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await documents.batchImport(file);
|
const { documentCount, collectionCount } = await documents.batchImport(
|
||||||
|
file
|
||||||
|
);
|
||||||
showToast(t("Import completed"));
|
showToast(t("Import completed"));
|
||||||
|
setImported({ documentCount, collectionCount });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showToast(err.message);
|
showToast(err.message);
|
||||||
} finally {
|
} finally {
|
||||||
@ -116,6 +121,17 @@ function ImportExport() {
|
|||||||
accept="application/zip"
|
accept="application/zip"
|
||||||
/>
|
/>
|
||||||
</VisuallyHidden>
|
</VisuallyHidden>
|
||||||
|
{importedDetails && (
|
||||||
|
<Notice>
|
||||||
|
<Trans
|
||||||
|
count={importedDetails.documentCount}
|
||||||
|
i18nKey="importSuccessful"
|
||||||
|
>
|
||||||
|
Import successful, {{ count: importedDetails.documentCount }}{" "}
|
||||||
|
documents were imported to your knowledge base.
|
||||||
|
</Trans>
|
||||||
|
</Notice>
|
||||||
|
)}
|
||||||
{file && !isImportable && (
|
{file && !isImportable && (
|
||||||
<ImportPreview>
|
<ImportPreview>
|
||||||
<Trans>
|
<Trans>
|
||||||
@ -126,7 +142,7 @@ function ImportExport() {
|
|||||||
)}
|
)}
|
||||||
{file && importDetails && isImportable ? (
|
{file && importDetails && isImportable ? (
|
||||||
<>
|
<>
|
||||||
<ImportPreview>
|
<ImportPreview as="div">
|
||||||
<Trans>
|
<Trans>
|
||||||
<strong>{{ fileName: file.name }}</strong> looks good, the
|
<strong>{{ fileName: file.name }}</strong> looks good, the
|
||||||
following collections and their documents will be imported:
|
following collections and their documents will be imported:
|
||||||
|
@ -508,6 +508,8 @@ export default class DocumentsStore extends BaseStore<Document> {
|
|||||||
|
|
||||||
this.addPolicies(res.policies);
|
this.addPolicies(res.policies);
|
||||||
res.data.collections.forEach(this.rootStore.collections.add);
|
res.data.collections.forEach(this.rootStore.collections.add);
|
||||||
|
|
||||||
|
return res.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
@ -1124,7 +1124,7 @@ router.post("documents.batchImport", auth(), async (ctx) => {
|
|||||||
const user = ctx.state.user;
|
const user = ctx.state.user;
|
||||||
authorize(user, "batchImport", Document);
|
authorize(user, "batchImport", Document);
|
||||||
|
|
||||||
const { collections } = await documentBatchImporter({
|
const { documents, attachments, collections } = await documentBatchImporter({
|
||||||
file,
|
file,
|
||||||
user,
|
user,
|
||||||
type,
|
type,
|
||||||
@ -1133,6 +1133,9 @@ router.post("documents.batchImport", auth(), async (ctx) => {
|
|||||||
|
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
data: {
|
data: {
|
||||||
|
attachmentCount: attachments.length,
|
||||||
|
documentCount: documents.length,
|
||||||
|
collectionCount: collections.length,
|
||||||
collections: collections.map((collection) =>
|
collections: collections.map((collection) =>
|
||||||
presentCollection(collection)
|
presentCollection(collection)
|
||||||
),
|
),
|
||||||
@ -1189,6 +1192,7 @@ router.post("documents.import", auth(), async (ctx) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const document = await documentCreator({
|
const document = await documentCreator({
|
||||||
|
source: "import",
|
||||||
title,
|
title,
|
||||||
text,
|
text,
|
||||||
publish,
|
publish,
|
||||||
|
@ -8,12 +8,14 @@ export default async function attachmentCreator({
|
|||||||
type,
|
type,
|
||||||
buffer,
|
buffer,
|
||||||
user,
|
user,
|
||||||
|
source,
|
||||||
ip,
|
ip,
|
||||||
}: {
|
}: {
|
||||||
name: string,
|
name: string,
|
||||||
type: string,
|
type: string,
|
||||||
buffer: Buffer,
|
buffer: Buffer,
|
||||||
user: User,
|
user: User,
|
||||||
|
source?: "import",
|
||||||
ip: string,
|
ip: string,
|
||||||
}) {
|
}) {
|
||||||
const key = `uploads/${user.id}/${uuid.v4()}/${name}`;
|
const key = `uploads/${user.id}/${uuid.v4()}/${name}`;
|
||||||
@ -32,7 +34,7 @@ export default async function attachmentCreator({
|
|||||||
|
|
||||||
await Event.create({
|
await Event.create({
|
||||||
name: "attachments.create",
|
name: "attachments.create",
|
||||||
data: { name },
|
data: { name, source },
|
||||||
modelId: attachment.id,
|
modelId: attachment.id,
|
||||||
teamId: user.teamId,
|
teamId: user.teamId,
|
||||||
actorId: user.id,
|
actorId: user.id,
|
||||||
|
@ -114,6 +114,7 @@ export default async function documentBatchImporter({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const document = await documentCreator({
|
const document = await documentCreator({
|
||||||
|
source: "import",
|
||||||
title,
|
title,
|
||||||
text,
|
text,
|
||||||
publish: true,
|
publish: true,
|
||||||
@ -134,6 +135,7 @@ export default async function documentBatchImporter({
|
|||||||
if (item.type === "attachment") {
|
if (item.type === "attachment") {
|
||||||
const buffer = await item.item.async("nodebuffer");
|
const buffer = await item.item.async("nodebuffer");
|
||||||
const attachment = await attachmentCreator({
|
const attachment = await attachmentCreator({
|
||||||
|
source: "import",
|
||||||
name: item.name,
|
name: item.name,
|
||||||
type,
|
type,
|
||||||
buffer,
|
buffer,
|
||||||
|
@ -14,6 +14,7 @@ export default async function documentCreator({
|
|||||||
index,
|
index,
|
||||||
user,
|
user,
|
||||||
editorVersion,
|
editorVersion,
|
||||||
|
source,
|
||||||
ip,
|
ip,
|
||||||
}: {
|
}: {
|
||||||
title: string,
|
title: string,
|
||||||
@ -28,6 +29,7 @@ export default async function documentCreator({
|
|||||||
index?: number,
|
index?: number,
|
||||||
user: User,
|
user: User,
|
||||||
editorVersion?: string,
|
editorVersion?: string,
|
||||||
|
source?: "import",
|
||||||
ip: string,
|
ip: string,
|
||||||
}): Document {
|
}): Document {
|
||||||
const templateId = templateDocument ? templateDocument.id : undefined;
|
const templateId = templateDocument ? templateDocument.id : undefined;
|
||||||
@ -53,7 +55,7 @@ export default async function documentCreator({
|
|||||||
collectionId: document.collectionId,
|
collectionId: document.collectionId,
|
||||||
teamId: document.teamId,
|
teamId: document.teamId,
|
||||||
actorId: user.id,
|
actorId: user.id,
|
||||||
data: { title: document.title, templateId },
|
data: { source, title: document.title, templateId },
|
||||||
ip,
|
ip,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -66,7 +68,7 @@ export default async function documentCreator({
|
|||||||
collectionId: document.collectionId,
|
collectionId: document.collectionId,
|
||||||
teamId: document.teamId,
|
teamId: document.teamId,
|
||||||
actorId: user.id,
|
actorId: user.id,
|
||||||
data: { title: document.title },
|
data: { source, title: document.title },
|
||||||
ip,
|
ip,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,10 @@ export type DocumentEvent =
|
|||||||
teamId: string,
|
teamId: string,
|
||||||
actorId: string,
|
actorId: string,
|
||||||
ip: string,
|
ip: string,
|
||||||
|
data: {
|
||||||
|
title: string,
|
||||||
|
source?: "import",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
name: "documents.move",
|
name: "documents.move",
|
||||||
|
@ -27,6 +27,9 @@ export default class Notifications {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async documentUpdated(event: DocumentEvent) {
|
async documentUpdated(event: DocumentEvent) {
|
||||||
|
// never send notifications when batch importing documents
|
||||||
|
if (event.data && event.data.source === "import") return;
|
||||||
|
|
||||||
const document = await Document.findByPk(event.documentId);
|
const document = await Document.findByPk(event.documentId);
|
||||||
if (!document) return;
|
if (!document) return;
|
||||||
|
|
||||||
|
@ -55,6 +55,9 @@ export default class Slack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async documentUpdated(event: DocumentEvent) {
|
async documentUpdated(event: DocumentEvent) {
|
||||||
|
// never send notifications when batch importing documents
|
||||||
|
if (event.data && event.data.source === "import") return;
|
||||||
|
|
||||||
const document = await Document.findByPk(event.documentId);
|
const document = await Document.findByPk(event.documentId);
|
||||||
if (!document) return;
|
if (!document) return;
|
||||||
|
|
||||||
|
@ -279,6 +279,8 @@
|
|||||||
"Export in progress…": "Export in progress…",
|
"Export in progress…": "Export in progress…",
|
||||||
"Import": "Import",
|
"Import": "Import",
|
||||||
"It is possible to import a zip file of folders and Markdown files previously exported from an Outline instance. Support will soon be added for importing from other services.": "It is possible to import a zip file of folders and Markdown files previously exported from an Outline instance. Support will soon be added for importing from other services.",
|
"It is possible to import a zip file of folders and Markdown files previously exported from an Outline instance. Support will soon be added for importing from other services.": "It is possible to import a zip file of folders and Markdown files previously exported from an Outline instance. Support will soon be added for importing from other services.",
|
||||||
|
"importSuccessful": "Import successful, {{ count }} document was imported into your knowledge base.",
|
||||||
|
"importSuccessful_plural": "Import successful, {{ count }} documents were imported into your knowledge base.",
|
||||||
"Sorry, the file <1>{{fileName}}</1> is missing valid collections or documents.": "Sorry, the file <1>{{fileName}}</1> is missing valid collections or documents.",
|
"Sorry, the file <1>{{fileName}}</1> is missing valid collections or documents.": "Sorry, the file <1>{{fileName}}</1> is missing valid collections or documents.",
|
||||||
"<0>{{fileName}}</0> looks good, the following collections and their documents will be imported:": "<0>{{fileName}}</0> looks good, the following collections and their documents will be imported:",
|
"<0>{{fileName}}</0> looks good, the following collections and their documents will be imported:": "<0>{{fileName}}</0> looks good, the following collections and their documents will be imported:",
|
||||||
"Importing": "Importing",
|
"Importing": "Importing",
|
||||||
|
Reference in New Issue
Block a user