From a807da6b6fed067888f817e2273b29b8b6219e52 Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Fri, 23 Jun 2023 12:05:24 -0400
Subject: fixed collection acls

---
 src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 77cb7f88c..430e8ecd5 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -9,7 +9,7 @@ import { RichTextField } from '../../../../fields/RichTextField';
 import { SchemaHeaderField } from '../../../../fields/SchemaHeaderField';
 import { Cast, DocCast, FieldValue, NumCast, StrCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
-import { GetEffectiveAcl } from '../../../../fields/util';
+import { GetEffectiveAcl, SharingPermissions } from '../../../../fields/util';
 import { intersectRect, returnFalse, Utils } from '../../../../Utils';
 import { CognitiveServices } from '../../../cognitive_services/CognitiveServices';
 import { Docs, DocumentOptions, DocUtils } from '../../../documents/Documents';
@@ -390,7 +390,11 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
         newCollection.x = this.Bounds.left;
         newCollection.y = this.Bounds.top;
         newCollection.layout_fitWidth = true;
-        selected.forEach(d => (d.embedContainer = newCollection));
+        newCollection['acl-Public'] = Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment;
+        selected.forEach(d => {
+            d.embedContainer = newCollection;
+            d['acl-Public'] = Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment;
+        });
         this.hideMarquee();
         return newCollection;
     });
-- 
cgit v1.2.3-70-g09d2


From 5a9af979cc293d0e3843270ee053c24bf0eb6ef5 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 5 Jul 2023 16:15:27 -0400
Subject: changed acl inheritance for docking views.

---
 src/client/documents/Documents.ts                  | 10 ++--
 src/client/util/LinkFollower.ts                    |  2 +-
 src/client/util/SharingManager.tsx                 | 70 ++++++++++------------
 src/client/views/DocComponent.tsx                  | 30 +++++-----
 src/client/views/DocumentDecorations.tsx           | 40 ++++++++-----
 .../views/collections/CollectionDockingView.tsx    | 12 ++--
 .../views/collections/CollectionTreeView.tsx       |  2 +-
 src/client/views/collections/TabDocView.tsx        |  2 +-
 src/client/views/collections/TreeView.tsx          |  8 +--
 .../collections/collectionFreeForm/MarqueeView.tsx |  2 +-
 src/client/views/nodes/ComparisonBox.tsx           |  2 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  2 +-
 .../formattedText/ProsemirrorExampleTransfer.ts    | 10 ++--
 src/fields/Doc.ts                                  | 11 +++-
 src/fields/util.ts                                 | 33 +++++-----
 15 files changed, 123 insertions(+), 113 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx')

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);
 
-- 
cgit v1.2.3-70-g09d2


From 06cfe3cbba127d865e788b00561f8a591af1bd81 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 11 Jul 2023 15:32:08 -0400
Subject: more fixes to simplify sharing

