aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/DocServer.ts2
-rw-r--r--src/client/util/GroupManager.tsx11
-rw-r--r--src/client/util/SharingManager.scss62
-rw-r--r--src/client/util/SharingManager.tsx258
-rw-r--r--src/client/views/MainViewModal.scss5
-rw-r--r--src/client/views/MainViewModal.tsx1
6 files changed, 218 insertions, 121 deletions
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index 2a7a7c59a..eac53bb02 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -31,7 +31,7 @@ export namespace DocServer {
export enum WriteMode {
Default = 0, //Anything goes
- Playground = 1, //Playground (write own/no read)
+ Playground = 1, //Playground (write own/no read other updates)
LiveReadonly = 2,//Live Readonly (no write/read others)
LivePlayground = 3,//Live Playground (write own/read others)
}
diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx
index c8d3be49b..220916ba7 100644
--- a/src/client/util/GroupManager.tsx
+++ b/src/client/util/GroupManager.tsx
@@ -7,7 +7,7 @@ import { Doc, DocListCast, Opt, DocListCastAsync } from "../../fields/Doc";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import * as fa from '@fortawesome/free-solid-svg-icons';
import { library } from "@fortawesome/fontawesome-svg-core";
-import { User } from "./SharingManager";
+import SharingManager, { User } from "./SharingManager";
import { Utils } from "../../Utils";
import * as RequestPromise from "request-promise";
import Select from 'react-select';
@@ -203,6 +203,7 @@ export default class GroupManager extends React.Component<{}> {
// TODO look at this later
// SharingManager.Instance.setInternalGroupSharing(group, "Not Shared");
Doc.RemoveDocFromList(this.GroupManagerDoc, "data", group);
+ SharingManager.Instance.removeGroup(group);
if (group === this.currentGroup) {
runInAction(() => this.currentGroup = undefined);
}
@@ -222,6 +223,7 @@ export default class GroupManager extends React.Component<{}> {
const memberList: string[] = JSON.parse(StrCast(groupDoc.members));
!memberList.includes(email) && memberList.push(email);
groupDoc.members = JSON.stringify(memberList);
+ SharingManager.Instance.shareWithAddedMember(groupDoc, email);
}
}
@@ -234,8 +236,11 @@ export default class GroupManager extends React.Component<{}> {
if (this.hasEditAccess(groupDoc)) {
const memberList: string[] = JSON.parse(StrCast(groupDoc.members));
const index = memberList.indexOf(email);
- index !== -1 && memberList.splice(index, 1);
- groupDoc.members = JSON.stringify(memberList);
+ if (index !== -1) {
+ const user = memberList.splice(index, 1)[0];
+ groupDoc.members = JSON.stringify(memberList);
+ SharingManager.Instance.removeMember(groupDoc, email);
+ }
}
}
diff --git a/src/client/util/SharingManager.scss b/src/client/util/SharingManager.scss
index 209c41651..2708876a3 100644
--- a/src/client/util/SharingManager.scss
+++ b/src/client/util/SharingManager.scss
@@ -4,6 +4,7 @@
// display: flex;
// flex-direction: column;
width: 600px;
+ height: 360px;
.dialogue-box {
width: 450;
@@ -14,10 +15,23 @@
transform: translate(-20px, -20px);
}
+ select {
+ text-align: justify;
+ text-align-last: end
+ }
+
.sharing-contents {
display: flex;
flex-direction: column;
+ .close-button {
+ position: absolute;
+ right: 1em;
+ top: 1em;
+ cursor: pointer;
+ z-index: 999;
+ }
+
.share-setup {
display: flex;
margin-bottom: 20px;
@@ -33,11 +47,14 @@
margin-left: -100;
border: none;
outline: none;
+ text-align: justify; // for Edge
+ text-align-last: end;
}
.share-button {
- height: 100%;
- margin-left: 3%;
+ height: 105%;
+ margin-left: 2%;
+ background-color: #979797;
}
}
@@ -57,8 +74,8 @@
.groups-list,
.users-list {
font-style: italic;
- background: white;
- border: 1px solid black;
+ background: gainsboro;
+ // border: 1px solid black;
padding-left: 10px;
padding-right: 10px;
overflow-y: scroll;
@@ -71,8 +88,14 @@
justify-content: center;
// color: red;
color: black;
- height: 150px;
+ height: 255px;
margin: 0 2;
+
+
+ .none {
+ font-style: italic;
+
+ }
}
}
}
@@ -146,7 +169,7 @@
font-size: 14;
font-weight: normal;
padding: 0;
- align-items: baseline;
+ align-items: center;
&:hover .padding {
white-space: unset;
@@ -164,6 +187,7 @@
.permissions-dropdown {
border: none;
height: 25;
+ background: gainsboro;
}
.edit-actions {
@@ -210,17 +234,17 @@
}
}
- .close-button {
- border-radius: 5px;
- margin-top: 20px;
- padding: 10px 0;
- background: aliceblue;
- transition: 0.5s ease all;
- border: 1px solid;
- border-color: aliceblue;
- }
-
- .close-button:hover {
- border-color: black;
- }
+ // .close-button {
+ // border-radius: 5px;
+ // margin-top: 20px;
+ // padding: 10px 0;
+ // background: aliceblue;
+ // transition: 0.5s ease all;
+ // border: 1px solid;
+ // border-color: aliceblue;
+ // }
+
+ // .close-button:hover {
+ // border-color: black;
+ // }
} \ No newline at end of file
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index b4977f8ea..372b6172d 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -1,7 +1,7 @@
import { observable, runInAction, action } from "mobx";
import * as React from "react";
import MainViewModal from "../views/MainViewModal";
-import { Doc, Opt, DocCastAsync } from "../../fields/Doc";
+import { Doc, Opt, DocCastAsync, DocListCast } from "../../fields/Doc";
import { DocServer } from "../DocServer";
import { Cast, StrCast } from "../../fields/Types";
import * as RequestPromise from "request-promise";
@@ -19,6 +19,8 @@ import { DictationOverlay } from "../views/DictationOverlay";
import GroupManager, { UserOptions } from "./GroupManager";
import GroupMemberView from "./GroupMemberView";
import Select from "react-select";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { List } from "../../fields/List";
library.add(fa.faCopy);
@@ -86,6 +88,8 @@ export default class SharingManager extends React.Component<{}> {
@observable private overlayOpacity = 0.4;
@observable private selectedUsers: UserOptions[] | null = null;
@observable private permissions: SharingPermissions = SharingPermissions.Edit;
+ @observable private sharedUsers: ValidatedUser[] = [];
+ @observable private sharedGroups: Doc[] = [];
// private get linkVisible() {
// return this.sharingDoc ? this.sharingDoc[PublicKey] !== SharingPermissions.None : false;
@@ -166,16 +170,52 @@ export default class SharingManager extends React.Component<{}> {
// sharingDoc[StrCast(group.groupName)] = permission;
// }
+ group.docsShared ? Doc.IndexOf(target, DocListCast(group.docsShared)) === -1 && (group.docsShared as List<Doc>).push(target) : group.docsShared = new List<Doc>([target]);
+
users.forEach(({ notificationDoc }) => {
- Doc.AddDocToList(notificationDoc, storage, target);
+
+ if (permission !== SharingPermissions.None) Doc.IndexOf(target, DocListCast(notificationDoc[storage])) === -1 && Doc.AddDocToList(notificationDoc, storage, target);
+ else Doc.IndexOf(target, DocListCast(notificationDoc[storage])) !== -1 && Doc.RemoveDocFromList(notificationDoc, storage, target);
+
});
}
- setInternalSharing = (recipient: ValidatedUser, permission: string, group?: Doc) => {
+ shareWithAddedMember = (group: Doc, email: string) => {
+ const user: ValidatedUser = this.users.find(user => user.user.email === email)!;
+
+ if (group.docsShared) {
+ DocListCast(group.docsShared).forEach(doc => Doc.IndexOf(doc, DocListCast(user.notificationDoc[storage])) === -1 && Doc.AddDocToList(user.notificationDoc, storage, doc));
+ }
+ }
+
+ removeMember = (group: Doc, email: string) => {
+ const user: ValidatedUser = this.users.find(user => user.user.email === email)!;
+
+ if (group.docsShared) {
+ DocListCast(group.docsShared).forEach(doc => Doc.IndexOf(doc, DocListCast(user.notificationDoc[storage])) !== -1 && Doc.RemoveDocFromList(user.notificationDoc, storage, doc));
+ }
+ }
+
+ removeGroup = (group: Doc) => {
+ if (group.docsShared) {
+ DocListCast(group.docsShared).forEach(doc => {
+ const ACL = `ACL-${StrCast(group.groupName)}`;
+ doc[ACL] = "Not Shared";
+
+ const members: string[] = JSON.parse(StrCast(group.members));
+ const users: ValidatedUser[] = this.users.filter(user => members.includes(user.user.email));
+
+ users.forEach(user => Doc.RemoveDocFromList(user.notificationDoc, storage, doc));
+ })
+ }
+ }
+
+ setInternalSharing = (recipient: ValidatedUser, permission: string) => {
const { user, notificationDoc } = recipient;
const target = this.targetDoc!;
// const manager = this.sharingDoc!;
- const key = user.userDocumentId;
+ const key = user.email.replace('.', '_');
+ // const key = user.userDocumentId;
const ACL = `ACL-${key}`;
@@ -183,43 +223,47 @@ export default class SharingManager extends React.Component<{}> {
target[ACL] = permission;
- Doc.AddDocToList(notificationDoc, storage, target);
-
-
- // let metadata = await DocCastAsync(manager[key]);
- // const permissions: { [key: string]: number } = metadata?.permissions ? JSON.parse(StrCast(metadata.permissions)) : {};
- // permissions[StrCast(group ? group.groupName : Doc.CurrentUserEmail)] = parseInt(HierarchyMapping.get(permission)!);
- // const max = Math.max(...Object.values(permissions));
-
- // switch (max) {
- // case 0:
- // // if (metadata) {
- // // const sharedAlias = (await DocCastAsync(metadata.sharedAlias))!;
- // // Doc.RemoveDocFromList(notificationDoc, storage, sharedAlias);
- // // manager[key] = undefined;
- // // }
- // Doc.RemoveDocFromList(notificationDoc, storage, target);
- // break;
-
- // case 1: case 2: case 3:
-
- // Doc.AddDocToList(notificationDoc, storage, target);
-
- // if (!metadata) {
- // metadata = new Doc;
- // const sharedAlias = Doc.MakeAlias(target);
- // Doc.AddDocToList(notificationDoc, storage, target);
- // metadata.sharedAlias = sharedAlias;
- // manager[key] = metadata;
- // }
- // metadata.permissions = JSON.stringify(permissions);
- // // metadata.usersShared = JSON.stringify(keys);
- // break;
- // }
- // if (metadata) metadata.maxPermission = HierarchyMapping.get(`${max}`);
+ if (permission !== SharingPermissions.None) Doc.IndexOf(target, DocListCast(notificationDoc[storage])) === -1 && Doc.AddDocToList(notificationDoc, storage, target);
+ else Doc.IndexOf(target, DocListCast(notificationDoc[storage])) !== -1 && Doc.RemoveDocFromList(notificationDoc, storage, target);
+
}
+
+ // let metadata = await DocCastAsync(manager[key]);
+ // const permissions: { [key: string]: number } = metadata?.permissions ? JSON.parse(StrCast(metadata.permissions)) : {};
+ // permissions[StrCast(group ? group.groupName : Doc.CurrentUserEmail)] = parseInt(HierarchyMapping.get(permission)!);
+ // const max = Math.max(...Object.values(permissions));
+
+ // switch (max) {
+ // case 0:
+ // // if (metadata) {
+ // // const sharedAlias = (await DocCastAsync(metadata.sharedAlias))!;
+ // // Doc.RemoveDocFromList(notificationDoc, storage, sharedAlias);
+ // // manager[key] = undefined;
+ // // }
+ // Doc.RemoveDocFromList(notificationDoc, storage, target);
+ // break;
+
+ // case 1: case 2: case 3:
+
+ // Doc.AddDocToList(notificationDoc, storage, target);
+
+ // if (!metadata) {
+ // metadata = new Doc;
+ // const sharedAlias = Doc.MakeAlias(target);
+ // Doc.AddDocToList(notificationDoc, storage, target);
+ // metadata.sharedAlias = sharedAlias;
+ // manager[key] = metadata;
+ // }
+ // metadata.permissions = JSON.stringify(permissions);
+ // // metadata.usersShared = JSON.stringify(keys);
+ // break;
+ // }
+
+ // if (metadata) metadata.maxPermission = HierarchyMapping.get(`${max}`);
+
+
// private setExternalSharing = (permission: string) => {
// const sharingDoc = this.sharingDoc;
// if (!sharingDoc) {
@@ -345,6 +389,67 @@ export default class SharingManager extends React.Component<{}> {
]
: [];
+ const userListContents: (JSX.Element | null)[] = this.users.map(({ user, notificationDoc }) => { // can't use async here
+ const userKey = user.email.replace('.', '_');
+ // const userKey = user.userDocumentId;
+ const permissions = this.computePermissions(userKey);
+ // const color = ColorMapping.get(permissions);
+
+ // console.log(manager);
+ // const metadata = manager[userKey] as Doc;
+ // const usersShared = StrCast(metadata?.usersShared, "");
+ // console.log(usersShared)
+
+ return permissions === SharingPermissions.None ? null : (
+ <div
+ key={userKey}
+ className={"container"}
+ >
+ <span className={"padding"}>{user.email}</span>
+ {/* <div className={"shared-by"}>{usersShared}</div> */}
+ <div className="edit-actions">
+ <select
+ className={"permissions-dropdown"}
+ value={permissions}
+ // style={{ color, borderColor: color }}
+ onChange={e => this.setInternalSharing({ user, notificationDoc }, e.currentTarget.value)}
+ >
+ {this.sharingOptions}
+ </select>
+ </div>
+ </div>
+ );
+ });
+
+
+ const groupListContents = GroupManager.Instance?.getAllGroups().map(group => {
+ const permissions = this.computePermissions(StrCast(group.groupName));
+ // const color = ColorMapping.get(permissions);
+
+ return permissions === SharingPermissions.None ? null : (
+ <div
+ key={StrCast(group.groupName)}
+ className={"container"}
+ >
+ <span className={"padding"}>{group.groupName}</span>
+ <div className="edit-actions">
+ <select
+ className={"permissions-dropdown"}
+ value={permissions}
+ // style={{ color, borderColor: color }}
+ onChange={e => this.setInternalGroupSharing(group, e.currentTarget.value)}
+ >
+ {this.sharingOptions}
+ </select>
+ <button onClick={action(() => GroupManager.Instance.currentGroup = group)}>Edit</button>
+ </div>
+ </div>
+ );
+ });
+
+ const displayUserList = userListContents?.every(user => user === null);
+ const displayGroupList = groupListContents?.every(group => group === null);
+
return (
<div className={"sharing-interface"}>
{GroupManager.Instance?.currentGroup ?
@@ -385,6 +490,9 @@ export default class SharingManager extends React.Component<{}> {
<div className={"hr-substitute"} /> */}
<div className="sharing-contents">
<p className={"share-title"}><b>Share </b>{this.focusOn(StrCast(this.targetDoc?.title, "this document"))}</p>
+ <div className={"close-button"} onClick={this.close}>
+ <FontAwesomeIcon icon={fa.faWindowClose} size={"lg"} />
+ </div>
{this.targetDoc?.author !== Doc.CurrentUserEmail ? null
:
<div className="share-setup">
@@ -407,69 +515,30 @@ export default class SharingManager extends React.Component<{}> {
}
<div className="main-container">
<div className={"individual-container"}>
- <div className={"users-list"} style={{ display: existOtherUsers ? "block" : "flex", minHeight: existOtherUsers ? undefined : 150 }}>{/*200*/}
+ <div className={"users-list"} style={{ display: displayUserList ? "flex" : "block" }}>{/*200*/}
{
- this.users.map(({ user, notificationDoc }) => { // can't use async here
- const userKey = user.userDocumentId;
- const permissions = this.computePermissions(userKey);
- // const color = ColorMapping.get(permissions);
-
- // console.log(manager);
- // const metadata = manager[userKey] as Doc;
- // const usersShared = StrCast(metadata?.usersShared, "");
- // console.log(usersShared)
-
-
- return permissions === SharingPermissions.None ? null : (
- <div
- key={userKey}
- className={"container"}
- >
- <span className={"padding"}>{user.email}</span>
- {/* <div className={"shared-by"}>{usersShared}</div> */}
- <div className="edit-actions">
- <select
- className={"permissions-dropdown"}
- value={permissions}
- // style={{ color, borderColor: color }}
- onChange={e => this.setInternalSharing({ user, notificationDoc }, e.currentTarget.value)}
- >
- {this.sharingOptions}
- </select>
- </div>
- </div>
- );
- })
+ displayUserList ?
+ <div
+ className={"none"}
+ >
+ There are no users this document has been shared with.
+ </div>
+ :
+ userListContents
}
</div>
</div>
<div className={"group-container"}>
- <div className={"groups-list"} style={{ display: existGroups ? "block" : "flex", minHeight: existOtherUsers ? undefined : 150 }}>{/*200*/}
+ <div className={"groups-list"} style={{ display: displayGroupList ? "flex" : "block" }}>{/*200*/}
{
- GroupManager.Instance?.getAllGroups().map(group => {
- const permissions = this.computePermissions(StrCast(group.groupName));
- // const color = ColorMapping.get(permissions);
- return permissions === SharingPermissions.None ? null : (
- <div
- key={StrCast(group.groupName)}
- className={"container"}
- >
- <span className={"padding"}>{group.groupName}</span>
- <div className="edit-actions">
- <select
- className={"permissions-dropdown"}
- value={permissions}
- // style={{ color, borderColor: color }}
- onChange={e => this.setInternalGroupSharing(group, e.currentTarget.value)}
- >
- {this.sharingOptions}
- </select>
- <button onClick={action(() => GroupManager.Instance.currentGroup = group)}>Edit</button>
- </div>
+ displayGroupList ?
+ <div
+ className={"none"}
+ >
+ There are no groups this document has been shared with.
</div>
- );
- })
-
+ :
+ groupListContents
}
</div>
@@ -477,7 +546,6 @@ export default class SharingManager extends React.Component<{}> {
</div>
</div>
- <div className={"close-button"} onClick={this.close}>Done</div>
</div>
);
}
diff --git a/src/client/views/MainViewModal.scss b/src/client/views/MainViewModal.scss
index f5a9ee76c..812fe540b 100644
--- a/src/client/views/MainViewModal.scss
+++ b/src/client/views/MainViewModal.scss
@@ -6,9 +6,10 @@
align-self: center;
align-content: center;
padding: 20px;
- background: gainsboro;
+ // background: gainsboro;
+ background: white;
border-radius: 10px;
- border: 3px solid black;
+ border: 0.5px solid black;
box-shadow: #00000044 5px 5px 10px;
transform: translate(-50%, -50%);
top: 50%;
diff --git a/src/client/views/MainViewModal.tsx b/src/client/views/MainViewModal.tsx
index a7bd5882d..c6b3532e8 100644
--- a/src/client/views/MainViewModal.tsx
+++ b/src/client/views/MainViewModal.tsx
@@ -22,7 +22,6 @@ export default class MainViewModal extends React.Component<MainViewOverlayProps>
<div
className={"dialogue-box"}
style={{
- backgroundColor: "gainsboro",
borderColor: "black",
...(p.dialogueBoxStyle || {}),
opacity: p.isDisplayed ? dialogueOpacity : 0