diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/util/CurrentUserUtils.ts | 51 | ||||
-rw-r--r-- | src/client/util/GroupManager.tsx | 2 | ||||
-rw-r--r-- | src/client/util/SharingManager.tsx | 29 | ||||
-rw-r--r-- | src/client/views/MainView.tsx | 338 | ||||
-rw-r--r-- | src/client/views/collections/CollectionStackingView.tsx | 1 | ||||
-rw-r--r-- | src/client/views/collections/CollectionStackingViewFieldColumn.tsx | 2 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/PropertiesView.scss | 2 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/PropertiesView.tsx | 56 | ||||
-rw-r--r-- | src/client/views/nodes/ContentFittingDocumentView.tsx | 3 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 1 | ||||
-rw-r--r-- | src/client/views/nodes/FieldView.tsx | 1 | ||||
-rw-r--r-- | src/client/views/nodes/MenuIconBox.tsx | 22 | ||||
-rw-r--r-- | src/fields/util.ts | 12 |
13 files changed, 256 insertions, 264 deletions
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 442be98d2..725be882e 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -48,8 +48,6 @@ export class CurrentUserUtils { @observable public static closedStack: any | undefined; @observable public static searchStack: any | undefined; - @observable public static panelContent: string = "none"; - // sets up the default User Templates - slideView, queryView, descriptionView static setupUserTemplateButtons(doc: Doc) { if (doc["template-button-query"] === undefined) { @@ -508,46 +506,39 @@ export class CurrentUserUtils { title: string, icon: string, click: string, }[] { return [ - { title: "Workspace", icon: "desktop", click: 'scriptContext.selectMenu("workspace")' }, - { title: "Catalog", icon: "file", click: 'scriptContext.selectMenu("catalog")' }, + { title: "Workspace", icon: "desktop", click: 'scriptContext.selectMenu("Workspace")' }, + { title: "Catalog", icon: "file", click: 'scriptContext.selectMenu("Catalog")' }, { title: "Archive", icon: "archive", click: 'scriptContext.selectMenu("deleted")' }, - { title: "Import", icon: "upload", click: 'scriptContext.selectMenu("upload")' }, - { title: "Sharing", icon: "users", click: 'GroupManager.Instance.open()' }, - { title: "Tools", icon: "wrench", click: 'scriptContext.selectMenu("tools")' }, - { title: "Help", icon: "question-circle", click: 'scriptContext.selectMenu("help")' }, + { title: "Import", icon: "upload", click: 'scriptContext.selectMenu("Import")' }, + { title: "Sharing", icon: "users", click: 'scriptContext.groupManager.open()' }, + { title: "Tools", icon: "wrench", click: 'scriptContext.selectMenu("Tools")' }, + { title: "Help", icon: "question-circle", click: 'scriptContext.selectMenu("Help")' }, { title: "Settings", icon: "cog", click: 'SettingsManager.Instance.open()' }, ]; } - static setupMenuButtons(doc: Doc) { - if (doc.menuStackBtns === undefined) { + static setupMenuPanel(doc: Doc) { + if (doc.menuStack === undefined) { const buttons = CurrentUserUtils.menuBtnDescriptions(); const menuBtns = buttons.map(({ title, icon, click }) => Docs.Create.MenuIconDocument({ icon, title, + _backgroundColor: "black", stayInCollection: true, _width: 60, - _height: 70, - onClick: ScriptField.MakeScript(click), + _height: 60, + onClick: ScriptField.MakeScript(click, { scriptContext: "any" }), })); - doc.menuStackBtns = new PrefetchProxy(Docs.Create.MasonryDocument(menuBtns, { - _xMargin: 0, _autoHeight: false, _width: 60, _columnWidth: 60, lockedPosition: true, _chromeStatus: "disabled", + doc.menuStack = new PrefetchProxy(Docs.Create.StackingDocument(menuBtns, { + title: "menuItemPanel", + _backgroundColor: "black", + _gridGap: 0, + _yMargin: 0, + _yPadding: 0, _xMargin: 0, _autoHeight: false, _width: 60, _columnWidth: 60, lockedPosition: true, _chromeStatus: "disabled", })); } - return doc.menuStackBtns as Doc; - } - - static setupMenuPanel(doc: Doc) { - doc.menuStack = undefined; - if (doc.menuStack === undefined) { - const menuBtns = CurrentUserUtils.setupMenuButtons(doc); - doc.menuStack = new PrefetchProxy(Docs.Create.StackingDocument([menuBtns], { - _yMargin: 0, _autoHeight: true, _xMargin: 0, - _width: 60, lockedPosition: true, _chromeStatus: "disabled", - })) as any as Doc; - } - return doc.menuStack; + return doc.menuStack as Doc; } @@ -696,9 +687,9 @@ export class CurrentUserUtils { onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel"), })); } - (doc["tabs-button-tools"] as Doc).sourcePanel; // prefetch sourcePanel + (doc["tabs-button-tools"] as any as Doc).sourcePanel; // prefetch sourcePanel - return doc["tabs-button-tools"] as Doc; + return doc["tabs-button-tools"] as any as Doc; } static setupWorkspaces(doc: Doc) { @@ -808,7 +799,7 @@ export class CurrentUserUtils { })); CurrentUserUtils.searchStack = new PrefetchProxy(Docs.Create.QueryDocument({ title: "search stack", })) as any as Doc; } - return doc["tabs-button-search"] as Doc; + return doc["tabs-button-search"] as any as Doc; } static setupSidebarContainer(doc: Doc) { diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index 72fba5c1b..dee0f105f 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -101,7 +101,7 @@ export default class GroupManager extends React.Component<{}> { */ @action open = () => { - SelectionManager.DeselectAll(); + // SelectionManager.DeselectAll(); this.isOpen = true; this.populateUsers(); this.populateGroups(); diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index 0d8b33fbe..9222f10c5 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -62,14 +62,12 @@ export default class SharingManager extends React.Component<{}> { @observable private groupSort: "ascending" | "descending" | "none" = "none"; private shareDocumentButtonRef: React.RefObject<HTMLButtonElement> = React.createRef(); - - // private get linkVisible() { // return this.sharingDoc ? this.sharingDoc[PublicKey] !== SharingPermissions.None : false; // } public open = (target: DocumentView) => { - SelectionManager.DeselectAll(); + // SelectionManager.DeselectAll(); this.populateUsers().then(action(() => { this.targetDocView = target; this.targetDoc = target.props.Document; @@ -82,7 +80,7 @@ export default class SharingManager extends React.Component<{}> { public close = action(() => { this.isOpen = false; - this.users = []; + // this.users = []; this.selectedUsers = null; setTimeout(action(() => { @@ -97,7 +95,12 @@ export default class SharingManager extends React.Component<{}> { SharingManager.Instance = this; } + componentDidMount() { + this.populateUsers(); + } + 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 => { @@ -117,17 +120,17 @@ export default class SharingManager extends React.Component<{}> { return Promise.all(evaluating); } - setInternalGroupSharing = (group: Doc, permission: string) => { + 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 = this.targetDoc!; + const target = targetDoc || this.targetDoc!; const ACL = `ACL-${StrCast(group.groupName)}`; // fix this - not needed (here and setinternalsharing and removegroup) // target[ACL] = permission; // Doc.GetProto(target)[ACL] = permission; - distributeAcls(ACL, permission as SharingPermissions, this.targetDoc!); + distributeAcls(ACL, permission as SharingPermissions, target); group.docsShared ? DocListCastAsync(group.docsShared).then(resolved => Doc.IndexOf(target, resolved!) === -1 && (group.docsShared as List<Doc>).push(target)) : group.docsShared = new List<Doc>([target]); @@ -182,14 +185,20 @@ export default class SharingManager extends React.Component<{}> { } } + 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); + } + // @action - setInternalSharing = (recipient: ValidatedUser, permission: string) => { + setInternalSharing = (recipient: ValidatedUser, permission: string, targetDoc?: Doc) => { const { user, notificationDoc } = recipient; - const target = this.targetDoc!; + const target = targetDoc || this.targetDoc!; const key = user.email.replace('.', '_'); const ACL = `ACL-${key}`; - distributeAcls(ACL, permission as SharingPermissions, this.targetDoc!); + distributeAcls(ACL, permission as SharingPermissions, target); if (permission !== SharingPermissions.None) { DocListCastAsync(notificationDoc[storage]).then(resolved => { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 9bad0867c..ec0bff8a7 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -1,7 +1,6 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { faHireAHelper } from '@fortawesome/free-brands-svg-icons'; import * as fa from '@fortawesome/free-solid-svg-icons'; -import { ANTIMODEMENU_HEIGHT } from './globalCssVariables.scss'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, configure, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; @@ -12,58 +11,54 @@ import { Doc, DocListCast, Field, Opt } from '../../fields/Doc'; import { Id } from '../../fields/FieldSymbols'; import { List } from '../../fields/List'; import { listSpec } from '../../fields/Schema'; -import { BoolCast, Cast, FieldValue, StrCast, NumCast } from '../../fields/Types'; +import { ScriptField } from '../../fields/ScriptField'; +import { BoolCast, Cast, FieldValue, StrCast } from '../../fields/Types'; import { TraceMobx } from '../../fields/util'; -import { CurrentUserUtils } from '../util/CurrentUserUtils'; -import { emptyFunction, emptyPath, returnFalse, returnOne, returnZero, returnTrue, Utils, returnEmptyFilter, setupMoveUpEvents } from '../../Utils'; +import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, Utils } from '../../Utils'; import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager'; +import HypothesisAuthenticationManager from '../apis/HypothesisAuthenticationManager'; import { DocServer } from '../DocServer'; import { Docs, DocumentOptions } from '../documents/Documents'; import { DocumentType } from '../documents/DocumentTypes'; +import { CurrentUserUtils } from '../util/CurrentUserUtils'; +import { DocumentManager } from '../util/DocumentManager'; +import GroupManager from '../util/GroupManager'; import { HistoryUtil } from '../util/History'; -import RichTextMenu from './nodes/formattedText/RichTextMenu'; import { Scripting } from '../util/Scripting'; +import { SelectionManager } from '../util/SelectionManager'; import SettingsManager from '../util/SettingsManager'; -import GroupManager from '../util/GroupManager'; import SharingManager from '../util/SharingManager'; +import { SnappingManager } from '../util/SnappingManager'; import { Transform } from '../util/Transform'; +import { TimelineMenu } from './animationtimeline/TimelineMenu'; import { CollectionDockingView } from './collections/CollectionDockingView'; +import FormatShapePane from "./collections/collectionFreeForm/FormatShapePane"; import MarqueeOptionsMenu from './collections/collectionFreeForm/MarqueeOptionsMenu'; +import { PropertiesView } from './collections/collectionFreeForm/PropertiesView'; import { CollectionLinearView } from './collections/CollectionLinearView'; +import CollectionMenu from './collections/CollectionMenu'; import { CollectionView, CollectionViewType } from './collections/CollectionView'; import { ContextMenu } from './ContextMenu'; import { DictationOverlay } from './DictationOverlay'; import { DocumentDecorations } from './DocumentDecorations'; import GestureOverlay from './GestureOverlay'; +import { ANTIMODEMENU_HEIGHT } from './globalCssVariables.scss'; import KeyManager from './GlobalKeyHandler'; +import { LinkMenu } from './linking/LinkMenu'; import "./MainView.scss"; import { MainViewNotifs } from './MainViewNotifs'; import { AudioBox } from './nodes/AudioBox'; +import { DocumentLinksButton } from './nodes/DocumentLinksButton'; import { DocumentView } from './nodes/DocumentView'; +import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; +import RichTextMenu from './nodes/formattedText/RichTextMenu'; +import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup'; +import { LinkDocPreview } from './nodes/LinkDocPreview'; import { RadialMenu } from './nodes/RadialMenu'; +import { TaskCompletionBox } from './nodes/TaskCompletedBox'; import { OverlayView } from './OverlayView'; import PDFMenu from './pdf/PDFMenu'; import { PreviewCursor } from './PreviewCursor'; -import { ScriptField, ComputedField } from '../../fields/ScriptField'; -import { TimelineMenu } from './animationtimeline/TimelineMenu'; -import { SnappingManager } from '../util/SnappingManager'; -import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; -import { DocumentManager } from '../util/DocumentManager'; -import { DocumentLinksButton } from './nodes/DocumentLinksButton'; -import { LinkMenu } from './linking/LinkMenu'; -import { LinkDocPreview } from './nodes/LinkDocPreview'; -import { TaskCompletionBox } from './nodes/TaskCompletedBox'; -import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup'; -import FormatShapePane from "./collections/collectionFreeForm/FormatShapePane"; -import HypothesisAuthenticationManager from '../apis/HypothesisAuthenticationManager'; -import CollectionMenu from './collections/CollectionMenu'; -import { Tooltip, AccordionActions } from '@material-ui/core'; -import { PropertiesView } from './collections/collectionFreeForm/PropertiesView'; -import { SelectionManager } from '../util/SelectionManager'; -import { PrefetchProxy } from '../../fields/Proxy'; -import { DragManager } from '../util/DragManager'; -import { discovery_v1, dialogflow_v2beta1 } from 'googleapis'; -import { undo } from 'prosemirror-history'; import { undoBatch } from '../util/UndoManager'; @observer @@ -314,9 +309,11 @@ export class MainView extends React.Component { getPHeight = () => this._panelHeight; getContentsHeight = () => this._panelHeight - this._buttonBarHeight; - defaultBackgroundColors = (doc: Doc) => { + defaultBackgroundColors = (doc: Opt<Doc>) => { + if (this.panelContent === doc?.title) return "lightgrey"; if (this.darkScheme) { switch (doc?.type) { + case DocumentType.MENUICON: return "white"; case DocumentType.RTF || DocumentType.LABEL || DocumentType.BUTTON: return "#2d2d2d"; case DocumentType.LINK: case DocumentType.COL: { @@ -326,6 +323,7 @@ export class MainView extends React.Component { } } else { switch (doc?.type) { + case DocumentType.MENUICON: return "black"; case DocumentType.RTF: return "#f1efeb"; case DocumentType.BUTTON: case DocumentType.LABEL: return "lightgray"; @@ -384,7 +382,6 @@ export class MainView extends React.Component { onPointerDown = (e: React.PointerEvent) => { if (this._flyoutTranslate) { this.panelContent = "none"; - CurrentUserUtils.panelContent = "none"; this._canClick = true; this._flyoutSizeOnDown = e.clientX; document.removeEventListener("pointermove", this.onPointerMove); @@ -431,9 +428,7 @@ export class MainView extends React.Component { @computed get closePosition() { return 55 + this.flyoutWidth } @computed get flyout() { - if (!(this.sidebarContent instanceof Doc)) { - return (null); - } + if (!this.sidebarContent) return null; return <div className="mainView-libraryFlyout"> <div className="mainView-contentArea" style={{ position: "relative", height: `100%`, width: "100%", overflow: "visible" }}> {this.flyoutWidth > 0 ? <div className="mainView-libraryFlyout-close" @@ -472,147 +467,125 @@ export class MainView extends React.Component { {this.docButtons}</div>; } - // @computed get menuPanel() { - - // return <div className="mainView-menuPanel"> - // <DocumentView - // Document={Doc.UserDoc().menuStack as Doc} - // DataDoc={undefined} - // LibraryPath={emptyPath} - // addDocument={undefined} - // addDocTab={this.addDocTabFunc} - // pinToPres={emptyFunction} - // NativeHeight={returnZero} - // NativeWidth={returnZero} - // rootSelected={returnTrue} - // removeDocument={returnFalse} - // onClick={undefined} - // ScreenToLocalTransform={this.mainContainerXf} - // ContentScaling={returnOne} - // PanelWidth={() => 80} - // PanelHeight={this.getContentsHeight} - // renderDepth={0} - // focus={emptyFunction} - // backgroundColor={this.defaultBackgroundColors} - // parentActive={returnTrue} - // whenActiveChanged={emptyFunction} - // bringToFront={emptyFunction} - // docFilters={returnEmptyFilter} - // ContainingCollectionView={undefined} - // ContainingCollectionDoc={undefined} - // relative={true} - // scriptContext={this} - // /> - // </div>; - // } - @computed get menuPanel() { - return <div className="mainView-menuPanel"> - <div className="mainView-menuPanel-button" style={{ backgroundColor: this.panelContent === "workspace" ? "lightgrey" : "" }}> - <div className="mainView-menuPanel-button-wrap" - style={{ backgroundColor: this.panelContent === "workspace" ? "lightgrey" : "" }} - onPointerDown={e => this.selectPanel("workspace")}> - <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="desktop" - color={this.panelContent === "workspace" ? "black" : "white"} size="lg" /> - <div className="mainView-menuPanel-button-label" - style={{ color: this.panelContent === "workspace" ? "black" : "white" }}> Workspace </div> - </div> - </div> - - <div className="mainView-menuPanel-button" style={{ backgroundColor: this.panelContent === "catalog" ? "lightgrey" : "" }}> - <div className="mainView-menuPanel-button-wrap" - style={{ backgroundColor: this.panelContent === "catalog" ? "lightgrey" : "" }} - onPointerDown={e => this.selectPanel("catalog")}> - <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="file" - color={this.panelContent === "catalog" ? "black" : "white"} size="lg" /> - <div className="mainView-menuPanel-button-label" - style={{ color: this.panelContent === "catalog" ? "black" : "white" }}> Catalog </div> - </div> - </div> - - <div className="mainView-menuPanel-button" style={{ backgroundColor: this.panelContent === "deleted" ? "lightgrey" : "" }}> - <div className="mainView-menuPanel-button-wrap" - style={{ backgroundColor: this.panelContent === "deleted" ? "lightgrey" : "" }} - onPointerDown={e => this.selectPanel("deleted")}> - <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="archive" - color={this.panelContent === "deleted" ? "black" : "white"} size="lg" /> - <div className="mainView-menuPanel-button-label" - style={{ color: this.panelContent === "deleted" ? "black" : "white" }}> Recently Used </div> - </div> - </div> - - <div className="mainView-menuPanel-button"> - <div className="mainView-menuPanel-button-wrap" - onPointerDown={e => this.selectPanel("upload")}> - <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="upload" color="white" size="lg" /> - <div className="mainView-menuPanel-button-label"> Import </div> - </div> - </div> - <div className="mainView-menuPanel-button"> - <div className="mainView-menuPanel-button-wrap" - //onPointerDown={e => this.selectPanel("sharing")} - onClick={() => GroupManager.Instance.open()}> - <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="users" color="white" size="lg" /> - <div className="mainView-menuPanel-button-label"> Sharing </div> - </div> - </div> - - <div className="mainView-menuPanel-button" style={{ marginBottom: "110px", backgroundColor: this.panelContent === "tools" ? "lightgrey" : "", }}> - <div className="mainView-menuPanel-button-wrap" - onPointerDown={e => this.selectPanel("tools")} - style={{ - backgroundColor: this.panelContent === "tools" ? "lightgrey" : "", - }}> - <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="wrench" - color={this.panelContent === "tools" ? "black" : "white"} size="lg" /> - <div className="mainView-menuPanel-button-label" - style={{ color: this.panelContent === "tools" ? "black" : "white" }}> Tools </div> - </div> - </div> - - <div className="mainView-menuPanel-button"> - <div className="mainView-menuPanel-button-wrap" - // style={{backgroundColor: this.panelContent= "help" ? "lightgrey" : "black"}} - onPointerDown={e => this.selectPanel("help")} > - <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="question-circle" color="white" size="lg" /> - <div className="mainView-menuPanel-button-label"> Help </div> - </div> - </div> - - <div className="mainView-menuPanel-button"> - <div className="mainView-menuPanel-button-wrap" - // onPointerDown={e => this.selectPanel("settings")} - onClick={() => SettingsManager.Instance.open()}> - <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="cog" color="white" size="lg" /> - <div className="mainView-menuPanel-button-label"> Settings </div> - </div> - </div> + return <div className="mainView-menuPanel"> + <DocumentView + Document={Doc.UserDoc().menuStack as Doc} + DataDoc={undefined} + LibraryPath={emptyPath} + addDocument={undefined} + addDocTab={this.addDocTabFunc} + pinToPres={emptyFunction} + NativeHeight={returnZero} + NativeWidth={returnZero} + rootSelected={returnTrue} + removeDocument={returnFalse} + onClick={undefined} + ScreenToLocalTransform={this.mainContainerXf} + ContentScaling={returnOne} + PanelWidth={() => 80} + PanelHeight={this.getContentsHeight} + renderDepth={0} + focus={emptyFunction} + backgroundColor={this.defaultBackgroundColors} + parentActive={returnTrue} + whenActiveChanged={emptyFunction} + bringToFront={emptyFunction} + docFilters={returnEmptyFilter} + ContainingCollectionView={undefined} + ContainingCollectionDoc={undefined} + relative={true} + scriptContext={this} + /> </div>; } - @action @undoBatch - selectPanel = (str: string) => { - if (this.panelContent === str && this.flyoutWidth !== 0) { - this.closeFlyout(); - } else { - this.panelContent = str; - MainView.expandFlyout(); - if (str === "tools") { - CurrentUserUtils.toolsBtn; - this.sidebarContent.proto = CurrentUserUtils.toolsStack; - } else if (str === "workspace") { - this.sidebarContent.proto = CurrentUserUtils.workspaceStack; - } else if (str === "catalog") { - this.sidebarContent.proto = CurrentUserUtils.catalogStack; - } else if (str === "deleted") { - this.sidebarContent.proto = CurrentUserUtils.closedStack; - } else if (str === "search") { - this.sidebarContent.proto = CurrentUserUtils.searchStack; - } - } - return true; - } + // @computed get menuPanel() { + // return <div className="mainView-menuPanel"> + // <div className="mainView-menuPanel-button" style={{ backgroundColor: this.panelContent === "workspace" ? "lightgrey" : "" }}> + // <div className="mainView-menuPanel-button-wrap" + // style={{ backgroundColor: this.panelContent === "workspace" ? "lightgrey" : "" }} + // onPointerDown={e => this.selectPanel("workspace")}> + // <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="desktop" + // color={this.panelContent === "workspace" ? "black" : "white"} size="lg" /> + // <div className="mainView-menuPanel-button-label" + // style={{ color: this.panelContent === "workspace" ? "black" : "white" }}> Workspace </div> + // </div> + // </div> + + // <div className="mainView-menuPanel-button" style={{ backgroundColor: this.panelContent === "catalog" ? "lightgrey" : "" }}> + // <div className="mainView-menuPanel-button-wrap" + // style={{ backgroundColor: this.panelContent === "catalog" ? "lightgrey" : "" }} + // onPointerDown={e => this.selectPanel("catalog")}> + // <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="file" + // color={this.panelContent === "catalog" ? "black" : "white"} size="lg" /> + // <div className="mainView-menuPanel-button-label" + // style={{ color: this.panelContent === "catalog" ? "black" : "white" }}> Catalog </div> + // </div> + // </div> + + // <div className="mainView-menuPanel-button" style={{ backgroundColor: this.panelContent === "deleted" ? "lightgrey" : "" }}> + // <div className="mainView-menuPanel-button-wrap" + // style={{ backgroundColor: this.panelContent === "deleted" ? "lightgrey" : "" }} + // onPointerDown={e => this.selectPanel("deleted")}> + // <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="archive" + // color={this.panelContent === "deleted" ? "black" : "white"} size="lg" /> + // <div className="mainView-menuPanel-button-label" + // style={{ color: this.panelContent === "deleted" ? "black" : "white" }}> Recently Used </div> + // </div> + // </div> + + // <div className="mainView-menuPanel-button"> + // <div className="mainView-menuPanel-button-wrap" + // onPointerDown={e => this.selectPanel("upload")}> + // <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="upload" color="white" size="lg" /> + // <div className="mainView-menuPanel-button-label"> Import </div> + // </div> + // </div> + + // <div className="mainView-menuPanel-button"> + // <div className="mainView-menuPanel-button-wrap" + // //onPointerDown={e => this.selectPanel("sharing")} + // onClick={() => GroupManager.Instance.open()}> + // <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="users" color="white" size="lg" /> + // <div className="mainView-menuPanel-button-label"> Sharing </div> + // </div> + // </div> + + // <div className="mainView-menuPanel-button" style={{ marginBottom: "110px", backgroundColor: this.panelContent === "tools" ? "lightgrey" : "", }}> + // <div className="mainView-menuPanel-button-wrap" + // onPointerDown={e => this.selectPanel("tools")} + // style={{ + // backgroundColor: this.panelContent === "tools" ? "lightgrey" : "", + // }}> + // <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="wrench" + // color={this.panelContent === "tools" ? "black" : "white"} size="lg" /> + // <div className="mainView-menuPanel-button-label" + // style={{ color: this.panelContent === "tools" ? "black" : "white" }}> Tools </div> + // </div> + // </div> + + // <div className="mainView-menuPanel-button"> + // <div className="mainView-menuPanel-button-wrap" + // // style={{backgroundColor: this.panelContent= "help" ? "lightgrey" : "black"}} + // onPointerDown={e => this.selectPanel("help")} > + // <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="question-circle" color="white" size="lg" /> + // <div className="mainView-menuPanel-button-label"> Help </div> + // </div> + // </div> + + // <div className="mainView-menuPanel-button"> + // <div className="mainView-menuPanel-button-wrap" + // // onPointerDown={e => this.selectPanel("settings")} + // onClick={() => SettingsManager.Instance.open()}> + // <FontAwesomeIcon className="mainView-menuPanel-button-icon" icon="cog" color="white" size="lg" /> + // <div className="mainView-menuPanel-button-label"> Settings </div> + // </div> + // </div> + // </div>; + // } + @action @undoBatch closeFlyout = () => { @@ -620,26 +593,23 @@ export class MainView extends React.Component { this.flyoutWidth = 0; } + get groupManager() { return GroupManager.Instance; } + @action @undoBatch selectMenu = (str: string) => { - if (CurrentUserUtils.panelContent === str && this.flyoutWidth !== 0) { - CurrentUserUtils.panelContent = "none"; + if (this.panelContent === str && this.flyoutWidth !== 0) { + this.panelContent = "none"; this.flyoutWidth = 0; } else { - CurrentUserUtils.panelContent = str; - MainView.expandFlyout(); - if (str === "tools") { - CurrentUserUtils.toolsBtn; - this.sidebarContent.proto = CurrentUserUtils.toolsStack; - } else if (str === "workspace") { - this.sidebarContent.proto = CurrentUserUtils.workspaceStack; - } else if (str === "catalog") { - this.sidebarContent.proto = CurrentUserUtils.catalogStack; - } else if (str === "deleted") { - this.sidebarContent.proto = CurrentUserUtils.closedStack; - } else if (str === "search") { - this.sidebarContent.proto = CurrentUserUtils.searchStack; + this.panelContent = str; + switch (this.panelContent) { + case "Tools": this.sidebarContent.proto = CurrentUserUtils.toolsStack; break; + case "Workspace": this.sidebarContent.proto = CurrentUserUtils.workspaceStack; break; + case "Catalog": this.sidebarContent.proto = CurrentUserUtils.catalogStack; break; + case "deleted": this.sidebarContent.proto = CurrentUserUtils.closedStack; break; + case "Search": this.sidebarContent.proto = CurrentUserUtils.searchStack; break; } + MainView.expandFlyout(); } return true; } @@ -674,7 +644,7 @@ export class MainView extends React.Component { const height = `calc(100% - ${n * Number(ANTIMODEMENU_HEIGHT.replace("px", ""))}px)`; const rightFlyout = this.selectedDocumentView ? this._propertiesWidth - 1 : this.propertiesWidth() > 10 ? 151.5 : 0; - return !this.userDoc || !(this.sidebarContent instanceof Doc) ? (null) : ( + return !this.userDoc ? (null) : ( <div className="mainView-mainContent" style={{ color: this.darkScheme ? "rgb(205,205,205)" : "black", //change to times 2 for both pinned @@ -686,7 +656,7 @@ export class MainView extends React.Component { <div className="mainView-flyoutContainer" onPointerLeave={this.pointerLeaveDragger} style={{ width: this.flyoutWidth }}> {this.flyoutWidth !== 0 ? <div className="mainView-libraryHandle" onPointerDown={this.onPointerDown} - style={{ backgroundColor: this.defaultBackgroundColors(this.sidebarContent) }}> + style={{ backgroundColor: this.defaultBackgroundColors(undefined) }}> <span title="library View Dragger" style={{ width: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "100%" : "3vw", //height: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "100%" : "100vh", diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 0332b4bf2..500d72fdb 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -227,6 +227,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) addDocTab={this.addDocTab} bringToFront={returnFalse} ContentScaling={returnOne} + scriptContext={this.props.scriptContext} pinToPres={this.props.pinToPres} />; } diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 76af70cd1..59a87b450 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -355,7 +355,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC {this.props.parent.Document._columnsHideIfEmpty ? (null) : headingView} { this.collapsed ? (null) : - <div style={{ marginTop: 5 }}> + <div> <div key={`${heading}-stack`} className={`collectionStackingView-masonry${singleColumn ? "Single" : "Grid"}`} style={{ padding: singleColumn ? `${columnYMargin}px ${0}px ${style.yMargin}px ${0}px` : `${columnYMargin}px ${0}px`, diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.scss b/src/client/views/collections/collectionFreeForm/PropertiesView.scss index f70e5f837..83e0fc0d5 100644 --- a/src/client/views/collections/collectionFreeForm/PropertiesView.scss +++ b/src/client/views/collections/collectionFreeForm/PropertiesView.scss @@ -227,6 +227,8 @@ border-radius: 6px; width: 170px; background-color: #ececec; + max-height: 130px; + overflow-y: scroll; .propertiesView-sharingTable-item { diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx index 7c8e7cdc3..c4291f2a4 100644 --- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx +++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx @@ -2,7 +2,7 @@ import React = require("react"); import { observer } from "mobx-react"; import "./PropertiesView.scss"; import { observable, action, computed, runInAction } from "mobx"; -import { Doc, Field, DocListCast, WidthSym, HeightSym } from "../../../../fields/Doc"; +import { Doc, Field, DocListCast, WidthSym, HeightSym, AclSym, AclPrivate, AclReadonly, AclAddonly, AclEdit, AclAdmin } from "../../../../fields/Doc"; import { DocumentView } from "../../nodes/DocumentView"; import { ComputedField } from "../../../../fields/ScriptField"; import { EditableView } from "../../EditableView"; @@ -20,6 +20,7 @@ import { Tooltip, Checkbox } from "@material-ui/core"; import SharingManager from "../../../util/SharingManager"; import { DocumentType } from "../../../documents/DocumentTypes"; import FormatShapePane from "./FormatShapePane"; +import { SharingPermissions, GetEffectiveAcl } from "../../../../fields/util"; interface PropertiesViewProps { @@ -255,20 +256,15 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { } } - @computed get permissionsSelect() { - return <select className="permissions-select" onChange={emptyFunction}> - <option key={"Can Edit"} value={"Can Edit"}> - Can Edit - </option> - <option key={"Can Add"} value={"Can Add"}> - Can Add - </option> - <option key={"Can View"} value={"Can View"}> - Can View - </option> - <option key={"Not Shared"} value={"Not Shared"}> - Not Shared - </option> + getPermissionsSelect(user: string) { + return <select className="permissions-select" + onChange={e => SharingManager.Instance.shareFromPropertiesSidebar(user, e.currentTarget.value as SharingPermissions, this.selectedDoc!)}> + {Object.values(SharingPermissions).map(permission => { + return ( + <option key={permission} value={permission} selected={this.selectedDoc![`ACL-${user.replace(".", "_")}`] === permission}> + {permission} + </option>); + })} </select>; } @@ -292,23 +288,41 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { </Tooltip>; } - sharingItem(name: string, notify: boolean, editable: boolean, permission?: string) { + sharingItem(name: string, notify: boolean, effectiveAcl: symbol, permission?: string) { return <div className="propertiesView-sharingTable-item"> <div className="propertiesView-sharingTable-item-name" style={{ width: notify ? "70px" : "80px" }}> {name} </div> {notify ? this.notifyIcon : null} <div className="propertiesView-sharingTable-item-permission"> - {editable ? this.permissionsSelect : permission} + {effectiveAcl === AclAdmin && permission !== "Owner" ? this.getPermissionsSelect(name) : permission} {permission === "Owner" ? this.expansionIcon : null} </div> </div>; } @computed get sharingTable() { + const AclMap = new Map<symbol, string>([ + [AclPrivate, SharingPermissions.None], + [AclReadonly, SharingPermissions.View], + [AclAddonly, SharingPermissions.Add], + [AclEdit, SharingPermissions.Edit], + [AclAdmin, SharingPermissions.Admin] + ]); + + const effectiveAcl = GetEffectiveAcl(this.selectedDoc!); + const tableEntries = []; + + if (this.selectedDoc![AclSym]) { + for (const [key, value] of Object.entries(this.selectedDoc![AclSym])) { + const name = key.substring(4).replace("_", "."); + if (name !== Doc.CurrentUserEmail && name !== this.selectedDoc!.author) tableEntries.push(this.sharingItem(name, false, effectiveAcl, AclMap.get(value)!)); + } + } + + tableEntries.unshift(this.sharingItem("Me", false, effectiveAcl, Doc.CurrentUserEmail === this.selectedDoc!.author ? "Owner" : StrCast(this.selectedDoc![`ACL-${Doc.CurrentUserEmail.replace(".", "_")}`]))); + if (Doc.CurrentUserEmail !== this.selectedDoc!.author) tableEntries.unshift(this.sharingItem(StrCast(this.selectedDoc!.author), false, effectiveAcl, "Owner")); + return <div className="propertiesView-sharingTable"> - {this.sharingItem("Me", false, false, "Owner")} - {this.sharingItem("Public", false, true)} - {this.sharingItem("Group 1", true, true)} - {this.sharingItem("Group 2", true, true)} + {tableEntries} </div>; } diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx index 6081def5d..f7e253f42 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.tsx +++ b/src/client/views/nodes/ContentFittingDocumentView.tsx @@ -78,6 +78,9 @@ export class ContentFittingDocumentView extends React.Component<DocumentViewProp render() { TraceMobx(); + if (this.props.Document.title === "Archive") { + console.log(""); + } return (<div className="contentFittingDocumentView" style={{ width: Math.abs(this.centeringYOffset) > 0.001 ? "auto" : this.props.PanelWidth(), height: Math.abs(this.centeringOffset) > 0.0001 ? "auto" : this.props.PanelHeight(), diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index f5ae9349a..6693407a1 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -844,6 +844,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu ChromeHeight={this.chromeHeight} isSelected={this.isSelected} select={this.select} + scriptContext={this.props.scriptContext} onClick={this.onClickFunc} layoutKey={this.finalLayoutKey} /> {this.layoutDoc.hideAllLinks ? (null) : this.allAnchors} diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 48e1f6ce3..23ae48108 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -60,6 +60,7 @@ export interface FieldViewProps { color?: string; xMargin?: number; yMargin?: number; + scriptContext?: any; } @observer diff --git a/src/client/views/nodes/MenuIconBox.tsx b/src/client/views/nodes/MenuIconBox.tsx index e1656fcba..0aa7b327e 100644 --- a/src/client/views/nodes/MenuIconBox.tsx +++ b/src/client/views/nodes/MenuIconBox.tsx @@ -2,15 +2,10 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { observer } from 'mobx-react'; import * as React from 'react'; import { createSchema, makeInterface } from '../../../fields/Schema'; +import { StrCast } from '../../../fields/Types'; import { DocComponent } from '../DocComponent'; -import './MenuIconBox.scss'; import { FieldView, FieldViewProps } from './FieldView'; -import { StrCast, Cast, NumCast } from '../../../fields/Types'; -import { Utils } from "../../../Utils"; -import { runInAction, observable, reaction, IReactionDisposer } from 'mobx'; -import { Doc } from '../../../fields/Doc'; -import { ScriptField } from '../../../fields/ScriptField'; -import { CurrentUserUtils } from '../../util/CurrentUserUtils'; +import './MenuIconBox.scss'; const MenuIconSchema = createSchema({ icon: "string" }); @@ -24,15 +19,12 @@ export class MenuIconBox extends DocComponent<FieldViewProps, MenuIconDocument>( render() { - const menuBTN = <div className="menuButton" style={{ backgroundColor: CurrentUserUtils.panelContent === this.dataDoc.title ? "lightgrey" : "" }}> + const color = this.props.backgroundColor?.(this.props.Document) === "lightgrey" ? "black" : "white"; + const menuBTN = <div className="menuButton" style={{ backgroundColor: this.props.backgroundColor?.(this.props.Document) }}> <div className="menuButton-wrap" - style={{ backgroundColor: CurrentUserUtils.panelContent === this.dataDoc.title ? "lightgrey" : "" }} - //onPointerDown={this.dataDoc.click} - > - <FontAwesomeIcon className="menuButton-icon" icon={StrCast(this.dataDoc.icon, "user") as any} - color={CurrentUserUtils.panelContent === this.dataDoc.title ? "black" : "white"} size="lg" /> - <div className="menuButton-label" - style={{ color: CurrentUserUtils.panelContent === this.dataDoc.title ? "black" : "white" }}> {this.dataDoc.title} </div> + style={{ backgroundColor: this.props.backgroundColor?.(this.props.Document) }} > + <FontAwesomeIcon className="menuButton-icon" icon={StrCast(this.dataDoc.icon, "user") as any} color={color} size="lg" /> + <div className="menuButton-label" style={{ color: color }}> {this.dataDoc.title} </div> </div> </div>; diff --git a/src/fields/util.ts b/src/fields/util.ts index a62795e64..267da70b4 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -1,5 +1,5 @@ import { UndoManager } from "../client/util/UndoManager"; -import { Doc, FieldResult, UpdatingFromServer, LayoutSym, AclPrivate, AclEdit, AclReadonly, AclAddonly, AclSym, CachedUpdates, DataSym, DocListCast, AclAdmin, FieldsSym, HeightSym, WidthSym } from "./Doc"; +import { Doc, FieldResult, UpdatingFromServer, LayoutSym, AclPrivate, AclEdit, AclReadonly, AclAddonly, AclSym, CachedUpdates, DataSym, DocListCast, AclAdmin, FieldsSym, HeightSym, WidthSym, fetchProto } from "./Doc"; import { SerializationHelper } from "../client/util/SerializationHelper"; import { ProxyField, PrefetchProxy } from "./Proxy"; import { RefField } from "./RefField"; @@ -183,12 +183,18 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc ["Admin", 4] ]); + let changed = false; + const dataDoc = target[DataSym]; - if (!inheritingFromCollection || !target[key] || HierarchyMapping.get(StrCast(target[key]))! > HierarchyMapping.get(acl)!) target[key] = acl; + if (!inheritingFromCollection || !target[key] || HierarchyMapping.get(StrCast(target[key]))! > HierarchyMapping.get(acl)!) { + target[key] = acl; + changed = true; + } if (dataDoc && (!inheritingFromCollection || !dataDoc[key] || HierarchyMapping.get(StrCast(dataDoc[key]))! > HierarchyMapping.get(acl)!)) { dataDoc[key] = acl; + changed = true; DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc)]).map(d => { if (d.author === Doc.CurrentUserEmail && (!inheritingFromCollection || !d[key] || HierarchyMapping.get(StrCast(d[key]))! > HierarchyMapping.get(acl)!)) { @@ -214,6 +220,8 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc } }); } + + changed && fetchProto(target); } const layoutProps = ["panX", "panY", "width", "height", "nativeWidth", "nativeHeight", "fitWidth", "fitToBox", |