---
 src/client/documents/Documents.ts                  | 31 ++++++------
 src/client/util/CurrentUserUtils.ts                |  6 +--
 src/client/util/DocumentManager.ts                 |  2 +-
 src/client/util/SharingManager.tsx                 |  9 ++--
 src/client/views/DashboardView.tsx                 | 15 +++---
 src/client/views/DocComponent.tsx                  | 15 +-----
 src/client/views/PropertiesView.tsx                | 55 ++++++++++------------
 .../views/collections/CollectionDockingView.tsx    |  4 +-
 .../collections/collectionFreeForm/MarqueeView.tsx |  8 +---
 src/client/views/nodes/button/FontIconBox.tsx      |  2 +-
 src/client/views/search/SearchBox.tsx              |  2 +-
 src/fields/Doc.ts                                  | 16 ++-----
 src/fields/DocSymbols.ts                           |  1 -
 src/fields/util.ts                                 | 39 +++++++--------
 14 files changed, 88 insertions(+), 117 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index f1ba852f9..4ebbfbd1c 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -169,8 +169,8 @@ export class DocumentOptions {
     _nativeDimModifiable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers');
     _nativeHeightUnfrozen?: BOOLt = new BoolInfo('native height can be changed independent of width by dragging decoration resizers');
 
-    'acl-Public'?: string; // public permissions
-    '_acl-Public'?: string; // public permissions
+    'acl-Guest'?: string; // public permissions
+    '_acl-Guest'?: string; // public permissions
     type?: DTYPEt = new DTypeInfo('type of document', true);
     type_collection?: COLLt = new CTypeInfo('how collection is rendered'); // sub type of a collection
     _type_collection?: COLLt = new CTypeInfo('how collection is rendered'); // sub type of a collection
@@ -825,8 +825,7 @@ export namespace Docs {
             const { omit: dataProps, extract: viewProps } = OmitKeys(options, viewKeys, '^_');
 
             // dataProps['acl-Override'] = SharingPermissions.Unset;
-            dataProps['acl-Public'] = options['acl-Public'] ? options['acl-Public'] : Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment;
-
+            dataProps['acl-Guest'] = options['acl-Guest'] ?? (Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.View);
             dataProps.isSystem = viewProps.isSystem;
             dataProps.isDataDoc = true;
             dataProps.author = Doc.CurrentUserEmail;
@@ -848,16 +847,17 @@ export namespace Docs {
                 dataDoc.proto = proto;
             }
 
-            const viewFirstProps: { [id: string]: any } = {};
-            // viewFirstProps['acl-Public'] = options['_acl-Public'] ? options['_acl-Public'] : Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment;
-            // viewFirstProps['acl-Override'] = SharingPermissions.Unset;
-            viewFirstProps.author = Doc.CurrentUserEmail;
+            const viewFirstProps: { [id: string]: any } = { author: Doc.CurrentUserEmail };
+            viewFirstProps['acl-Guest'] = options['_acl-Guest'] ?? (Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.View);
             let viewDoc: Doc;
             // determines whether viewDoc should be created using placeholder Doc or default
             if (placeholderDoc) {
                 placeholderDoc._height = options._height !== undefined ? Number(options._height) : undefined;
                 placeholderDoc._width = options._width !== undefined ? Number(options._width) : undefined;
                 viewDoc = Doc.assign(placeholderDoc, viewFirstProps, true, true);
+                Array.from(Object.keys(placeholderDoc))
+                    .filter(key => key.startsWith('acl'))
+                    .forEach(key => (dataDoc[key] = viewDoc[key] = placeholderDoc[key]));
             } else {
                 viewDoc = Doc.assign(Doc.MakeDelegate(dataDoc, delegId), viewFirstProps, true, true);
             }
@@ -997,7 +997,7 @@ export namespace Docs {
             I.rotation = 0;
             I.defaultDoubleClick = 'click';
             I.author_date = new DateField();
-            I['acl-Public'] = Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment;
+            I['acl-Guest'] = Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.View;
             //I['acl-Override'] = SharingPermissions.Unset;
             I[Initializing] = false;
 
@@ -1169,10 +1169,13 @@ export namespace Docs {
             const doc = DockDocument(
                 configs.map(c => c.doc),
                 JSON.stringify(layoutConfig),
-                options,
+                Doc.CurrentUserEmail === 'guest' ? options : { 'acl-Guest': SharingPermissions.View, ...options },
                 id
             );
-            configs.map(c => Doc.SetContainer(c.doc, doc));
+            configs.map(c => {
+                Doc.SetContainer(c.doc, doc);
+                inheritParentAcls(doc, c.doc, false);
+            });
             return doc;
         }
 
@@ -1332,8 +1335,8 @@ export namespace DocUtils {
                 source,
                 target,
                 {
-                    'acl-Public': SharingPermissions.Augment,
-                    '_acl-Public': SharingPermissions.Augment,
+                    'acl-Guest': SharingPermissions.Augment,
+                    '_acl-Guest': SharingPermissions.Augment,
                     title: ComputedField.MakeFunction('generateLinkTitle(self)') as any,
                     link_anchor_1_useSmallAnchor: source.useSmallAnchor ? true : undefined,
                     link_anchor_2_useSmallAnchor: target.useSmallAnchor ? true : undefined,
@@ -1854,8 +1857,6 @@ export namespace DocUtils {
             Doc.SetInPlace(ndoc, 'title', ndoc.title + ' ' + NumCast(dragFactory['dragFactory_count']).toString(), true);
         }
 
-        if (ndoc && Doc.ActiveDashboard) inheritParentAcls(Doc.ActiveDashboard, ndoc);
-
         return ndoc;
     }
     export function delegateDragFactory(dragFactory: Doc) {
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 11a8dcaf6..2cee37380 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -765,7 +765,7 @@ export class CurrentUserUtils {
             linkDocs.title = "LINK DATABASE: " + Doc.CurrentUserEmail;
             linkDocs.author = Doc.CurrentUserEmail;
             linkDocs.data = new List<Doc>([]);
-            linkDocs["acl-Public"] = SharingPermissions.Augment;
+            linkDocs["acl-Guest"] = SharingPermissions.Augment;
             doc.myLinkDatabase = new PrefetchProxy(linkDocs);
         }
     }
@@ -788,7 +788,7 @@ export class CurrentUserUtils {
             childContextMenuScripts: new List<ScriptField>([addToDashboards!,]),
             childContextMenuLabels: new List<string>(["Add to Dashboards",]),
             childContextMenuIcons: new List<string>(["user-plus",]),
-            "acl-Public": SharingPermissions.Augment, "_acl-Public": SharingPermissions.Augment,
+            "acl-Guest": SharingPermissions.Augment, "_acl-Guest": SharingPermissions.Augment,
             childDragAction: "embed", isSystem: true, contentPointerEvents: "all", childLimitHeight: 0, _yMargin: 0, _gridGap: 15, childDontRegisterViews:true,
             // NOTE: treeViewHideTitle & _layout_showTitle is for a TreeView's editable title, _layout_showTitle is for DocumentViews title bar
             _layout_showTitle: "title", treeViewHideTitle: true, ignoreClick: true, _lockedPosition: true, layout_boxShadow: "0 0", _chromeHidden: true, dontRegisterView: true, 
@@ -823,7 +823,7 @@ export class CurrentUserUtils {
             async () => {
                 const groups = await DocListCastAsync(DocCast(doc.globalGroupDatabase).data);
                 const mygroups = groups?.filter(group => JSON.parse(StrCast(group.members)).includes(Doc.CurrentUserEmail)) || [];
-                SetCachedGroups(["Public", ...mygroups?.map(g => StrCast(g.title))]);
+                SetCachedGroups(["Guest", ...mygroups?.map(g => StrCast(g.title))]);
             }, { fireImmediately: true });
         doc.isSystem ?? (doc.isSystem = true);
         doc.title ?? (doc.title = Doc.CurrentUserEmail);
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 3f0848d00..b921b3116 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -194,7 +194,7 @@ export class DocumentManager {
         var containerDocContext = srcContext ? [srcContext, doc] : [doc];
         while (
             containerDocContext.length &&
-            containerDocContext[0]?.embedContainer &&
+            DocCast(containerDocContext[0]?.embedContainer) &&
             DocCast(containerDocContext[0].embedContainer)?._type_collection !== CollectionViewType.Docking &&
             (includeExistingViews || !DocumentManager.Instance.getDocumentView(containerDocContext[0]))
         ) {
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 37c813279..407396cb4 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -159,7 +159,7 @@ export class SharingManager extends React.Component<{}> {
         const target = targetDoc || this.targetDoc!;
         const acl = `acl-${normalizeEmail(user.email)}`;
         const docs = SelectionManager.Views().length < 2 ? [target] : SelectionManager.Views().map(docView => docView.rootDoc);
-        docs.map(doc => (this.layoutDocAcls ? doc : Doc.GetProto(doc))).forEach(doc => {
+        docs.map(doc => (this.layoutDocAcls || doc.dockingConfig ? doc : Doc.GetProto(doc))).forEach(doc => {
             distributeAcls(acl, permission as SharingPermissions, doc, undefined, this.overrideNested ? true : undefined);
             if (permission !== SharingPermissions.None) Doc.AddDocToList(sharingDoc, storage, doc);
             else GetEffectiveAcl(doc, user.email) === AclPrivate && Doc.RemoveDocFromList(sharingDoc, storage, (doc.createdFrom as Doc) || doc);
@@ -176,7 +176,7 @@ export class SharingManager extends React.Component<{}> {
         const acl = `acl-${normalizeEmail(StrCast(group.title))}`;
 
         const docs = SelectionManager.Views().length < 2 ? [target] : SelectionManager.Views().map(docView => docView.rootDoc);
-        docs.map(doc => (this.layoutDocAcls ? doc : Doc.GetProto(doc))).forEach(doc => {
+        docs.map(doc => (this.layoutDocAcls || doc.dockingConfig ? doc : Doc.GetProto(doc))).forEach(doc => {
             distributeAcls(acl, permission as SharingPermissions, doc, undefined, this.overrideNested ? true : undefined);
 
             if (group instanceof Doc) {
@@ -218,7 +218,7 @@ export class SharingManager extends React.Component<{}> {
      */
     shareFromPropertiesSidebar = undoable((shareWith: string, permission: SharingPermissions, docs: Doc[], layout: boolean) => {
         if (layout) this.layoutDocAcls = true;
-        if (shareWith !== 'Public' && shareWith !== 'Override') {
+        if (shareWith !== 'Guest') {
             const user = this.users.find(({ user: { email } }) => email === (shareWith === 'Me' ? Doc.CurrentUserEmail : shareWith));
             docs.forEach(doc => {
                 if (user) this.setInternalSharing(user, permission, doc);
@@ -291,7 +291,6 @@ export class SharingManager extends React.Component<{}> {
     private sharingOptions(uniform: boolean, override?: boolean) {
         const dropdownValues: string[] = Object.values(SharingPermissions);
         if (!uniform) dropdownValues.unshift('-multiple-');
-        if (!override) dropdownValues.splice(dropdownValues.indexOf(SharingPermissions.Unset), 1);
         return dropdownValues.map(permission => (
             <option key={permission} value={permission}>
                 {concat(ReverseHierarchyMap.get(permission)?.image, ' ', permission)}
@@ -504,7 +503,7 @@ export class SharingManager extends React.Component<{}> {
 
         // the list of groups shared with
         const groupListMap: (Doc | { title: string })[] = groups.filter(({ title }) => (docs.length > 1 ? commonKeys.includes(`acl-${normalizeEmail(StrCast(title))}`) : true));
-        groupListMap.unshift({ title: 'Public' }); //, { title: "ALL" });
+        groupListMap.unshift({ title: 'Guest' }); //, { title: "ALL" });
         const groupListContents = groupListMap.map(group => {
             let groupKey = `acl-${StrCast(group.title)}`;
             const uniform = docs.every(doc => doc?.[DocAcl]?.[groupKey] === docs[0]?.[DocAcl]?.[groupKey]);
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx
index 123090fcf..9b16ecfa7 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -1,16 +1,17 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Button, ColorPicker, FontSize, IconButton, Size } from 'browndash-components';
+import { Button, ColorPicker, Size } from 'browndash-components';
 import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
+import { FaPlus } from 'react-icons/fa';
 import { Doc, DocListCast, DocListCastAsync } from '../../fields/Doc';
-import { AclPrivate, AclUnset, DocAcl, DocData } from '../../fields/DocSymbols';
+import { AclPrivate, DocAcl } from '../../fields/DocSymbols';
 import { Id } from '../../fields/FieldSymbols';
 import { List } from '../../fields/List';
 import { PrefetchProxy } from '../../fields/Proxy';
 import { listSpec } from '../../fields/Schema';
 import { ScriptField } from '../../fields/ScriptField';
-import { Cast, DocCast, ImageCast, StrCast } from '../../fields/Types';
+import { Cast, ImageCast, StrCast } from '../../fields/Types';
 import { DocServer } from '../DocServer';
 import { Docs, DocumentOptions, DocUtils } from '../documents/Documents';
 import { CollectionViewType } from '../documents/DocumentTypes';
@@ -25,7 +26,6 @@ import './DashboardView.scss';
 import { Colors } from './global/globalEnums';
 import { MainViewModal } from './MainViewModal';
 import { ButtonType } from './nodes/button/FontIconBox';
-import { FaPlus } from 'react-icons/fa';
 
 enum DashboardGroup {
     MyDashboards,
@@ -167,8 +167,8 @@ export class DashboardView extends React.Component {
                         {this.getDashboards(this.selectedDashboardGroup).map(dashboard => {
                             const href = ImageCast(dashboard.thumb)?.url.href;
                             const shared = Object.keys(dashboard[DocAcl])
-                                .filter(key => key !== `acl-${Doc.CurrentUserEmailNormalized}` && !['acl-Me', 'acl-Public'].includes(key))
-                                .some(key => ![AclUnset, AclPrivate].includes(dashboard[DocAcl][key]));
+                                .filter(key => key !== `acl-${Doc.CurrentUserEmailNormalized}` && !['acl-Me', 'acl-Guest'].includes(key))
+                                .some(key => dashboard[DocAcl][key] !== AclPrivate);
                             return (
                                 <div className="dashboard-container" key={dashboard[Id]} style={{ background: shared ? 'lightgreen' : '' }} onContextMenu={e => this.onContextMenu(dashboard, e)} onClick={e => this.clickDashboard(e, dashboard)}>
                                     <img
@@ -378,9 +378,6 @@ export class DashboardView extends React.Component {
         const freeformDoc = Doc.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions);
         const dashboardDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600 }], { title: title }, id, 'row');
 
-        // switching the tabs from the datadoc to the regular doc
-        const dashboardTabs = DocListCast(dashboardDoc[DocData].data);
-        dashboardDoc.data = new List<Doc>(dashboardTabs);
         dashboardDoc['pane-count'] = 1;
 
         Doc.AddDocToList(dashboards, 'data', dashboardDoc);
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 10985c3f1..a41fc8ded 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -190,23 +190,12 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
             }
             const added = docs;
             if (added.length) {
-                Object.keys(Doc.GetProto(this.rootDoc)[DocAcl]) // apply all collection acls (except pseudo-acl 'Me') to each added doc
-                    .filter(key => key !== 'acl-Me')
-                    .forEach(key =>
-                        added.forEach(d => {
-                            const permissionString = StrCast(Doc.GetProto(this.props.Document)[key]);
-                            const permissionSymbol = ReverseHierarchyMap.get(permissionString)?.acl;
-                            const permission = permissionSymbol && HierarchyMapping.get(permissionSymbol)?.name;
-                            distributeAcls(key, permission ?? SharingPermissions.Augment, d, undefined, false);
-                        })
-                    );
-
                 if ([AclAugment, AclEdit, AclAdmin].includes(effectiveAcl)) {
-                    added.map(doc => {
+                    added.forEach(doc => {
                         doc._dragOnlyWithinContainer = undefined;
                         if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.rootDoc;
                         Doc.SetContainer(doc, this.rootDoc);
-                        inheritParentAcls(targetDataDoc, doc);
+                        inheritParentAcls(targetDataDoc, doc, true);
                     });
 
                     const annoDocs = targetDataDoc[annotationKey ?? this.annotationKey] as List<Doc>;
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 633401d58..2e10bf346 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -308,21 +308,16 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     /**
      * @returns the options for the permissions dropdown.
      */
-    getPermissionsSelect(user: string, permission: string) {
-        const dropdownValues: string[] = Object.values(SharingPermissions);
+    getPermissionsSelect(user: string, permission: string, showGuestOptions: boolean) {
+        const dropdownValues: string[] = showGuestOptions ? [SharingPermissions.None, SharingPermissions.View] : Object.values(SharingPermissions);
         if (permission === '-multiple-') dropdownValues.unshift(permission);
-        if (user !== 'Override') {
-            dropdownValues.splice(dropdownValues.indexOf(SharingPermissions.Unset), 1);
-        }
         return (
             <select className="propertiesView-permissions-select" value={permission} onChange={e => this.changePermissions(e, user)}>
-                {dropdownValues
-                    .filter(permission => !Doc.noviceMode || ![SharingPermissions.View].includes(permission as any))
-                    .map(permission => (
-                        <option className="propertiesView-permisssions-select" key={permission} value={permission}>
-                            {concat(ReverseHierarchyMap.get(permission)?.image, ' ', permission)}
-                        </option>
-                    ))}
+                {dropdownValues.map(permission => (
+                    <option className="propertiesView-permisssions-select" key={permission} value={permission}>
+                        {concat(ReverseHierarchyMap.get(permission)?.image, ' ', permission)}
+                    </option>
+                ))}
             </select>
         );
     }
@@ -379,7 +374,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                 </div>
                 {/* {name !== "Me" ? this.notifyIcon : null} */}
                 <div className="propertiesView-sharingTable-item-permission">
-                    {this.colorACLDropDown(name, admin, permission, showExpansionIcon)}
+                    {this.colorACLDropDown(name, admin, permission, false)}
                     {(permission === 'Owner' && name == 'Me') || showExpansionIcon ? this.expansionIcon : null}
                 </div>
             </div>
@@ -389,13 +384,13 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     /**
      * @returns a colored dropdown bar reflective of the permission
      */
-    colorACLDropDown(name: string, admin: boolean, permission: string, showExpansionIcon?: boolean) {
+    colorACLDropDown(name: string, admin: boolean, permission: string, showGuestOptions: boolean) {
         var shareImage = ReverseHierarchyMap.get(permission)?.image;
         return (
             <div>
                 <div className={'propertiesView-shareDropDown'}>
                     <div className={`propertiesView-shareDropDown${permission}`}>
-                        <div className="propertiesView-shareDropDown">{admin && permission !== 'Owner' ? this.getPermissionsSelect(name, permission) : concat(shareImage, ' ', permission)}</div>
+                        <div className="propertiesView-shareDropDown">{admin && permission !== 'Owner' ? this.getPermissionsSelect(name, permission, showGuestOptions) : concat(shareImage, ' ', permission)}</div>
                     </div>
                 </div>
             </div>
@@ -430,15 +425,16 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         const individualTableEntries = [];
         const usersAdded: string[] = []; // all shared users being added - organized by denormalized email
 
+        const seldoc = this.layoutDocAcls || !this.selectedDoc ? this.selectedDoc : Doc.GetProto(this.selectedDoc);
         // adds each user to usersAdded
         SharingManager.Instance.users.forEach(eachUser => {
             var userOnDoc = true;
-            if (this.selectedDoc) {
-                if (this.selectedDoc['acl-' + normalizeEmail(eachUser.user.email)] == '' || this.selectedDoc['acl-' + normalizeEmail(eachUser.user.email)] == undefined) {
+            if (seldoc) {
+                if (Doc.GetT(seldoc, 'acl-' + normalizeEmail(eachUser.user.email), 'string', true) === '' || Doc.GetT(seldoc, 'acl-' + normalizeEmail(eachUser.user.email), 'string', true) === undefined) {
                     userOnDoc = false;
                 }
             }
-            if (userOnDoc && !usersAdded.includes(eachUser.user.email) && eachUser.user.email != 'Public' && eachUser.user.email != target.author) {
+            if (userOnDoc && !usersAdded.includes(eachUser.user.email) && eachUser.user.email !== 'guest' && eachUser.user.email != target.author) {
                 usersAdded.push(eachUser.user.email);
             }
         });
@@ -447,15 +443,16 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         usersAdded.sort(this.sortUsers);
         usersAdded.map(userEmail => {
             const userKey = `acl-${normalizeEmail(userEmail)}`;
-            var permission = StrCast(target[userKey]);
+            var aclField = Doc.GetT(this.layoutDocAcls ? target : Doc.GetProto(target), userKey, 'string', true);
+            var permission = StrCast(aclField);
             individualTableEntries.unshift(this.sharingItem(userEmail, showAdmin, permission!, false)); // adds each user
         });
 
         // adds current user
         var userEmail = Doc.CurrentUserEmail;
+        if (userEmail == 'guest') userEmail = 'Guest';
         const userKey = `acl-${normalizeEmail(userEmail)}`;
-        if (userEmail == 'guest') userEmail = 'Public';
-        if (!usersAdded.includes(userEmail) && userEmail != 'Public' && userEmail != target.author) {
+        if (!usersAdded.includes(userEmail) && userEmail !== 'Guest' && userEmail != target.author) {
             var permission;
             if (this.layoutDocAcls) {
                 if (target[DocAcl][userKey]) permission = HierarchyMapping.get(target[DocAcl][userKey])?.name;
@@ -473,7 +470,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         const groupList = GroupManager.Instance?.allGroups || [];
         groupList.sort(this.sortGroups);
         groupList.map(group => {
-            if (group.title != 'Public' && this.selectedDoc) {
+            if (group.title != 'Guest' && this.selectedDoc) {
                 const groupKey = 'acl-' + normalizeEmail(StrCast(group.title));
                 if (this.selectedDoc[groupKey] != '' && this.selectedDoc[groupKey] != undefined) {
                     var permission;
@@ -489,17 +486,11 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
         });
 
         // public permission
-        const publicPermission = StrCast((this.layoutDocAcls ? target : Doc.GetProto(target))['acl-Public']);
+        const publicPermission = StrCast((this.layoutDocAcls ? target : Doc.GetProto(target))['acl-Guest']);
 
         return (
             <div>
                 <br />
-                Public / Guest Users
-                <div>{this.colorACLDropDown('Public', showAdmin, publicPermission!, false)}</div>
-                <div>
-                    {' '}
-                    <br></br> Individual Users with Access to this Document{' '}
-                </div>
                 <div className="propertiesView-sharingTable">{<div> {individualTableEntries}</div>}</div>
                 {groupTableEntries.length > 0 ? (
                     <div>
@@ -510,6 +501,12 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         <div className="propertiesView-sharingTable">{<div> {groupTableEntries}</div>}</div>
                     </div>
                 ) : null}
+                Guest
+                <div>{this.colorACLDropDown('Guest', true, publicPermission!, true)}</div>
+                <div>
+                    {' '}
+                    <br></br> Individual Users with Access to this Document{' '}
+                </div>
             </div>
         );
     }
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 13d3b2cdc..8d1b46ebb 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -517,7 +517,7 @@ export class CollectionDockingView extends CollectionSubView() {
                     _layout_fitWidth: true,
                     title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`,
                 });
-                inheritParentAcls(this.rootDoc, docToAdd);
+                inheritParentAcls(this.rootDoc, docToAdd, false);
                 CollectionDockingView.AddSplit(docToAdd, OpenWhereMod.none, stack);
             }
         });
@@ -560,7 +560,7 @@ export class CollectionDockingView extends CollectionSubView() {
                             _freeform_backgroundGrid: true,
                             title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`,
                         });
-                        inheritParentAcls(this.dataDoc, Doc.GetProto(docToAdd));
+                        inheritParentAcls(this.dataDoc, docToAdd, false);
                         CollectionDockingView.AddSplit(docToAdd, OpenWhereMod.none, stack);
                     }
                 })
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 764b1e08a..e2718b52d 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -9,7 +9,7 @@ import { RichTextField } from '../../../../fields/RichTextField';
 import { SchemaHeaderField } from '../../../../fields/SchemaHeaderField';
 import { Cast, DocCast, FieldValue, NumCast, StrCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
-import { GetEffectiveAcl, SharingPermissions } from '../../../../fields/util';
+import { distributeAcls, GetEffectiveAcl, SharingPermissions } from '../../../../fields/util';
 import { intersectRect, returnFalse, Utils } from '../../../../Utils';
 import { CognitiveServices } from '../../../cognitive_services/CognitiveServices';
 import { Docs, DocumentOptions, DocUtils } from '../../../documents/Documents';
@@ -390,11 +390,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
         newCollection.x = this.Bounds.left;
         newCollection.y = this.Bounds.top;
         newCollection.layout_fitWidth = true;
-        newCollection['acl-Public'] = Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment;
-        selected.forEach(d => {
-            Doc.SetContainer(d, newCollection);
-            d['acl-Public'] = Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment;
-        });
+        selected.forEach(d => Doc.SetContainer(d, newCollection));
         this.hideMarquee();
         return newCollection;
     });
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index 5bba51ec8..a0b0caf98 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -597,7 +597,7 @@ ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: b
             if (contentFrameNumber !== undefined) {
                 CollectionFreeFormDocumentView.setStringValues(contentFrameNumber, dv.rootDoc, { fieldKey: color });
             } else {
-                dv.rootDoc['_' + fieldKey] = color;
+                dv.dataDoc[fieldKey] = color;
             }
         });
     } else {
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index d13c09443..ab9eebd78 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -222,7 +222,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
             'width',
             'layout_autoHeight',
             'acl-Override',
-            'acl-Public',
+            'acl-Guest',
             'embedContainer',
             'zIndex',
             'height',
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 698e09915..6121668e3 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -20,7 +20,6 @@ import {
     AclEdit,
     AclPrivate,
     AclReadonly,
-    AclUnset,
     Animation,
     CachedUpdates,
     DirectLinks,
@@ -134,7 +133,6 @@ export const HierarchyMapping: Map<symbol, { level:aclLevel; name: SharingPermis
     [AclAugment,  { level: aclLevel.augmentable,  name: SharingPermissions.Augment, image: '⬟' }],
     [AclEdit,     { level: aclLevel.editable,     name: SharingPermissions.Edit,    image: '⬢' }],
     [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 }]));
 
@@ -380,7 +378,8 @@ export class Doc extends RefField {
         return self.resolvedDataDoc && !self.isTemplateForField ? self : Doc.GetProto(Cast(Doc.Layout(self).resolvedDataDoc, Doc, null) || self);
     }
     @computed get __LAYOUT__(): Doc | undefined {
-        const templateLayoutDoc = Cast(Doc.LayoutField(this[SelfProxy]), Doc, null);
+        const self = this[SelfProxy];
+        const templateLayoutDoc = Cast(Doc.LayoutField(self), Doc, null);
         if (templateLayoutDoc) {
             let renderFieldKey: any;
             const layoutField = templateLayoutDoc[StrCast(templateLayoutDoc.layout_fieldKey, 'layout')];
@@ -389,7 +388,7 @@ export class Doc extends RefField {
             } else {
                 return Cast(layoutField, Doc, null);
             }
-            return Cast(this[SelfProxy][renderFieldKey + '-layout[' + templateLayoutDoc[Id] + ']'], Doc, null) || templateLayoutDoc;
+            return Cast(self[renderFieldKey + '-layout[' + templateLayoutDoc[Id] + ']'], Doc, null) || templateLayoutDoc;
         }
         return undefined;
     }
@@ -480,11 +479,6 @@ 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') && !key.includes(Doc.CurrentUserEmailNormalized))
-                .forEach(key => (doc[key] = Doc.GetProto(container)[key]));
-        }
     }
     export function RunCachedUpdate(doc: Doc, field: string) {
         const update = doc[CachedUpdates][field];
@@ -697,7 +691,7 @@ export namespace Doc {
             Doc.SetLayout(embedding, Doc.MakeEmbedding(layout));
         }
         embedding.createdFrom = doc;
-        embedding.proto_embeddingId = Doc.GetProto(doc).proto_embeddingId = DocListCast(Doc.GetProto(doc).proto_embeddings).length + 1;
+        embedding.proto_embeddingId = Doc.GetProto(doc).proto_embeddingId = DocListCast(Doc.GetProto(doc).proto_embeddings).length - 1;
         embedding.title = ComputedField.MakeFunction(`renameEmbedding(this)`);
         embedding.author = Doc.CurrentUserEmail;
 
@@ -1027,7 +1021,6 @@ export namespace Doc {
             Doc.AddDocToList(Doc.GetProto(copy)[DocData], 'proto_embeddings', copy);
         }
         copy.embedContainer = undefined;
-        Doc.defaultAclPrivate && (copy['acl-Public'] = 'Not Shared');
         if (retitle) {
             copy.title = incrementTitleCopy(StrCast(copy.title));
         }
@@ -1087,7 +1080,6 @@ export namespace Doc {
             const applied = ApplyTemplateTo(templateDoc, target, targetKey, templateDoc.title + '(...' + _applyCount++ + ')');
             target.layout_fieldKey = targetKey;
             applied && (Doc.GetProto(applied).type = templateDoc.type);
-            Doc.defaultAclPrivate && (applied['acl-Public'] = 'Not Shared');
             return applied;
         }
         return undefined;
diff --git a/src/fields/DocSymbols.ts b/src/fields/DocSymbols.ts
index eab26ed10..66d1ab094 100644
--- a/src/fields/DocSymbols.ts
+++ b/src/fields/DocSymbols.ts
@@ -13,7 +13,6 @@ export const DocFields = Symbol('DocFields');
 export const DocCss = Symbol('DocCss');
 export const DocAcl = Symbol('DocAcl');
 export const DirectLinks = Symbol('DocDirectLinks');
-export const AclUnset = Symbol('DocAclUnset');
 export const AclPrivate = Symbol('DocAclOwnerOnly');
 export const AclReadonly = Symbol('DocAclReadOnly');
 export const AclAugment = Symbol('DocAclAugment');
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 034229319..e89cb1fb1 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -131,17 +131,19 @@ export function denormalizeEmail(email: string) {
 /**
  * Copies parent's acl fields to the child
  */
-export function inheritParentAcls(parent: Doc, child: Doc) {
+export function inheritParentAcls(parent: Doc, child: Doc, layoutOnly: boolean) {
     if (GetEffectiveAcl(parent) !== AclAdmin) return;
-    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 sharePermission = HierarchyMapping.get(symbol.acl!)!.name;
-            key.startsWith('acl') && distributeAcls(key, sharePermission, child);
-        }
-    }
+    Object.keys(parent)
+        .filter(key => key.startsWith('acl'))
+        .forEach(key => {
+            // if the default acl mode is private, then don't inherit the acl-guest permission, but set it to private.
+            // const permission: string = key === 'acl-guest' && Doc.defaultAclPrivate ? AclPrivate : parent[key];
+            const parAcl = ReverseHierarchyMap.get(StrCast(parent[key]))?.acl;
+            if (parAcl) {
+                const sharePermission = HierarchyMapping.get(parAcl)?.name;
+                sharePermission && distributeAcls(key, sharePermission, child, undefined, false, layoutOnly);
+            }
+        });
 }
 
 /**
@@ -160,7 +162,6 @@ export function inheritParentAcls(parent: Doc, child: Doc) {
  * Unset: Remove a sharing permission (eg., used )
  */
 export enum SharingPermissions {
-    Unset = 'None',
     Admin = 'Admin',
     Edit = 'Edit',
     Augment = 'Augment',
@@ -233,7 +234,7 @@ function getEffectiveAcl(target: any, user?: string): symbol {
  * @param allowUpgrade whether permissions can be made less restrictive
  * inheritingFromCollection is not currently being used but could be used if acl assignment defaults change
  */
-export function distributeAcls(key: string, acl: SharingPermissions, target: Doc, visited?: Doc[], allowUpgrade?: boolean) {
+export function distributeAcls(key: string, acl: SharingPermissions, target: Doc, visited?: Doc[], allowUpgrade?: boolean, layoutOnly = false) {
     const selfKey = `acl-${Doc.CurrentUserEmailNormalized}`;
     if (!visited) visited = [] as Doc[];
     if (!target || visited.includes(target) || key === selfKey) return;
@@ -243,19 +244,19 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc
     const dataDoc = target[DocData];
     const curVal = ReverseHierarchyMap.get(StrCast(dataDoc[key]))?.level ?? 0;
     const aclVal = ReverseHierarchyMap.get(acl)?.level ?? 0;
-    if (dataDoc && (allowUpgrade !== false|| !dataDoc[key] || curVal > aclVal)) {
+    if (!layoutOnly && dataDoc && (allowUpgrade !== false || !dataDoc[key] || curVal > aclVal)) {
         // propagate ACLs to links, children, and annotations
 
-        LinkManager.Links(dataDoc).forEach(link => distributeAcls(key, acl, link, visited, allowUpgrade? true: false));
+        LinkManager.Links(dataDoc).forEach(link => distributeAcls(key, acl, link, visited, allowUpgrade ? true : false));
 
         DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc)]).forEach(d => {
-            distributeAcls(key, acl, d, visited, allowUpgrade ? true: false);
-            d !== d[DocData] && distributeAcls(key, acl, d[DocData], visited, allowUpgrade ? true: false);
+            distributeAcls(key, acl, d, visited, allowUpgrade ? true : false);
+            d !== d[DocData] && distributeAcls(key, acl, d[DocData], visited, allowUpgrade ? true : false);
         });
 
         DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc) + '_annotations']).forEach(d => {
-            distributeAcls(key, acl, d, visited, allowUpgrade? true: false);
-            d !== d[DocData] && distributeAcls(key, acl, d[DocData], visited, allowUpgrade? true: false);
+            distributeAcls(key, acl, d, visited, allowUpgrade ? true : false);
+            d !== d[DocData] && distributeAcls(key, acl, d[DocData], visited, allowUpgrade ? true : false);
         });
 
         if (GetEffectiveAcl(dataDoc) === AclAdmin) {
@@ -266,7 +267,7 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc
 
     let layoutDocChanged = false; // determines whether fetchProto should be called or not (i.e. is there a change that should be reflected in target[AclSym])
     // if it is inheriting from a collection, it only inherits if A) allowUpgrade is set B) the key doesn't already exist or c) the right being inherited is more restrictive
-    if (GetEffectiveAcl(target) === AclAdmin && (allowUpgrade || !target[key] || ReverseHierarchyMap.get(StrCast(target[key]))!.level > ReverseHierarchyMap.get(acl)!.level)) {
+    if (GetEffectiveAcl(target) === AclAdmin && (allowUpgrade || !Doc.GetT(target, key, 'boolean', true) || ReverseHierarchyMap.get(StrCast(target[key]))!.level > aclVal)) {
         target[key] = acl;
         layoutDocChanged = true;
     }
-- 
cgit v1.2.3-70-g09d2


From d7a3e39e901054d0308df158cfa578a94f80c467 Mon Sep 17 00:00:00 2001
From: geireann <geireann.lindfield@gmail.com>
Date: Wed, 19 Jul 2023 12:15:56 -0400
Subject: got rid of ctrl-s to create a text slide.

---
 src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index e2718b52d..090cf356c 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -161,7 +161,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
                         });
                 })
             );
-        } else if (e.key === 's' && e.ctrlKey) {
+        } /* else if (e.key === 's' && e.ctrlKey) {
             e.preventDefault();
             const slide = DocUtils.copyDragFactory(DocCast(Doc.UserDoc().emptySlide))!;
             slide.x = x;
@@ -170,7 +170,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             TreeView._editTitleOnLoad = { id: slide[Id], parent: undefined };
             this.props.addDocument?.(slide);
             e.stopPropagation();
-        } else if (!e.ctrlKey && !e.metaKey && SelectionManager.Views().length < 2) {
+        }*/ else if (!e.ctrlKey && !e.metaKey && SelectionManager.Views().length < 2) {
             FormattedTextBox.SelectOnLoadChar = Doc.UserDoc().defaultTextLayout && !this.props.childLayoutString ? e.key : '';
             FormattedTextBox.LiveTextUndo = UndoManager.StartBatch('type new note');
             this.props.addLiveTextDocument(DocUtils.GetNewTextDoc('-typed text-', x, y, 200, 100, this.props.xPadding === 0));
-- 
cgit v1.2.3-70-g09d2

