chore: Improvements to document move behavior (#4689)
* chore: Improvements to document move behavior * test
This commit is contained in:
@@ -33,7 +33,10 @@ describe("getDocumentParents", () => {
|
||||
const document = await buildDocument();
|
||||
const collection = await buildCollection({
|
||||
documentStructure: [
|
||||
{ ...parent.toJSON(), children: [document.toJSON()] },
|
||||
{
|
||||
...(await parent.toNavigationNode()),
|
||||
children: [await document.toNavigationNode()],
|
||||
},
|
||||
],
|
||||
});
|
||||
const result = collection.getDocumentParents(document.id);
|
||||
@@ -46,7 +49,10 @@ describe("getDocumentParents", () => {
|
||||
const document = await buildDocument();
|
||||
const collection = await buildCollection({
|
||||
documentStructure: [
|
||||
{ ...parent.toJSON(), children: [document.toJSON()] },
|
||||
{
|
||||
...(await parent.toNavigationNode()),
|
||||
children: [await document.toNavigationNode()],
|
||||
},
|
||||
],
|
||||
});
|
||||
const result = collection.getDocumentParents(parent.id);
|
||||
@@ -66,9 +72,11 @@ describe("getDocumentTree", () => {
|
||||
test("should return document tree", async () => {
|
||||
const document = await buildDocument();
|
||||
const collection = await buildCollection({
|
||||
documentStructure: [document.toJSON()],
|
||||
documentStructure: [await document.toNavigationNode()],
|
||||
});
|
||||
expect(collection.getDocumentTree(document.id)).toEqual(document.toJSON());
|
||||
expect(collection.getDocumentTree(document.id)).toEqual(
|
||||
await document.toNavigationNode()
|
||||
);
|
||||
});
|
||||
|
||||
test("should return nested documents in tree", async () => {
|
||||
@@ -76,15 +84,20 @@ describe("getDocumentTree", () => {
|
||||
const document = await buildDocument();
|
||||
const collection = await buildCollection({
|
||||
documentStructure: [
|
||||
{ ...parent.toJSON(), children: [document.toJSON()] },
|
||||
{
|
||||
...(await parent.toNavigationNode()),
|
||||
children: [await document.toNavigationNode()],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(collection.getDocumentTree(parent.id)).toEqual({
|
||||
...parent.toJSON(),
|
||||
children: [document.toJSON()],
|
||||
...(await parent.toNavigationNode()),
|
||||
children: [await document.toNavigationNode()],
|
||||
});
|
||||
expect(collection.getDocumentTree(document.id)).toEqual(document.toJSON());
|
||||
expect(collection.getDocumentTree(document.id)).toEqual(
|
||||
await document.toNavigationNode()
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -92,10 +105,11 @@ describe("#addDocumentToStructure", () => {
|
||||
test("should add as last element without index", async () => {
|
||||
const { collection } = await seed();
|
||||
const id = uuidv4();
|
||||
const newDocument = new Document({
|
||||
const newDocument = await buildDocument({
|
||||
id,
|
||||
title: "New end node",
|
||||
parentDocumentId: null,
|
||||
teamId: collection.teamId,
|
||||
});
|
||||
await collection.addDocumentToStructure(newDocument);
|
||||
expect(collection.documentStructure!.length).toBe(2);
|
||||
@@ -105,10 +119,11 @@ describe("#addDocumentToStructure", () => {
|
||||
test("should add with an index", async () => {
|
||||
const { collection } = await seed();
|
||||
const id = uuidv4();
|
||||
const newDocument = new Document({
|
||||
const newDocument = await buildDocument({
|
||||
id,
|
||||
title: "New end node",
|
||||
parentDocumentId: null,
|
||||
teamId: collection.teamId,
|
||||
});
|
||||
await collection.addDocumentToStructure(newDocument, 1);
|
||||
expect(collection.documentStructure!.length).toBe(2);
|
||||
@@ -118,10 +133,11 @@ describe("#addDocumentToStructure", () => {
|
||||
test("should add as a child if with parent", async () => {
|
||||
const { collection, document } = await seed();
|
||||
const id = uuidv4();
|
||||
const newDocument = new Document({
|
||||
const newDocument = await buildDocument({
|
||||
id,
|
||||
title: "New end node",
|
||||
parentDocumentId: document.id,
|
||||
teamId: collection.teamId,
|
||||
});
|
||||
await collection.addDocumentToStructure(newDocument, 1);
|
||||
expect(collection.documentStructure!.length).toBe(1);
|
||||
@@ -132,16 +148,18 @@ describe("#addDocumentToStructure", () => {
|
||||
|
||||
test("should add as a child if with parent with index", async () => {
|
||||
const { collection, document } = await seed();
|
||||
const newDocument = new Document({
|
||||
const newDocument = await buildDocument({
|
||||
id: uuidv4(),
|
||||
title: "node",
|
||||
parentDocumentId: document.id,
|
||||
teamId: collection.teamId,
|
||||
});
|
||||
const id = uuidv4();
|
||||
const secondDocument = new Document({
|
||||
const secondDocument = await buildDocument({
|
||||
id,
|
||||
title: "New start node",
|
||||
parentDocumentId: document.id,
|
||||
teamId: collection.teamId,
|
||||
});
|
||||
await collection.addDocumentToStructure(newDocument);
|
||||
await collection.addDocumentToStructure(secondDocument, 0);
|
||||
@@ -154,10 +172,11 @@ describe("#addDocumentToStructure", () => {
|
||||
test("should append supplied json over document's own", async () => {
|
||||
const { collection } = await seed();
|
||||
const id = uuidv4();
|
||||
const newDocument = new Document({
|
||||
const newDocument = await buildDocument({
|
||||
id: uuidv4(),
|
||||
title: "New end node",
|
||||
parentDocumentId: null,
|
||||
teamId: collection.teamId,
|
||||
});
|
||||
await collection.addDocumentToStructure(newDocument, undefined, {
|
||||
documentJson: {
|
||||
|
||||
@@ -554,7 +554,7 @@ class Collection extends ParanoidModel {
|
||||
*/
|
||||
updateDocument = async function (
|
||||
updatedDocument: Document,
|
||||
options?: { transaction?: Transaction | null }
|
||||
options?: { transaction?: Transaction | null | undefined }
|
||||
) {
|
||||
if (!this.documentStructure) {
|
||||
return;
|
||||
@@ -563,21 +563,23 @@ class Collection extends ParanoidModel {
|
||||
const { id } = updatedDocument;
|
||||
|
||||
const updateChildren = (documents: NavigationNode[]) => {
|
||||
return documents.map((document) => {
|
||||
if (document.id === id) {
|
||||
document = {
|
||||
...(updatedDocument.toJSON() as NavigationNode),
|
||||
children: document.children,
|
||||
};
|
||||
} else {
|
||||
document.children = updateChildren(document.children);
|
||||
}
|
||||
return Promise.all(
|
||||
documents.map(async (document) => {
|
||||
if (document.id === id) {
|
||||
document = {
|
||||
...(await updatedDocument.toNavigationNode(options)),
|
||||
children: document.children,
|
||||
};
|
||||
} else {
|
||||
document.children = await updateChildren(document.children);
|
||||
}
|
||||
|
||||
return document;
|
||||
});
|
||||
return document;
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
this.documentStructure = updateChildren(this.documentStructure);
|
||||
this.documentStructure = await updateChildren(this.documentStructure);
|
||||
// Sequelize doesn't seem to set the value with splice on JSONB field
|
||||
// https://github.com/sequelize/sequelize/blob/e1446837196c07b8ff0c23359b958d68af40fd6d/src/model.js#L3937
|
||||
this.changed("documentStructure", true);
|
||||
@@ -602,7 +604,10 @@ class Collection extends ParanoidModel {
|
||||
}
|
||||
|
||||
// If moving existing document with children, use existing structure
|
||||
const documentJson = { ...document.toJSON(), ...options.documentJson };
|
||||
const documentJson = {
|
||||
...(await document.toNavigationNode(options)),
|
||||
...options.documentJson,
|
||||
};
|
||||
|
||||
if (!document.parentDocumentId) {
|
||||
// Note: Index is supported on DB level but it's being ignored
|
||||
|
||||
@@ -36,6 +36,7 @@ import parseTitle from "@shared/utils/parseTitle";
|
||||
import { SLUG_URL_REGEX } from "@shared/utils/urlHelpers";
|
||||
import { DocumentValidation } from "@shared/validations";
|
||||
import slugify from "@server/utils/slugify";
|
||||
import type { NavigationNode } from "~/types";
|
||||
import Backlink from "./Backlink";
|
||||
import Collection from "./Collection";
|
||||
import FileOperation from "./FileOperation";
|
||||
@@ -750,14 +751,41 @@ class Document extends ParanoidModel {
|
||||
return notEmpty ? lines[1] : "";
|
||||
};
|
||||
|
||||
toJSON = () => {
|
||||
// Warning: only use for new documents as order of children is
|
||||
// handled in the collection's documentStructure
|
||||
/**
|
||||
* Returns a JSON representation of the document suitable for use in the
|
||||
* collection documentStructure.
|
||||
*
|
||||
* @param options Optional transaction to use for the query
|
||||
* @returns Promise resolving to a NavigationNode
|
||||
*/
|
||||
toNavigationNode = async (options?: {
|
||||
transaction?: Transaction | null | undefined;
|
||||
}): Promise<NavigationNode> => {
|
||||
const childDocuments = await (this.constructor as typeof Document)
|
||||
.unscoped()
|
||||
.findAll({
|
||||
where: {
|
||||
teamId: this.teamId,
|
||||
parentDocumentId: this.id,
|
||||
archivedAt: {
|
||||
[Op.is]: null,
|
||||
},
|
||||
publishedAt: {
|
||||
[Op.ne]: null,
|
||||
},
|
||||
},
|
||||
transaction: options?.transaction,
|
||||
});
|
||||
|
||||
const children = await Promise.all(
|
||||
childDocuments.map((child) => child.toNavigationNode(options))
|
||||
);
|
||||
|
||||
return {
|
||||
id: this.id,
|
||||
title: this.title,
|
||||
url: this.url,
|
||||
children: [],
|
||||
children,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user