aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2023-07-05 16:15:27 -0400
committerbobzel <zzzman@gmail.com>2023-07-05 16:15:27 -0400
commit5a9af979cc293d0e3843270ee053c24bf0eb6ef5 (patch)
tree1c03d5fb55a97f5e3da96a448af5079ec2b0e42b
parentbf609fdadc164da5663671a0c42c3a13056ee376 (diff)
changed acl inheritance for docking views.
-rw-r--r--src/client/documents/Documents.ts10
-rw-r--r--src/client/util/LinkFollower.ts2
-rw-r--r--src/client/util/SharingManager.tsx70
-rw-r--r--src/client/views/DocComponent.tsx30
-rw-r--r--src/client/views/DocumentDecorations.tsx40
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx12
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx2
-rw-r--r--src/client/views/collections/TabDocView.tsx2
-rw-r--r--src/client/views/collections/TreeView.tsx8
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx2
-rw-r--r--src/client/views/nodes/ComparisonBox.tsx2
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx2
-rw-r--r--src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts10
-rw-r--r--src/fields/Doc.ts11
-rw-r--r--src/fields/util.ts33
15 files changed, 123 insertions, 113 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 06ff95df0..18e8b5940 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -859,7 +859,7 @@ export namespace Docs {
// users placeholderDoc as proto if it exists
const dataDoc = Doc.assign(placeholderDoc ? Doc.GetProto(placeholderDoc) : Doc.MakeDelegate(proto, protoId), dataProps, undefined, true);
-
+
if (placeholderDoc) {
dataDoc.proto = proto;
}
@@ -1053,7 +1053,7 @@ export namespace Docs {
export function FreeformDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _xPadding: 20, _yPadding: 20, ...options, _type_collection: CollectionViewType.Freeform }, id);
- documents.forEach(d => (d.embedContainer = inst));
+ documents.forEach(d => Doc.SetContainer(d, inst));
return inst;
}
@@ -1158,7 +1158,9 @@ export namespace Docs {
}
export function DockDocument(documents: Array<Doc>, config: string, options: DocumentOptions, id?: string) {
- return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { treeViewFreezeChildren: 'remove|add', ...options, type_collection: CollectionViewType.Docking, dockingConfig: config }, id);
+ const ret = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { treeViewFreezeChildren: 'remove|add', ...options, type_collection: CollectionViewType.Docking, dockingConfig: config }, id);
+ documents.map(c => Doc.SetContainer(c, ret));
+ return ret;
}
export function DirectoryImportDocument(options: DocumentOptions = {}) {
@@ -1186,7 +1188,7 @@ export namespace Docs {
options,
id
);
- configs.map(c => (c.doc.embedContainer = doc));
+ configs.map(c => Doc.SetContainer(c.doc, doc));
return doc;
}
diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts
index f74409e42..3e526c4c0 100644
--- a/src/client/util/LinkFollower.ts
+++ b/src/client/util/LinkFollower.ts
@@ -103,7 +103,7 @@ export class LinkFollower {
Doc.AddDocToList(sourceDocParent, Doc.LayoutFieldKey(sourceDocParent), target);
movedTarget = true;
}
- target.embedContainer = sourceDocParent;
+ Doc.SetContainer(target, sourceDocParent);
const moveTo = [NumCast(sourceDoc.x) + NumCast(sourceDoc.followLinkXoffset), NumCast(sourceDoc.y) + NumCast(sourceDoc.followLinkYoffset)];
if (sourceDoc.followLinkXoffset !== undefined && moveTo[0] !== target.x) {
target.x = moveTo[0];
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 534a9cfde..64b2bb5b8 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -1,12 +1,11 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { IconButton, Size } from 'browndash-components';
import { concat, intersection } from 'lodash';
import { action, computed, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import Select from 'react-select';
import * as RequestPromise from 'request-promise';
-import { Doc, DocCastAsync, DocListCast, DocListCastAsync, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc';
+import { Doc, DocListCast, DocListCastAsync, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc';
import { AclAdmin, AclPrivate, AclUnset, DocAcl, DocData } from '../../fields/DocSymbols';
import { Id } from '../../fields/FieldSymbols';
import { List } from '../../fields/List';
@@ -24,7 +23,6 @@ import { GroupManager, UserOptions } from './GroupManager';
import { GroupMemberView } from './GroupMemberView';
import { SelectionManager } from './SelectionManager';
import './SharingManager.scss';
-import { Docs } from '../documents/Documents';
export interface User {
email: string;
@@ -166,7 +164,7 @@ export class SharingManager extends React.Component<{}> {
// or if the 'Override Nested' checkbox is selected
var childDocs = DocListCast(target.data);
childDocs.map(doc => {
- if (this.overrideNested || doc[acl]==undefined){
+ if (this.overrideNested || doc[acl] == undefined) {
this.setInternalSharing(recipient, permission, doc);
}
});
@@ -207,7 +205,7 @@ export class SharingManager extends React.Component<{}> {
// or if the 'Override Private' checkbox is selected
var childDocs = DocListCast(target.data);
childDocs.map(doc => {
- if (this.overrideNested || doc[acl]==undefined){
+ if (this.overrideNested || doc[acl] == undefined) {
this.setInternalGroupSharing(group, permission, doc);
}
});
@@ -288,7 +286,7 @@ export class SharingManager extends React.Component<{}> {
this.shareFromPropertiesSidebar(shareWith, permission, DocListCast(doc.data), layout);
}
if (GetEffectiveAcl(doc) === AclAdmin) {
- if ( shareWith == 'Public' && layout) shareWith = 'Public-layout';
+ if (shareWith == 'Public' && layout) shareWith = 'Public-layout';
distributeAcls(`acl-${shareWith}`, permission, doc, undefined, undefined, isDashboard);
}
this.setDashboardBackground(doc, permission as SharingPermissions);
@@ -538,13 +536,12 @@ export class SharingManager extends React.Component<{}> {
const uniform = docs.map(doc => (this.layoutDocAcls ? doc : doc[DocData])).every(doc => doc?.[DocAcl]?.[userKey] === docs[0]?.[DocAcl]?.[userKey]);
// const permissions = uniform ? StrCast(targetDoc?.[userKey]) : '-multiple-';
let permissions = this.layoutDocAcls ? (targetDoc[DocAcl][userKey] ? HierarchyMapping.get(targetDoc[DocAcl][userKey])?.name : StrCast(Doc.GetProto(targetDoc)[userKey])) : StrCast(targetDoc[userKey]);
- if (this.layoutDocAcls){
+ if (this.layoutDocAcls) {
if (targetDoc[DocAcl][userKey]) permissions = HierarchyMapping.get(targetDoc[DocAcl][userKey])?.name;
- else if (targetDoc['embedContainer']) permissions = StrCast(Doc.GetProto(DocCast(targetDoc['embedContainer']))[userKey]);
+ else if (targetDoc['embedContainer']) permissions = StrCast(Doc.GetProto(DocCast(targetDoc['embedContainer']))[userKey]);
else permissions = uniform ? StrCast(Doc.GetProto(targetDoc)?.[userKey]) : '-multiple-';
- }
- else permissions = uniform ? StrCast(targetDoc?.[userKey]) : '-multiple-';
-
+ } else permissions = uniform ? StrCast(targetDoc?.[userKey]) : '-multiple-';
+
return !permissions ? null : (
<div key={userKey} className={'container'}>
<span className={'padding'}>{user.email}</span>
@@ -570,12 +567,11 @@ export class SharingManager extends React.Component<{}> {
// the owner of the doc and the current user are placed at the top of the user list.
const userKey = `acl-${normalizeEmail(Doc.CurrentUserEmail)}`;
var curUserPermission;
- if (this.layoutDocAcls){
- if (targetDoc[DocAcl][userKey]) curUserPermission = HierarchyMapping.get(targetDoc[DocAcl][userKey])?.name;
- else if (targetDoc['embedContainer']) curUserPermission = StrCast(Doc.GetProto(DocCast(targetDoc['embedContainer']))[userKey]);
- else curUserPermission = StrCast(Doc.GetProto(targetDoc)?.[userKey]);
- }
- else curUserPermission = StrCast(targetDoc[userKey]);
+ if (this.layoutDocAcls) {
+ if (targetDoc[DocAcl][userKey]) curUserPermission = HierarchyMapping.get(targetDoc[DocAcl][userKey])?.name;
+ else if (targetDoc['embedContainer']) curUserPermission = StrCast(Doc.GetProto(DocCast(targetDoc['embedContainer']))[userKey]);
+ else curUserPermission = StrCast(Doc.GetProto(targetDoc)?.[userKey]);
+ } else curUserPermission = StrCast(targetDoc[userKey]);
// const curUserPermission = HierarchyMapping.get(effectiveAcls[0])!.name
userListContents.unshift(
sameAuthor ? (
@@ -609,16 +605,15 @@ export class SharingManager extends React.Component<{}> {
.every(doc => (this.layoutDocAcls ? doc?.[DocAcl]?.[groupKey] === docs[0]?.[DocAcl]?.[groupKey] : doc?.[DocData]?.[DocAcl]?.[groupKey] === docs[0]?.[DocData]?.[DocAcl]?.[groupKey]));
// const permissions = uniform ? StrCast(targetDoc?.[`acl-${StrCast(group.title)}`]) : '-multiple-';
let permissions = this.layoutDocAcls ? (targetDoc[DocAcl][groupKey] ? HierarchyMapping.get(targetDoc[DocAcl][groupKey])?.name : StrCast(Doc.GetProto(targetDoc)[groupKey])) : StrCast(targetDoc[groupKey]);
- if (this.layoutDocAcls){
- if (groupKey == 'acl-Public') groupKey = 'acl-Public-layout';
- if (targetDoc[DocAcl][groupKey]) permissions = HierarchyMapping.get(targetDoc[DocAcl][groupKey])?.name;
- else{
- if (groupKey == 'acl-Public-layout') groupKey = 'acl-Public';
- if (targetDoc['embedContainer']) permissions = StrCast(Doc.GetProto(DocCast(targetDoc['embedContainer']))[groupKey]);
- else permissions = uniform ? StrCast(Doc.GetProto(targetDoc)?.[groupKey]) : '-multiple-';
- }
+ if (this.layoutDocAcls) {
+ if (groupKey == 'acl-Public') groupKey = 'acl-Public-layout';
+ if (targetDoc[DocAcl][groupKey]) permissions = HierarchyMapping.get(targetDoc[DocAcl][groupKey])?.name;
+ else {
+ if (groupKey == 'acl-Public-layout') groupKey = 'acl-Public';
+ if (targetDoc['embedContainer']) permissions = StrCast(Doc.GetProto(DocCast(targetDoc['embedContainer']))[groupKey]);
+ else permissions = uniform ? StrCast(Doc.GetProto(targetDoc)?.[groupKey]) : '-multiple-';
}
- else permissions = uniform ? StrCast(targetDoc?.[groupKey]) : '-multiple-';
+ } else permissions = uniform ? StrCast(targetDoc?.[groupKey]) : '-multiple-';
return !permissions ? null : (
<div key={groupKey} className={'container'}>
@@ -629,7 +624,7 @@ export class SharingManager extends React.Component<{}> {
<FontAwesomeIcon icon={'info-circle'} color={'#e8e8e8'} size={'sm'} style={{ backgroundColor: '#1e89d7', borderRadius: '100%', border: '1px solid #1e89d7' }} />
</div>
) : null}
- <div className={"edit-actions"}>
+ <div className={'edit-actions'}>
{admin || this.myDocAcls ? (
<select className={`permissions-dropdown-${permissions}`} value={permissions} onChange={e => this.setInternalGroupSharing(group, e.currentTarget.value)}>
{this.sharingOptions(uniform, group.title === 'Override')}
@@ -649,16 +644,15 @@ export class SharingManager extends React.Component<{}> {
{GroupManager.Instance?.currentGroup ? <GroupMemberView group={GroupManager.Instance.currentGroup} onCloseButtonClick={action(() => (GroupManager.Instance.currentGroup = undefined))} /> : null}
<div className="sharing-contents">
<p className="share-title">
- <div className="share-info" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/properties/sharing-and-permissions/', '_blank')} >
- <FontAwesomeIcon icon={'question-circle'} size={'sm'} onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/properties/sharing-and-permissions/', '_blank')}/>
+ <div className="share-info" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/properties/sharing-and-permissions/', '_blank')}>
+ <FontAwesomeIcon icon={'question-circle'} size={'sm'} onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/properties/sharing-and-permissions/', '_blank')} />
</div>
<b>Share </b>
{this.focusOn(docs.length < 2 ? StrCast(targetDoc?.title, 'this document') : '-multiple-')}
</p>
<button className="share-copy-link" onClick={this.copyURL}>
- <FontAwesomeIcon title={"Copy Public URL"} icon={'copy'} size={'sm'} onClick={this.copyURL}/>
- &nbsp;
- Copy Public URL
+ <FontAwesomeIcon title={'Copy Public URL'} icon={'copy'} size={'sm'} onClick={this.copyURL} />
+ &nbsp; Copy Public URL
</button>
<div className={'close-button'} onClick={this.close}>
<FontAwesomeIcon icon={'times'} color={'black'} size={'lg'} />
@@ -682,7 +676,7 @@ export class SharingManager extends React.Component<{}> {
}),
}}
/>
- <div className='permissions-select'>
+ <div className="permissions-select">
<select className={`permissions-dropdown-${this.permissions}`} onChange={this.handlePermissionsChange} value={this.permissions}>
{this.sharingOptions(true)}
</select>
@@ -706,9 +700,9 @@ export class SharingManager extends React.Component<{}> {
</div>
</div>
) : (
- <div className='share-container'>
- <div className='acl-container'>
- <div className='layoutDoc-acls'>
+ <div className="share-container">
+ <div className="acl-container">
+ <div className="layoutDoc-acls">
<input type="checkbox" onChange={action(() => (this.layoutDocAcls = !this.layoutDocAcls))} checked={this.layoutDocAcls} /> <label>Layout</label>
</div>
</div>
@@ -717,7 +711,7 @@ export class SharingManager extends React.Component<{}> {
<div className="main-container">
<div className={'individual-container'}>
<div className="user-sort" onClick={action(() => (this.individualSort = this.individualSort === 'ascending' ? 'descending' : this.individualSort === 'descending' ? 'none' : 'ascending'))}>
- <div className='title-individual'>
+ <div className="title-individual">
Individuals &nbsp;
{this.individualSort === 'ascending' ? (
<FontAwesomeIcon icon={'caret-up'} size={'xs'} />
@@ -732,7 +726,7 @@ export class SharingManager extends React.Component<{}> {
</div>
<div className={'group-container'}>
<div className="user-sort" onClick={action(() => (this.groupSort = this.groupSort === 'ascending' ? 'descending' : this.groupSort === 'descending' ? 'none' : 'ascending'))}>
- <div className='title-group'>
+ <div className="title-group">
Groups &nbsp;
<div className="group-info" onClick={action(() => GroupManager.Instance?.open())}>
<FontAwesomeIcon icon={'info-circle'} color={'#e8e8e8'} size={'sm'} style={{ backgroundColor: '#1e89d7', borderRadius: '100%', border: '1px solid #1e89d7' }} />
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index f3aa8451a..1d0feec74 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -196,52 +196,52 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
aclKeys.forEach(key =>
added.forEach(d => {
- if (key != 'acl-Me'){
- const permissionString = StrCast(Doc.GetProto(this.props.Document)[key])
- const permissionSymbol = ReverseHierarchyMap.get(permissionString)!.acl
- const permission = HierarchyMapping.get(permissionSymbol)!.name
- distributeAcls(key, permission, Doc.GetProto(d))
+ if (key != 'acl-Me') {
+ const permissionString = StrCast(Doc.GetProto(this.props.Document)[key]);
+ const permissionSymbol = ReverseHierarchyMap.get(permissionString)!.acl;
+ const permission = HierarchyMapping.get(permissionSymbol)!.name;
+ distributeAcls(key, permission, Doc.GetProto(d));
}
})
);
if (effectiveAcl === AclAugment) {
added.map(doc => {
- doc.embedContainer = this.props.Document;
+ Doc.SetContainer(doc, this.props.Document);
if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.props.Document;
Doc.AddDocToList(targetDataDoc, annotationKey ?? this.annotationKey, doc);
const parent = DocCast(doc.embedContainer);
doc.embedContainer && inheritParentAcls(parent, doc);
for (const key of Object.keys(parent)) {
- const symbol = ReverseHierarchyMap.get(StrCast(parent[key]))
- if (symbol && key.startsWith('acl')){
+ const symbol = ReverseHierarchyMap.get(StrCast(parent[key]));
+ if (symbol && key.startsWith('acl')) {
const sharePermission = HierarchyMapping.get(symbol.acl!)!.name;
const user = SharingManager.Instance?.users.filter(({ user: { email } }) => normalizeEmail(email) == key.slice(4))[0];
if (user && sharePermission !== SharingPermissions.None) return Doc.AddDocToList(user.sharingDoc, 'data', doc);
}
}
});
- } else {
- added
+ } else {
+ added
.filter(doc => [AclAdmin, AclEdit].includes(GetEffectiveAcl(doc)))
.map(doc => {
// only make a pushpin if we have acl's to edit the document
//DocUtils.LeavePushpin(doc);
doc._dragOnlyWithinContainer = undefined;
- doc.embedContainer = this.props.Document;
+ Doc.SetContainer(doc, this.props.Document);
if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.rootDoc;
const parent = DocCast(doc.embedContainer);
doc.embedContainer && inheritParentAcls(parent, doc);
for (const key of Object.keys(Doc.GetProto(parent))) {
- const symbol = ReverseHierarchyMap.get(StrCast(parent[key]))
- if (symbol && key.startsWith('acl')){
+ const symbol = ReverseHierarchyMap.get(StrCast(parent[key]));
+ if (symbol && key.startsWith('acl')) {
const sharePermission = HierarchyMapping.get(symbol.acl!)!.name;
const user = SharingManager.Instance?.users.filter(({ user: { email } }) => normalizeEmail(email) == key.slice(4))[0];
if (user && sharePermission !== SharingPermissions.None) return Doc.AddDocToList(user.sharingDoc, 'data', doc);
}
}
- });
-
+ });
+
const annoDocs = targetDataDoc[annotationKey ?? this.annotationKey] as List<Doc>;
if (annoDocs instanceof List) annoDocs.push(...added.filter(add => !annoDocs.includes(add)));
else targetDataDoc[annotationKey ?? this.annotationKey] = new List<Doc>(added);
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 4454a3ec1..cdd9e62d8 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -201,9 +201,9 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
onBackgroundMove = (dragTitle: boolean, e: PointerEvent): boolean => {
const first = SelectionManager.Views()[0];
const effectiveLayoutAcl = GetEffectiveLayoutAcl(first.rootDoc);
- if (effectiveLayoutAcl != AclAdmin && effectiveLayoutAcl != AclEdit && effectiveLayoutAcl != AclAugment){
+ if (effectiveLayoutAcl != AclAdmin && effectiveLayoutAcl != AclEdit && effectiveLayoutAcl != AclAugment) {
return false;
- }
+ }
const dragDocView = SelectionManager.Views()[0];
const containers = new Set<Doc | undefined>();
SelectionManager.Views().forEach(v => containers.add(DocCast(v.rootDoc.embedContainer)));
@@ -766,13 +766,14 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
// sharing
const acl = this.showLayoutAcl ? GetEffectiveLayoutAcl(seldocview.rootDoc) : GetEffectiveAcl(seldocview.rootDoc);
- const docShareMode = HierarchyMapping.get(acl)!.name
+ const docShareMode = HierarchyMapping.get(acl)!.name;
const shareMode = StrCast(docShareMode);
var shareSymbolIcon = ReverseHierarchyMap.get(shareMode)?.image;
// hide the decorations if the parent chooses to hide it or if the document itself hides it
const hideDecorations = seldocview.props.hideDecorations || seldocview.rootDoc.hideDecorations;
- const hideResizers = ![AclAdmin, AclEdit, AclAugment].includes(GetEffectiveLayoutAcl(seldocview.rootDoc)) || hideDecorations || seldocview.props.hideResizeHandles || seldocview.rootDoc.layout_hideResizeHandles || this._isRounding || this._isRotating;
+ const hideResizers =
+ ![AclAdmin, AclEdit, AclAugment].includes(GetEffectiveLayoutAcl(seldocview.rootDoc)) || hideDecorations || seldocview.props.hideResizeHandles || seldocview.rootDoc.layout_hideResizeHandles || this._isRounding || this._isRotating;
const hideTitle = hideDecorations || seldocview.props.hideDecorationTitle || seldocview.rootDoc.layout_hideDecorationTitle || this._isRounding || this._isRotating;
const hideDocumentButtonBar = hideDecorations || seldocview.props.hideDocumentButtonBar || seldocview.rootDoc.layout_hideDocumentButtonBar || this._isRounding || this._isRotating;
// if multiple documents have been opened at the same time, then don't show open button
@@ -826,26 +827,26 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
const radiusHandleLocation = Math.min(radiusHandle, maxDist);
const sharingMenu = docShareMode ? (
- <div className='documentDecorations-share' >
+ <div className="documentDecorations-share">
<div className={`documentDecorations-share${shareMode}`}>
&nbsp;
{shareSymbolIcon + ' ' + shareMode}
&nbsp;
- {!Doc.noviceMode ?
- <div className='checkbox'>
- <div className='checkbox-box'>
- <input type="checkbox" checked={this.showLayoutAcl} onChange={action(() => (this.showLayoutAcl = !this.showLayoutAcl))} />
+ {!Doc.noviceMode ? (
+ <div className="checkbox">
+ <div className="checkbox-box">
+ <input type="checkbox" checked={this.showLayoutAcl} onChange={action(() => (this.showLayoutAcl = !this.showLayoutAcl))} />
</div>
- <div className='checkbox-text'> Layout </div>
+ <div className="checkbox-text"> Layout </div>
</div>
- : null }
+ ) : null}
&nbsp;
</div>
</div>
) : (
<div />
);
-
+
const titleArea = this._editingTitle ? (
<input
ref={this._keyinput}
@@ -860,8 +861,17 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
onPointerDown={e => e.stopPropagation()}
/>
) : (
- <div className="documentDecorations-title" key="title" onPointerDown={e => {e.stopPropagation}}>
- { hideTitle ? null : <span className={`documentDecorations-titleSpan${colorScheme}`} onPointerDown={this.onTitleDown}>{this.selectionTitle}</span>}
+ <div
+ className="documentDecorations-title"
+ key="title"
+ onPointerDown={e => {
+ e.stopPropagation;
+ }}>
+ {hideTitle ? null : (
+ <span className={`documentDecorations-titleSpan${colorScheme}`} onPointerDown={this.onTitleDown}>
+ {this.selectionTitle}
+ </span>
+ )}
{sharingMenu}
{!useLock ? null : (
<Tooltip key="lock" title={<div className="dash-tooltip">toggle ability to interact with document</div>} placement="top">
@@ -872,7 +882,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
)}
</div>
);
-
+
return (
<div className={`documentDecorations${colorScheme}`} style={{ opacity: this._showNothing ? 0.1 : undefined }}>
<div
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 32fb4d8df..ce9eb9f17 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -461,7 +461,7 @@ export class CollectionDockingView extends CollectionSubView() {
const newtabdocs = origtabdocs.map(origtabdoc => Doc.MakeEmbedding(origtabdoc));
if (newtabdocs.length) {
Doc.GetProto(newtab).data = new List<Doc>(newtabdocs);
- newtabdocs.forEach(ntab => (ntab.embedContainer = newtab));
+ newtabdocs.forEach(ntab => Doc.SetContainer(ntab, newtab));
}
json = json.replace(origtab[Id], newtab[Id]);
return newtab;
@@ -497,11 +497,11 @@ export class CollectionDockingView extends CollectionSubView() {
tabCreated = (tab: any) => {
const aclKeys = Object.keys(Doc.GetProto(this.props.Document)[DocAcl] ?? {});
aclKeys.forEach(key => {
- if (key != 'acl-Me'){
- const permissionString = StrCast(Doc.GetProto(this.props.Document)[key])
- const permissionSymbol = ReverseHierarchyMap.get(permissionString)!.acl
- const permission = HierarchyMapping.get(permissionSymbol)!.name
- distributeAcls(key, permission, Doc.GetProto(tab))
+ if (key != 'acl-Me') {
+ const permissionString = StrCast(Doc.GetProto(this.props.Document)[key]);
+ const permissionSymbol = ReverseHierarchyMap.get(permissionString)!.acl;
+ const permission = HierarchyMapping.get(permissionSymbol)!.name;
+ distributeAcls(key, permission, Doc.GetProto(tab));
}
});
this.tabMap.add(tab);
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 4cd3885f5..d78a0e781 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -180,7 +180,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
const doAddDoc = (doc: Doc | Doc[]) =>
(doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => {
const res = flg && Doc.AddDocToList(this.doc[DocData], this.props.fieldKey, doc, relativeTo, before);
- res && (doc.embedContainer = this.props.Document);
+ res && Doc.SetContainer(doc, this.props.Document);
return res;
}, true);
if (this.doc.resolvedDataDoc instanceof Promise) return false;
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 4d780f46b..3473eee18 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -262,7 +262,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
pinDoc.presMovement = doc.type === DocumentType.SCRIPTING || pinProps?.pinDocLayout ? PresMovement.None : PresMovement.Zoom;
pinDoc.presDuration = pinDoc.presDuration ?? 1000;
pinDoc.groupWithUp = false;
- pinDoc.embedContainer = curPres;
+ Doc.SetContainer(pinDoc, curPres);
// these should potentially all be props passed down by the CollectionTreeView to the TreeView elements. That way the PresBox could configure all of its children at render time
pinDoc.treeViewRenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area
pinDoc.treeViewHeaderWidth = '100%'; // forces the header to grow to be the same size as its largest sibling.
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 8d8d895c6..a2269075d 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -392,7 +392,7 @@ export class TreeView extends React.Component<TreeViewProps> {
const innerAdd = (doc: Doc) => {
const dataIsComputed = ComputedField.WithoutComputed(() => FieldValue(this.dataDoc[this.fieldKey])) instanceof ComputedField;
const added = (!dataIsComputed || (this.dropping && this.moving)) && Doc.AddDocToList(this.dataDoc, this.fieldKey, doc);
- dataIsComputed && (doc.embedContainer = this.doc.embedContainer);
+ dataIsComputed && Doc.SetContainer(doc, this.doc.embedContainer);
return added;
};
return (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && innerAdd(doc), true as boolean);
@@ -455,7 +455,7 @@ export class TreeView extends React.Component<TreeViewProps> {
const innerAdd = (doc: Doc) => {
const dataIsComputed = ComputedField.WithoutComputed(() => FieldValue(this.dataDoc[key])) instanceof ComputedField;
const added = (!dataIsComputed || (this.dropping && this.moving)) && Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true);
- dataIsComputed && (doc.embedContainer = this.doc.embedContainer);
+ dataIsComputed && Doc.SetContainer(doc, this.doc.embedContainer);
return added;
};
return (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && innerAdd(doc), true as boolean);
@@ -563,7 +563,7 @@ export class TreeView extends React.Component<TreeViewProps> {
}
const dataIsComputed = ComputedField.WithoutComputed(() => FieldValue(this.dataDoc[key])) instanceof ComputedField;
const added = (!dataIsComputed || (this.dropping && this.moving)) && Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true);
- !dataIsComputed && added && (doc.embedContainer = this.doc.embedContainer);
+ !dataIsComputed && added && Doc.SetContainer(doc, this.doc.embedContainer);
return added;
};
@@ -1192,7 +1192,7 @@ export class TreeView extends React.Component<TreeViewProps> {
TreeView._editTitleOnLoad = editTitle ? { id: child[Id], parent } : undefined;
Doc.AddDocToList(newParent, fieldKey, child, addAfter, false);
newParent.treeViewOpen = true;
- child.embedContainer = treeView.Document;
+ Doc.SetContainer(child, treeView.Document);
}
};
const indent = i === 0 ? undefined : (editTitle: boolean) => dentDoc(editTitle, docs[i - 1], undefined, treeViewRefs.get(docs[i - 1]));
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 9b0abc48b..764b1e08a 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -392,7 +392,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
newCollection.layout_fitWidth = true;
newCollection['acl-Public'] = Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment;
selected.forEach(d => {
- d.embedContainer = newCollection;
+ Doc.SetContainer(d, newCollection);
d['acl-Public'] = Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment;
});
this.hideMarquee();
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index 2290e0711..ca5ec9389 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -46,7 +46,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
if (dropEvent.complete.docDragData) {
const droppedDocs = dropEvent.complete.docDragData?.droppedDocuments;
const added = dropEvent.complete.docDragData.moveDocument?.(droppedDocs, this.rootDoc, (doc: Doc | Doc[]) => this.addDoc(doc instanceof Doc ? doc : doc.lastElement(), fieldKey));
- droppedDocs.lastElement().embedContainer = this.dataDoc;
+ Doc.SetContainer(droppedDocs.lastElement(), this.dataDoc);
!added && e.preventDefault();
e.stopPropagation(); // prevent parent Doc from registering new position so that it snaps back into place
return added;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 202a9f851..e5ea8e0c1 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -564,7 +564,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}
if (added) {
draggedDoc._freeform_fitContentsToBox = true;
- draggedDoc.embedContainer = this.rootDoc;
+ Doc.SetContainer(draggedDoc, this.rootDoc);
const view = this._editorView!;
view.dispatch(view.state.tr.insert(view.posAtCoords({ left: de.x, top: de.y })!.pos, node));
}
diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
index d2273c91c..112a0d87e 100644
--- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
+++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
@@ -4,7 +4,7 @@ import { Schema } from 'prosemirror-model';
import { splitListItem, wrapInList } from 'prosemirror-schema-list';
import { EditorState, NodeSelection, TextSelection, Transaction } from 'prosemirror-state';
import { liftTarget } from 'prosemirror-transform';
-import { AclAdmin, AclAugment, AclEdit} from '../../../../fields/DocSymbols';
+import { AclAdmin, AclAugment, AclEdit } from '../../../../fields/DocSymbols';
import { GetEffectiveAcl } from '../../../../fields/util';
import { Utils } from '../../../../Utils';
import { Docs } from '../../../documents/Documents';
@@ -50,8 +50,8 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey
switch (GetEffectiveAcl(props.DataDoc)) {
case AclAugment:
const prevNode = state.selection.$cursor.nodeBefore;
- const prevUser = prevNode.marks[prevNode.marks.length-1].attrs.userid
- if (prevUser != Doc.CurrentUserEmail){
+ const prevUser = !prevNode ? Doc.CurrentUserEmail : prevNode.marks[prevNode.marks.length - 1].attrs.userid;
+ if (prevUser != Doc.CurrentUserEmail) {
return false;
}
}
@@ -263,7 +263,7 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey
bind('Backspace', (state: EditorState, dispatch: (tx: Transaction) => void) => {
if (props.onKey?.(event, props)) return true;
if (!canEdit(state)) return true;
-
+
if (
!deleteSelection(state, (tx: Transaction) => {
dispatch(updateBullets(tx, schema));
@@ -334,7 +334,7 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey
//Command to create a blank space
bind('Space', (state: EditorState, dispatch: (tx: Transaction) => void) => {
- if (GetEffectiveAcl(props.DataDoc)!=AclEdit && GetEffectiveAcl(props.DataDoc)!=AclAugment && GetEffectiveAcl(props.DataDoc)!=AclAdmin) return true;
+ if (GetEffectiveAcl(props.DataDoc) != AclEdit && GetEffectiveAcl(props.DataDoc) != AclAugment && GetEffectiveAcl(props.DataDoc) != AclAdmin) return true;
const marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks());
dispatch(splitMetadata(marks, state.tr));
return false;
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 99712fb04..9c138d348 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -20,7 +20,6 @@ import {
AclEdit,
AclPrivate,
AclReadonly,
- AclSelfEdit,
AclUnset,
Animation,
CachedUpdates,
@@ -138,7 +137,7 @@ export const HierarchyMapping: Map<symbol, { level:aclLevel; name: SharingPermis
[AclAdmin, { level: aclLevel.admin, name: SharingPermissions.Admin, image: '⬢' }],
[AclUnset, { level: aclLevel.unset, name: SharingPermissions.Unset, image: '▲' }],
]);
-export const ReverseHierarchyMap: Map<string, { level: aclLevel; acl: symbol ; image: string}> = new Map(Array.from(HierarchyMapping.entries()).map(value => [value[1].name, { level: value[1].level, acl: value[0], image: value[1].image }]));
+export const ReverseHierarchyMap: Map<string, { level: aclLevel; acl: symbol; image: string }> = new Map(Array.from(HierarchyMapping.entries()).map(value => [value[1].name, { level: value[1].level, acl: value[0], image: value[1].image }]));
// caches the document access permissions for the current user.
// this recursively updates all protos as well.
@@ -478,6 +477,14 @@ export namespace Doc {
// });
// }
+ export function SetContainer(doc: Doc, container: Doc) {
+ doc.embedContainer = container;
+ if (Doc.GetProto(container).author === doc.author) {
+ Object.keys(Doc.GetProto(container))
+ .filter(key => key.startsWith('acl'))
+ .forEach(key => (doc[key] = Doc.GetProto(container)[key]));
+ }
+ }
export function RunCachedUpdate(doc: Doc, field: string) {
const update = doc[CachedUpdates][field];
if (update) {
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 0f613d926..48de36efe 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -131,10 +131,10 @@ export function inheritParentAcls(parent: Doc, child: Doc) {
for (const key of Object.keys(parent)) {
// if the default acl mode is private, then don't inherit the acl-Public permission, but set it to private.
// const permission: string = key === 'acl-Public' && Doc.defaultAclPrivate ? AclPrivate : parent[key];
- const symbol = ReverseHierarchyMap.get(StrCast(parent[key]))
- if (symbol){
+ const symbol = ReverseHierarchyMap.get(StrCast(parent[key]));
+ if (symbol) {
const sharePermission = HierarchyMapping.get(symbol.acl!)!.name;
- key.startsWith('acl') && distributeAcls(key, sharePermission, child)
+ key.startsWith('acl') && distributeAcls(key, sharePermission, child);
}
}
}
@@ -171,7 +171,7 @@ const getEffectiveAclCache = computedFn(function (target: any, user?: string) {
// return layout acl from cache or chache the acl and return.
const getEffectiveLayoutAclCache = computedFn(function (target: any, user?: string) {
return getEffectiveLayoutAcl(target, user);
- }, true);
+}, true);
/**
* Calculates the effective access right to a document for the current user.
@@ -183,13 +183,13 @@ export function GetEffectiveAcl(target: any, user?: string): symbol {
}
/**
-* Calculates the effective access layout right to a document for the current user. By getting the container's effective acl if the layout acl isn't set.
-*/
+ * Calculates the effective access layout right to a document for the current user. By getting the container's effective acl if the layout acl isn't set.
+ */
export function GetEffectiveLayoutAcl(target: any, user?: string): symbol {
if (!target) return AclPrivate;
if (target[UpdatingFromServer]) return AclAdmin;
return getEffectiveLayoutAclCache(target, user);
- }
+}
function getPropAcl(target: any, prop: string | symbol | number) {
if (typeof prop === 'symbol' || target[UpdatingFromServer]) return AclAdmin; // requesting the UpdatingFromServer prop or AclSym must always go through to keep the local DB consistent
@@ -234,9 +234,9 @@ function getEffectiveAcl(target: any, user?: string): symbol {
}
/**
-* Returns the layout acl that is effective on the document passed through as the target. If no layout acls
-* have been set, it returns the regular acls for the document target is contained in.
-*/
+ * Returns the layout acl that is effective on the document passed through as the target. If no layout acls
+ * have been set, it returns the regular acls for the document target is contained in.
+ */
function getEffectiveLayoutAcl(target: any, user?: string): symbol {
const targetAcls = target[DocAcl];
@@ -248,27 +248,24 @@ function getEffectiveLayoutAcl(target: any, user?: string): symbol {
if ((GetCachedGroupByName(entity) || userChecked === entity || entity === 'Me') && entity != 'Public') {
if (effectiveAcl && HierarchyMapping.get(value as symbol)!.level > HierarchyMapping.get(effectiveAcl)!.level) {
effectiveAcl = value as symbol;
- }
- else{
+ } else {
effectiveAcl = value as symbol;
}
}
}
- if (effectiveAcl){
+ if (effectiveAcl) {
return DocServer?.Control?.isReadOnly?.() && HierarchyMapping.get(effectiveAcl)!.level < aclLevel.editable ? AclEdit : effectiveAcl;
- }
- else{
+ } else {
return GetEffectiveAcl(Doc.GetProto(target['embedContainer']), user);
}
}
// authored documents are private until an ACL is set.
const targetAuthor = target.__fieldTuples?.author || target.author; // target may be a Doc of Proxy, so check __fieldTuples.author and .author
if (targetAuthor && targetAuthor !== userChecked) return AclPrivate;
- return AclAdmin;
+ return AclAdmin;
}
-
/**
* Recursively distributes the access right for a user across the children of a document and its annotations.
* @param key the key storing the access right (e.g. acl-groupname)
@@ -286,7 +283,7 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc
//apparently we can't call updateCachedAcls twice (once for the main dashboard, and again for the nested dashboard...???)
updateCachedAcls(target);
}
- return;
+ //return;
}
visited.push(target);