Files
outline/app/hooks/useCollectionTrees.ts
Tom Moor d8b4fef554 feat: Collection admins (#5273
* Split permissions for reading documents from updating collection

* fix: Admins should have collection read permission, tests

* tsc

* Add admin option to permission selector

* Combine publish and create permissions, update -> createDocuments where appropriate

* Plural -> singular

* wip

* Quick version of collection structure loading, will revisit

* Remove documentIds method

* stash

* fixing tests to account for admin creation

* Add self-hosted migration

* fix: Allow groups to have admin permission

* Prefetch collection documents

* fix: Document explorer (move/publish) not working with async documents

* fix: Cannot re-parent document to collection by drag and drop

* fix: Cannot drag to import into collection item without admin permission

* Remove unused isEditor getter
2023-04-30 06:38:47 -07:00

85 lines
2.4 KiB
TypeScript

import * as React from "react";
import { NavigationNode, NavigationNodeType } from "@shared/types";
import Collection from "~/models/Collection";
import useStores from "~/hooks/useStores";
/**
* React hook that modifies the document structure
* of all collections present in store. Adds extra attributes
* like type, depth and parent to each of the nodes in document
* structure.
*
* @return {NavigationNode[]} collectionTrees root collection nodes of modified trees
*/
export default function useCollectionTrees(): NavigationNode[] {
const { collections } = useStores();
const getCollectionTree = (collection: Collection): NavigationNode => {
const addType = (node: NavigationNode): NavigationNode => {
if (node.children.length > 0) {
node.children = node.children.map(addType);
}
node.type = node.type ? node.type : NavigationNodeType.Document;
return node;
};
const addParent = (
node: NavigationNode,
parent: NavigationNode | null = null
): NavigationNode => {
if (node.children.length > 0) {
node.children = node.children.map((child) => addParent(child, node));
}
node.parent = parent;
return node;
};
const addDepth = (node: NavigationNode, depth = 0): NavigationNode => {
if (node.children.length > 0) {
node.children = node.children.map((child) =>
addDepth(child, depth + 1)
);
}
node.depth = depth;
return node;
};
const addCollectionId = (
node: NavigationNode,
collectionId = collection.id
): NavigationNode => {
if (node.children.length > 0) {
node.children = node.children.map((child) =>
addCollectionId(child, collectionId)
);
}
node.collectionId = collectionId;
return node;
};
const collectionNode: NavigationNode = {
id: collection.id,
title: collection.name,
url: collection.url,
type: NavigationNodeType.Collection,
children: collection.documents || [],
parent: null,
};
return addParent(addCollectionId(addDepth(addType(collectionNode))));
};
const key = collections.orderedData.map((o) => o.documents?.length).join("-");
const collectionTrees = React.useMemo(
() => collections.orderedData.map(getCollectionTree),
// eslint-disable-next-line react-hooks/exhaustive-deps
[collections.orderedData, key]
);
return collectionTrees;
}