aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorusodhi <61431818+usodhi@users.noreply.github.com>2020-08-30 14:42:51 +0530
committerusodhi <61431818+usodhi@users.noreply.github.com>2020-08-30 14:42:51 +0530
commit204c978c09ef749c02e43604966d861c79b6f5ed (patch)
tree73cfa54dae3b33e4192846efc8ad83f321ebfb73 /src
parent4d1c5e5060db6aafc0689f0c83a757def1d30ca1 (diff)
changes for multiple docs selected + other small changes
Diffstat (limited to 'src')
-rw-r--r--src/client/util/GroupManager.tsx2
-rw-r--r--src/client/util/SharingManager.scss2
-rw-r--r--src/client/util/SharingManager.tsx200
-rw-r--r--src/client/views/collections/collectionFreeForm/PropertiesView.tsx40
-rw-r--r--src/fields/util.ts3
5 files changed, 153 insertions, 94 deletions
diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx
index 314640012..af7ad1cdf 100644
--- a/src/client/util/GroupManager.tsx
+++ b/src/client/util/GroupManager.tsx
@@ -87,6 +87,7 @@ export class GroupManager extends React.Component<{}> {
const members: string[] = JSON.parse(StrCast(group.members));
if (members.includes(Doc.CurrentUserEmail)) this.currentUserGroups.push(StrCast(group.groupName));
});
+ this.currentUserGroups.push("Public");
setGroups(this.currentUserGroups);
});
}
@@ -116,6 +117,7 @@ export class GroupManager extends React.Component<{}> {
close = () => {
this.isOpen = false;
this.currentGroup = undefined;
+ this.selectedUsers = null;
// this.users = [];
this.createGroupModalOpen = false;
TaskCompletionBox.taskCompleted = false;
diff --git a/src/client/util/SharingManager.scss b/src/client/util/SharingManager.scss
index 42c300712..b756716bf 100644
--- a/src/client/util/SharingManager.scss
+++ b/src/client/util/SharingManager.scss
@@ -121,7 +121,7 @@
overflow-y: scroll;
overflow-x: hidden;
text-align: left;
- display: flex;
+ display: block;
align-content: center;
align-items: center;
text-align: center;
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 538c01780..6fdbac41b 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -4,7 +4,7 @@ import { observer } from "mobx-react";
import * as React from "react";
import Select from "react-select";
import * as RequestPromise from "request-promise";
-import { AclAdmin, AclPrivate, DataSym, Doc, DocListCast, Opt } from "../../fields/Doc";
+import { AclAdmin, AclPrivate, DataSym, Doc, DocListCast, Opt, AclSym } from "../../fields/Doc";
import { List } from "../../fields/List";
import { Cast, StrCast } from "../../fields/Types";
import { distributeAcls, GetEffectiveAcl, SharingPermissions } from "../../fields/util";
@@ -19,6 +19,8 @@ import { DocumentManager } from "./DocumentManager";
import { GroupManager, UserOptions } from "./GroupManager";
import { GroupMemberView } from "./GroupMemberView";
import "./SharingManager.scss";
+import { SelectionManager } from "./SelectionManager";
+import { intersection } from "lodash";
export interface User {
email: string;
@@ -79,7 +81,6 @@ export class SharingManager extends React.Component<{}> {
public open = (target?: DocumentView, target_doc?: Doc) => {
runInAction(() => this.users = []);
- // SelectionManager.DeselectAll();
this.populateUsers();
runInAction(() => {
this.targetDocView = target;
@@ -88,12 +89,11 @@ export class SharingManager extends React.Component<{}> {
this.isOpen = this.targetDoc !== undefined;
this.permissions = SharingPermissions.Edit;
});
- this.targetDoc!.author === Doc.CurrentUserEmail && !this.targetDoc![`ACL-${Doc.CurrentUserEmail.replace(".", "_")}`] && distributeAcls(`ACL-${Doc.CurrentUserEmail.replace(".", "_")}`, SharingPermissions.Admin, this.targetDoc!);
}
public close = action(() => {
this.isOpen = false;
- this.selectedUsers = null; // resets the list of users and seleected users (in the react-select component)
+ this.selectedUsers = null; // resets the list of users and selected users (in the react-select component)
TaskCompletionBox.taskCompleted = false;
setTimeout(action(() => {
// this.copied = false;
@@ -147,21 +147,29 @@ export class SharingManager extends React.Component<{}> {
* @param permission
*/
setInternalGroupSharing = (group: Doc, permission: string, targetDoc?: Doc) => {
- const members: string[] = JSON.parse(StrCast(group.members));
- const users: ValidatedUser[] = this.users.filter(({ user: { email } }) => members.includes(email));
const target = targetDoc || this.targetDoc!;
const key = StrCast(group.groupName).replace(".", "_");
const ACL = `ACL-${key}`;
- GetEffectiveAcl(target) === AclAdmin && distributeAcls(ACL, permission as SharingPermissions, target);
+ const docs = SelectionManager.SelectedDocuments().length < 2 ? [target] : SelectionManager.SelectedDocuments().map(docView => docView.props.Document);
- // if documents have been shared, add the target to that list if it doesn't already exist, otherwise create a new list with the target
- group.docsShared ? Doc.IndexOf(target, DocListCast(group.docsShared)) === -1 && (group.docsShared as List<Doc>).push(target) : group.docsShared = new List<Doc>([target]);
+ docs.forEach(doc => {
+ doc.author === Doc.CurrentUserEmail && !doc[`ACL-${Doc.CurrentUserEmail.replace(".", "_")}`] && distributeAcls(`ACL-${Doc.CurrentUserEmail.replace(".", "_")}`, SharingPermissions.Admin, doc);
+ GetEffectiveAcl(doc) === AclAdmin && distributeAcls(ACL, permission as SharingPermissions, doc);
- users.forEach(({ user, notificationDoc }) => {
- if (permission !== SharingPermissions.None) Doc.IndexOf(target, DocListCast(notificationDoc[storage])) === -1 && Doc.AddDocToList(notificationDoc, storage, target); // add the target to the notificationDoc if it hasn't already been added
- else GetEffectiveAcl(target, undefined, user.email) === AclPrivate && Doc.IndexOf((target.aliasOf as Doc || target), DocListCast(notificationDoc[storage])) !== -1 && Doc.RemoveDocFromList(notificationDoc, storage, (target.aliasOf as Doc || target)); // remove the target from the list if it already exists
+ if (key !== "Public") {
+ const members: string[] = JSON.parse(StrCast(group.members));
+ const users: ValidatedUser[] = this.users.filter(({ user: { email } }) => members.includes(email));
+
+ // if documents have been shared, add the doc to that list if it doesn't already exist, otherwise create a new list with the doc
+ group.docsShared ? Doc.IndexOf(doc, DocListCast(group.docsShared)) === -1 && (group.docsShared as List<Doc>).push(doc) : group.docsShared = new List<Doc>([doc]);
+
+ users.forEach(({ user, notificationDoc }) => {
+ if (permission !== SharingPermissions.None) Doc.IndexOf(doc, DocListCast(notificationDoc[storage])) === -1 && Doc.AddDocToList(notificationDoc, storage, doc); // add the doc to the notificationDoc if it hasn't already been added
+ else GetEffectiveAcl(doc, undefined, user.email) === AclPrivate && Doc.IndexOf((doc.aliasOf as Doc || doc), DocListCast(notificationDoc[storage])) !== -1 && Doc.RemoveDocFromList(notificationDoc, storage, (doc.aliasOf as Doc || doc)); // remove the doc from the list if it already exists
+ });
+ }
});
}
@@ -178,13 +186,19 @@ export class SharingManager extends React.Component<{}> {
/**
* Called from the properties sidebar to change permissions of a user.
*/
- shareFromPropertiesSidebar = (shareWith: string, permission: SharingPermissions, target: Doc) => {
+ shareFromPropertiesSidebar = (shareWith: string, permission: SharingPermissions, docs: Doc[]) => {
if (shareWith !== "Public") {
const user = this.users.find(({ user: { email } }) => email === (shareWith === "Me" ? Doc.CurrentUserEmail : shareWith));
- if (user) this.setInternalSharing(user, permission, target);
- else this.setInternalGroupSharing(GroupManager.Instance.getGroup(shareWith)!, permission, target);
+ docs.forEach(doc => {
+ if (user) this.setInternalSharing(user, permission, doc);
+ else this.setInternalGroupSharing(GroupManager.Instance.getGroup(shareWith)!, permission, doc);
+ });
+ }
+ else {
+ docs.forEach(doc => {
+ if (GetEffectiveAcl(doc) === AclAdmin) distributeAcls("ACL-Public", permission, doc);
+ });
}
- else if (GetEffectiveAcl(target) === AclAdmin) distributeAcls("ACL-Public", permission, target);
}
/**
@@ -230,11 +244,16 @@ export class SharingManager extends React.Component<{}> {
const key = user.email.replace('.', '_');
const ACL = `ACL-${key}`;
- GetEffectiveAcl(target) === AclAdmin && distributeAcls(ACL, permission as SharingPermissions, target);
- if (permission !== SharingPermissions.None) Doc.IndexOf(target, DocListCast(notificationDoc[storage])) === -1 && Doc.AddDocToList(notificationDoc, storage, target);
- else GetEffectiveAcl(target, undefined, user.email) === AclPrivate && Doc.IndexOf((target.aliasOf as Doc || target), DocListCast(notificationDoc[storage])) !== -1 && Doc.RemoveDocFromList(notificationDoc, storage, (target.aliasOf as Doc || target));
+ const docs = SelectionManager.SelectedDocuments().length < 2 ? [target] : SelectionManager.SelectedDocuments().map(docView => docView.props.Document);
+ docs.forEach(doc => {
+ doc.author === Doc.CurrentUserEmail && !doc[`ACL-${Doc.CurrentUserEmail.replace(".", "_")}`] && distributeAcls(`ACL-${Doc.CurrentUserEmail.replace(".", "_")}`, SharingPermissions.Admin, doc);
+ GetEffectiveAcl(doc) === AclAdmin && distributeAcls(ACL, permission as SharingPermissions, doc);
+
+ if (permission !== SharingPermissions.None) Doc.IndexOf(doc, DocListCast(notificationDoc[storage])) === -1 && Doc.AddDocToList(notificationDoc, storage, doc);
+ else GetEffectiveAcl(doc, undefined, user.email) === AclPrivate && Doc.IndexOf((doc.aliasOf as Doc || doc), DocListCast(notificationDoc[storage])) !== -1 && Doc.RemoveDocFromList(notificationDoc, storage, (doc.aliasOf as Doc || doc));
+ });
}
@@ -264,8 +283,10 @@ export class SharingManager extends React.Component<{}> {
/**
* Returns the SharingPermissions (Admin, Can Edit etc) access that's used to share
*/
- private get sharingOptions() {
- return Object.values(SharingPermissions).map(permission =>
+ private sharingOptions(uniform: boolean) {
+ const dropdownValues: string[] = Object.values(SharingPermissions);
+ if (!uniform) dropdownValues.unshift("-multiple-");
+ return dropdownValues.map(permission =>
(
<option key={permission} value={permission}>
{permission}
@@ -276,27 +297,30 @@ export class SharingManager extends React.Component<{}> {
private focusOn = (contents: string) => {
const title = this.targetDoc ? StrCast(this.targetDoc.title) : "";
+ const docs = SelectionManager.SelectedDocuments().length > 1 ? SelectionManager.SelectedDocuments().map(docView => docView.props.Document) : [this.targetDoc];
return (
<span
className={"focus-span"}
title={title}
onClick={() => {
let context: Opt<CollectionView>;
- if (this.targetDoc && this.targetDocView && (context = this.targetDocView.props.ContainingCollectionView)) {
+ if (this.targetDoc && this.targetDocView && docs.length === 1 && (context = this.targetDocView.props.ContainingCollectionView)) {
DocumentManager.Instance.jumpToDocument(this.targetDoc, true, undefined, context.props.Document);
}
}}
onPointerEnter={action(() => {
- if (this.targetDoc) {
- Doc.BrushDoc(this.targetDoc);
+ if (docs.length) {
+ docs.forEach(doc => doc && Doc.BrushDoc(doc));
this.dialogueBoxOpacity = 0.1;
this.overlayOpacity = 0.1;
}
})}
onPointerLeave={action(() => {
- this.targetDoc && Doc.UnBrushDoc(this.targetDoc);
- this.dialogueBoxOpacity = 1;
- this.overlayOpacity = 0.4;
+ if (docs.length) {
+ docs.forEach(doc => doc && Doc.UnBrushDoc(doc));
+ this.dialogueBoxOpacity = 1;
+ this.overlayOpacity = 0.4;
+ }
})}
>
{contents}
@@ -405,29 +429,39 @@ export class SharingManager extends React.Component<{}> {
const users = this.individualSort === "ascending" ? this.users.slice().sort(this.sortUsers) : this.individualSort === "descending" ? this.users.slice().sort(this.sortUsers).reverse() : this.users;
const groups = this.groupSort === "ascending" ? groupList.slice().sort(this.sortGroups) : this.groupSort === "descending" ? groupList.slice().sort(this.sortGroups).reverse() : groupList;
- const targetDoc = this.layoutDocAcls ? this.targetDoc : this.targetDoc?.[DataSym];
+ // handles the case where multiple documents are selected
+ const docs = SelectionManager.SelectedDocuments().length < 2 ?
+ [this.layoutDocAcls ? this.targetDoc : this.targetDoc?.[DataSym]]
+ : SelectionManager.SelectedDocuments().map(docView => this.layoutDocAcls ? docView.props.Document : docView.props.Document?.[DataSym]);
+
+ const targetDoc = docs[0];
+
+ // tslint:disable-next-line: no-unnecessary-callback-wrapper
+ const admin = docs.map(doc => GetEffectiveAcl(doc)).every(acl => acl === AclAdmin); // if the user has admin access to all selected docs
- const effectiveAcl = targetDoc ? GetEffectiveAcl(targetDoc) : AclPrivate;
+ // users in common between all docs
+ const commonKeys = intersection(...docs.map(doc => this.layoutDocAcls ? doc?.[AclSym] && Object.keys(doc[AclSym]) : doc?.[DataSym]?.[AclSym] && Object.keys(doc[DataSym][AclSym])));
// the list of users shared with
- const userListContents: (JSX.Element | null)[] = users.map(({ user, notificationDoc }) => {
- const userKey = user.email.replace('.', '_');
- const permissions = StrCast(targetDoc?.[`ACL-${userKey}`]);
+ const userListContents: (JSX.Element | null)[] = users.filter(({ user }) => docs.length > 1 ? commonKeys.includes(`ACL-${user.email.replace('.', '_')}`) : true).map(({ user, notificationDoc }) => {
+ const userKey = `ACL-${user.email.replace('.', '_')}`;
+ const uniform = docs.every(doc => this.layoutDocAcls ? doc?.[AclSym]?.[userKey] === docs[0]?.[AclSym]?.[userKey] : doc?.[DataSym]?.[AclSym]?.[userKey] === docs[0]?.[DataSym]?.[AclSym]?.[userKey]);
+ const permissions = uniform ? StrCast(targetDoc?.[userKey]) : "-multiple-";
- return !permissions || user.email === targetDoc?.author ? (null) : (
+ return !permissions ? (null) : (
<div
key={userKey}
className={"container"}
>
<span className={"padding"}>{user.email}</span>
<div className="edit-actions">
- {effectiveAcl === AclAdmin ? (
+ {admin ? (
<select
className={"permissions-dropdown"}
value={permissions}
onChange={e => this.setInternalSharing({ user, notificationDoc }, e.currentTarget.value)}
>
- {this.sharingOptions}
+ {this.sharingOptions(uniform)}
</select>
) : (
<div className={"permissions-dropdown"}>
@@ -439,22 +473,26 @@ export class SharingManager extends React.Component<{}> {
);
});
+ // checks if every doc has the same author
+ const sameAuthor = docs.every(doc => doc?.author === docs[0]?.author);
+
// the owner of the doc and the current user are placed at the top of the user list.
userListContents.unshift(
- (
- <div
- key={"owner"}
- className={"container"}
- >
- <span className={"padding"}>{targetDoc?.author === Doc.CurrentUserEmail ? "Me" : targetDoc?.author}</span>
- <div className="edit-actions">
- <div className={"permissions-dropdown"}>
- Owner
+ sameAuthor ?
+ (
+ <div
+ key={"owner"}
+ className={"container"}
+ >
+ <span className={"padding"}>{targetDoc?.author === Doc.CurrentUserEmail ? "Me" : targetDoc?.author}</span>
+ <div className="edit-actions">
+ <div className={"permissions-dropdown"}>
+ Owner
+ </div>
</div>
</div>
- </div>
- ),
- targetDoc?.author !== Doc.CurrentUserEmail ?
+ ) : null,
+ sameAuthor && targetDoc?.author !== Doc.CurrentUserEmail ?
(
<div
key={"me"}
@@ -470,35 +508,47 @@ export class SharingManager extends React.Component<{}> {
) : null
);
+ // dummy doc for public acl
+ const publicDoc = new Doc;
+ publicDoc.groupName = "Public";
// the list of groups shared with
- const groupListContents = groups.map(group => {
- const permissions = StrCast(targetDoc?.[`ACL-${StrCast(group.groupName)}`]);
-
- return !permissions ? null : (
+ const groupListMap = groups.filter(({ groupName }) => docs.length > 1 ? commonKeys.includes(`ACL-${StrCast(groupName).replace('.', '_')}`) : true);
+ groupListMap.unshift(publicDoc);
+ const groupListContents = groupListMap.map(group => {
+ const groupKey = `ACL-${StrCast(group.groupName)}`;
+ const uniform = docs.every(doc => this.layoutDocAcls ? doc?.[AclSym]?.[groupKey] === docs[0]?.[AclSym]?.[groupKey] : doc?.[DataSym]?.[AclSym]?.[groupKey] === docs[0]?.[DataSym]?.[AclSym]?.[groupKey]);
+ const permissions = uniform ? StrCast(targetDoc?.[`ACL-${StrCast(group.groupName)}`]) : "-multiple-";
+
+ return !permissions ? (null) : (
<div
- key={StrCast(group.groupName)}
+ key={groupKey}
className={"container"}
>
<div className={"padding"}>{group.groupName}</div>
- <div className="group-info" onClick={action(() => GroupManager.Instance.currentGroup = group)}>
- <FontAwesomeIcon icon={"info-circle"} color={"#e8e8e8"} size={"sm"} style={{ backgroundColor: "#1e89d7", borderRadius: "100%", border: "1px solid #1e89d7" }} />
- </div>
+ {group.groupName !== "Public" ?
+ (<div className="group-info" onClick={action(() => GroupManager.Instance.currentGroup = group)}>
+ <FontAwesomeIcon icon={"info-circle"} color={"#e8e8e8"} size={"sm"} style={{ backgroundColor: "#1e89d7", borderRadius: "100%", border: "1px solid #1e89d7" }} />
+ </div>)
+ : (null)}
<div className="edit-actions">
- <select
- className={"permissions-dropdown"}
- value={permissions}
- onChange={e => this.setInternalGroupSharing(group, e.currentTarget.value)}
- >
- {this.sharingOptions}
- </select>
+ {admin ? (
+ <select
+ className={"permissions-dropdown"}
+ value={permissions}
+ onChange={e => this.setInternalGroupSharing(group, e.currentTarget.value)}
+ >
+ {this.sharingOptions(uniform)}
+ </select>
+ ) : (
+ <div className={"permissions-dropdown"}>
+ {permissions}
+ </div>
+ )}
</div>
</div>
);
});
- // don't display the group list if all groups are null
- const displayGroupList = !groupListContents?.every(group => group === null);
-
return (
<div className={"sharing-interface"}>
{GroupManager.Instance?.currentGroup ?
@@ -538,7 +588,7 @@ export class SharingManager extends React.Component<{}> {
</div>
<div className={"hr-substitute"} /> */}
<div className="sharing-contents">
- <p className={"share-title"}><b>Share </b>{this.focusOn(StrCast(targetDoc?.title, "this document"))}</p>
+ <p className={"share-title"}><b>Share </b>{this.focusOn(docs.length < 2 ? StrCast(targetDoc?.title, "this document") : "-multiple-")}</p>
<div className={"close-button"} onClick={this.close}>
<FontAwesomeIcon icon={"times"} color={"black"} size={"lg"} />
</div>
@@ -559,7 +609,7 @@ export class SharingManager extends React.Component<{}> {
}}
/>
<select className="permissions-select" onChange={this.handlePermissionsChange} value={this.permissions}>
- {this.sharingOptions}
+ {this.sharingOptions(true)}
</select>
<button ref={this.shareDocumentButtonRef} className="share-button" onClick={this.share}>
Share
@@ -583,7 +633,7 @@ export class SharingManager extends React.Component<{}> {
: this.individualSort === "descending" ? <FontAwesomeIcon icon={"caret-down"} size={"xs"} />
: <FontAwesomeIcon icon={"caret-right"} size={"xs"} />}
</div>
- <div className={"users-list"} style={{ display: "block" }}>{/*200*/}
+ <div className={"users-list"}>
{userListContents}
</div>
</div>
@@ -596,18 +646,8 @@ export class SharingManager extends React.Component<{}> {
: <FontAwesomeIcon icon={"caret-right"} size={"xs"} />}
</div>
- <div className={"groups-list"} style={{ display: !displayGroupList ? "flex" : "block" }}>{/*200*/}
- {
- !displayGroupList ?
- <div
- className={"none"}
- >
- There are no groups this document has been shared with.
- </div>
- :
- groupListContents
- }
-
+ <div className={"groups-list"}>
+ {groupListContents}
</div>
</div>
</div>
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
index f9ffb4260..4d9445caa 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
@@ -27,6 +27,7 @@ import "./FormatShapePane.scss";
import "./PropertiesView.scss";
import { CollectionDockingView } from "../CollectionDockingView";
import { ParentDocSelector, SelectorContextMenu } from "../ParentDocumentSelector";
+import { intersection } from "lodash";
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -317,17 +318,20 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
*/
@undoBatch
changePermissions = (e: any, user: string) => {
- SharingManager.Instance.shareFromPropertiesSidebar(user, e.currentTarget.value as SharingPermissions, this.selectedDoc!);
+ const docs = SelectionManager.SelectedDocuments().length < 2 ? [this.selectedDoc!] : SelectionManager.SelectedDocuments().map(docView => docView.props.Document);
+ SharingManager.Instance.shareFromPropertiesSidebar(user, e.currentTarget.value as SharingPermissions, docs);
}
/**
* @returns the options for the permissions dropdown.
*/
getPermissionsSelect(user: string, permission: string) {
+ const dropdownValues: string[] = Object.values(SharingPermissions);
+ if (permission === "-multiple-") dropdownValues.unshift(permission);
return <select className="permissions-select"
value={permission}
onChange={e => this.changePermissions(e, user)}>
- {Object.values(SharingPermissions).map(permission => {
+ {dropdownValues.map(permission => {
return (
<option key={permission} value={permission}>
{permission}
@@ -365,7 +369,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
/**
* @returns a row of the permissions panel
*/
- sharingItem(name: string, effectiveAcl: symbol, permission: string) {
+ sharingItem(name: string, admin: boolean, permission: string) {
return <div className="propertiesView-sharingTable-item" key={name + permission}
// style={{ backgroundColor: this.selectedUser === name ? "#bcecfc" : "" }}
// onPointerDown={action(() => this.selectedUser = this.selectedUser === name ? "" : name)}
@@ -373,7 +377,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
<div className="propertiesView-sharingTable-item-name" style={{ width: name !== "Me" ? "85px" : "80px" }}> {name} </div>
{/* {name !== "Me" ? this.notifyIcon : null} */}
<div className="propertiesView-sharingTable-item-permission">
- {effectiveAcl === AclAdmin && permission !== "Owner" ? this.getPermissionsSelect(name, permission) : permission}
+ {admin && permission !== "Owner" ? this.getPermissionsSelect(name, permission) : permission}
{permission === "Owner" ? this.expansionIcon : null}
</div>
</div>;
@@ -391,17 +395,29 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
[AclAdmin, SharingPermissions.Admin]
]);
- const target = this.layoutDocAcls ? this.selectedDoc! : this.selectedDoc![DataSym];
+ // all selected docs
+ const docs = SelectionManager.SelectedDocuments().length < 2 ?
+ [this.layoutDocAcls ? this.selectedDoc! : this.selectedDoc![DataSym]]
+ : SelectionManager.SelectedDocuments().map(docView => this.layoutDocAcls ? docView.props.Document : docView.props.Document[DataSym]);
+
+ const target = docs[0];
+
+ // tslint:disable-next-line: no-unnecessary-callback-wrapper
+ const effectiveAcls = docs.map(doc => GetEffectiveAcl(doc));
+ const showAdmin = effectiveAcls.every(acl => acl === AclAdmin);
+
+ // users in common between all docs
+ const commonKeys = intersection(...docs.map(doc => this.layoutDocAcls ? doc?.[AclSym] && Object.keys(doc[AclSym]) : doc?.[DataSym][AclSym] && Object.keys(doc[DataSym][AclSym])));
- const effectiveAcl = GetEffectiveAcl(target);
const tableEntries = [];
// DocCastAsync(Doc.UserDoc().sidebarUsersDisplayed).then(sidebarUsersDisplayed => {
- if (target[AclSym]) {
- for (const [key, value] of Object.entries(target[AclSym])) {
+ if (commonKeys.length) {
+ for (const key of commonKeys) {
const name = key.substring(4).replace("_", ".");
+ const uniform = docs.every(doc => this.layoutDocAcls ? doc?.[AclSym]?.[key] === docs[0]?.[AclSym]?.[key] : doc?.[DataSym]?.[AclSym]?.[key] === docs[0]?.[DataSym]?.[AclSym]?.[key]);
if (name !== Doc.CurrentUserEmail && name !== target.author && name !== "Public"/* && sidebarUsersDisplayed![name] !== false*/) {
- tableEntries.push(this.sharingItem(name, effectiveAcl, AclMap.get(value as symbol)!));
+ tableEntries.push(this.sharingItem(name, showAdmin, uniform ? AclMap.get(this.layoutDocAcls ? target[AclSym][key] : target[DataSym][AclSym][key])! : "-multiple-"));
}
}
}
@@ -414,9 +430,9 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
// })
// shifts the current user, owner, public to the top of the doc.
- tableEntries.unshift(this.sharingItem("Public", effectiveAcl, (AclMap.get(target[AclSym]?.["ACL-Public"]) || SharingPermissions.None)));
- tableEntries.unshift(this.sharingItem("Me", effectiveAcl, Doc.CurrentUserEmail === target.author ? "Owner" : AclMap.get(effectiveAcl)!));
- if (Doc.CurrentUserEmail !== target.author) tableEntries.unshift(this.sharingItem(StrCast(target.author), effectiveAcl, "Owner"));
+ tableEntries.unshift(this.sharingItem("Public", showAdmin, docs.every(doc => doc["ACL-Public"] === docs[0]["ACL-Public"]) ? (AclMap.get(target[AclSym]?.["ACL-Public"]) || SharingPermissions.None) : "-multiple-"));
+ tableEntries.unshift(this.sharingItem("Me", showAdmin, docs.every(doc => doc.author === Doc.CurrentUserEmail) ? "Owner" : effectiveAcls.every(acl => acl === effectiveAcls[0]) ? AclMap.get(effectiveAcls[0])! : "-multiple-"));
+ if (Doc.CurrentUserEmail !== target.author && docs.every(doc => doc.author === docs[0].author)) tableEntries.unshift(this.sharingItem(StrCast(target.author), showAdmin, "Owner"));
return <div className="propertiesView-sharingTable">
{tableEntries}
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 9679527e4..069f01195 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -183,7 +183,8 @@ export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number,
for (const [key, value] of Object.entries(target[AclSym])) {
// there are issues with storing fields with . in the name, so they are replaced with _ during creation
// as a result we need to restore them again during this comparison.
- if (currentUserGroups.includes(key.substring(4).replace("_", ".")) || userChecked === key.substring(4).replace("_", ".")) {
+ const entity = key.substring(4).replace('_', '.'); // an individual or a group
+ if (currentUserGroups.includes(entity) || userChecked === entity) {
if (HierarchyMapping.get(value as symbol)! > HierarchyMapping.get(effectiveAcl)!) {
effectiveAcl = value as symbol;
if (effectiveAcl === AclAdmin) break;