diff options
Diffstat (limited to 'src/client/util/SharingManager.tsx')
-rw-r--r-- | src/client/util/SharingManager.tsx | 289 |
1 files changed, 165 insertions, 124 deletions
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index 48a3c023f..6fdbac41b 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -1,30 +1,26 @@ -import { observable, runInAction, action } from "mobx"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { action, observable, runInAction } from "mobx"; +import { observer } from "mobx-react"; import * as React from "react"; -import MainViewModal from "../views/MainViewModal"; -import { Doc, Opt, AclAdmin, AclPrivate, DocListCast } from "../../fields/Doc"; -import { DocServer } from "../DocServer"; -import { Cast, StrCast } from "../../fields/Types"; +import Select from "react-select"; import * as RequestPromise from "request-promise"; +import { AclAdmin, AclPrivate, DataSym, Doc, DocListCast, Opt, AclSym } from "../../fields/Doc"; +import { List } from "../../fields/List"; +import { Cast, StrCast } from "../../fields/Types"; +import { distributeAcls, GetEffectiveAcl, SharingPermissions } from "../../fields/util"; import { Utils } from "../../Utils"; -import "./SharingManager.scss"; -import { observer } from "mobx-react"; -import * as fa from '@fortawesome/free-solid-svg-icons'; -import { DocumentView } from "../views/nodes/DocumentView"; -import { SelectionManager } from "./SelectionManager"; -import { DocumentManager } from "./DocumentManager"; +import { DocServer } from "../DocServer"; import { CollectionView } from "../views/collections/CollectionView"; 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"; -import { distributeAcls, SharingPermissions, GetEffectiveAcl } from "../../fields/util"; +import { MainViewModal } from "../views/MainViewModal"; +import { DocumentView } from "../views/nodes/DocumentView"; import { TaskCompletionBox } from "../views/nodes/TaskCompletedBox"; -import { library } from "@fortawesome/fontawesome-svg-core"; - -library.add(fa.faInfoCircle, fa.faCaretUp, fa.faCaretRight, fa.faCaretDown); - +import { DocumentManager } from "./DocumentManager"; +import { GroupManager, UserOptions } from "./GroupManager"; +import { GroupMemberView } from "./GroupMemberView"; +import "./SharingManager.scss"; +import { SelectionManager } from "./SelectionManager"; +import { intersection } from "lodash"; export interface User { email: string; @@ -47,6 +43,8 @@ interface GroupedOptions { const indType = "!indType/"; const groupType = "!groupType/"; +const storage = "data"; + /** * A user who also has a notificationDoc. */ @@ -55,10 +53,9 @@ interface ValidatedUser { notificationDoc: Doc; } -const storage = "data"; @observer -export default class SharingManager extends React.Component<{}> { +export class SharingManager extends React.Component<{}> { public static Instance: SharingManager; @observable private isOpen = false; // whether the SharingManager modal is open or not @observable private users: ValidatedUser[] = []; // the list of users with notificationDocs @@ -75,29 +72,28 @@ export default class SharingManager extends React.Component<{}> { // if both showUserOptions and showGroupOptions are false then both are displayed @observable private showUserOptions: boolean = false; // whether to show individuals as options when sharing (in the react-select component) @observable private showGroupOptions: boolean = false; // // whether to show groups as options when sharing (in the react-select component) - private populating: boolean = false; + private populating: boolean = false; // whether the list of users is populating or not + @observable private layoutDocAcls: boolean = false; // whether the layout doc or data doc's acls are to be used // private get linkVisible() { // return this.sharingDoc ? this.sharingDoc[PublicKey] !== SharingPermissions.None : false; // } - public open = (target: DocumentView) => { + public open = (target?: DocumentView, target_doc?: Doc) => { runInAction(() => this.users = []); - // SelectionManager.DeselectAll(); this.populateUsers(); runInAction(() => { this.targetDocView = target; - this.targetDoc = target.props.Document; + this.targetDoc = target_doc || target?.props.Document; DictationOverlay.Instance.hasActiveModal = true; - this.isOpen = true; + this.isOpen = this.targetDoc !== undefined; this.permissions = SharingPermissions.Edit; }); - this.targetDoc!.author === Doc.CurrentUserEmail && !this.targetDoc![`ACL-${Doc.CurrentUserEmail.replace(".", "_")}`] && distributeAcls(`ACL-${Doc.CurrentUserEmail.replace(".", "_")}`, SharingPermissions.Admin, this.targetDoc!); } public close = action(() => { this.isOpen = false; - this.selectedUsers = null; // resets the list of users and seleected users (in the react-select component) + this.selectedUsers = null; // resets the list of users and selected users (in the react-select component) TaskCompletionBox.taskCompleted = false; setTimeout(action(() => { // this.copied = false; @@ -119,7 +115,7 @@ export default class SharingManager extends React.Component<{}> { } /** - * Populates the list of validated users (this.users) by adding registered users which have a sidebar-sharing. + * Populates the list of validated users (this.users) by adding registered users which have a mySharedDocs. */ populateUsers = async () => { if (!this.populating) { @@ -132,7 +128,7 @@ export default class SharingManager extends React.Component<{}> { if (isCandidate) { const userDocument = await DocServer.GetRefField(user.userDocumentId); if (userDocument instanceof Doc) { - const notificationDoc = await Cast(userDocument["sidebar-sharing"], Doc); + const notificationDoc = await Cast(userDocument.mySharedDocs, Doc); runInAction(() => { if (notificationDoc instanceof Doc) { this.users.push({ user, notificationDoc }); @@ -151,20 +147,29 @@ export default class SharingManager extends React.Component<{}> { * @param permission */ setInternalGroupSharing = (group: Doc, permission: string, targetDoc?: Doc) => { - const members: string[] = JSON.parse(StrCast(group.members)); - const users: ValidatedUser[] = this.users.filter(({ user: { email } }) => members.includes(email)); const target = targetDoc || this.targetDoc!; - const ACL = `ACL-${StrCast(group.groupName)}`; + const key = StrCast(group.groupName).replace(".", "_"); + const ACL = `ACL-${key}`; + + const docs = SelectionManager.SelectedDocuments().length < 2 ? [target] : SelectionManager.SelectedDocuments().map(docView => docView.props.Document); + + docs.forEach(doc => { + doc.author === Doc.CurrentUserEmail && !doc[`ACL-${Doc.CurrentUserEmail.replace(".", "_")}`] && distributeAcls(`ACL-${Doc.CurrentUserEmail.replace(".", "_")}`, SharingPermissions.Admin, doc); + GetEffectiveAcl(doc) === AclAdmin && distributeAcls(ACL, permission as SharingPermissions, doc); - target.author === Doc.CurrentUserEmail && distributeAcls(ACL, permission as SharingPermissions, target); + if (key !== "Public") { + const members: string[] = JSON.parse(StrCast(group.members)); + const users: ValidatedUser[] = this.users.filter(({ user: { email } }) => members.includes(email)); - // if documents have been shared, add the target to that list if it doesn't already exist, otherwise create a new list with the target - group.docsShared ? Doc.IndexOf(target, DocListCast(group.docsShared)) === -1 && (group.docsShared as List<Doc>).push(target) : group.docsShared = new List<Doc>([target]); + // if documents have been shared, add the doc to that list if it doesn't already exist, otherwise create a new list with the doc + group.docsShared ? Doc.IndexOf(doc, DocListCast(group.docsShared)) === -1 && (group.docsShared as List<Doc>).push(doc) : group.docsShared = new List<Doc>([doc]); - users.forEach(({ notificationDoc }) => { - if (permission !== SharingPermissions.None) Doc.IndexOf(target, DocListCast(notificationDoc[storage])) === -1 && Doc.AddDocToList(notificationDoc, storage, target); // add the target to the notificationDoc if it hasn't already been added - else Doc.IndexOf(target, DocListCast(notificationDoc[storage])) !== -1 && Doc.RemoveDocFromList(notificationDoc, storage, target); // remove the target from the list if it already exists + users.forEach(({ user, notificationDoc }) => { + if (permission !== SharingPermissions.None) Doc.IndexOf(doc, DocListCast(notificationDoc[storage])) === -1 && Doc.AddDocToList(notificationDoc, storage, doc); // add the doc to the notificationDoc if it hasn't already been added + else GetEffectiveAcl(doc, undefined, user.email) === AclPrivate && Doc.IndexOf((doc.aliasOf as Doc || doc), DocListCast(notificationDoc[storage])) !== -1 && Doc.RemoveDocFromList(notificationDoc, storage, (doc.aliasOf as Doc || doc)); // remove the doc from the list if it already exists + }); + } }); } @@ -175,17 +180,25 @@ export default class SharingManager extends React.Component<{}> { */ shareWithAddedMember = (group: Doc, emailId: string) => { const user: ValidatedUser = this.users.find(({ user: { email } }) => email === emailId)!; - if (group.docsShared) DocListCast(group.docsShared).forEach(doc => Doc.IndexOf(doc, DocListCast(user.notificationDoc[storage])) === -1 && Doc.AddDocToList(user.notificationDoc, storage, doc)); } /** * Called from the properties sidebar to change permissions of a user. */ - shareFromPropertiesSidebar = (shareWith: string, permission: SharingPermissions, target: Doc) => { - const user = this.users.find(({ user: { email } }) => email === (shareWith === "Me" ? Doc.CurrentUserEmail : shareWith)); - if (user) this.setInternalSharing(user, permission, target); - else this.setInternalGroupSharing(GroupManager.Instance.getGroup(shareWith)!, permission, target); + shareFromPropertiesSidebar = (shareWith: string, permission: SharingPermissions, docs: Doc[]) => { + if (shareWith !== "Public") { + const user = this.users.find(({ user: { email } }) => email === (shareWith === "Me" ? Doc.CurrentUserEmail : shareWith)); + docs.forEach(doc => { + if (user) this.setInternalSharing(user, permission, doc); + else this.setInternalGroupSharing(GroupManager.Instance.getGroup(shareWith)!, permission, doc); + }); + } + else { + docs.forEach(doc => { + if (GetEffectiveAcl(doc) === AclAdmin) distributeAcls("ACL-Public", permission, doc); + }); + } } /** @@ -231,14 +244,16 @@ export default class SharingManager extends React.Component<{}> { const key = user.email.replace('.', '_'); const ACL = `ACL-${key}`; - target.author === Doc.CurrentUserEmail && distributeAcls(ACL, permission as SharingPermissions, 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); - } + const docs = SelectionManager.SelectedDocuments().length < 2 ? [target] : SelectionManager.SelectedDocuments().map(docView => docView.props.Document); + + docs.forEach(doc => { + doc.author === Doc.CurrentUserEmail && !doc[`ACL-${Doc.CurrentUserEmail.replace(".", "_")}`] && distributeAcls(`ACL-${Doc.CurrentUserEmail.replace(".", "_")}`, SharingPermissions.Admin, doc); + GetEffectiveAcl(doc) === AclAdmin && distributeAcls(ACL, permission as SharingPermissions, doc); + + if (permission !== SharingPermissions.None) Doc.IndexOf(doc, DocListCast(notificationDoc[storage])) === -1 && Doc.AddDocToList(notificationDoc, storage, doc); + else GetEffectiveAcl(doc, undefined, user.email) === AclPrivate && Doc.IndexOf((doc.aliasOf as Doc || doc), DocListCast(notificationDoc[storage])) !== -1 && Doc.RemoveDocFromList(notificationDoc, storage, (doc.aliasOf as Doc || doc)); + }); } @@ -268,8 +283,10 @@ export default class SharingManager extends React.Component<{}> { /** * Returns the SharingPermissions (Admin, Can Edit etc) access that's used to share */ - private get sharingOptions() { - return Object.values(SharingPermissions).map(permission => + private sharingOptions(uniform: boolean) { + const dropdownValues: string[] = Object.values(SharingPermissions); + if (!uniform) dropdownValues.unshift("-multiple-"); + return dropdownValues.map(permission => ( <option key={permission} value={permission}> {permission} @@ -280,27 +297,30 @@ export default class SharingManager extends React.Component<{}> { private focusOn = (contents: string) => { const title = this.targetDoc ? StrCast(this.targetDoc.title) : ""; + const docs = SelectionManager.SelectedDocuments().length > 1 ? SelectionManager.SelectedDocuments().map(docView => docView.props.Document) : [this.targetDoc]; return ( <span className={"focus-span"} title={title} onClick={() => { let context: Opt<CollectionView>; - if (this.targetDoc && this.targetDocView && (context = this.targetDocView.props.ContainingCollectionView)) { + if (this.targetDoc && this.targetDocView && docs.length === 1 && (context = this.targetDocView.props.ContainingCollectionView)) { DocumentManager.Instance.jumpToDocument(this.targetDoc, true, undefined, context.props.Document); } }} onPointerEnter={action(() => { - if (this.targetDoc) { - Doc.BrushDoc(this.targetDoc); + if (docs.length) { + docs.forEach(doc => doc && Doc.BrushDoc(doc)); this.dialogueBoxOpacity = 0.1; this.overlayOpacity = 0.1; } })} onPointerLeave={action(() => { - this.targetDoc && Doc.UnBrushDoc(this.targetDoc); - this.dialogueBoxOpacity = 1; - this.overlayOpacity = 0.4; + if (docs.length) { + docs.forEach(doc => doc && Doc.UnBrushDoc(doc)); + this.dialogueBoxOpacity = 1; + this.overlayOpacity = 0.4; + } })} > {contents} @@ -372,8 +392,8 @@ export default class SharingManager extends React.Component<{}> { * @returns the main interface of the SharingManager. */ private get sharingInterface() { - const groupList = GroupManager.Instance?.getAllGroups() || []; + const groupList = GroupManager.Instance?.getAllGroups() || []; const sortedUsers = this.users.slice().sort(this.sortUsers) .map(({ user: { email } }) => ({ label: email, value: indType + email })); const sortedGroups = groupList.slice().sort(this.sortGroups) @@ -406,30 +426,42 @@ export default class SharingManager extends React.Component<{}> { } } - 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 users = this.individualSort === "ascending" ? this.users.slice().sort(this.sortUsers) : this.individualSort === "descending" ? this.users.slice().sort(this.sortUsers).reverse() : this.users; + const groups = this.groupSort === "ascending" ? groupList.slice().sort(this.sortGroups) : this.groupSort === "descending" ? groupList.slice().sort(this.sortGroups).reverse() : groupList; + + // handles the case where multiple documents are selected + const docs = SelectionManager.SelectedDocuments().length < 2 ? + [this.layoutDocAcls ? this.targetDoc : this.targetDoc?.[DataSym]] + : SelectionManager.SelectedDocuments().map(docView => this.layoutDocAcls ? docView.props.Document : docView.props.Document?.[DataSym]); + + const targetDoc = docs[0]; + + // tslint:disable-next-line: no-unnecessary-callback-wrapper + const admin = docs.map(doc => GetEffectiveAcl(doc)).every(acl => acl === AclAdmin); // if the user has admin access to all selected docs - const effectiveAcl = this.targetDoc ? GetEffectiveAcl(this.targetDoc) : AclPrivate; + // users in common between all docs + const commonKeys = intersection(...docs.map(doc => this.layoutDocAcls ? doc?.[AclSym] && Object.keys(doc[AclSym]) : doc?.[DataSym]?.[AclSym] && Object.keys(doc[DataSym][AclSym]))); // the list of users shared with - const userListContents: (JSX.Element | null)[] = users.map(({ user, notificationDoc }) => { - const userKey = user.email.replace('.', '_'); - const permissions = StrCast(this.targetDoc?.[`ACL-${userKey}`]); + const userListContents: (JSX.Element | null)[] = users.filter(({ user }) => docs.length > 1 ? commonKeys.includes(`ACL-${user.email.replace('.', '_')}`) : true).map(({ user, notificationDoc }) => { + const userKey = `ACL-${user.email.replace('.', '_')}`; + const uniform = docs.every(doc => this.layoutDocAcls ? doc?.[AclSym]?.[userKey] === docs[0]?.[AclSym]?.[userKey] : doc?.[DataSym]?.[AclSym]?.[userKey] === docs[0]?.[DataSym]?.[AclSym]?.[userKey]); + const permissions = uniform ? StrCast(targetDoc?.[userKey]) : "-multiple-"; - return !permissions || user.email === this.targetDoc?.author ? null : ( + return !permissions ? (null) : ( <div key={userKey} className={"container"} > <span className={"padding"}>{user.email}</span> <div className="edit-actions"> - {effectiveAcl === AclAdmin ? ( + {admin ? ( <select className={"permissions-dropdown"} value={permissions} onChange={e => this.setInternalSharing({ user, notificationDoc }, e.currentTarget.value)} > - {this.sharingOptions} + {this.sharingOptions(uniform)} </select> ) : ( <div className={"permissions-dropdown"}> @@ -441,22 +473,26 @@ export default class SharingManager extends React.Component<{}> { ); }); + // checks if every doc has the same author + const sameAuthor = docs.every(doc => doc?.author === docs[0]?.author); + // the owner of the doc and the current user are placed at the top of the user list. userListContents.unshift( - ( - <div - key={"owner"} - className={"container"} - > - <span className={"padding"}>{this.targetDoc?.author === Doc.CurrentUserEmail ? "Me" : this.targetDoc?.author}</span> - <div className="edit-actions"> - <div className={"permissions-dropdown"}> - Owner + sameAuthor ? + ( + <div + key={"owner"} + className={"container"} + > + <span className={"padding"}>{targetDoc?.author === Doc.CurrentUserEmail ? "Me" : targetDoc?.author}</span> + <div className="edit-actions"> + <div className={"permissions-dropdown"}> + Owner + </div> </div> </div> - </div> - ), - this.targetDoc?.author !== Doc.CurrentUserEmail ? + ) : null, + sameAuthor && targetDoc?.author !== Doc.CurrentUserEmail ? ( <div key={"me"} @@ -465,42 +501,54 @@ export default class SharingManager extends React.Component<{}> { <span className={"padding"}>Me</span> <div className="edit-actions"> <div className={"permissions-dropdown"}> - {this.targetDoc?.[`ACL-${Doc.CurrentUserEmail.replace(".", "_")}`]} + {targetDoc?.[`ACL-${Doc.CurrentUserEmail.replace(".", "_")}`]} </div> </div> </div> ) : null ); + // dummy doc for public acl + const publicDoc = new Doc; + publicDoc.groupName = "Public"; // the list of groups shared with - const groupListContents = groups.map(group => { - const permissions = StrCast(this.targetDoc?.[`ACL-${StrCast(group.groupName)}`]); - - return !permissions ? null : ( + const groupListMap = groups.filter(({ groupName }) => docs.length > 1 ? commonKeys.includes(`ACL-${StrCast(groupName).replace('.', '_')}`) : true); + groupListMap.unshift(publicDoc); + const groupListContents = groupListMap.map(group => { + const groupKey = `ACL-${StrCast(group.groupName)}`; + const uniform = docs.every(doc => this.layoutDocAcls ? doc?.[AclSym]?.[groupKey] === docs[0]?.[AclSym]?.[groupKey] : doc?.[DataSym]?.[AclSym]?.[groupKey] === docs[0]?.[DataSym]?.[AclSym]?.[groupKey]); + const permissions = uniform ? StrCast(targetDoc?.[`ACL-${StrCast(group.groupName)}`]) : "-multiple-"; + + return !permissions ? (null) : ( <div - key={StrCast(group.groupName)} + key={groupKey} className={"container"} > <div className={"padding"}>{group.groupName}</div> - <div className="group-info" onClick={action(() => GroupManager.Instance.currentGroup = group)}> - <FontAwesomeIcon icon={fa.faInfoCircle} color={"#e8e8e8"} size={"sm"} style={{ backgroundColor: "#1e89d7", borderRadius: "100%", border: "1px solid #1e89d7" }} /> - </div> + {group.groupName !== "Public" ? + (<div className="group-info" onClick={action(() => GroupManager.Instance.currentGroup = group)}> + <FontAwesomeIcon icon={"info-circle"} color={"#e8e8e8"} size={"sm"} style={{ backgroundColor: "#1e89d7", borderRadius: "100%", border: "1px solid #1e89d7" }} /> + </div>) + : (null)} <div className="edit-actions"> - <select - className={"permissions-dropdown"} - value={permissions} - onChange={e => this.setInternalGroupSharing(group, e.currentTarget.value)} - > - {this.sharingOptions} - </select> + {admin ? ( + <select + className={"permissions-dropdown"} + value={permissions} + onChange={e => this.setInternalGroupSharing(group, e.currentTarget.value)} + > + {this.sharingOptions(uniform)} + </select> + ) : ( + <div className={"permissions-dropdown"}> + {permissions} + </div> + )} </div> </div> ); }); - // don't display the group list if all groups are null - const displayGroupList = !groupListContents?.every(group => group === null); - return ( <div className={"sharing-interface"}> {GroupManager.Instance?.currentGroup ? @@ -519,7 +567,7 @@ export default class SharingManager extends React.Component<{}> { style={{ backgroundColor: this.copied ? "lawngreen" : "gainsboro" }} onClick={this.copy} > - <FontAwesomeIcon icon={fa.faCopy} /> + <FontAwesomeIcon icon={"copy"} /> </div> </div> } @@ -540,7 +588,7 @@ export default class SharingManager extends React.Component<{}> { </div> <div className={"hr-substitute"} /> */} <div className="sharing-contents"> - <p className={"share-title"}><b>Share </b>{this.focusOn(StrCast(this.targetDoc?.title, "this document"))}</p> + <p className={"share-title"}><b>Share </b>{this.focusOn(docs.length < 2 ? StrCast(targetDoc?.title, "this document") : "-multiple-")}</p> <div className={"close-button"} onClick={this.close}> <FontAwesomeIcon icon={"times"} color={"black"} size={"lg"} /> </div> @@ -561,7 +609,7 @@ export default class SharingManager extends React.Component<{}> { }} /> <select className="permissions-select" onChange={this.handlePermissionsChange} value={this.permissions}> - {this.sharingOptions} + {this.sharingOptions(true)} </select> <button ref={this.shareDocumentButtonRef} className="share-button" onClick={this.share}> Share @@ -571,6 +619,9 @@ export default class SharingManager extends React.Component<{}> { <input type="checkbox" onChange={action(() => this.showUserOptions = !this.showUserOptions)} /> <label style={{ marginRight: 10 }}>Individuals</label> <input type="checkbox" onChange={action(() => this.showGroupOptions = !this.showGroupOptions)} /> <label>Groups</label> </div> + <div className="layoutDoc-acls"> + <input type="checkbox" onChange={action(() => this.layoutDocAcls = !this.layoutDocAcls)} checked={this.layoutDocAcls} /> <label>Layout</label> + </div> </div> } <div className="main-container"> @@ -578,11 +629,11 @@ export default class SharingManager extends React.Component<{}> { <div className="user-sort" onClick={action(() => this.individualSort = this.individualSort === "ascending" ? "descending" : this.individualSort === "descending" ? "none" : "ascending")}> - Individuals {this.individualSort === "ascending" ? <FontAwesomeIcon icon={fa.faCaretUp} size={"xs"} /> - : this.individualSort === "descending" ? <FontAwesomeIcon icon={fa.faCaretDown} size={"xs"} /> - : <FontAwesomeIcon icon={fa.faCaretRight} size={"xs"} />} + Individuals {this.individualSort === "ascending" ? <FontAwesomeIcon icon={"caret-up"} size={"xs"} /> + : this.individualSort === "descending" ? <FontAwesomeIcon icon={"caret-down"} size={"xs"} /> + : <FontAwesomeIcon icon={"caret-right"} size={"xs"} />} </div> - <div className={"users-list"} style={{ display: "block" }}>{/*200*/} + <div className={"users-list"}> {userListContents} </div> </div> @@ -590,23 +641,13 @@ export default class SharingManager extends React.Component<{}> { <div className="user-sort" onClick={action(() => this.groupSort = this.groupSort === "ascending" ? "descending" : this.groupSort === "descending" ? "none" : "ascending")}> - Groups {this.groupSort === "ascending" ? <FontAwesomeIcon icon={fa.faCaretUp} size={"xs"} /> - : this.groupSort === "descending" ? <FontAwesomeIcon icon={fa.faCaretDown} size={"xs"} /> - : <FontAwesomeIcon icon={fa.faCaretRight} size={"xs"} />} + Groups {this.groupSort === "ascending" ? <FontAwesomeIcon icon={"caret-up"} size={"xs"} /> + : this.groupSort === "descending" ? <FontAwesomeIcon icon={"caret-down"} size={"xs"} /> + : <FontAwesomeIcon icon={"caret-right"} size={"xs"} />} </div> - <div className={"groups-list"} style={{ display: !displayGroupList ? "flex" : "block" }}>{/*200*/} - { - !displayGroupList ? - <div - className={"none"} - > - There are no groups this document has been shared with. - </div> - : - groupListContents - } - + <div className={"groups-list"}> + {groupListContents} </div> </div> </div> |