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
This commit is contained in:
@@ -60,7 +60,6 @@ export default abstract class BaseModel {
|
||||
};
|
||||
|
||||
updateFromJson = (data: any) => {
|
||||
// const isNew = !data.id && !this.id && this.isNew;
|
||||
set(this, { ...data, isNew: false });
|
||||
this.persistedAttributes = this.toAPI();
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { trim } from "lodash";
|
||||
import { action, computed, observable } from "mobx";
|
||||
import { action, computed, observable, runInAction } from "mobx";
|
||||
import {
|
||||
CollectionPermission,
|
||||
FileOperationFormat,
|
||||
@@ -18,6 +18,8 @@ export default class Collection extends ParanoidModel {
|
||||
@observable
|
||||
isSaving: boolean;
|
||||
|
||||
isFetching = false;
|
||||
|
||||
@Field
|
||||
@observable
|
||||
id: string;
|
||||
@@ -57,32 +59,34 @@ export default class Collection extends ParanoidModel {
|
||||
direction: "asc" | "desc";
|
||||
};
|
||||
|
||||
documents: NavigationNode[];
|
||||
@observable
|
||||
documents?: NavigationNode[];
|
||||
|
||||
url: string;
|
||||
|
||||
urlId: string;
|
||||
|
||||
@computed
|
||||
get isEmpty(): boolean {
|
||||
get isEmpty(): boolean | undefined {
|
||||
if (!this.documents) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return (
|
||||
this.documents.length === 0 &&
|
||||
this.store.rootStore.documents.inCollection(this.id).length === 0
|
||||
);
|
||||
}
|
||||
|
||||
@computed
|
||||
get documentIds(): string[] {
|
||||
const results: string[] = [];
|
||||
|
||||
const travelNodes = (nodes: NavigationNode[]) =>
|
||||
nodes.forEach((node) => {
|
||||
results.push(node.id);
|
||||
travelNodes(node.children);
|
||||
});
|
||||
|
||||
travelNodes(this.documents);
|
||||
return results;
|
||||
/**
|
||||
* Convenience method to return if a collection is considered private.
|
||||
* This means that a membership is required to view it rather than just being
|
||||
* a workspace member.
|
||||
*
|
||||
* @returns boolean
|
||||
*/
|
||||
get isPrivate(): boolean {
|
||||
return !this.permission;
|
||||
}
|
||||
|
||||
@computed
|
||||
@@ -98,10 +102,35 @@ export default class Collection extends ParanoidModel {
|
||||
}
|
||||
|
||||
@computed
|
||||
get sortedDocuments() {
|
||||
get sortedDocuments(): NavigationNode[] | undefined {
|
||||
if (!this.documents) {
|
||||
return undefined;
|
||||
}
|
||||
return sortNavigationNodes(this.documents, this.sort);
|
||||
}
|
||||
|
||||
fetchDocuments = async (options?: { force: boolean }) => {
|
||||
if (this.isFetching) {
|
||||
return;
|
||||
}
|
||||
if (this.documents && options?.force !== true) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.isFetching = true;
|
||||
const { data } = await client.post("/collections.documents", {
|
||||
id: this.id,
|
||||
});
|
||||
|
||||
runInAction("Collection#fetchDocuments", () => {
|
||||
this.documents = data;
|
||||
});
|
||||
} finally {
|
||||
this.isFetching = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the document identified by the given id in the collection in memory.
|
||||
* Does not update the document in the database.
|
||||
@@ -110,6 +139,10 @@ export default class Collection extends ParanoidModel {
|
||||
*/
|
||||
@action
|
||||
updateDocument(document: Pick<Document, "id" | "title" | "url">) {
|
||||
if (!this.documents) {
|
||||
throw new Error("Collection documents not loaded");
|
||||
}
|
||||
|
||||
const travelNodes = (nodes: NavigationNode[]) =>
|
||||
nodes.forEach((node) => {
|
||||
if (node.id === document.id) {
|
||||
@@ -131,6 +164,10 @@ export default class Collection extends ParanoidModel {
|
||||
*/
|
||||
@action
|
||||
removeDocument(documentId: string) {
|
||||
if (!this.documents) {
|
||||
throw new Error("Collection documents not loaded");
|
||||
}
|
||||
|
||||
this.documents = this.documents.filter(function f(node): boolean {
|
||||
if (node.id === documentId) {
|
||||
return false;
|
||||
@@ -163,7 +200,7 @@ export default class Collection extends ParanoidModel {
|
||||
});
|
||||
};
|
||||
|
||||
if (this.documents) {
|
||||
if (this.sortedDocuments) {
|
||||
travelNodes(this.sortedDocuments);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { computed } from "mobx";
|
||||
import { observable } from "mobx";
|
||||
import { CollectionPermission } from "@shared/types";
|
||||
import BaseModel from "./BaseModel";
|
||||
|
||||
@@ -9,12 +9,8 @@ class CollectionGroupMembership extends BaseModel {
|
||||
|
||||
collectionId: string;
|
||||
|
||||
@observable
|
||||
permission: CollectionPermission;
|
||||
|
||||
@computed
|
||||
get isEditor(): boolean {
|
||||
return this.permission === CollectionPermission.ReadWrite;
|
||||
}
|
||||
}
|
||||
|
||||
export default CollectionGroupMembership;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { computed } from "mobx";
|
||||
import { observable } from "mobx";
|
||||
import { CollectionPermission } from "@shared/types";
|
||||
import BaseModel from "./BaseModel";
|
||||
|
||||
@@ -9,12 +9,8 @@ class Membership extends BaseModel {
|
||||
|
||||
collectionId: string;
|
||||
|
||||
@observable
|
||||
permission: CollectionPermission;
|
||||
|
||||
@computed
|
||||
get isEditor(): boolean {
|
||||
return this.permission === CollectionPermission.ReadWrite;
|
||||
}
|
||||
}
|
||||
|
||||
export default Membership;
|
||||
|
||||
Reference in New Issue
Block a user