aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/util/CurrentUserUtils.ts14
-rw-r--r--src/client/util/SearchUtil.ts2
-rw-r--r--src/client/util/SharingManager.tsx16
-rw-r--r--src/client/views/MainView.tsx69
-rw-r--r--src/client/views/collections/CollectionMenu.tsx3
-rw-r--r--src/fields/Doc.ts74
-rw-r--r--src/fields/util.ts9
7 files changed, 90 insertions, 97 deletions
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 7cc35d67a..d45a2c90a 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -566,7 +566,7 @@ export class CurrentUserUtils {
title: "menuItemPanel",
childDropAction: "alias",
dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
- _backgroundColor: "black",
+ _backgroundColor: "black", ignoreClick: true,
_gridGap: 0,
_yMargin: 0,
_yPadding: 0, _xMargin: 0, _autoHeight: false, _width: 60, _columnWidth: 60, lockedPosition: true, _chromeStatus: "disabled", system: true
@@ -729,7 +729,7 @@ export class CurrentUserUtils {
if (doc.myTools === undefined) {
const toolsStack = new PrefetchProxy(Docs.Create.StackingDocument([doc.myCreators as Doc, doc.myColorPicker as Doc], {
- title: "My Tools", _width: 500, _yMargin: 20, lockedPosition: true, _chromeStatus: "disabled", forceActive: true, system: true, _stayInCollection: true, _hideContextMenu: true,
+ title: "My Tools", _width: 500, _yMargin: 20, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", forceActive: true, system: true, _stayInCollection: true, _hideContextMenu: true,
})) as any as Doc;
doc.myTools = toolsStack;
@@ -743,7 +743,7 @@ export class CurrentUserUtils {
doc.myDashboards = new PrefetchProxy(Docs.Create.TreeDocument([], {
title: "My Dashboards", _height: 400,
treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
- treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false,
+ treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false, ignoreClick: true,
lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same", system: true
}));
const newDashboard = ScriptField.MakeScript(`createNewDashboard(Doc.UserDoc())`);
@@ -759,7 +759,7 @@ export class CurrentUserUtils {
doc.myPresentations = new PrefetchProxy(Docs.Create.TreeDocument([], {
title: "My Presentations", _height: 100,
treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
- treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false,
+ treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false, ignoreClick: true,
lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same", system: true
}));
const newPresentations = ScriptField.MakeScript(`createNewPresentation()`);
@@ -777,7 +777,7 @@ export class CurrentUserUtils {
doc.myRecentlyClosedDocs = new PrefetchProxy(Docs.Create.TreeDocument([], {
title: "Recently Closed", _height: 500,
treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
- treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false,
+ treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false, ignoreClick: true,
lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same", system: true
}));
const clearAll = ScriptField.MakeScript(`getProto(self).data = new List([])`);
@@ -792,7 +792,7 @@ export class CurrentUserUtils {
doc.myFilter = new PrefetchProxy(Docs.Create.FilterDocument({
title: "FilterDoc", _height: 500,
treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "none",
- treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false,
+ treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false, ignoreClick: true,
lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same", system: true
}));
const clearAll = ScriptField.MakeScript(`getProto(self).data = new List([])`);
@@ -808,7 +808,7 @@ export class CurrentUserUtils {
doc.treeViewExpandedView = "fields";
doc.myUserDoc = new PrefetchProxy(Docs.Create.TreeDocument([doc], {
treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, title: "My UserDoc",
- treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false,
+ treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false, ignoreClick: true,
lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same", system: true
})) as any as Doc;
}
diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts
index 08ad49dcc..79759a71d 100644
--- a/src/client/util/SearchUtil.ts
+++ b/src/client/util/SearchUtil.ts
@@ -44,7 +44,7 @@ export namespace SearchUtil {
const header = query.match(/_[atnb]?:/) ? replacedQuery : "DEFAULT:" + replacedQuery;
replacedQuery = `{!join from=id to=proto_i}* AND ${header}`;
}
- console.log("Q: " + replacedQuery + " fq: " + options.fq);
+ //console.log("Q: " + replacedQuery + " fq: " + options.fq);
const gotten = await rp.get(rpquery, { qs: { ...options, q: replacedQuery } });
const result: IdSearchResult = gotten.startsWith("<") ? { ids: [], docs: [], numFound: 0, lines: [] } : JSON.parse(gotten);
if (!returnDocs) {
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index bcd7d4056..984583ed5 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -7,7 +7,7 @@ import * as RequestPromise from "request-promise";
import { AclAdmin, AclPrivate, DataSym, Doc, DocListCast, Opt, AclSym, AclAddonly, AclEdit, AclReadonly } from "../../fields/Doc";
import { List } from "../../fields/List";
import { Cast, StrCast } from "../../fields/Types";
-import { distributeAcls, GetEffectiveAcl, SharingPermissions, TraceMobx } from "../../fields/util";
+import { distributeAcls, GetEffectiveAcl, SharingPermissions, TraceMobx, normalizeEmail } from "../../fields/util";
import { Utils } from "../../Utils";
import { DocServer } from "../DocServer";
import { CollectionView } from "../views/collections/CollectionView";
@@ -154,13 +154,13 @@ export class SharingManager extends React.Component<{}> {
setInternalGroupSharing = (group: Doc | { groupName: string }, permission: string, targetDoc?: Doc) => {
const target = targetDoc || this.targetDoc!;
- const key = StrCast(group.groupName).replace(".", "_");
+ const key = normalizeEmail(StrCast(group.groupName));
const acl = `acl-${key}`;
const docs = SelectionManager.SelectedDocuments().length < 2 ? [target] : SelectionManager.SelectedDocuments().map(docView => docView.props.Document);
docs.forEach(doc => {
- doc.author === Doc.CurrentUserEmail && !doc[`acl-${Doc.CurrentUserEmail.replace(".", "_")}`] && distributeAcls(`acl-${Doc.CurrentUserEmail.replace(".", "_")}`, SharingPermissions.Admin, doc);
+ doc.author === Doc.CurrentUserEmail && !doc[`acl-${Doc.CurrentUserEmailNormalized}`] && distributeAcls(`acl-${Doc.CurrentUserEmailNormalized}`, SharingPermissions.Admin, doc);
distributeAcls(acl, permission as SharingPermissions, doc);
if (group instanceof Doc) {
@@ -246,13 +246,13 @@ export class SharingManager extends React.Component<{}> {
setInternalSharing = (recipient: ValidatedUser, permission: string, targetDoc?: Doc) => {
const { user, notificationDoc } = recipient;
const target = targetDoc || this.targetDoc!;
- const key = user.email.replace('.', '_');
+ const key = normalizeEmail(user.email);
const acl = `acl-${key}`;
const docs = SelectionManager.SelectedDocuments().length < 2 ? [target] : SelectionManager.SelectedDocuments().map(docView => docView.props.Document);
docs.forEach(doc => {
- doc.author === Doc.CurrentUserEmail && !doc[`acl-${Doc.CurrentUserEmail.replace(".", "_")}`] && distributeAcls(`acl-${Doc.CurrentUserEmail.replace(".", "_")}`, SharingPermissions.Admin, doc);
+ doc.author === Doc.CurrentUserEmail && !doc[`acl-${Doc.CurrentUserEmailNormalized}`] && distributeAcls(`acl-${Doc.CurrentUserEmailNormalized}`, SharingPermissions.Admin, doc);
distributeAcls(acl, permission as SharingPermissions, doc);
if (permission !== SharingPermissions.None) Doc.IndexOf(doc, DocListCast(notificationDoc[storage])) === -1 && Doc.AddDocToList(notificationDoc, storage, doc);
@@ -456,8 +456,8 @@ export class SharingManager extends React.Component<{}> {
const commonKeys = intersection(...docs.map(doc => this.layoutDocAcls ? doc?.[AclSym] && Object.keys(doc[AclSym]) : doc?.[DataSym]?.[AclSym] && Object.keys(doc[DataSym][AclSym])));
// the list of users shared with
- const userListContents: (JSX.Element | null)[] = users.filter(({ user }) => docs.length > 1 ? commonKeys.includes(`acl-${user.email.replace('.', '_')}`) : docs[0]?.author !== user.email).map(({ user, notificationDoc, userColor }) => {
- const userKey = `acl-${user.email.replace('.', '_')}`;
+ const userListContents: (JSX.Element | null)[] = users.filter(({ user }) => docs.length > 1 ? commonKeys.includes(`acl-${normalizeEmail(user.email)}`) : docs[0]?.author !== user.email).map(({ user, notificationDoc, userColor }) => {
+ const userKey = `acl-${normalizeEmail(user.email)}`;
const uniform = docs.every(doc => this.layoutDocAcls ? doc?.[AclSym]?.[userKey] === docs[0]?.[AclSym]?.[userKey] : doc?.[DataSym]?.[AclSym]?.[userKey] === docs[0]?.[DataSym]?.[AclSym]?.[userKey]);
const permissions = uniform ? StrCast(targetDoc?.[userKey]) : "-multiple-";
@@ -514,7 +514,7 @@ export class SharingManager extends React.Component<{}> {
<span className={"padding"}>Me</span>
<div className="edit-actions">
<div className={"permissions-dropdown"}>
- {targetDoc?.[`acl-${Doc.CurrentUserEmail.replace(".", "_")}`]}
+ {targetDoc?.[`acl-${Doc.CurrentUserEmailNormalized}`]}
</div>
</div>
</div>
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 5193c3c02..8e30eba2a 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -312,39 +312,40 @@ export class MainView extends React.Component {
}
@computed get flyout() {
- return <div className={`mainView-libraryFlyout${this._flyoutWidth ? "" : "-out"}`} style={{ minWidth: this._flyoutWidth, width: this._flyoutWidth }} >
- <div className="mainView-contentArea" >
- <DocumentView
- Document={this._sidebarContent}
- DataDoc={undefined}
- LibraryPath={emptyPath}
- addDocument={undefined}
- addDocTab={this.addDocTabFunc}
- pinToPres={emptyFunction}
- rootSelected={returnTrue}
- removeDocument={returnFalse}
- onClick={undefined}
- ScreenToLocalTransform={this.mainContainerXf}
- ContentScaling={returnOne}
- PanelWidth={this.flyoutWidthFunc}
- PanelHeight={this.getContentsHeight}
- renderDepth={0}
- focus={emptyFunction}
- backgroundColor={this.defaultBackgroundColors}
- parentActive={returnTrue}
- whenActiveChanged={emptyFunction}
- bringToFront={emptyFunction}
- docFilters={returnEmptyFilter}
- docRangeFilters={returnEmptyFilter}
- searchFilterDocs={returnEmptyDoclist}
- ContainingCollectionView={undefined}
- ContainingCollectionDoc={undefined}
- relative={true}
- forcedBackgroundColor={() => "lightgrey"}
- />
- </div>
- {this.docButtons}
- </div>;
+ return !this._flyoutWidth ? <div className={`mainView-libraryFlyout-out"}`} style={{ width: 0 }} /> :
+ <div className="mainView-libraryFlyout" style={{ minWidth: this._flyoutWidth, width: this._flyoutWidth }} >
+ <div className="mainView-contentArea" >
+ <DocumentView
+ Document={this._sidebarContent}
+ DataDoc={undefined}
+ LibraryPath={emptyPath}
+ addDocument={undefined}
+ addDocTab={this.addDocTabFunc}
+ pinToPres={emptyFunction}
+ rootSelected={returnTrue}
+ removeDocument={returnFalse}
+ onClick={undefined}
+ ScreenToLocalTransform={this.mainContainerXf}
+ ContentScaling={returnOne}
+ PanelWidth={this.flyoutWidthFunc}
+ PanelHeight={this.getContentsHeight}
+ renderDepth={0}
+ focus={emptyFunction}
+ backgroundColor={this.defaultBackgroundColors}
+ parentActive={returnTrue}
+ whenActiveChanged={emptyFunction}
+ bringToFront={emptyFunction}
+ docFilters={returnEmptyFilter}
+ docRangeFilters={returnEmptyFilter}
+ searchFilterDocs={returnEmptyDoclist}
+ ContainingCollectionView={undefined}
+ ContainingCollectionDoc={undefined}
+ relative={true}
+ forcedBackgroundColor={() => "lightgrey"}
+ />
+ </div>
+ {this.docButtons}
+ </div>;
}
@computed get menuPanel() {
@@ -394,6 +395,8 @@ export class MainView extends React.Component {
SearchBox.Instance._searchFullDB = "My Stuff";
SearchBox.Instance.enter(undefined);
break;
+ case "Help":
+ break;
default:
this.expandFlyout(button);
}
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 51d1d5559..e9cb57fed 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -234,8 +234,9 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
@undoBatch
viewChanged = (e: React.ChangeEvent) => {
+ const target = this.document !== Doc.UserDoc().sidebar ? this.document : this.document.proto as Doc;
//@ts-ignore
- this.document._viewType = e.target.selectedOptions[0].value;
+ target._viewType = e.target.selectedOptions[0].value;
}
commandChanged = (e: React.ChangeEvent) => {
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 48fd831d6..59be3a27c 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -19,42 +19,30 @@ import { DateField } from "./DateField";
import { listSpec } from "./Schema";
import { ComputedField, ScriptField } from "./ScriptField";
import { Cast, FieldValue, NumCast, StrCast, ToConstructor } from "./Types";
-import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, updateFunction, GetEffectiveAcl, SharingPermissions } from "./util";
+import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, updateFunction, GetEffectiveAcl, SharingPermissions, normalizeEmail } from "./util";
import { LinkManager } from "../client/util/LinkManager";
import JSZip = require("jszip");
import { saveAs } from "file-saver";
import { CollectionDockingView } from "../client/views/collections/CollectionDockingView";
import { SelectionManager } from "../client/util/SelectionManager";
+import { CurrentUserUtils } from "../client/util/CurrentUserUtils";
export namespace Field {
export function toKeyValueString(doc: Doc, key: string): string {
const onDelegate = Object.keys(doc).includes(key);
-
const field = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
- if (Field.IsField(field)) {
- return (onDelegate ? "=" : "") + (field instanceof ComputedField ? `:=${field.script.originalScript}` : Field.toScriptString(field));
- }
- return "";
+ return !Field.IsField(field) ? "" : (onDelegate ? "=" : "") + (field instanceof ComputedField ? `:=${field.script.originalScript}` : Field.toScriptString(field));
}
export function toScriptString(field: Field): string {
- if (typeof field === "string") {
- return `"${field}"`;
- } else if (typeof field === "number" || typeof field === "boolean") {
- return String(field);
- } else {
- return field[ToScriptString]();
- }
+ if (typeof field === "string") return `"${field}"`;
+ if (typeof field === "number" || typeof field === "boolean") return String(field);
+ return field[ToScriptString]();
}
export function toString(field: Field): string {
- if (typeof field === "string") {
- return field;
- } else if (typeof field === "number" || typeof field === "boolean") {
- return String(field);
- } else if (field instanceof ObjectField) {
- return field[ToString]();
- } else if (field instanceof RefField) {
- return field[ToString]();
- }
+ if (typeof field === "string") return field;
+ if (typeof field === "number" || typeof field === "boolean") return String(field);
+ if (field instanceof ObjectField) return field[ToString]();
+ if (field instanceof RefField) return field[ToString]();
return "";
}
export function IsField(field: any): field is Field;
@@ -86,16 +74,10 @@ export function DocListCastAsync(field: FieldResult, defaultValue?: Doc[]) {
return list ? Promise.all(list).then(() => list) : Promise.resolve(defaultValue);
}
-export async function DocCastAsync(field: FieldResult): Promise<Opt<Doc>> {
- return Cast(field, Doc);
-}
+export async function DocCastAsync(field: FieldResult): Promise<Opt<Doc>> { return Cast(field, Doc); }
-export function DocListCast(field: FieldResult): Doc[] {
- return Cast(field, listSpec(Doc), []).filter(d => d instanceof Doc) as Doc[];
-}
-export function DocListCastOrNull(field: FieldResult) {
- return Cast(field, listSpec(Doc), null)?.filter(d => d instanceof Doc) as Doc[] | undefined;
-}
+export function DocListCast(field: FieldResult) { return Cast(field, listSpec(Doc), []).filter(d => d instanceof Doc) as Doc[]; }
+export function DocListCastOrNull(field: FieldResult) { return Cast(field, listSpec(Doc), null)?.filter(d => d instanceof Doc) as Doc[] | undefined; }
export const WidthSym = Symbol("Width");
export const HeightSym = Symbol("Height");
@@ -128,10 +110,6 @@ export function fetchProto(doc: Doc) {
if (Object.keys(permissions).length) doc[AclSym] = permissions;
- if (GetEffectiveAcl(doc) === AclPrivate) {
- runInAction(() => doc[FieldsSym](true));
- }
-
if (doc.proto instanceof Promise) {
doc.proto.then(fetchProto);
return doc.proto;
@@ -193,17 +171,11 @@ export class Doc extends RefField {
}
}
private get __fieldKeys() { return this.___fieldKeys; }
- private set __fieldKeys(value) {
- this.___fieldKeys = value;
- }
-
- @observable
- private ___fields: any = {};
+ private set __fieldKeys(value) { this.___fieldKeys = value; }
- @observable
- private ___fieldKeys: any = {};
- @observable
- public [AclSym]: { [key: string]: symbol };
+ @observable private ___fields: any = {};
+ @observable private ___fieldKeys: any = {};
+ @observable public [AclSym]: { [key: string]: symbol };
private [UpdatingFromServer]: boolean = false;
@@ -213,7 +185,11 @@ export class Doc extends RefField {
private [Self] = this;
private [SelfProxy]: any;
- public [FieldsSym](clear?: boolean) { return clear ? this.___fields = this.___fieldKeys = {} : this.___fields; }
+ public [FieldsSym](clear?: boolean) {
+ const self = this[SelfProxy];
+ runInAction(() => clear && Array.from(Object.keys(self)).forEach(key => delete self[key]));
+ return this.___fields;
+ }
public [WidthSym] = () => NumCast(this[SelfProxy]._width);
public [HeightSym] = () => NumCast(this[SelfProxy]._height);
public [ToScriptString] = () => `DOC-"${this[Self][Id]}"-`;
@@ -242,6 +218,7 @@ export class Doc extends RefField {
private [CachedUpdates]: { [key: string]: () => void | Promise<any> } = {};
public static CurrentUserEmail: string = "";
+ public static get CurrentUserEmailNormalized() { return normalizeEmail(Doc.CurrentUserEmail); }
public async [HandleUpdate](diff: any) {
const set = diff.$set;
const sameAuthor = this.author === Doc.CurrentUserEmail;
@@ -263,6 +240,11 @@ export class Doc extends RefField {
if (prev === AclPrivate && GetEffectiveAcl(this) !== AclPrivate) {
DocServer.GetRefField(this[Id], true);
}
+ if (prev !== AclPrivate && GetEffectiveAcl(this) === AclPrivate) {
+ this[UpdatingFromServer] = true;
+ this[FieldsSym](true);
+ this[UpdatingFromServer] = false;
+ }
};
if (sameAuthor || fKey.startsWith("acl") || DocServer.getFieldWriteMode(fKey) !== DocServer.WriteMode.Playground) {
delete this[CachedUpdates][fKey];
diff --git a/src/fields/util.ts b/src/fields/util.ts
index f0ff2dad4..6c92aef81 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -116,6 +116,13 @@ export function OVERRIDE_acl(val: boolean) {
_overrideAcl = val;
}
+export function normalizeEmail(email: string) {
+ return email.replace('.', '__');
+}
+export function denormalizeEmail(email: string) {
+ return email.replace('__', '.');
+}
+
// playground mode allows the user to add/delete documents or make layout changes without them saving to the server
// let playgroundMode = false;
@@ -184,7 +191,7 @@ export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number,
for (const [key, value] of Object.entries(target[AclSym])) {
// there are issues with storing fields with . in the name, so they are replaced with _ during creation
// as a result we need to restore them again during this comparison.
- const entity = key.substring(4).replace('_', '.'); // an individual or a group
+ const entity = denormalizeEmail(key.substring(4)); // an individual or a group
if (currentUserGroups.includes(entity) || userChecked === entity) {
if (HierarchyMapping.get(value as symbol)! > HierarchyMapping.get(effectiveAcl)!) {
effectiveAcl = value as symbol;