From 467afe6346bf3188461721fa78eed0f9ac214da7 Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Wed, 1 Jul 2020 16:55:51 +0530 Subject: ui changes + related functionality changes --- src/client/util/SharingManager.scss | 122 +++++++++++++++++++++++------------- 1 file changed, 80 insertions(+), 42 deletions(-) (limited to 'src/client/util/SharingManager.scss') diff --git a/src/client/util/SharingManager.scss b/src/client/util/SharingManager.scss index fcbc05f8a..209c41651 100644 --- a/src/client/util/SharingManager.scss +++ b/src/client/util/SharingManager.scss @@ -1,9 +1,9 @@ @import "../views/globalCssVariables"; .sharing-interface { - display: flex; - flex-direction: column; - width: 730px; + // display: flex; + // flex-direction: column; + width: 600px; .dialogue-box { width: 450; @@ -16,6 +16,66 @@ .sharing-contents { display: flex; + flex-direction: column; + + .share-setup { + display: flex; + margin-bottom: 20px; + align-items: center; + height: 36; + + .user-search { + width: 90%; + } + + .permissions-select { + z-index: 1; + margin-left: -100; + border: none; + outline: none; + } + + .share-button { + height: 100%; + margin-left: 3%; + } + } + + .main-container { + display: flex; + + + .individual-container, + .group-container { + width: 50%; + + .share-title { + 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; + overflow-y: scroll; + overflow-x: hidden; + text-align: left; + display: flex; + align-content: center; + align-items: center; + text-align: center; + justify-content: center; + // color: red; + color: black; + height: 150px; + margin: 0 2; + } + } + } button { background: $darker-alt-accent; @@ -31,37 +91,6 @@ transition: transform 0.2s; height: 25; } - - .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; - overflow-y: scroll; - overflow-x: hidden; - text-align: left; - display: flex; - align-content: center; - align-items: center; - text-align: center; - justify-content: center; - color: red; - height: 150px; - margin: 0 2; - } - } } .focus-span { @@ -69,11 +98,12 @@ } p { - font-size: 15px; + font-size: 20px; text-align: left; - font-style: italic; - padding: 0; + // font-style: italic; + // padding: 0; margin: 0 0 20px 0; + color: black; } .hr-substitute { @@ -108,9 +138,9 @@ -moz-user-select: none; -ms-user-select: none; user-select: none; - width: 700px; - min-width: 700px; - max-width: 700px; + width: 100%; + // min-width: 700px; + // max-width: 700px; text-align: left; font-style: normal; font-size: 14; @@ -118,20 +148,28 @@ padding: 0; align-items: baseline; + &:hover .padding { + white-space: unset; + } + .padding { padding: 0 10px 0 0; color: black; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + max-width: 48%; } .permissions-dropdown { - outline: none; + border: none; height: 25; } .edit-actions { display: flex; position: absolute; - right: 51.5%; + right: -10; } } -- cgit v1.2.3-70-g09d2 From 293c62ea3eccbeb2565960abb5ab02fabb5e20a0 Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Fri, 3 Jul 2020 16:16:36 +0530 Subject: many changes related to adding and removing document from the notificationDoc of a user --- src/client/DocServer.ts | 2 +- src/client/util/GroupManager.tsx | 11 +- src/client/util/SharingManager.scss | 62 ++++++--- src/client/util/SharingManager.tsx | 258 +++++++++++++++++++++++------------- src/client/views/MainViewModal.scss | 5 +- src/client/views/MainViewModal.tsx | 1 - 6 files changed, 218 insertions(+), 121 deletions(-) (limited to 'src/client/util/SharingManager.scss') 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).push(target) : group.docsShared = new List([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 : ( +
+ {user.email} + {/*
{usersShared}
*/} +
+ +
+
+ ); + }); + + + const groupListContents = GroupManager.Instance?.getAllGroups().map(group => { + const permissions = this.computePermissions(StrCast(group.groupName)); + // const color = ColorMapping.get(permissions); + + return permissions === SharingPermissions.None ? null : ( +
+ {group.groupName} +
+ + +
+
+ ); + }); + + const displayUserList = userListContents?.every(user => user === null); + const displayGroupList = groupListContents?.every(group => group === null); + return (
{GroupManager.Instance?.currentGroup ? @@ -385,6 +490,9 @@ export default class SharingManager extends React.Component<{}> {
*/}

Share {this.focusOn(StrCast(this.targetDoc?.title, "this document"))}

+
+ +
{this.targetDoc?.author !== Doc.CurrentUserEmail ? null :
@@ -407,69 +515,30 @@ export default class SharingManager extends React.Component<{}> { }
-
{/*200*/} +
{/*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 : ( -
- {user.email} - {/*
{usersShared}
*/} -
- -
-
- ); - }) + displayUserList ? +
+ There are no users this document has been shared with. +
+ : + userListContents }
-
{/*200*/} +
{/*200*/} { - GroupManager.Instance?.getAllGroups().map(group => { - const permissions = this.computePermissions(StrCast(group.groupName)); - // const color = ColorMapping.get(permissions); - return permissions === SharingPermissions.None ? null : ( -
- {group.groupName} -
- - -
+ displayGroupList ? +
+ There are no groups this document has been shared with.
- ); - }) - + : + groupListContents }
@@ -477,7 +546,6 @@ export default class SharingManager extends React.Component<{}> {
-
Done
); } 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
Date: Tue, 14 Jul 2020 22:12:01 +0530 Subject: added group creation modal to GroupManager + much ui --- src/client/util/GroupManager.scss | 174 ++++++++++++++++++--------------- src/client/util/GroupManager.tsx | 183 +++++++++++++++++++++-------------- src/client/util/GroupMemberView.scss | 37 +++++-- src/client/util/GroupMemberView.tsx | 21 +++- src/client/util/SharingManager.scss | 17 ++-- src/client/util/SharingManager.tsx | 63 ++++++------ src/client/views/MainViewModal.tsx | 2 +- src/fields/util.ts | 4 +- 8 files changed, 300 insertions(+), 201 deletions(-) (limited to 'src/client/util/SharingManager.scss') diff --git a/src/client/util/GroupManager.scss b/src/client/util/GroupManager.scss index 544a79e98..2da1f0d95 100644 --- a/src/client/util/GroupManager.scss +++ b/src/client/util/GroupManager.scss @@ -1,23 +1,60 @@ -@import "../views/globalCssVariables"; +// @import "../views/globalCssVariables"; .group-interface { - background-color: whitesmoke !important; - color: grey; - width: 450px; + // background-color: whitesmoke !important; + // color: grey; + width: 550px; height: 300px; .dialogue-box { - width: 450; - height: 300; + .group-create { + display: flex; + flex-direction: column; + height: 90%; + justify-content: space-between; + // flex-basis: 30%; + margin-left: 5px; + + input { + border-radius: 5px; + // border: none; + padding: 8px; + min-width: 100%; + margin: 4px 0 4px 0; + border: 1px solid hsl(0, 0%, 80%); + outline: none; + + &:focus { + // border: unset; + border: 2.5px solid #2684FF; + } + } + + p { + font-size: 20px; + text-align: left; + color: black; + } + + button { + align-self: flex-end; + } + } } + // .dialogue-box { + // width: 450; + // height: 300; + // } + button { - background: $lighter-alt-accent; + // background: $lighter-alt-accent; + align-self: center; outline: none; border-radius: 5px; border: 0px; - color: #fcfbf7; - text-transform: uppercase; + // color: #fcfbf7; + text-transform: none; letter-spacing: 2px; font-size: 75%; padding: 10px; @@ -36,12 +73,6 @@ border-radius: 10px; } - button { - width: 100%; - align-self: center; - background: $darker-alt-accent; - } - .delete-button { background: rgb(227, 86, 86); } @@ -55,82 +86,73 @@ } .group-heading { - letter-spacing: .5em; + display: flex; + align-items: center; + margin-bottom: 25px; + + p { + font-size: 20px; + text-align: left; + // margin: 0 0 20px 0; + margin-right: 15px; + color: black; + // width: 60%; + } } .group-body { - display: flex; + // display: flex; justify-content: space-between; - max-height: 80%; - - .group-create { - display: flex; - flex-direction: column; - flex-basis: 30%; - margin-left: 5px; - - input { - border-radius: 5px; - border: none; - padding: 4px; - min-width: 100%; - margin: 4px 0 4px 0; - } + // max-height: 80%; + height: 100%; + background-color: #e8e8e8; + // flex-direction: column; - } - - .group-content { - padding-left: 1em; - padding-right: 1em; - justify-content: space-around; - text-align: left; + // padding-left: 1em; + padding-right: 1em; + justify-content: space-around; + text-align: left; - overflow-y: auto; - width: 100%; - - .group-row { - display: flex; - position: relative; - margin-bottom: 5px; - min-height: 40px; - border: 1px solid; - border-radius: 10px; - align-items: center; - - .group-name { - position: relative; - max-width: 65%; - left: 10; - } + overflow-y: auto; + width: 100%; - button { - position: absolute; - width: 30%; - right: 2; - margin-top: 0; - } + .group-row { + display: flex; + // position: relative; + margin-bottom: 5px; + min-height: 30px; + // border: 1px solid; + // border-radius: 10px; + align-items: center; + + .group-name { + // position: relative; + max-width: 65%; + // left: 10; + margin: 0 10; + color: black; } - ::placeholder { - color: $intermediate-color; + .group-info { + cursor: pointer; } - input { - border-radius: 5px; - border: none; - padding: 4px; - min-width: 100%; - margin: 2px 0; + button { + position: absolute; + width: 30%; + right: 2; + margin-top: 0; } + } + input { + border-radius: 5px; + border: none; + padding: 4px; + min-width: 100%; + margin: 2px 0; } - } - h1 { - color: $dark-color; - text-transform: uppercase; - letter-spacing: 2px; - font-size: 120%; } } \ No newline at end of file diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index 23bdd248b..f2b502ae0 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -12,11 +12,12 @@ import { Utils } from "../../Utils"; import * as RequestPromise from "request-promise"; import Select from 'react-select'; import "./GroupManager.scss"; -import { StrCast } from "../../fields/Types"; +import { StrCast, Cast } from "../../fields/Types"; import GroupMemberView from "./GroupMemberView"; import { setGroups } from "../../fields/util"; +import { DocServer } from "../DocServer"; -library.add(fa.faWindowClose); +library.add(fa.faPlus, fa.faTimes, fa.faInfoCircle); export interface UserOptions { label: string; @@ -33,47 +34,37 @@ export default class GroupManager extends React.Component<{}> { @observable private users: string[] = []; // list of users populated from the database. @observable private selectedUsers: UserOptions[] | null = null; // list of users selected in the "Select users" dropdown. @observable currentGroup: Opt; // the currently selected group. + @observable private createGroupModalOpen: boolean = false; private inputRef: React.RefObject = React.createRef(); // the ref for the input box. - currentUserGroups: string[] = []; + private currentUserGroups: string[] = []; + @observable private buttonColour: "#979797" | "black" = "#979797"; constructor(props: Readonly<{}>) { super(props); GroupManager.Instance = this; } - // sets up the list of users - componentDidMount() { - this.populateUsers().then(resolved => runInAction(() => this.users = resolved)); - - // this.getAllGroups().forEach(group => { - // const members: string[] = JSON.parse(StrCast(group.members)); - // if (members.includes(Doc.CurrentUserEmail)) this.currentUserGroups.push(group); - // }); - DocListCastAsync(this.GroupManagerDoc?.data).then(groups => { - groups?.forEach(group => { - const members: string[] = JSON.parse(StrCast(group.members)); - if (members.includes(Doc.CurrentUserEmail)) this.currentUserGroups.push(StrCast(group.groupName)); - }); - }) - .finally(() => setGroups(this.currentUserGroups)); - - // (this.GroupManagerDoc?.data as List).forEach(group => { - // Promise.resolve(group).then(resolvedGroup => { - // const members: string[] = JSON.parse(StrCast(resolvedGroup.members)); - // if (members.includes(Doc.CurrentUserEmail)) this.currentUserGroups.push(resolvedGroup); - // }); - // }); - - } - /** - * Fetches the list of users stored on the database and @returns a list of the emails. + * Fetches the list of users stored on the database. */ populateUsers = async () => { - const userList: User[] = JSON.parse(await RequestPromise.get(Utils.prepend("/getUsers"))); - // const currentUserIndex = userList.findIndex(user => user.email === Doc.CurrentUserEmail); - // currentUserIndex !== -1 && userList.splice(currentUserIndex, 1); - return userList.map(user => user.email); + const userList = await RequestPromise.get(Utils.prepend("/getUsers")); + const raw = JSON.parse(userList) as User[]; + const evaluating = raw.map(async user => { + const isCandidate = user.email !== Doc.CurrentUserEmail; + if (isCandidate) { + const userDocument = await DocServer.GetRefField(user.userDocumentId); + if (userDocument instanceof Doc) { + const notificationDoc = await Cast(userDocument.rightSidebarCollection, Doc); + runInAction(() => { + if (notificationDoc instanceof Doc) { + this.users.push(user.email); + } + }); + } + } + }); + return Promise.all(evaluating); } /** @@ -90,6 +81,15 @@ export default class GroupManager extends React.Component<{}> { open = () => { SelectionManager.DeselectAll(); this.isOpen = true; + this.populateUsers(); + DocListCastAsync(this.GroupManagerDoc?.data).then(groups => { + groups?.forEach(group => { + const members: string[] = JSON.parse(StrCast(group.members)); + if (members.includes(Doc.CurrentUserEmail)) this.currentUserGroups.push(StrCast(group.groupName)); + }); + + setGroups(this.currentUserGroups); + }); } /** @@ -99,6 +99,8 @@ export default class GroupManager extends React.Component<{}> { close = () => { this.isOpen = false; this.currentGroup = undefined; + this.users = []; + this.createGroupModalOpen = false; } /** @@ -277,6 +279,7 @@ export default class GroupManager extends React.Component<{}> { */ @action createGroup = () => { + // this.createGroupModalOpen = true; if (!this.inputRef.current?.value) { alert("Please enter a group name"); return; @@ -288,6 +291,66 @@ export default class GroupManager extends React.Component<{}> { this.createGroupDoc(this.inputRef.current.value, this.selectedUsers?.map(user => user.value)); this.selectedUsers = null; this.inputRef.current.value = ""; + this.buttonColour = "#979797"; + } + + private get groupCreationModal() { + const contents = ( +
+
+

