aboutsummaryrefslogtreecommitdiff
path: root/src/client/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/util')
-rw-r--r--src/client/util/CurrentUserUtils.ts99
-rw-r--r--src/client/util/DocumentManager.ts5
-rw-r--r--src/client/util/DragManager.ts4
-rw-r--r--src/client/util/GroupManager.tsx5
-rw-r--r--src/client/util/GroupMemberView.tsx3
-rw-r--r--src/client/util/LinkManager.ts4
-rw-r--r--src/client/util/PingManager.ts6
-rw-r--r--src/client/util/ReplayMovements.ts1
-rw-r--r--src/client/util/ServerStats.tsx26
-rw-r--r--src/client/util/SettingsManager.tsx11
-rw-r--r--src/client/util/SharingManager.tsx11
-rw-r--r--src/client/util/reportManager/ReportManager.tsx5
12 files changed, 96 insertions, 84 deletions
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 21bcec6d1..c9a5175bb 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -1,4 +1,4 @@
-import { reaction } from "mobx";
+import { observable, reaction, runInAction } from "mobx";
import * as rp from 'request-promise';
import { Doc, DocListCast, DocListCastAsync, Opt } from "../../fields/Doc";
import { FieldLoader } from "../../fields/FieldLoader";
@@ -152,7 +152,7 @@ export class CurrentUserUtils {
{ noteType: "Idea", backgroundColor: "pink", icon: "lightbulb" },
{ noteType: "Topic", backgroundColor: "lightblue", icon: "book-open" }];
const reqdNoteList = reqdTempOpts.map(opts => {
- const reqdOpts = {...opts, title: "text", width:200, layout_autoHeight: true, layout_fitWidth: true};
+ const reqdOpts = {...opts, isSystem:true, title: "text", width:200, layout_autoHeight: true, layout_fitWidth: true};
const noteType = tempNotes ? DocListCast(tempNotes.data).find(doc => doc.noteType === opts.noteType): undefined;
return DocUtils.AssignOpts(noteType, reqdOpts) ?? MakeTemplate(Docs.Create.TextDocument("",reqdOpts), true, opts.noteType??"Note");
});
@@ -295,7 +295,7 @@ export class CurrentUserUtils {
{ toolTip: "Tap or drag to create a note", title: "Note", icon: "sticky-note", dragFactory: doc.emptyNote as Doc, clickFactory: DocCast(doc.emptyNote)},
{ toolTip: "Tap or drag to create a flashcard", title: "Flashcard", icon: "id-card", dragFactory: doc.emptyFlashcard as Doc, clickFactory: DocCast(doc.emptyFlashcard)},
{ toolTip: "Tap or drag to create an equation", title: "Math", icon: "calculator", dragFactory: doc.emptyEquation as Doc, clickFactory: DocCast(doc.emptyEquation)},
- { toolTip: "Tap or drag to create a physics simulation", title: "Simulation", icon: "atom", dragFactory: doc.emptySimulation as Doc, },
+ { toolTip: "Tap or drag to create a physics simulation", title: "Simulation", icon: "atom", dragFactory: doc.emptySimulation as Doc, funcs: { hidden: "IsNoviceMode()"}},
{ toolTip: "Tap or drag to create a note board", title: "Notes", icon: "folder", dragFactory: doc.emptyNoteboard as Doc, clickFactory: DocCast(doc.emptyNoteboard)},
{ toolTip: "Tap or drag to create a collection", title: "Col", icon: "folder", dragFactory: doc.emptyCollection as Doc, clickFactory: DocCast(doc.emptyTab)},
{ toolTip: "Tap or drag to create a webpage", title: "Web", icon: "globe-asia", dragFactory: doc.emptyWebpage as Doc, clickFactory: DocCast(doc.emptyWebpage)},
@@ -303,18 +303,19 @@ export class CurrentUserUtils {
{ toolTip: "Tap or drag to create an audio recorder", title: "Audio", icon: "microphone", dragFactory: doc.emptyAudio as Doc, clickFactory: DocCast(doc.emptyAudio), openFactoryLocation: OpenWhere.overlay},
{ toolTip: "Tap or drag to create a map", title: "Map", icon: "map-marker-alt", dragFactory: doc.emptyMap as Doc, clickFactory: DocCast(doc.emptyMap)},
{ toolTip: "Tap or drag to create a screen grabber", title: "Grab", icon: "photo-video", dragFactory: doc.emptyScreengrab as Doc, clickFactory: DocCast(doc.emptyScreengrab), openFactoryLocation: OpenWhere.overlay},
- { toolTip: "Tap or drag to create a WebCam recorder", title: "WebCam", icon: "photo-video", dragFactory: doc.emptyWebCam as Doc, clickFactory: DocCast(doc.emptyWebCam), openFactoryLocation: OpenWhere.overlay},
+ { toolTip: "Tap or drag to create a WebCam recorder", title: "WebCam", icon: "photo-video", dragFactory: doc.emptyWebCam as Doc, clickFactory: DocCast(doc.emptyWebCam), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}},
{ toolTip: "Tap or drag to create a button", title: "Button", icon: "bolt", dragFactory: doc.emptyButton as Doc, clickFactory: DocCast(doc.emptyButton)},
- { toolTip: "Tap or drag to create a scripting box", title: "Script", icon: "terminal", dragFactory: doc.emptyScript as Doc, clickFactory: DocCast(doc.emptyScript)},
+ { toolTip: "Tap or drag to create a scripting box", title: "Script", icon: "terminal", dragFactory: doc.emptyScript as Doc, clickFactory: DocCast(doc.emptyScript), funcs: { hidden: "IsNoviceMode()"}},
{ toolTip: "Tap or drag to create a data viz node", title: "DataViz", icon: "file", dragFactory: doc.emptyDataViz as Doc, clickFactory: DocCast(doc.emptyDataViz)},
- { toolTip: "Tap or drag to create a bullet slide", title: "PPT Slide", icon: "file", dragFactory: doc.emptySlide as Doc, clickFactory: DocCast(doc.emptySlide), openFactoryLocation: OpenWhere.overlay},
- { toolTip: "Tap or drag to create a data note", title: "DataNote", icon: "window-maximize",dragFactory: doc.emptyHeader as Doc,clickFactory: DocCast(doc.emptyHeader), openFactoryAsDelegate: true },
- { toolTip: "Toggle a Calculator REPL", title: "replviewer", icon: "calculator", clickFactory: '<ScriptingRepl />' as any, openFactoryLocation: OpenWhere.overlay}, // hack: clickFactory is not a Doc but will get interpreted as a custom UI by the openDoc() onClick script
- { toolTip: "Toggle an UndoStack", title: "undostacker", icon: "calculator", clickFactory: "<UndoStack>" as any, openFactoryLocation: OpenWhere.overlay},
+ { toolTip: "Tap or drag to create a bullet slide", title: "PPT Slide", icon: "file", dragFactory: doc.emptySlide as Doc, clickFactory: DocCast(doc.emptySlide), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}},
+ { toolTip: "Tap or drag to create a data note", title: "DataNote", icon: "window-maximize",dragFactory: doc.emptyHeader as Doc,clickFactory: DocCast(doc.emptyHeader), openFactoryAsDelegate: true , funcs: { hidden: "IsNoviceMode()"}},
+ { toolTip: "Toggle a Calculator REPL", title: "replviewer", icon: "calculator", clickFactory: '<ScriptingRepl />' as any, openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}}, // hack: clickFactory is not a Doc but will get interpreted as a custom UI by the openDoc() onClick script
+ { toolTip: "Toggle an UndoStack", title: "undostacker", icon: "calculator", clickFactory: "<UndoStack>" as any, openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}},
].map(tuple => (
{ openFactoryLocation: OpenWhere.addRight,
scripts: { onClick: 'openDoc(copyDragFactory(this.clickFactory,this.openFactoryAsDelegate), this.openFactoryLocation)',
onDragStart: '{ return copyDragFactory(this.dragFactory,this.openFactoryAsDelegate); }'},
+ funcs: tuple.funcs,
...tuple, }))
}
@@ -323,7 +324,7 @@ export class CurrentUserUtils {
const creatorBtns = CurrentUserUtils.creatorBtnDescriptors(doc).map((reqdOpts) => {
const btn = dragCreatorDoc ? DocListCast(dragCreatorDoc.data).find(doc => doc.title === reqdOpts.title): undefined;
const opts:DocumentOptions = {...OmitKeys(reqdOpts, ["funcs", "scripts", "backgroundColor"]).omit,
- _width: 35, _height: 35, _layout_hideContextMenu: true, _dragOnlyWithinContainer: true,
+ _width: 60, _height: 60, _layout_hideContextMenu: true, _dragOnlyWithinContainer: true,
btnType: ButtonType.ToolButton, backgroundColor: reqdOpts.backgroundColor ?? Colors.DARK_GRAY, color: Colors.WHITE, isSystem: true,
};
return DocUtils.AssignScripts(DocUtils.AssignOpts(btn, opts) ?? Docs.Create.FontIconDocument(opts), reqdOpts.scripts, reqdOpts.funcs);
@@ -339,16 +340,16 @@ export class CurrentUserUtils {
}
/// returns descriptions needed to buttons for the left sidebar to open up panes displaying different collections of documents
- static leftSidebarMenuBtnDescriptions(doc: Doc):{title:string, target:Doc, icon:string, toolTip: string, scripts:{[key:string]:any}, funcs?:{[key:string]:any}}[] {
+ static leftSidebarMenuBtnDescriptions(doc: Doc):{title:string, target:Doc, icon:string, toolTip: string, scripts:{[key:string]:any}, funcs?:{[key:string]:any}, hidden?: boolean}[] {
const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(self.target.data).filter(doc => !docList(self.target.viewed).includes(doc)).length.toString())";
const getActiveDashTrails = "Doc.ActiveDashboard?.myTrails";
return [
{ title: "Dashboards", toolTip: "Dashboards", target: this.setupDashboards(doc, "myDashboards"), ignoreClick: true, icon: "desktop", funcs: {hidden: "IsNoviceMode()"} },
{ title: "Search", toolTip: "Search ⌘F", target: this.setupSearcher(doc, "mySearcher"), ignoreClick: true, icon: "search", },
{ title: "Files", toolTip: "Files", target: this.setupFilesystem(doc, "myFilesystem"), ignoreClick: true, icon: "folder-open", },
- { title: "Tools", toolTip: "Tools", target: this.setupToolsBtnPanel(doc, "myTools"), ignoreClick: true, icon: "wrench", funcs: {hidden: "IsNoviceMode()"} },
+ { title: "Tools", toolTip: "Tools", target: this.setupToolsBtnPanel(doc, "myTools"), ignoreClick: true, icon: "wrench", },
{ title: "Imports", toolTip: "Imports ⌘I", target: this.setupImportSidebar(doc, "myImports"), ignoreClick:false, icon: "upload", },
- { title: "Closed", toolTip: "Recently Closed", target: this.setupRecentlyClosed(doc, "myRecentlyClosed"), ignoreClick: true, icon: "archive", },
+ { title: "Closed", toolTip: "Recently Closed", target: this.setupRecentlyClosed(doc, "myRecentlyClosed"), ignoreClick: true, icon: "archive", hidden: true }, // this doc is hidden from the Sidebar, but it's still being used in MyFilesystem which ignores the hidden field
{ title: "Shared", toolTip: "Shared Docs", target: Doc.MySharedDocs, ignoreClick: true, icon: "users", funcs: {badgeValue: badgeValue}},
{ title: "Trails", toolTip: "Trails ⌘R", target: Doc.UserDoc(), ignoreClick: true, icon: "pres-trail", funcs: {target: getActiveDashTrails}},
{ title: "User Doc", toolTip: "User Doc", target: this.setupUserDocView(doc, "myUserDocView"), ignoreClick: true, icon: "address-card",funcs: {hidden: "IsNoviceMode()"} },
@@ -357,17 +358,17 @@ export class CurrentUserUtils {
/// the empty panel that is filled with whichever left menu button's panel has been selected
static setupLeftSidebarPanel(doc: Doc, field="myLeftSidebarPanel") {
- DocUtils.AssignDocField(doc, field, (opts) => Doc.assign(new Doc(), opts as any), {isSystem:true, undoIgnoreFields: new List<string>(['proto'])});
+ DocUtils.AssignDocField(doc, field, (opts) => Doc.assign(new Doc(), opts as any), {title:"leftSidebarPanel", isSystem:true, undoIgnoreFields: new List<string>(['proto'])});
}
/// Initializes the left sidebar menu buttons and the panels they open up
static setupLeftSidebarMenu(doc: Doc, field="myLeftSidebarMenu") {
this.setupLeftSidebarPanel(doc);
const myLeftSidebarMenu = DocCast(doc[field]);
- const menuBtns = CurrentUserUtils.leftSidebarMenuBtnDescriptions(doc).map(({ title, target, icon, toolTip, scripts, funcs }) => {
+ const menuBtns = CurrentUserUtils.leftSidebarMenuBtnDescriptions(doc).map(({ title, target, icon, toolTip, hidden, scripts, funcs }) => {
const btnDoc = myLeftSidebarMenu ? DocListCast(myLeftSidebarMenu.data).find(doc => doc.title === title) : undefined;
const reqdBtnOpts:DocumentOptions = {
- title, icon, target, toolTip, btnType: ButtonType.MenuButton, isSystem: true, undoIgnoreFields: new List<string>(['height', 'data_columnHeaders']), dontRegisterView: true,
+ title, icon, target, toolTip, hidden, btnType: ButtonType.MenuButton, isSystem: true, undoIgnoreFields: new List<string>(['height', 'data_columnHeaders']), dontRegisterView: true,
_width: 60, _height: 60, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true,
};
return DocUtils.AssignScripts(DocUtils.AssignOpts(btnDoc, reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), scripts, funcs);
@@ -495,7 +496,7 @@ export class CurrentUserUtils {
const reqdOpts:DocumentOptions = {
title: "My Dashboards", childHideLinkButton: true, treeViewFreezeChildren: "remove|add", treeViewHideTitle: true, layout_boxShadow: "0 0", childDontRegisterViews: true,
dropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, isSystem: true, treeViewTruncateTitleWidth: 350, ignoreClick: true,
- layout_headerButton: newDashboardButton, childDragAction: "embed",
+ layout_headerButton: newDashboardButton, childDragAction: "none",
_layout_showTitle: "title", _height: 400, _gridGap: 5, _forceActive: true, _lockedPosition: true,
contextMenuLabels:new List<string>(contextMenuLabels),
contextMenuIcons:new List<string>(contextMenuIcons),
@@ -519,7 +520,6 @@ export class CurrentUserUtils {
/// initializes the left sidebar File system pane
static setupFilesystem(doc: Doc, field:string) {
var myFilesystem = DocCast(doc[field]);
- const myFileOrphans = DocUtils.AssignDocField(doc, "myFileOrphans", (opts) => Docs.Create.TreeDocument([], opts), { title: "Unfiled", undoIgnoreFields:new List<string>(['treeViewSortCriterion']), _dragOnlyWithinContainer: true, isSystem: true, isFolder: true });
const newFolder = `TreeView_addNewFolder()`;
const newFolderOpts: DocumentOptions = {
@@ -530,14 +530,15 @@ export class CurrentUserUtils {
const newFolderButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myFilesystem?.layout_headerButton), newFolderOpts) ?? Docs.Create.FontIconDocument(newFolderOpts), newFolderScript);
const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _height: 100, _gridGap: 5, _forceActive: true, _lockedPosition: true,
- title: "My Documents", layout_headerButton: newFolderButton, treeViewHideTitle: true, dropAction: "proto", isSystem: true,
+ title: "My Documents", layout_headerButton: newFolderButton, treeViewHideTitle: true, dropAction: 'add', isSystem: true,
isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, layout_boxShadow: "0 0", childDontRegisterViews: true,
treeViewTruncateTitleWidth: 350, ignoreClick: true, childDragAction: "embed",
childContextMenuLabels: new List<string>(["Create new folder"]),
childContextMenuIcons: new List<string>(["plus"]),
layout_explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard."
};
- myFilesystem = DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.TreeDocument(items??[], opts), reqdOpts, [myFileOrphans]);
+ const fileFolders = new Set(DocListCast(DocCast(doc[field])?.data));
+ myFilesystem = DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.TreeDocument(items??[], opts), reqdOpts, Array.from(fileFolders));
const childContextMenuScripts = [newFolder];
if (Cast(myFilesystem.childContextMenuScripts, listSpec(ScriptField), null)?.length !== childContextMenuScripts.length) {
myFilesystem.childContextMenuScripts = new List<ScriptField>(childContextMenuScripts.map(script => ScriptField.MakeFunction(script)!));
@@ -547,8 +548,8 @@ export class CurrentUserUtils {
/// initializes the panel displaying docs that have been recently closed
static setupRecentlyClosed(doc: Doc, field:string) {
- const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _lockedPosition: true, _gridGap: 5, _forceActive: true,
- title: "My Recently Closed", childHideLinkButton: true, treeViewHideTitle: true, childDragAction: "embed", isSystem: true,
+ const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _lockedPosition: true, _gridGap: 5, _forceActive: true, isFolder: true,
+ title: "My Recently Closed", childHideLinkButton: true, treeViewHideTitle: true, childDragAction: "move", isSystem: true,
treeViewTruncateTitleWidth: 350, ignoreClick: true, layout_boxShadow: "0 0", childDontRegisterViews: true, dropAction: "same",
contextMenuLabels: new List<string>(["Empty recently closed"]),
contextMenuIcons:new List<string>(["trash"]),
@@ -562,8 +563,6 @@ export class CurrentUserUtils {
toolTip: "Empty recently closed",};
DocUtils.AssignDocField(recentlyClosed, "layout_headerButton", (opts) => Docs.Create.FontIconDocument(opts), clearBtnsOpts, undefined, {onClick: clearAll("self.target")});
- //if (recentlyClosed.layout_headerButton !== clearDocsButton) Doc.GetProto(recentlyClosed).layout_headerButton = clearDocsButton;
-
if (!Cast(recentlyClosed.contextMenuScripts, listSpec(ScriptField),null)?.find((script) => script.script.originalScript === clearAll("self"))) {
recentlyClosed.contextMenuScripts = new List<ScriptField>([ScriptField.MakeScript(clearAll("self"))!])
}
@@ -777,6 +776,7 @@ export class CurrentUserUtils {
const linkDocs = new Doc(linkDatabaseId, true);
linkDocs.title = "LINK DATABASE: " + Doc.CurrentUserEmail;
linkDocs.author = Doc.CurrentUserEmail;
+ linkDocs.isSystem = true;
linkDocs.data = new List<Doc>([]);
linkDocs["acl-Guest"] = SharingPermissions.Augment;
doc.myLinkDatabase = new PrefetchProxy(linkDocs);
@@ -877,11 +877,13 @@ export class CurrentUserUtils {
this.setupDockedButtons(doc); // the bottom bar of font icons
this.setupLeftSidebarMenu(doc); // the left-side column of buttons that open their contents in a flyout panel on the left
this.setupDocTemplates(doc); // sets up the template menu of templates
- this.setupFieldInfos(doc); // sets up the collection of field info descriptions for each possible DocumentOption
+ //this.setupFieldInfos(doc); // sets up the collection of field info descriptions for each possible DocumentOption
DocUtils.AssignDocField(doc, "globalScriptDatabase", (opts) => Docs.Prototypes.MainScriptDocument(), {});
- DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "header bar", isSystem: true, childDocumentsActive:false, dropAction: 'move'}); // drop down panel at top of dashboard for stashing documents
+ DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "My Header Bar", isSystem: true, childDocumentsActive:false, dropAction: 'move'}); // drop down panel at top of dashboard for stashing documents
+ Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MyDashboards)
Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MySharedDocs)
+ Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MyRecentlyClosed)
if (doc.activeDashboard instanceof Doc) {
// undefined means ColorScheme.Light until all CSS is updated with values for each color scheme (e.g., see MainView.scss, DocumentDecorations.scss)
@@ -889,7 +891,7 @@ export class CurrentUserUtils {
}
new LinkManager();
- setTimeout(DocServer.UPDATE_SERVER_CACHE, 2500);
+ DocServer.CacheNeedsUpdate && setTimeout(DocServer.UPDATE_SERVER_CACHE, 2500);
setInterval(DocServer.UPDATE_SERVER_CACHE, 120000);
return doc;
}
@@ -912,10 +914,12 @@ export class CurrentUserUtils {
});
}
+ @observable public static ServerVersion: string = ';'
public static async loadCurrentUser() {
return rp.get(Utils.prepend("/getCurrentUser")).then(async response => {
if (response) {
- const result: { id: string, email: string, cacheDocumentIds: string, resolvedPorts: string } = JSON.parse(response);
+ const result: { version: string, userDocumentId: string, sharingDocumentId: string, linkDatabaseId: string, email: string, cacheDocumentIds: string, resolvedPorts: string } = JSON.parse(response);
+ runInAction(() => CurrentUserUtils.ServerVersion = result.version);
Doc.CurrentUserEmail = result.email;
resolvedPorts = result.resolvedPorts as any;
DocServer.init(window.location.protocol, window.location.hostname, resolvedPorts.socket, result.email);
@@ -923,11 +927,9 @@ export class CurrentUserUtils {
{
const ids = result.cacheDocumentIds.split(";");
const batch = 30000;
- FieldLoader.active = true;
for (let i = 0; i < ids.length; i = Math.min(ids.length, i+batch)) {
await DocServer.GetRefFields(ids.slice(i, i+batch));
}
- FieldLoader.active = false;
}
return result;
} else {
@@ -936,27 +938,24 @@ export class CurrentUserUtils {
});
}
- public static async loadUserDocument(id: string) {
- await rp.get(Utils.prepend("/getUserDocumentIds")).then(ids => {
- const { userDocumentId, sharingDocumentId, linkDatabaseId } = JSON.parse(ids);
- if (userDocumentId) {
- return DocServer.GetRefField(userDocumentId).then(async field => {
- Docs.newAccount = !(field instanceof Doc);
- await Docs.Prototypes.initialize();
- const userDoc = Docs.newAccount ? new Doc(userDocumentId, true) : field as Doc;
- this.updateUserDocument(Doc.SetUserDoc(userDoc), sharingDocumentId, linkDatabaseId);
- if (Docs.newAccount) {
- if (Doc.CurrentUserEmail === "guest") {
- DashboardView.createNewDashboard(undefined, "guest dashboard");
- } else {
- userDoc.activePage = "home";
- }
- }
- return userDoc;
- });
- } else {
- throw new Error("There should be a user id! Why does Dash think there isn't one?");
+ public static async loadUserDocument(info:{
+ userDocumentId: string;
+ sharingDocumentId: string;
+ linkDatabaseId: string;
+ }) {
+ return DocServer.GetRefField(info.userDocumentId).then(async field => {
+ Docs.newAccount = !(field instanceof Doc);
+ await Docs.Prototypes.initialize();
+ const userDoc = Docs.newAccount ? new Doc(info.userDocumentId, true) : field as Doc;
+ this.updateUserDocument(Doc.SetUserDoc(userDoc), info.sharingDocumentId, info.linkDatabaseId);
+ if (Docs.newAccount) {
+ if (Doc.CurrentUserEmail === "guest") {
+ DashboardView.createNewDashboard(undefined, "guest dashboard");
+ } else {
+ userDoc.activePage = "home";
+ }
}
+ return userDoc;
});
}
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 8e4e0d8f3..42132c2d7 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -75,7 +75,7 @@ export class DocumentManager {
@action
public AddView = (view: DocumentView) => {
- //console.log("MOUNT " + view.props.Document.title + "/" + view.props.LayoutTemplateString);
+ if (view.props.LayoutTemplateString?.includes(KeyValueBox.name)) return;
if (view.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) {
const viewAnchorIndex = view.props.LayoutTemplateString.includes('link_anchor_2') ? 'link_anchor_2' : 'link_anchor_1';
const link = view.rootDoc;
@@ -251,6 +251,7 @@ export class DocumentManager {
options: DocFocusOptions, // options for how to navigate to target
finished?: (changed: boolean) => void // func called after focusing on target with flag indicating whether anything needed to be done.
) => {
+ Doc.RemoveDocFromList(Doc.MyRecentlyClosed, undefined, targetDoc);
const docContextPath = DocumentManager.GetContextPath(targetDoc, true);
if (docContextPath.some(doc => doc.hidden)) options.toggleTarget = false;
let rootContextView =
@@ -335,7 +336,7 @@ export function DocFocusOrOpen(doc: Doc, options: DocFocusOptions = { willZoomCe
if (dv && (!containingDoc || dv.props.docViewPath().lastElement()?.Document === containingDoc)) {
DocumentManager.Instance.showDocumentView(dv, options).then(() => dv && Doc.linkFollowHighlight(dv.rootDoc));
} else {
- const container = DocCast(containingDoc ?? doc.embedContainer ?? doc);
+ const container = DocCast(containingDoc ?? doc.embedContainer ?? Doc.BestEmbedding(doc));
const showDoc = !Doc.IsSystem(container) ? container : doc;
options.toggleTarget = undefined;
DocumentManager.Instance.showDocument(showDoc, options, () => DocumentManager.Instance.showDocument(doc, { ...options, openLocation: undefined })).then(() => {
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 85101fcab..f4ff38515 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -15,7 +15,7 @@ import { SelectionManager } from './SelectionManager';
import { SnappingManager } from './SnappingManager';
import { UndoManager } from './UndoManager';
-export type dropActionType = 'embed' | 'copy' | 'move' | 'same' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call dropPropertiesToRemove
+export type dropActionType = 'embed' | 'copy' | 'move' | 'add' | 'same' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call dropPropertiesToRemove
/**
* Initialize drag
@@ -213,6 +213,8 @@ export namespace DragManager {
? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result)
: docDragData.dropAction === 'embed'
? Doc.BestEmbedding(d)
+ : docDragData.dropAction === 'add'
+ ? d
: docDragData.dropAction === 'proto'
? Doc.GetProto(d)
: docDragData.dropAction === 'copy'
diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx
index e406d89e7..f35844020 100644
--- a/src/client/util/GroupManager.tsx
+++ b/src/client/util/GroupManager.tsx
@@ -16,6 +16,7 @@ import { listSpec } from '../../fields/Schema';
import { DateField } from '../../fields/DateField';
import { Id } from '../../fields/FieldSymbols';
import { Button, IconButton, Size, Type } from 'browndash-components';
+import { SettingsManager } from './SettingsManager';
/**
* Interface for options for the react-select component
@@ -281,7 +282,7 @@ export class GroupManager extends React.Component<{}> {
*/
private get groupCreationModal() {
const contents = (
- <div className="group-create" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
+ <div className="group-create" style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.userColor }}>
<div className="group-heading" style={{ marginBottom: 0 }}>
<p>
<b>New Group</b>
@@ -366,7 +367,7 @@ export class GroupManager extends React.Component<{}> {
const groups = this.groupSort === 'ascending' ? this.allGroups.sort(sortGroups) : this.groupSort === 'descending' ? this.allGroups.sort(sortGroups).reverse() : this.allGroups;
return (
- <div className="group-interface" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
+ <div className="group-interface" style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.userColor }}>
{this.groupCreationModal}
{this.currentGroup ? <GroupMemberView group={this.currentGroup} onCloseButtonClick={action(() => (this.currentGroup = undefined))} /> : null}
<div className="group-heading">
diff --git a/src/client/util/GroupMemberView.tsx b/src/client/util/GroupMemberView.tsx
index 057f94f64..535d8ccc2 100644
--- a/src/client/util/GroupMemberView.tsx
+++ b/src/client/util/GroupMemberView.tsx
@@ -9,6 +9,7 @@ import { MainViewModal } from '../views/MainViewModal';
import { GroupManager, UserOptions } from './GroupManager';
import './GroupMemberView.scss';
import { Button, IconButton, Size, Type } from 'browndash-components';
+import { SettingsManager } from './SettingsManager';
interface GroupMemberViewProps {
group: Doc;
@@ -28,7 +29,7 @@ export class GroupMemberView extends React.Component<GroupMemberViewProps> {
const hasEditAccess = GroupManager.Instance.hasEditAccess(this.props.group);
return !this.props.group ? null : (
- <div className="editing-interface" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
+ <div className="editing-interface" style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.userColor }}>
<div className="editing-header">
<input
className="group-title"
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index c7f092565..ef4b21b05 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -1,7 +1,8 @@
-import { action, observable, observe } from 'mobx';
+import { action, observable, observe, runInAction } from 'mobx';
import { computedFn } from 'mobx-utils';
import { Doc, DocListCast, DocListCastAsync, Field, Opt } from '../../fields/Doc';
import { DirectLinks } from '../../fields/DocSymbols';
+import { FieldLoader } from '../../fields/FieldLoader';
import { List } from '../../fields/List';
import { ProxyField } from '../../fields/Proxy';
import { Cast, DocCast, PromiseValue, StrCast } from '../../fields/Types';
@@ -132,6 +133,7 @@ export class LinkManager {
},
true
);
+ runInAction(() => (FieldLoader.ServerLoadStatus.message = 'links'));
LinkManager.addLinkDB(Doc.LinkDBDoc());
}
diff --git a/src/client/util/PingManager.ts b/src/client/util/PingManager.ts
index 0c41a1ea7..4dd2fcd35 100644
--- a/src/client/util/PingManager.ts
+++ b/src/client/util/PingManager.ts
@@ -1,5 +1,6 @@
-import { action, observable } from 'mobx';
+import { action, observable, runInAction } from 'mobx';
import { Networking } from '../Network';
+import { CurrentUserUtils } from './CurrentUserUtils';
export class PingManager {
// create static instance and getter for global use
@observable static _instance: PingManager;
@@ -18,7 +19,8 @@ export class PingManager {
};
sendPing = async (): Promise<void> => {
try {
- await Networking.PostToServer('/ping', { date: new Date() });
+ const res = await Networking.PostToServer('/ping', { date: new Date() });
+ runInAction(() => (CurrentUserUtils.ServerVersion = res.message));
!this.IsBeating && this.setIsBeating(true);
} catch {
if (this.IsBeating) {
diff --git a/src/client/util/ReplayMovements.ts b/src/client/util/ReplayMovements.ts
index cbc465d6a..d99630f82 100644
--- a/src/client/util/ReplayMovements.ts
+++ b/src/client/util/ReplayMovements.ts
@@ -187,7 +187,6 @@ export class ReplayMovements {
} else {
// tab wasn't open - open it and play the movement
const openedColFFView = this.openTab(movement.doc);
- console.log('openedColFFView', openedColFFView);
openedColFFView && this.zoomAndPan(movement, openedColFFView);
}
diff --git a/src/client/util/ServerStats.tsx b/src/client/util/ServerStats.tsx
index 6a6ec158e..3c7c35a7e 100644
--- a/src/client/util/ServerStats.tsx
+++ b/src/client/util/ServerStats.tsx
@@ -6,6 +6,7 @@ import './SharingManager.scss';
import { PingManager } from './PingManager';
import { StrCast } from '../../fields/Types';
import { Doc } from '../../fields/Doc';
+import { SettingsManager } from './SettingsManager';
@observer
export class ServerStats extends React.Component<{}> {
@@ -42,21 +43,22 @@ export class ServerStats extends React.Component<{}> {
*/
@computed get sharingInterface() {
return (
- <div style={{
- display: "flex",
- height: 300,
- width: 400,
- background: StrCast(Doc.UserDoc().userBackgroundColor),
- opacity: 0.6}}>
- <div style={{width: 300,height: 100,margin: "auto",display: "flex",flexDirection: "column"}}>
- {PingManager.Instance.IsBeating ? 'The server connection is active' :
- 'The server connection has been interrupted.NOTE: Any changes made will appear to persist but will be lost after a browser refreshes.'}
-
- <br/>
+ <div
+ style={{
+ display: 'flex',
+ height: 300,
+ width: 400,
+ background: SettingsManager.Instance?.userBackgroundColor,
+ opacity: 0.6,
+ }}>
+ <div style={{ width: 300, height: 100, margin: 'auto', display: 'flex', flexDirection: 'column' }}>
+ {PingManager.Instance.IsBeating ? 'The server connection is active' : 'The server connection has been interrupted.NOTE: Any changes made will appear to persist but will be lost after a browser refreshes.'}
+
+ <br />
<span>Active users:{this._stats?.socketMap.length}</span>
{this._stats?.socketMap.map((user: any) => (
<p>{user.username}</p>
- ))}
+ ))}
</div>
</div>
);
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index b8e327968..b2b5be070 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -1,10 +1,12 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Button, ColorPicker, Dropdown, DropdownType, EditableText, Group, NumberDropdown, Size, Toggle, ToggleType, Type } from 'browndash-components';
import { action, computed, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { ColorState, SketchPicker } from 'react-color';
+import { BsGoogle } from 'react-icons/bs';
+import { FaFillDrip, FaPalette } from 'react-icons/fa';
import { Doc } from '../../fields/Doc';
-import { Id } from '../../fields/FieldSymbols';
+import { DashVersion } from '../../fields/DocSymbols';
import { BoolCast, Cast, StrCast } from '../../fields/Types';
import { addStyleSheet, addStyleSheetRule, Utils } from '../../Utils';
import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
@@ -12,13 +14,9 @@ import { DocServer } from '../DocServer';
import { Networking } from '../Network';
import { MainViewModal } from '../views/MainViewModal';
import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox';
-import { DragManager } from './DragManager';
import { GroupManager } from './GroupManager';
import './SettingsManager.scss';
import { undoBatch } from './UndoManager';
-import { Button, ColorPicker, Dropdown, DropdownType, EditableText, Group, NumberDropdown, Size, Toggle, ToggleType, Type } from 'browndash-components';
-import { BsGoogle } from 'react-icons/bs';
-import { FaFillDrip, FaPalette } from 'react-icons/fa';
const higflyout = require('@hig/flyout');
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -452,6 +450,7 @@ export class SettingsManager extends React.Component<{}> {
</div>
<div className="settings-user">
+ <div style={{ color: 'black' }}>{DashVersion}</div>
<div className="settings-username" style={{ color: this.userBackgroundColor }}>
{Doc.CurrentUserEmail}
</div>
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index cadcb1f8a..6171c01d7 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -8,6 +8,7 @@ import Select from 'react-select';
import * as RequestPromise from 'request-promise';
import { Doc, DocListCast, DocListCastAsync, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc';
import { AclAdmin, AclPrivate, DocAcl, DocData } from '../../fields/DocSymbols';
+import { FieldLoader } from '../../fields/FieldLoader';
import { Id } from '../../fields/FieldSymbols';
import { StrCast } from '../../fields/Types';
import { distributeAcls, GetEffectiveAcl, normalizeEmail, SharingPermissions, TraceMobx } from '../../fields/util';
@@ -23,6 +24,7 @@ import { GroupManager, UserOptions } from './GroupManager';
import { GroupMemberView } from './GroupMemberView';
import { LinkManager } from './LinkManager';
import { SelectionManager } from './SelectionManager';
+import { SettingsManager } from './SettingsManager';
import './SharingManager.scss';
import { undoable } from './UndoManager';
@@ -136,6 +138,7 @@ export class SharingManager extends React.Component<{}> {
this.populating = true;
const userList = await RequestPromise.get(Utils.prepend('/getUsers'));
const raw = (JSON.parse(userList) as User[]).filter(user => user.email !== 'guest' && user.email !== Doc.CurrentUserEmail);
+ runInAction(() => (FieldLoader.ServerLoadStatus.message = 'users'));
const docs = await DocServer.GetRefFields(raw.reduce((list, user) => [...list, user.sharingDocumentId, user.linkDatabaseId], [] as string[]));
raw.map(
action((newUser: User) => {
@@ -144,7 +147,7 @@ export class SharingManager extends React.Component<{}> {
if (sharingDoc instanceof Doc && linkDatabase instanceof Doc) {
if (!this.users.find(user => user.user.email === newUser.email)) {
this.users.push({ user: newUser, sharingDoc, linkDatabase, userColor: StrCast(sharingDoc.userColor) });
- LinkManager.addLinkDB(linkDatabase);
+ //LinkManager.addLinkDB(linkDatabase);
}
}
})
@@ -525,10 +528,10 @@ export class SharingManager extends React.Component<{}> {
const permissions = uniform ? StrCast(targetDoc?.[groupKey]) : '-multiple-';
return !permissions ? null : (
- <div key={groupKey} className={'container'} style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}>
+ <div key={groupKey} className={'container'} style={{ background: SettingsManager.Instance.userBackgroundColor, color: SettingsManager.Instance.userColor }}>
<div className={'padding'}>{StrCast(group.title)}</div>
&nbsp;
- {group instanceof Doc ? <IconButton icon={<FontAwesomeIcon icon={'info-circle'} />} size={Size.XSMALL} color={StrCast(Doc.UserDoc().userColor)} onClick={action(() => (GroupManager.Instance.currentGroup = group))} /> : null}
+ {group instanceof Doc ? <IconButton icon={<FontAwesomeIcon icon={'info-circle'} />} size={Size.XSMALL} color={SettingsManager.Instance.userColor} onClick={action(() => (GroupManager.Instance.currentGroup = group))} /> : null}
<div className={'edit-actions'}>
{admin || this.myDocAcls ? (
<select className={`permissions-dropdown-${permissions}`} value={permissions} onChange={e => this.setInternalGroupSharing(group, e.currentTarget.value)}>
@@ -550,7 +553,7 @@ export class SharingManager extends React.Component<{}> {
<div
className="sharing-contents"
style={{
- background: StrCast(Doc.UserDoc().userBackgroundColor),
+ background: SettingsManager.Instance.userBackgroundColor,
color: StrCast(Doc.UserDoc().userColor),
}}>
<p className="share-title" style={{ color: StrCast(Doc.UserDoc().userColor) }}>
diff --git a/src/client/util/reportManager/ReportManager.tsx b/src/client/util/reportManager/ReportManager.tsx
index e684bd637..7aad0f2b1 100644
--- a/src/client/util/reportManager/ReportManager.tsx
+++ b/src/client/util/reportManager/ReportManager.tsx
@@ -19,6 +19,7 @@ import { BugType, FileData, Priority, ReportForm, ViewState, bugDropdownItems, d
import { Filter, FormInput, FormTextArea, IssueCard, IssueView, Tag } from './ReportManagerComponents';
import { StrCast } from '../../../fields/Types';
import { MdRefresh } from 'react-icons/md';
+import { SettingsManager } from '../SettingsManager';
const higflyout = require('@hig/flyout');
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -213,11 +214,11 @@ export class ReportManager extends React.Component<{}> {
* @returns the component that dispays all issues
*/
private viewIssuesComponent = () => {
- const darkMode = isDarkMode(StrCast(Doc.UserDoc().userBackgroundColor));
+ const darkMode = isDarkMode(SettingsManager.Instance.userBackgroundColor);
const colors = darkMode ? darkColors : lightColors;
return (
- <div className="view-issues" style={{ backgroundColor: StrCast(Doc.UserDoc().userBackgroundColor), color: colors.text }}>
+ <div className="view-issues" style={{ backgroundColor: SettingsManager.Instance.userBackgroundColor, color: colors.text }}>
<div className="left" style={{ display: this.rightExpanded ? 'none' : 'flex' }}>
<div className="report-header">
<h2 style={{ color: colors.text }}>Open Issues</h2>