Files
outline/server/commands/documentDuplicator.ts
wmTJc9IK0Q 21d4816a00 Copy fullWidth property when duplicating documents (#11980)
* Add fullWidth property copying to document duplication

Agent-Logs-Url: https://github.com/wmTJc9IK0Q/outline/sessions/6f30db31-b386-4c3d-8f04-db4dacfc2cdc

Co-authored-by: wmTJc9IK0Q <171362836+wmTJc9IK0Q@users.noreply.github.com>

* Fix lint errors in tests

Agent-Logs-Url: https://github.com/wmTJc9IK0Q/outline/sessions/6f30db31-b386-4c3d-8f04-db4dacfc2cdc

Co-authored-by: wmTJc9IK0Q <171362836+wmTJc9IK0Q@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Remove unnecessary declaration

---------

Co-authored-by: anthropic-code-agent[bot] <242468646+Claude@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-09 20:58:04 -04:00

114 lines
3.4 KiB
TypeScript

import { Op } from "sequelize";
import type { Document } from "@server/models";
import { Collection } from "@server/models";
import { DocumentHelper } from "@server/models/helpers/DocumentHelper";
import { ProsemirrorHelper } from "@server/models/helpers/ProsemirrorHelper";
import type { APIContext } from "@server/types";
import documentCreator from "./documentCreator";
type Props = {
/** The document to duplicate */
document: Document;
/** The collection to add the duplicated document to */
collection?: Collection | null;
/** Override of the parent document to add the duplicate to */
parentDocumentId?: string;
/** Override of the duplicated document title */
title?: string;
/** Override of the duplicated document publish state */
publish?: boolean;
/** Whether to duplicate child documents */
recursive?: boolean;
};
export default async function documentDuplicator(
ctx: APIContext,
{ document, collection, parentDocumentId, title, publish, recursive }: Props
): Promise<Document[]> {
const newDocuments: Document[] = [];
const sharedProperties = {
collectionId: collection?.id,
publish: publish ?? !!document.publishedAt,
};
const duplicated = await documentCreator(ctx, {
parentDocumentId,
icon: document.icon,
color: document.color,
fullWidth: document.fullWidth,
title: title ?? document.title,
content: ProsemirrorHelper.removeMarks(
DocumentHelper.toProsemirror(document),
["comment"]
),
sourceMetadata: {
...document.sourceMetadata,
originalDocumentId: document.id,
},
...sharedProperties,
});
duplicated.collection = collection ?? null;
newDocuments.push(duplicated);
const originalCollection = document?.collectionId
? await Collection.findByPk(document.collectionId, {
attributes: {
include: ["documentStructure"],
},
})
: null;
async function duplicateChildDocuments(
original: Document,
duplicatedDocument: Document
) {
const childDocuments = await original.findChildDocuments(
{
archivedAt: original.archivedAt
? {
[Op.ne]: null,
}
: {
[Op.eq]: null,
},
},
ctx
);
const sorted = DocumentHelper.sortDocumentsByStructure(
childDocuments,
originalCollection?.getDocumentTree(original.id)?.children ?? []
).reverse(); // we have to reverse since the child documents will be added in reverse order
for (const childDocument of sorted) {
const duplicatedChildDocument = await documentCreator(ctx, {
parentDocumentId: duplicatedDocument.id,
icon: childDocument.icon,
color: childDocument.color,
fullWidth: childDocument.fullWidth,
title: childDocument.title,
content: ProsemirrorHelper.removeMarks(
DocumentHelper.toProsemirror(childDocument),
["comment"]
),
sourceMetadata: {
...childDocument.sourceMetadata,
originalDocumentId: childDocument.id,
},
...sharedProperties,
});
duplicatedChildDocument.collection = collection ?? null;
newDocuments.push(duplicatedChildDocument);
await duplicateChildDocuments(childDocument, duplicatedChildDocument);
}
}
if (recursive) {
await duplicateChildDocuments(document, duplicated);
}
return newDocuments;
}