New Group

+
this.createGroupModalOpen = false)}> + +
+
+ this.buttonColour = this.inputRef.current?.value ? "black" : "#979797")} /> + - this.props.group.groupName = e.currentTarget.value} + > +
- +
- {GroupManager.Instance.hasEditAccess(this.props.group) ?
@@ -55,13 +60,18 @@ export default class GroupMemberView extends React.Component : null}
+
{members.map(member => (
{member}
- {GroupManager.Instance.hasEditAccess(this.props.group) ? : null} + {GroupManager.Instance.hasEditAccess(this.props.group) ? +
GroupManager.Instance.removeMemberFromGroup(this.props.group, member)}> + +
+ : null}
))}
@@ -75,6 +85,7 @@ export default class GroupMemberView extends React.Component; } diff --git a/src/client/util/SharingManager.scss b/src/client/util/SharingManager.scss index 2708876a3..ce23ce413 100644 --- a/src/client/util/SharingManager.scss +++ b/src/client/util/SharingManager.scss @@ -6,10 +6,10 @@ width: 600px; height: 360px; - .dialogue-box { - width: 450; - height: 300; - } + // .dialogue-box { + // width: 450; + // height: 300; + // } .overlay { transform: translate(-20px, -20px); @@ -60,11 +60,13 @@ .main-container { display: flex; - + margin-top: -10px; .individual-container, .group-container { width: 50%; + display: flex; + flex-direction: column; .share-title { margin-top: 20px; @@ -74,7 +76,7 @@ .groups-list, .users-list { font-style: italic; - background: gainsboro; + background: #e8e8e8; // border: 1px solid black; padding-left: 10px; padding-right: 10px; @@ -88,7 +90,7 @@ justify-content: center; // color: red; color: black; - height: 255px; + height: 250px; margin: 0 2; @@ -187,7 +189,6 @@ .permissions-dropdown { border: none; height: 25; - background: gainsboro; } .edit-actions { diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index af68edab6..6c7c634eb 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -22,7 +22,7 @@ import Select from "react-select"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { List } from "../../fields/List"; -library.add(fa.faCopy); +library.add(fa.faCopy, fa.faTimes); export interface User { email: string; @@ -140,7 +140,7 @@ export default class SharingManager extends React.Component<{}> { 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 users: ValidatedUser[] = this.users.filter(({ user: { email } }) => members.includes(email)); const target = this.targetDoc!; const ACL = `ACL-${StrCast(group.groupName)}`; @@ -160,8 +160,8 @@ export default class SharingManager extends React.Component<{}> { }); } - shareWithAddedMember = (group: Doc, email: string) => { - const user: ValidatedUser = this.users.find(user => user.user.email === email)!; + shareWithAddedMember = (group: Doc, emailId: string) => { + const user: ValidatedUser = this.users.find(({ user: { email } }) => email === emailId)!; if (group.docsShared) { DocListCastAsync(group.docsShared).then(docsShared => { @@ -173,8 +173,8 @@ export default class SharingManager extends React.Component<{}> { } } - removeMember = (group: Doc, email: string) => { - const user: ValidatedUser = this.users.find(user => user.user.email === email)!; + removeMember = (group: Doc, emailId: string) => { + const user: ValidatedUser = this.users.find(({ user: { email } }) => email === emailId)!; if (group.docsShared) { DocListCastAsync(group.docsShared).then(docsShared => { @@ -194,9 +194,9 @@ export default class SharingManager extends React.Component<{}> { doc[ACL] = "Not Shared"; const members: string[] = JSON.parse(StrCast(group.members)); - const users: ValidatedUser[] = this.users.filter(user => members.includes(user.user.email)); + const users: ValidatedUser[] = this.users.filter(({ user: { email } }) => members.includes(email)); - users.forEach(user => Doc.RemoveDocFromList(user.notificationDoc, storage, doc)); + users.forEach(({ notificationDoc }) => Doc.RemoveDocFromList(notificationDoc, storage, doc)); }); }); @@ -330,24 +330,6 @@ export default class SharingManager extends React.Component<{}> { ); } - private computePermissions = (userKey: string) => { - // const sharingDoc = this.sharingDoc; - // if (!sharingDoc) { - // return SharingPermissions.None; - // } - // const metadata = sharingDoc[userKey] as Doc | string; - - if (!this.targetDoc) return SharingPermissions.None; - - const ACL = `ACL-${userKey}`; - const permission = StrCast(this.targetDoc[ACL]); - - // if (!metadata) { - // return SharingPermissions.None; - // } - return StrCast(this.targetDoc[ACL], SharingPermissions.None); - } - @action handleUsersChange = (selectedOptions: any) => { this.selectedUsers = selectedOptions as UserOptions[]; @@ -381,7 +363,7 @@ export default class SharingManager extends React.Component<{}> { [ { label: 'Individuals', - options: GroupManager.Instance.options.map(({ label, value }) => ({ label, value: "!indType/" + value })) + options: this.users.map(({ user: { email } }) => ({ label: email, value: "!indType/" + email })) }, { label: 'Groups', @@ -390,10 +372,12 @@ export default class SharingManager extends React.Component<{}> { ] : []; + console.log(this.users); + 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 permissions = StrCast(this.targetDoc?.[`ACL-${userKey}`], SharingPermissions.None); // const color = ColorMapping.get(permissions); // console.log(manager); @@ -401,7 +385,7 @@ export default class SharingManager extends React.Component<{}> { // const usersShared = StrCast(metadata?.usersShared, ""); // console.log(usersShared) - return permissions === SharingPermissions.None ? null : ( + return permissions === SharingPermissions.None || user.email === this.targetDoc?.author ? null : (
{ ); }); + userListContents.unshift( + ( +
+ {this.targetDoc?.author} +
+
+ Owner +
+
+
+ ) + ); const groupListContents = GroupManager.Instance?.getAllGroups().map(group => { - const permissions = this.computePermissions(StrCast(group.groupName)); + const permissions = StrCast(this.targetDoc?.[`ACL-${StrCast(group.groupName)}`], SharingPermissions.None); // const color = ColorMapping.get(permissions); return permissions === SharingPermissions.None ? null : ( @@ -492,7 +491,7 @@ export default class SharingManager extends React.Component<{}> {

Share {this.focusOn(StrCast(this.targetDoc?.title, "this document"))}

- +
{this.targetDoc?.author !== Doc.CurrentUserEmail ? null : @@ -516,6 +515,7 @@ export default class SharingManager extends React.Component<{}> { }
+
Individuals
{/*200*/} { displayUserList ? @@ -530,6 +530,7 @@ export default class SharingManager extends React.Component<{}> {
+
Groups
{/*200*/} { displayGroupList ? diff --git a/src/client/views/MainViewModal.tsx b/src/client/views/MainViewModal.tsx index 0b73a6ad7..249715511 100644 --- a/src/client/views/MainViewModal.tsx +++ b/src/client/views/MainViewModal.tsx @@ -21,7 +21,7 @@ export default class MainViewModal extends React.Component const dialogueOpacity = p.dialogueBoxDisplayedOpacity || 1; const overlayOpacity = p.overlayDisplayedOpacity || 0.4; return !p.isDisplayed ? (null) : ( -
+
Date: Wed, 15 Jul 2020 16:49:56 +0530 Subject: ui + sorting --- src/client/util/GroupManager.scss | 99 ++++++++++++++++++++---------------- src/client/util/GroupManager.tsx | 74 +++++++++++++++++++-------- src/client/util/GroupMemberView.scss | 27 ++++++++-- src/client/util/GroupMemberView.tsx | 21 ++++++-- src/client/util/SharingManager.scss | 23 +++++++-- src/client/util/SharingManager.tsx | 68 +++++++++++++++++-------- 6 files changed, 215 insertions(+), 97 deletions(-) (limited to 'src/client/util/SharingManager.scss') diff --git a/src/client/util/GroupManager.scss b/src/client/util/GroupManager.scss index 2da1f0d95..8a2c616b1 100644 --- a/src/client/util/GroupManager.scss +++ b/src/client/util/GroupManager.scss @@ -20,9 +20,10 @@ // border: none; padding: 8px; min-width: 100%; - margin: 4px 0 4px 0; + // margin: 4px 0 4px 0; border: 1px solid hsl(0, 0%, 80%); outline: none; + height: 30; &:focus { // border: unset; @@ -100,59 +101,69 @@ } } + .main-container { + display: flex; + flex-direction: column; - .group-body { - // display: flex; - justify-content: space-between; - // max-height: 80%; - height: 100%; - background-color: #e8e8e8; - // flex-direction: column; + .sort-groups { + text-align: left; + margin-left: 5; + cursor: pointer; + } - // padding-left: 1em; - padding-right: 1em; - justify-content: space-around; - text-align: left; + .group-body { + // display: flex; + justify-content: space-between; + // max-height: 80%; + height: 220; + background-color: #e8e8e8; + // flex-direction: column; + + // padding-left: 1em; + padding-right: 1em; + justify-content: space-around; + text-align: left; - overflow-y: auto; - width: 100%; + overflow-y: auto; + width: 100%; - .group-row { - display: flex; - // position: relative; - margin-bottom: 5px; - min-height: 30px; - // border: 1px solid; - // border-radius: 10px; - align-items: center; - - .group-name { + .group-row { + display: flex; // position: relative; - max-width: 65%; - // left: 10; - margin: 0 10; - color: black; - } + margin-bottom: 5px; + min-height: 30px; + // border: 1px solid; + // border-radius: 10px; + align-items: center; + + .group-name { + // position: relative; + max-width: 65%; + // left: 10; + margin: 0 10; + color: black; + } - .group-info { - cursor: pointer; + .group-info { + cursor: pointer; + } + + button { + position: absolute; + width: 30%; + right: 2; + margin-top: 0; + } } - button { - position: absolute; - width: 30%; - right: 2; - margin-top: 0; + input { + border-radius: 5px; + border: none; + padding: 4px; + min-width: 100%; + margin: 2px 0; } - } - input { - border-radius: 5px; - border: none; - padding: 4px; - min-width: 100%; - margin: 2px 0; } - } } \ No newline at end of file diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index f2b502ae0..2d8930660 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -38,31 +38,38 @@ export default class GroupManager extends React.Component<{}> { private inputRef: React.RefObject = React.createRef(); // the ref for the input box. private currentUserGroups: string[] = []; @observable private buttonColour: "#979797" | "black" = "#979797"; + @observable private groupSort: "ascending" | "descending" | "none" = "none"; + constructor(props: Readonly<{}>) { super(props); GroupManager.Instance = this; } + componentDidMount() { + this.populateUsers(); + } + /** * Fetches the list of users stored on the database. */ populateUsers = async () => { + runInAction(() => this.users = []); const userList = await RequestPromise.get(Utils.prepend("/getUsers")); const raw = JSON.parse(userList) as User[]; const evaluating = raw.map(async user => { - const isCandidate = user.email !== Doc.CurrentUserEmail; - if (isCandidate) { - const userDocument = await DocServer.GetRefField(user.userDocumentId); - if (userDocument instanceof Doc) { - const notificationDoc = await Cast(userDocument.rightSidebarCollection, Doc); - runInAction(() => { - if (notificationDoc instanceof Doc) { - this.users.push(user.email); - } - }); - } + // const isCandidate = user.email !== Doc.CurrentUserEmail; + // if (isCandidate) { + const userDocument = await DocServer.GetRefField(user.userDocumentId); + if (userDocument instanceof Doc) { + const notificationDoc = await Cast(userDocument.rightSidebarCollection, Doc); + runInAction(() => { + if (notificationDoc instanceof Doc) { + this.users.push(user.email); + } + }); } + // } }); return Promise.all(evaluating); } @@ -99,7 +106,7 @@ export default class GroupManager extends React.Component<{}> { close = () => { this.isOpen = false; this.currentGroup = undefined; - this.users = []; + // this.users = []; this.createGroupModalOpen = false; } @@ -304,6 +311,7 @@ export default class GroupManager extends React.Component<{}> {
{ * A getter that @returns the main interface for the GroupManager. */ private get groupInterface() { + + const sortGroups = (d1: Doc, d2: Doc) => { + const g1 = StrCast(d1.groupName); + const g2 = StrCast(d2.groupName); + + return g1 < g2 ? -1 : g1 === g2 ? 0 : 1; + }; + + let groups = this.getAllGroups(); + groups = this.groupSort === "ascending" ? groups.sort(sortGroups) : this.groupSort === "descending" ? groups.sort(sortGroups).reverse() : groups; + return (
{this.groupCreationModal} @@ -375,19 +394,30 @@ export default class GroupManager extends React.Component<{}> {
-
- {this.getAllGroups().map(group => -
-
{group.groupName}
-
this.currentGroup = group)}> - -
- {/* */} -
- )} +
+ )} +
+
); } diff --git a/src/client/util/GroupMemberView.scss b/src/client/util/GroupMemberView.scss index 9bdf832e0..a34e5b989 100644 --- a/src/client/util/GroupMemberView.scss +++ b/src/client/util/GroupMemberView.scss @@ -8,7 +8,7 @@ // color: black; hr { - margin-top: 10; + margin-top: 20; } button { @@ -17,7 +17,7 @@ border-radius: 5px; border: 0px; color: #fcfbf7; - // text-transform: uppercase; + text-transform: none; letter-spacing: 2px; font-size: 75%; padding: 10px; @@ -45,15 +45,33 @@ outline: none; color: black; margin-top: -5; + height: 20; + text-overflow: ellipsis; + + &:hover { + text-overflow: visible; + overflow-x: auto; + } + } + + .sort-emails { + float: left; + margin: -18 0 0 5; + cursor: pointer; } .group-buttons { display: flex; margin-top: 5; + margin-bottom: 25; .add-member-dropdown { width: 65%; margin: 0 5; + + input { + height: 30; + } } } } @@ -61,7 +79,7 @@ .editing-contents { overflow-y: auto; // max-height: 67%; - height: 67%; + height: 65%; width: 100%; color: black; margin-top: -15px; @@ -70,6 +88,7 @@ display: flex; align-items: center; margin-bottom: 10px; + position: relative; // border: 1px solid; // border-radius: 10px; @@ -83,7 +102,7 @@ .remove-button { position: absolute; - right: 30; + right: 10; cursor: pointer; } } diff --git a/src/client/util/GroupMemberView.tsx b/src/client/util/GroupMemberView.tsx index 2462ee4d5..ebe9830ba 100644 --- a/src/client/util/GroupMemberView.tsx +++ b/src/client/util/GroupMemberView.tsx @@ -4,7 +4,7 @@ import { observer } from "mobx-react"; import GroupManager, { UserOptions } from "./GroupManager"; import { library } from "@fortawesome/fontawesome-svg-core"; import { StrCast } from "../../fields/Types"; -import { action } from "mobx"; +import { action, observable } from "mobx"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import * as fa from '@fortawesome/free-solid-svg-icons'; import Select from "react-select"; @@ -21,10 +21,17 @@ interface GroupMemberViewProps { @observer export default class GroupMemberView extends React.Component { + @observable private memberSort: "ascending" | "descending" | "none" = "none"; private get editingInterface() { - const members: string[] = this.props.group ? JSON.parse(StrCast(this.props.group.members)) : []; + let members: string[] = this.props.group ? JSON.parse(StrCast(this.props.group.members)) : []; + members = this.memberSort === "ascending" ? members.sort() : this.memberSort === "descending" ? members.sort().reverse() : members; + const options: UserOptions[] = this.props.group ? GroupManager.Instance.options.filter(option => !(JSON.parse(StrCast(this.props.group.members)) as string[]).includes(option.value)) : []; + console.log(this.props.group, options); + console.log(GroupManager.Instance.options); + + return (!this.props.group ? null :
@@ -59,11 +66,19 @@ export default class GroupMemberView extends React.Component GroupManager.Instance.deleteGroup(this.props.group)}>Delete group
: null} +
this.memberSort = this.memberSort === "ascending" ? "descending" : this.memberSort === "descending" ? "none" : "ascending")}> + Emails {this.memberSort === "ascending" ? "↑" : this.memberSort === "descending" ? "↓" : ""} {/* → */} +

{members.map(member => ( -
+
{member}
diff --git a/src/client/util/SharingManager.scss b/src/client/util/SharingManager.scss index ce23ce413..572b94ffb 100644 --- a/src/client/util/SharingManager.scss +++ b/src/client/util/SharingManager.scss @@ -1,4 +1,4 @@ -@import "../views/globalCssVariables"; +// @import "../views/globalCssVariables"; .sharing-interface { // display: flex; @@ -40,6 +40,10 @@ .user-search { width: 90%; + + input { + height: 30; + } } .permissions-select { @@ -68,6 +72,12 @@ display: flex; flex-direction: column; + .user-sort { + text-align: left; + margin-left: 10; + cursor: pointer; + } + .share-title { margin-top: 20px; margin-bottom: 20px; @@ -103,12 +113,12 @@ } button { - background: $darker-alt-accent; + // background: $darker-alt-accent; outline: none; border-radius: 5px; border: 0px; color: #fcfbf7; - text-transform: uppercase; + text-transform: none; letter-spacing: 2px; font-size: 75%; padding: 0 10; @@ -173,6 +183,10 @@ padding: 0; align-items: center; + .group-info { + cursor: pointer; + } + &:hover .padding { white-space: unset; } @@ -183,12 +197,13 @@ text-overflow: ellipsis; overflow: hidden; white-space: nowrap; - max-width: 48%; + max-width: 40%; } .permissions-dropdown { border: none; height: 25; + background-color: #e8e8e8; } .edit-actions { diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index 6c7c634eb..817b7c6b8 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -75,6 +75,9 @@ 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 individualSort: "ascending" | "descending" | "none" = "none"; + @observable private groupSort: "ascending" | "descending" | "none" = "none"; + // private get linkVisible() { // return this.sharingDoc ? this.sharingDoc[PublicKey] !== SharingPermissions.None : false; @@ -151,8 +154,6 @@ export default class SharingManager extends React.Component<{}> { // group.docsShared ? Doc.IndexOf(target, DocListCast(group.docsShared)) === -1 && (group.docsShared as List).push(target) : group.docsShared = new List([target]); users.forEach(({ notificationDoc }) => { - - DocListCastAsync(notificationDoc[storage]).then(res => console.log(res)); DocListCastAsync(notificationDoc[storage]).then(resolved => { if (permission !== SharingPermissions.None) Doc.IndexOf(target, resolved!) === -1 && Doc.AddDocToList(notificationDoc, storage, target); else Doc.IndexOf(target, resolved!) !== -1 && Doc.RemoveDocFromList(notificationDoc, storage, target); @@ -353,28 +354,44 @@ export default class SharingManager extends React.Component<{}> { this.selectedUsers = null; } + sortUsers = (u1: ValidatedUser, u2: ValidatedUser) => { + const { email: e1 } = u1.user; + const { email: e2 } = u2.user; + return e1 < e2 ? -1 : e1 === e2 ? 0 : 1; + } + + sortGroups = (group1: Doc, group2: Doc) => { + const g1 = StrCast(group1.groupName); + const g2 = StrCast(group2.groupName); + return g1 < g2 ? -1 : g1 === g2 ? 0 : 1; + } + private get sharingInterface() { - const existOtherUsers = this.users.length > 0; - const existGroups = GroupManager.Instance?.getAllGroups().length > 0; - // const manager = this.sharingDoc!; + const groupList = GroupManager.Instance?.getAllGroups() || []; + + const sortedUsers = this.users.sort(this.sortUsers) + .map(({ user: { email } }) => ({ label: email, value: "!indType/" + email })); + const sortedGroups = groupList.sort(this.sortGroups) + .map(({ groupName }) => ({ label: StrCast(groupName), value: "!groupType/" + StrCast(groupName) })); const options: GroupOptions[] = GroupManager.Instance ? [ { label: 'Individuals', - options: this.users.map(({ user: { email } }) => ({ label: email, value: "!indType/" + email })) + options: sortedUsers }, { label: 'Groups', - options: GroupManager.Instance.getAllGroups().map(({ groupName }) => ({ label: StrCast(groupName), value: "!groupType/" + StrCast(groupName) })) + options: sortedGroups } ] : []; - console.log(this.users); + const users = this.individualSort === "ascending" ? this.users.sort(this.sortUsers) : this.individualSort === "descending" ? this.users.sort(this.sortUsers).reverse() : this.users; + const groups = this.groupSort === "ascending" ? groupList.sort(this.sortGroups) : this.groupSort === "descending" ? groupList.sort(this.sortGroups).reverse() : groupList; - const userListContents: (JSX.Element | null)[] = this.users.map(({ user, notificationDoc }) => { // can't use async here + const userListContents: (JSX.Element | null)[] = users.map(({ user, notificationDoc }) => { // can't use async here const userKey = user.email.replace('.', '_'); // const userKey = user.userDocumentId; const permissions = StrCast(this.targetDoc?.[`ACL-${userKey}`], SharingPermissions.None); @@ -422,7 +439,7 @@ export default class SharingManager extends React.Component<{}> { ) ); - const groupListContents = GroupManager.Instance?.getAllGroups().map(group => { + const groupListContents = groups.map(group => { const permissions = StrCast(this.targetDoc?.[`ACL-${StrCast(group.groupName)}`], SharingPermissions.None); // const color = ColorMapping.get(permissions); @@ -431,7 +448,10 @@ export default class SharingManager extends React.Component<{}> { key={StrCast(group.groupName)} className={"container"} > - {group.groupName} +
{group.groupName}
+
GroupManager.Instance.currentGroup = group)}> + +
-
); }); - const displayUserList = userListContents?.every(user => user === null); - const displayGroupList = groupListContents?.every(group => group === null); + const displayUserList = !userListContents?.every(user => user === null); + const displayGroupList = !groupListContents?.every(group => group === null); return (
@@ -515,10 +534,14 @@ export default class SharingManager extends React.Component<{}> { }
-
Individuals
-
{/*200*/} +
this.individualSort = this.individualSort === "ascending" ? "descending" : this.individualSort === "descending" ? "none" : "ascending")}> + Individuals {this.individualSort === "ascending" ? "↑" : this.individualSort === "descending" ? "↓" : ""} {/* → */} +
+
{/*200*/} { - displayUserList ? + !displayUserList ?
@@ -530,10 +553,15 @@ export default class SharingManager extends React.Component<{}> {
-
Groups
-
{/*200*/} +
this.groupSort = this.groupSort === "ascending" ? "descending" : this.groupSort === "descending" ? "none" : "ascending")}> + Groups {this.groupSort === "ascending" ? "↑" : this.groupSort === "descending" ? "↓" : ""} {/* → */} + +
+
{/*200*/} { - displayGroupList ? + !displayGroupList ?
-- cgit v1.2.3-70-g09d2 From 3ad593cc8865d3fa1dc22bf403ad7cfaf1a751e6 Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Wed, 15 Jul 2020 21:52:23 +0530 Subject: bugfix + cleanup --- src/client/util/GroupManager.scss | 25 -------- src/client/util/GroupManager.tsx | 4 -- src/client/util/GroupMemberView.scss | 10 --- src/client/util/GroupMemberView.tsx | 3 - src/client/util/SharingManager.scss | 30 --------- src/client/util/SharingManager.tsx | 106 +++++--------------------------- src/client/views/nodes/DocumentView.tsx | 22 +++---- src/fields/Doc.ts | 2 +- 8 files changed, 28 insertions(+), 174 deletions(-) (limited to 'src/client/util/SharingManager.scss') diff --git a/src/client/util/GroupManager.scss b/src/client/util/GroupManager.scss index 8a2c616b1..34d4f40f8 100644 --- a/src/client/util/GroupManager.scss +++ b/src/client/util/GroupManager.scss @@ -1,8 +1,4 @@ -// @import "../views/globalCssVariables"; - .group-interface { - // background-color: whitesmoke !important; - // color: grey; width: 550px; height: 300px; @@ -12,21 +8,17 @@ flex-direction: column; height: 90%; justify-content: space-between; - // flex-basis: 30%; margin-left: 5px; input { border-radius: 5px; - // border: none; padding: 8px; min-width: 100%; - // margin: 4px 0 4px 0; border: 1px solid hsl(0, 0%, 80%); outline: none; height: 30; &:focus { - // border: unset; border: 2.5px solid #2684FF; } } @@ -43,18 +35,12 @@ } } - // .dialogue-box { - // width: 450; - // height: 300; - // } button { - // background: $lighter-alt-accent; align-self: center; outline: none; border-radius: 5px; border: 0px; - // color: #fcfbf7; text-transform: none; letter-spacing: 2px; font-size: 75%; @@ -94,10 +80,8 @@ p { font-size: 20px; text-align: left; - // margin: 0 0 20px 0; margin-right: 15px; color: black; - // width: 60%; } } @@ -112,14 +96,10 @@ } .group-body { - // display: flex; justify-content: space-between; - // max-height: 80%; height: 220; background-color: #e8e8e8; - // flex-direction: column; - // padding-left: 1em; padding-right: 1em; justify-content: space-around; text-align: left; @@ -129,17 +109,12 @@ .group-row { display: flex; - // position: relative; margin-bottom: 5px; min-height: 30px; - // border: 1px solid; - // border-radius: 10px; align-items: center; .group-name { - // position: relative; max-width: 65%; - // left: 10; margin: 0 10; color: black; } diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index 2d8930660..12951f2ab 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -286,7 +286,6 @@ export default class GroupManager extends React.Component<{}> { */ @action createGroup = () => { - // this.createGroupModalOpen = true; if (!this.inputRef.current?.value) { alert("Please enter a group name"); return; @@ -410,9 +409,6 @@ export default class GroupManager extends React.Component<{}> {
this.currentGroup = group)}>
- {/* */}
)}
diff --git a/src/client/util/GroupMemberView.scss b/src/client/util/GroupMemberView.scss index a34e5b989..c609c5c7b 100644 --- a/src/client/util/GroupMemberView.scss +++ b/src/client/util/GroupMemberView.scss @@ -1,18 +1,12 @@ -// @import "../views/globalCssVariables"; - .editing-interface { - // background-color: whitesmoke !important; - // color: grey; width: 100%; height: 100%; - // color: black; hr { margin-top: 20; } button { - // background: $darker-alt-accent; outline: none; border-radius: 5px; border: 0px; @@ -78,7 +72,6 @@ .editing-contents { overflow-y: auto; - // max-height: 67%; height: 65%; width: 100%; color: black; @@ -89,11 +82,8 @@ align-items: center; margin-bottom: 10px; position: relative; - // border: 1px solid; - // border-radius: 10px; .user-email { - // position: relative; min-width: 65%; word-break: break-all; padding: 0 5; diff --git a/src/client/util/GroupMemberView.tsx b/src/client/util/GroupMemberView.tsx index ebe9830ba..f20670c4e 100644 --- a/src/client/util/GroupMemberView.tsx +++ b/src/client/util/GroupMemberView.tsx @@ -28,9 +28,6 @@ export default class GroupMemberView extends React.Component !(JSON.parse(StrCast(this.props.group.members)) as string[]).includes(option.value)) : []; - console.log(this.props.group, options); - console.log(GroupManager.Instance.options); - return (!this.props.group ? null :
diff --git a/src/client/util/SharingManager.scss b/src/client/util/SharingManager.scss index 572b94ffb..130785672 100644 --- a/src/client/util/SharingManager.scss +++ b/src/client/util/SharingManager.scss @@ -1,16 +1,7 @@ -// @import "../views/globalCssVariables"; - .sharing-interface { - // display: flex; - // flex-direction: column; width: 600px; height: 360px; - // .dialogue-box { - // width: 450; - // height: 300; - // } - .overlay { transform: translate(-20px, -20px); } @@ -87,7 +78,6 @@ .users-list { font-style: italic; background: #e8e8e8; - // border: 1px solid black; padding-left: 10px; padding-right: 10px; overflow-y: scroll; @@ -98,7 +88,6 @@ align-items: center; text-align: center; justify-content: center; - // color: red; color: black; height: 250px; margin: 0 2; @@ -113,7 +102,6 @@ } button { - // background: $darker-alt-accent; outline: none; border-radius: 5px; border: 0px; @@ -135,8 +123,6 @@ p { font-size: 20px; text-align: left; - // font-style: italic; - // padding: 0; margin: 0 0 20px 0; color: black; } @@ -174,8 +160,6 @@ -ms-user-select: none; user-select: none; width: 100%; - // min-width: 700px; - // max-width: 700px; text-align: left; font-style: normal; font-size: 14; @@ -249,18 +233,4 @@ padding-top: 12px; } } - - // .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 be86b183f..8d4e508ac 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -36,13 +36,6 @@ export enum SharingPermissions { None = "Not Shared" } -// const ColorMapping = new Map([ -// [SharingPermissions.None, "red"], -// [SharingPermissions.View, "maroon"], -// [SharingPermissions.Add, "blue"], -// [SharingPermissions.Edit, "green"] -// ]); - interface GroupOptions { label: string; options: UserOptions[]; @@ -67,10 +60,9 @@ 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; + // @observable private copied = false; @observable private dialogueBoxOpacity = 1; @observable private overlayOpacity = 0.4; @observable private selectedUsers: UserOptions[] | null = null; @@ -90,32 +82,20 @@ export default class SharingManager extends React.Component<{}> { this.targetDoc = target.props.Document; DictationOverlay.Instance.hasActiveModal = true; this.isOpen = true; - // if (!this.sharingDoc) { - // this.sharingDoc = new Doc; - // } })); - // runInAction(() => this.groups = GroupManager.Instance.getAllGroups()); } public close = action(() => { this.isOpen = false; this.users = []; setTimeout(action(() => { - this.copied = false; + // this.copied = false; DictationOverlay.Instance.hasActiveModal = false; this.targetDoc = undefined; }), 500); }); - // private get sharingDoc() { - // return this.targetDoc ? Cast(this.targetDoc[SharingKey], Doc) as Doc : undefined; - // } - - // private set sharingDoc(value: Doc | undefined) { - // this.targetDoc && (this.targetDoc[SharingKey] = value); - // } - constructor(props: {}) { super(props); SharingManager.Instance = this; @@ -152,7 +132,6 @@ export default class SharingManager extends React.Component<{}> { Doc.GetProto(target)[ACL] = permission; group.docsShared ? DocListCastAsync(group.docsShared).then(resolved => Doc.IndexOf(target, resolved!) === -1 && (group.docsShared as List).push(target)) : group.docsShared = new List([target]); - // group.docsShared ? Doc.IndexOf(target, DocListCast(group.docsShared)) === -1 && (group.docsShared as List).push(target) : group.docsShared = new List([target]); users.forEach(({ notificationDoc }) => { DocListCastAsync(notificationDoc[storage]).then(resolved => { @@ -171,7 +150,6 @@ export default class SharingManager extends React.Component<{}> { DocListCastAsync(user.notificationDoc[storage]).then(resolved => Doc.IndexOf(doc, resolved!) === -1 && Doc.AddDocToList(user.notificationDoc, storage, doc)); }); }); - // DocListCast(group.docsShared).forEach(doc => Doc.IndexOf(doc, DocListCast(user.notificationDoc[storage])) === -1 && Doc.AddDocToList(user.notificationDoc, storage, doc)); } } @@ -184,7 +162,6 @@ export default class SharingManager extends React.Component<{}> { DocListCastAsync(user.notificationDoc[storage]).then(resolved => Doc.IndexOf(doc, resolved!) !== -1 && Doc.RemoveDocFromList(user.notificationDoc, storage, doc)); }); }); - // DocListCast(group.docsShared).forEach(doc => Doc.IndexOf(doc, DocListCast(user.notificationDoc[storage])) === -1 && Doc.AddDocToList(user.notificationDoc, storage, doc)); } } @@ -208,14 +185,10 @@ export default class SharingManager extends React.Component<{}> { setInternalSharing = (recipient: ValidatedUser, permission: string) => { const { user, notificationDoc } = recipient; const target = this.targetDoc!; - // const manager = this.sharingDoc!; const key = user.email.replace('.', '_'); - // const key = user.userDocumentId; const ACL = `ACL-${key}`; - // const permissions: { [key: string]: number } = target[ACL] ? JSON.parse(StrCast(target[ACL])) : {}; - target[ACL] = permission; Doc.GetProto(target)[ACL] = permission; @@ -228,47 +201,12 @@ export default class SharingManager extends React.Component<{}> { } else { DocListCastAsync(notificationDoc[storage]).then(resolved => { - Doc.IndexOf(target, resolved!) === -1 && Doc.RemoveDocFromList(notificationDoc, storage, target); + Doc.IndexOf(target, resolved!) !== -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) { @@ -277,20 +215,20 @@ export default class SharingManager extends React.Component<{}> { // sharingDoc[PublicKey] = permission; // } - private get sharingUrl() { - if (!this.targetDoc) { - return undefined; - } - const baseUrl = Utils.prepend("/doc/" + this.targetDoc[Id]); - return `${baseUrl}?sharing=true`; - } + // private get sharingUrl() { + // if (!this.targetDoc) { + // return undefined; + // } + // const baseUrl = Utils.prepend("/doc/" + this.targetDoc[Id]); + // return `${baseUrl}?sharing=true`; + // } - copy = action(() => { - if (this.sharingUrl) { - Utils.CopyText(this.sharingUrl); - this.copied = true; - } - }); + // copy = action(() => { + // if (this.sharingUrl) { + // Utils.CopyText(this.sharingUrl); + // this.copied = true; + // } + // }); private get sharingOptions() { return Object.values(SharingPermissions).map(permission => { @@ -394,14 +332,7 @@ export default class SharingManager extends React.Component<{}> { const userListContents: (JSX.Element | null)[] = users.map(({ user, notificationDoc }) => { // can't use async here const userKey = user.email.replace('.', '_'); - // const userKey = user.userDocumentId; const permissions = StrCast(this.targetDoc?.[`ACL-${userKey}`], SharingPermissions.None); - // 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 || user.email === this.targetDoc?.author ? null : (
{ className={"container"} > {user.email} - {/*
{usersShared}
*/}
this.setInternalGroupSharing(group, e.currentTarget.value)} > {this.sharingOptions} @@ -582,7 +509,6 @@ export default class SharingManager extends React.Component<{}> { } render() { - // console.log(this.sharingDoc); return ( (Docu !Doc.UserDoc().novice && helpItems.push({ description: "Show Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" }); cm.addItem({ description: "Help...", noexpand: true, subitems: helpItems, icon: "question" }); - const existingAcls = cm.findByDescription("Privacy..."); - const aclItems: ContextMenuProps[] = existingAcls && "subitems" in existingAcls ? existingAcls.subitems : []; - aclItems.push({ description: "Make Add Only", event: () => this.setAcl("addOnly"), icon: "concierge-bell" }); - aclItems.push({ description: "Make Read Only", event: () => this.setAcl("readOnly"), icon: "concierge-bell" }); - aclItems.push({ description: "Make Private", event: () => this.setAcl("ownerOnly"), icon: "concierge-bell" }); - aclItems.push({ description: "Make Editable", event: () => this.setAcl("write"), icon: "concierge-bell" }); - aclItems.push({ description: "Test Private", event: () => this.testAcl("ownerOnly"), icon: "concierge-bell" }); - aclItems.push({ description: "Test Readonly", event: () => this.testAcl("readOnly"), icon: "concierge-bell" }); - !existingAcls && cm.addItem({ description: "Privacy...", subitems: aclItems, icon: "question" }); - - cm.addItem({ description: `${getPlaygroundMode() ? "Disable" : "Enable"} playground mode`, event: togglePlaygroundMode, icon: "concierge-bell" }); + // const existingAcls = cm.findByDescription("Privacy..."); + // const aclItems: ContextMenuProps[] = existingAcls && "subitems" in existingAcls ? existingAcls.subitems : []; + // aclItems.push({ description: "Make Add Only", event: () => this.setAcl(SharingPermissions.Add), icon: "concierge-bell" }); + // aclItems.push({ description: "Make Read Only", event: () => this.setAcl(SharingPermissions.View), icon: "concierge-bell" }); + // aclItems.push({ description: "Make Private", event: () => this.setAcl(SharingPermissions.None), icon: "concierge-bell" }); + // aclItems.push({ description: "Make Editable", event: () => this.setAcl(SharingPermissions.Edit), icon: "concierge-bell" }); + // aclItems.push({ description: "Test Private", event: () => this.testAcl(SharingPermissions.None), icon: "concierge-bell" }); + // aclItems.push({ description: "Test Readonly", event: () => this.testAcl(SharingPermissions.View), icon: "concierge-bell" }); + // !existingAcls && cm.addItem({ description: "Privacy...", subitems: aclItems, icon: "question" }); + + // cm.addItem({ description: `${getPlaygroundMode() ? "Disable" : "Enable"} playground mode`, event: togglePlaygroundMode, icon: "concierge-bell" }); // const recommender_subitems: ContextMenuProps[] = []; diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 8ab4735a7..5dfc14a4a 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -109,7 +109,7 @@ const AclMap = new Map([ ]); export function fetchProto(doc: Doc) { - if (doc.author !== Doc.CurrentUserEmail) { // storing acls for groups needs to be extended here - AclSym should store a datastructure that stores information about permissions + if (doc.author !== Doc.CurrentUserEmail) { untracked(() => { const permissions: { [key: string]: symbol } = {}; -- cgit v1.2.3-70-g09d2