aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/util/GroupManager.tsx27
-rw-r--r--src/client/util/SharingManager.scss62
-rw-r--r--src/client/util/SharingManager.tsx121
3 files changed, 156 insertions, 54 deletions
diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx
index 7f48ca014..fa8da86c1 100644
--- a/src/client/util/GroupManager.tsx
+++ b/src/client/util/GroupManager.tsx
@@ -88,7 +88,7 @@ export default class GroupManager extends React.Component<{}> {
/**
* @returns a list of all group documents.
*/
- getAllGroups(): Doc[] {
+ private getAllGroups(): Doc[] {
const groupDoc = this.GroupManagerDoc;
return groupDoc ? DocListCast(groupDoc.data) : [];
}
@@ -97,12 +97,32 @@ export default class GroupManager extends React.Component<{}> {
* @returns a group document based on the group name.
* @param groupName
*/
- getGroup(groupName: string): Doc | undefined {
+ private getGroup(groupName: string): Doc | undefined {
const groupDoc = this.getAllGroups().find(group => group.groupName === groupName);
return groupDoc;
}
/**
+ * @returns a readonly copy of a single group document
+ */
+ getGroupCopy(groupName: string): Doc | undefined {
+ const groupDoc = this.getGroup(groupName);
+ if (groupDoc) {
+ const { members, owners } = groupDoc;
+ return Doc.assign(new Doc, { groupName, members: StrCast(members), owners: StrCast(owners) });
+ }
+ return undefined;
+ }
+ /**
+ * @returns a readonly copy of the list of group documents
+ */
+ getAllGroupsCopy(): Doc[] {
+ return this.getAllGroups().map(({ groupName, owners, members }) =>
+ Doc.assign(new Doc, { groupName: (groupName as string), owners: (owners as string), members: (members as string) })
+ );
+ }
+
+ /**
* @returns the members of the admin group.
*/
get adminGroupMembers(): string[] {
@@ -194,7 +214,6 @@ export default class GroupManager extends React.Component<{}> {
*/
@action
handleChange = (selectedOptions: any) => {
- console.log(selectedOptions);
this.selectedUsers = selectedOptions as UserOptions[];
}
@@ -312,7 +331,7 @@ export default class GroupManager extends React.Component<{}> {
<div className="group-row">
<div className="group-name">{group.groupName}</div>
<button onClick={action(() => this.currentGroup = group)}>
- {this.hasEditAccess(this.getGroup(StrCast(group.groupName)) as Doc) ? "Edit" : "View"}
+ {this.hasEditAccess(group) ? "Edit" : "View"}
</button>
</div>
)}
diff --git a/src/client/util/SharingManager.scss b/src/client/util/SharingManager.scss
index dec9f751a..1aff345a0 100644
--- a/src/client/util/SharingManager.scss
+++ b/src/client/util/SharingManager.scss
@@ -1,13 +1,52 @@
.sharing-interface {
display: flex;
flex-direction: column;
+ width: 730px;
+
+ .sharing-contents {
+ display: flex;
+
+ .individual-container,
+ .group-container {
+ width: 50%;
+
+ .share-groups,
+ .share-individual {
+ margin-top: 20px;
+ margin-bottom: 20px;
+ }
+
+ .groups-list,
+ .users-list {
+ font-style: italic;
+ background: white;
+ border: 1px solid black;
+ padding-left: 10px;
+ padding-right: 10px;
+ // max-height: 200px;
+ overflow: scroll;
+ height: -webkit-fill-available;
+ text-align: left;
+ display: flex;
+ align-content: center;
+ align-items: center;
+ text-align: center;
+ justify-content: center;
+ color: red;
+
+ // width: 50%;
+ max-height: 150px;
+ }
+ }
+ }
.focus-span {
text-decoration: underline;
}
p {
- font-size: 20px;
+ // font-size: 20px;
+ font-size: 15px;
text-align: left;
font-style: italic;
padding: 0;
@@ -36,28 +75,7 @@
}
}
- .share-individual {
- margin-top: 20px;
- margin-bottom: 20px;
- }
- .users-list {
- font-style: italic;
- background: white;
- border: 1px solid black;
- padding-left: 10px;
- padding-right: 10px;
- max-height: 200px;
- overflow: scroll;
- height: -webkit-fill-available;
- text-align: left;
- display: flex;
- align-content: center;
- align-items: center;
- text-align: center;
- justify-content: center;
- color: red;
- }
.container {
display: block;
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 2e660e819..3d796539c 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -17,6 +17,7 @@ import { SelectionManager } from "./SelectionManager";
import { DocumentManager } from "./DocumentManager";
import { CollectionView } from "../views/collections/CollectionView";
import { DictationOverlay } from "../views/DictationOverlay";
+import GroupManager from "./GroupManager";
library.add(fa.faCopy);
@@ -28,7 +29,7 @@ export interface User {
export enum SharingPermissions {
None = "Not Shared",
View = "Can View",
- Add = "Can Add and Comment",
+ Add = "Can Add",
Edit = "Can Edit"
}
@@ -39,6 +40,13 @@ const ColorMapping = new Map<string, string>([
[SharingPermissions.Edit, "green"]
]);
+const HierarchyMapping = new Map<string, number>([
+ [SharingPermissions.None, 0],
+ [SharingPermissions.View, 1],
+ [SharingPermissions.Add, 2],
+ [SharingPermissions.Edit, 3]
+]);
+
const SharingKey = "sharingPermissions";
const PublicKey = "publicLinkPermissions";
const DefaultColor = "black";
@@ -55,6 +63,7 @@ export default class SharingManager extends React.Component<{}> {
public static Instance: SharingManager;
@observable private isOpen = false;
@observable private users: ValidatedUser[] = [];
+ @observable private groups: Doc[] = [];
@observable private targetDoc: Doc | undefined;
@observable private targetDocView: DocumentView | undefined;
@observable private copied = false;
@@ -76,6 +85,8 @@ export default class SharingManager extends React.Component<{}> {
this.sharingDoc = new Doc;
}
}));
+
+ runInAction(() => this.groups = GroupManager.Instance.getAllGroupsCopy());
}
public close = action(() => {
@@ -121,11 +132,30 @@ export default class SharingManager extends React.Component<{}> {
return Promise.all(evaluating);
}
+ setInternalGroupSharing = (group: Doc, permission: string) => {
+ const members: string[] = JSON.parse(StrCast(group.members));
+ const users: ValidatedUser[] = this.users.filter(user => members.includes(user.user.email));
+
+ const sharingDoc = this.sharingDoc!;
+ if (permission === SharingPermissions.None) {
+ const metadata = sharingDoc[group[Id]];
+ if (metadata) sharingDoc[group[Id]] = undefined;
+ }
+ else {
+ sharingDoc[group[Id]] = permission;
+ }
+
+ users.forEach(user => {
+ this.setInternalSharing(user, permission);
+ });
+ }
+
setInternalSharing = async (recipient: ValidatedUser, state: string) => {
const { user, notificationDoc } = recipient;
const target = this.targetDoc!;
const manager = this.sharingDoc!;
const key = user.userDocumentId;
+
if (state === SharingPermissions.None) {
const metadata = (await DocCastAsync(manager[key]));
if (metadata) {
@@ -211,15 +241,17 @@ export default class SharingManager extends React.Component<{}> {
if (!sharingDoc) {
return SharingPermissions.None;
}
- const metadata = sharingDoc[userKey] as Doc;
+ const metadata = sharingDoc[userKey] as Doc | string;
if (!metadata) {
return SharingPermissions.None;
}
- return StrCast(metadata.permissions, SharingPermissions.None);
+ return StrCast(metadata instanceof Doc ? metadata.permissions : metadata, SharingPermissions.None);
}
+
private get sharingInterface() {
const existOtherUsers = this.users.length > 0;
+ const existGroups = this.groups.length > 0;
return (
<div className={"sharing-interface"}>
<p className={"share-link"}>Manage the public link to {this.focusOn("this document...")}</p>
@@ -252,31 +284,64 @@ export default class SharingManager extends React.Component<{}> {
</select>
</div>
<div className={"hr-substitute"} />
- <p className={"share-individual"}>Privately share {this.focusOn("this document")} with an individual...</p>
- <div className={"users-list"} style={{ display: existOtherUsers ? "block" : "flex", minHeight: existOtherUsers ? undefined : 200 }}>
- {!existOtherUsers ? "There are no other users in your database." :
- this.users.map(({ user, notificationDoc }) => {
- const userKey = user.userDocumentId;
- const permissions = this.computePermissions(userKey);
- const color = ColorMapping.get(permissions);
- return (
- <div
- key={userKey}
- className={"container"}
- >
- <select
- className={"permissions-dropdown"}
- value={permissions}
- style={{ color, borderColor: color }}
- onChange={e => this.setInternalSharing({ user, notificationDoc }, e.currentTarget.value)}
- >
- {this.sharingOptions}
- </select>
- <span className={"padding"}>{user.email}</span>
- </div>
- );
- })
- }
+ <div className="sharing-contents">
+ <div className={"individual-container"}>
+ <p className={"share-individual"}>Privately share {this.focusOn("this document")} with an individual...</p>
+ <div className={"users-list"} style={{ display: existOtherUsers ? "block" : "flex", minHeight: existOtherUsers ? undefined : 150 }}>{/*200*/}
+ {!existOtherUsers ? "There are no other users in your database." :
+ this.users.map(({ user, notificationDoc }) => {
+ const userKey = user.userDocumentId;
+ const permissions = this.computePermissions(userKey);
+ const color = ColorMapping.get(permissions);
+ return (
+ <div
+ key={userKey}
+ className={"container"}
+ >
+ <select
+ className={"permissions-dropdown"}
+ value={permissions}
+ style={{ color, borderColor: color }}
+ onChange={e => this.setInternalSharing({ user, notificationDoc }, e.currentTarget.value)}
+ >
+ {this.sharingOptions}
+ </select>
+ <span className={"padding"}>{user.email}</span>
+ </div>
+ );
+ })
+ }
+ </div>
+ </div>
+ <div className={"group-container"}>
+ <p className={"share-groups"}>Privately share {this.focusOn("this document")} with a group...</p>
+ <div className={"groups-list"} style={{ display: existGroups ? "block" : "flex", minHeight: existOtherUsers ? undefined : 150 }}>{/*200*/}
+ {!existGroups ? "There are no groups in your database." :
+ this.groups.map(group => {
+ const permissions = this.computePermissions(group[Id]);
+ const color = ColorMapping.get(permissions);
+ return (
+ <div
+ key={group[Id]}
+ className={"container"}
+ >
+ <select
+ className={"permissions-dropdown"}
+ value={permissions}
+ style={{ color, borderColor: color }}
+ onChange={e => this.setInternalGroupSharing(group, e.currentTarget.value)}
+ >
+ {this.sharingOptions}
+ </select>
+ <span className={"padding"}>{group.groupName}</span>
+ </div>
+ );
+ })
+
+ }
+
+ </div>
+ </div>
</div>
<div className={"close-button"} onClick={this.close}>Done</div>
</div>