aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/CollectionDockingView.tsx
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2023-04-05 22:44:03 -0400
committerbobzel <zzzman@gmail.com>2023-04-05 22:44:03 -0400
commit9b41da1af16b982ee8ac2fc09f2f8b5d67eac9fb (patch)
treebc3f57cd5b31fd453d272c925f6d5b728ab63bae /src/client/views/collections/CollectionDockingView.tsx
parent9dae453967183b294bf4f7444b948023a1d52d39 (diff)
parent8f7e99641f84ad15f34ba9e4a60b664ac93d2e5d (diff)
Merge branch 'master' into data-visualization-view-naafi
Diffstat (limited to 'src/client/views/collections/CollectionDockingView.tsx')
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx136
1 files changed, 90 insertions, 46 deletions
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 6d70cc0d2..4d000542c 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -1,12 +1,12 @@
import { action, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
-import * as ReactDOM from 'react-dom';
+import * as ReactDOM from 'react-dom/client';
import * as GoldenLayout from '../../../client/goldenLayout';
import { Doc, DocListCast, Opt } from '../../../fields/Doc';
import { Id } from '../../../fields/FieldSymbols';
import { InkTool } from '../../../fields/InkField';
import { List } from '../../../fields/List';
-import { Cast, NumCast, StrCast } from '../../../fields/Types';
+import { Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types';
import { ImageField } from '../../../fields/URLField';
import { inheritParentAcls } from '../../../fields/util';
import { emptyFunction, incrementTitleCopy } from '../../../Utils';
@@ -25,12 +25,15 @@ import { CollectionFreeFormView } from './collectionFreeForm';
import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
import { TabDocView } from './TabDocView';
import React = require('react');
+import { OpenWhere, OpenWhereMod } from '../nodes/DocumentView';
+import { OverlayView } from '../OverlayView';
+import { ScriptingRepl } from '../ScriptingRepl';
const _global = (window /* browser */ || global) /* node */ as any;
@observer
export class CollectionDockingView extends CollectionSubView() {
@observable public static Instance: CollectionDockingView | undefined;
- public static makeDocumentConfig(document: Doc, panelName?: string, width?: number) {
+ public static makeDocumentConfig(document: Doc, panelName?: string, width?: number, keyValue?: boolean) {
return {
type: 'react-component',
component: 'DocumentFrameRenderer',
@@ -38,6 +41,7 @@ export class CollectionDockingView extends CollectionSubView() {
width: width,
props: {
documentId: document[Id],
+ keyValue,
panelName, // name of tab that can be used to close or replace its contents
},
};
@@ -56,11 +60,12 @@ export class CollectionDockingView extends CollectionSubView() {
constructor(props: SubCollectionViewProps) {
super(props);
- runInAction(() => (CollectionDockingView.Instance = this));
+ if (this.props.renderDepth < 0) runInAction(() => (CollectionDockingView.Instance = this));
//Why is this here?
(window as any).React = React;
(window as any).ReactDOM = ReactDOM;
DragManager.StartWindowDrag = this.StartOtherDrag;
+ this.rootDoc.myTrails; // this is equivalent to having a prefetchProxy for myTrails which is needed for the My Trails button in the UI which assumes that Doc.ActiveDashboard.myTrails is legit...
}
/**
@@ -73,7 +78,7 @@ export class CollectionDockingView extends CollectionSubView() {
public StartOtherDrag = (e: { pageX: number; pageY: number }, dragDocs: Doc[], finishDrag?: (aborted: boolean) => void) => {
this._flush = this._flush ?? UndoManager.StartBatch('golden layout drag');
const config = dragDocs.length === 1 ? CollectionDockingView.makeDocumentConfig(dragDocs[0]) : { type: 'row', content: dragDocs.map(doc => CollectionDockingView.makeDocumentConfig(doc)) };
- const dragSource = this._goldenLayout.createDragSource(document.createElement('div'), config);
+ const dragSource = CollectionDockingView.Instance?._goldenLayout.createDragSource(document.createElement('div'), config);
this.tabDragStart(dragSource, finishDrag);
dragSource._dragListener.onMouseDown({ pageX: e.pageX, pageY: e.pageY, preventDefault: emptyFunction, button: 0 });
};
@@ -141,10 +146,10 @@ export class CollectionDockingView extends CollectionSubView() {
@undoBatch
@action
- public static ReplaceTab(document: Doc, panelName: string, stack: any, addToSplit?: boolean): boolean {
+ public static ReplaceTab(document: Doc, panelName: OpenWhereMod, stack: any, addToSplit?: boolean, keyValue?: boolean): boolean {
const instance = CollectionDockingView.Instance;
if (!instance) return false;
- const newConfig = CollectionDockingView.makeDocumentConfig(document, panelName);
+ const newConfig = CollectionDockingView.makeDocumentConfig(document, panelName, undefined, keyValue);
if (!panelName && stack) {
const activeContentItemIndex = stack.contentItems.findIndex((item: any) => item.config === stack._activeContentItem.config);
const newContentItem = stack.layoutManager.createContentItem(newConfig, instance._goldenLayout);
@@ -154,19 +159,22 @@ export class CollectionDockingView extends CollectionSubView() {
}
const tab = Array.from(instance.tabMap.keys()).find(tab => tab.contentItem.config.props.panelName === panelName);
if (tab) {
- tab.header.parent.addChild(newConfig, undefined);
const j = tab.header.parent.contentItems.indexOf(tab.contentItem);
- !addToSplit && j !== -1 && tab.header.parent.contentItems[j].remove();
- return instance.layoutChanged();
+ if (newConfig.props.documentId !== tab.header.parent.contentItems[j].config.props.documentId) {
+ tab.header.parent.addChild(newConfig, undefined);
+ !addToSplit && j !== -1 && tab.header.parent.contentItems[j].remove();
+ return instance.layoutChanged();
+ }
+ return false;
}
return CollectionDockingView.AddSplit(document, panelName, stack, panelName);
}
@undoBatch
- public static ToggleSplit(doc: Doc, location: string, stack?: any, panelName?: string) {
+ public static ToggleSplit(doc: Doc, location: OpenWhereMod, stack?: any, panelName?: string, keyValue?: boolean) {
return CollectionDockingView.Instance && Array.from(CollectionDockingView.Instance.tabMap.keys()).findIndex(tab => tab.DashDoc === doc) !== -1
? CollectionDockingView.CloseSplit(doc)
- : CollectionDockingView.AddSplit(doc, location, stack, panelName);
+ : CollectionDockingView.AddSplit(doc, location, stack, panelName, keyValue);
}
//
@@ -174,10 +182,10 @@ export class CollectionDockingView extends CollectionSubView() {
//
@undoBatch
@action
- public static AddSplit(document: Doc, pullSide: string, stack?: any, panelName?: string) {
+ public static AddSplit(document: Doc, pullSide: OpenWhereMod, stack?: any, panelName?: string, keyValue?: boolean) {
if (document?._viewType === CollectionViewType.Docking) return DashboardView.openDashboard(document);
if (!CollectionDockingView.Instance) return false;
- const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === document);
+ const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === document && !keyValue);
if (tab) {
tab.header.parent.setActiveContentItem(tab.contentItem);
return true;
@@ -185,11 +193,11 @@ export class CollectionDockingView extends CollectionSubView() {
const instance = CollectionDockingView.Instance;
const glayRoot = instance._goldenLayout.root;
if (!instance) return false;
- const docContentConfig = CollectionDockingView.makeDocumentConfig(document, panelName);
+ const docContentConfig = CollectionDockingView.makeDocumentConfig(document, panelName, undefined, keyValue);
if (!pullSide && stack) {
stack.addChild(docContentConfig, undefined);
- stack.setActiveContentItem(stack.contentItems[stack.contentItems.length - 1]);
+ setTimeout(() => stack.setActiveContentItem(stack.contentItems[stack.contentItems.length - 1]));
} else {
const newContentItem = () => {
const newItem = glayRoot.layoutManager.createContentItem({ type: 'stack', content: [docContentConfig] }, instance._goldenLayout);
@@ -207,14 +215,15 @@ export class CollectionDockingView extends CollectionSubView() {
// if row
switch (pullSide) {
default:
- case 'right':
+ case OpenWhereMod.none:
+ case OpenWhereMod.right:
glayRoot.contentItems[0].addChild(newContentItem());
break;
- case 'left':
+ case OpenWhereMod.left:
glayRoot.contentItems[0].addChild(newContentItem(), 0);
break;
- case 'top':
- case 'bottom':
+ case OpenWhereMod.top:
+ case OpenWhereMod.bottom:
// if not going in a row layout, must add already existing content into column
const rowlayout = glayRoot.contentItems[0];
const newColumn = rowlayout.layoutManager.createContentItem({ type: 'column' }, instance._goldenLayout);
@@ -280,12 +289,13 @@ export class CollectionDockingView extends CollectionSubView() {
this.stateChanged();
return true;
}
-
setupGoldenLayout = async () => {
+ //const config = StrCast(this.props.Document.dockingConfig, JSON.stringify(DashboardView.resetDashboard(this.props.Document)));
const config = StrCast(this.props.Document.dockingConfig);
if (config) {
const matches = config.match(/\"documentId\":\"[a-z0-9-]+\"/g);
const docids = matches?.map(m => m.replace('"documentId":"', '').replace('"', '')) ?? [];
+
await Promise.all(docids.map(id => DocServer.GetRefField(id)));
if (this._goldenLayout) {
@@ -311,10 +321,12 @@ export class CollectionDockingView extends CollectionSubView() {
glay.root.layoutManager.on('itemDropped', this.tabItemDropped);
glay.root.layoutManager.on('dragStart', this.tabDragStart);
glay.root.layoutManager.on('activeContentItemChanged', this.stateChanged);
+ } else {
+ console.log('ERROR: no config for dashboard!!');
}
};
- componentDidMount: () => void = () => {
+ componentDidMount: () => void = async () => {
if (this._containerRef.current) {
this._lightboxReactionDisposer = reaction(
() => LightboxView.LightboxDoc,
@@ -331,8 +343,11 @@ export class CollectionDockingView extends CollectionSubView() {
this._ignoreStateChange = '';
}
);
- setTimeout(this.setupGoldenLayout);
- //window.addEventListener('resize', this.onResize); // bcz: would rather add this event to the parent node, but resize events only come from Window
+ reaction(
+ () => this.props.PanelWidth(),
+ width => !this._goldenLayout && width > 20 && setTimeout(() => this.setupGoldenLayout()), // need to wait for the collectiondockingview-container to have it's width/height since golden layout reads that to configure its windows
+ { fireImmediately: true }
+ );
}
};
@@ -380,6 +395,7 @@ export class CollectionDockingView extends CollectionSubView() {
const className = typeof htmlTarget.className === 'string' ? htmlTarget.className : '';
if (!className.includes('lm_close') && !className.includes('lm_maximise')) {
this._flush = UndoManager.StartBatch('golden layout edit');
+ DocServer.UPDATE_SERVER_CACHE();
}
}
}
@@ -394,11 +410,10 @@ export class CollectionDockingView extends CollectionSubView() {
const _width = Number(getComputedStyle(content).width.replace('px', ''));
const _height = Number(getComputedStyle(content).height.replace('px', ''));
return CollectionFreeFormView.UpdateIcon(this.layoutDoc[Id] + '-icon' + new Date().getTime(), content, _width, _height, _width, _height, 0, 1, true, this.layoutDoc[Id] + '-icon', (iconFile, _nativeWidth, _nativeHeight) => {
- const img = Docs.Create.ImageDocument(new ImageField(iconFile), { title: this.rootDoc.title + '-icon', _width, _height, _nativeWidth, _nativeHeight });
- const proto = Cast(img.proto, Doc, null)!;
- proto['data-nativeWidth'] = _width;
- proto['data-nativeHeight'] = _height;
- this.dataDoc.thumb = img;
+ const proto = this.dataDoc; // Cast(img.proto, Doc, null)!;
+ proto['thumb-nativeWidth'] = _width;
+ proto['thumb-nativeHeight'] = _height;
+ proto.thumb = new ImageField(iconFile);
});
}
}
@@ -429,7 +444,8 @@ export class CollectionDockingView extends CollectionSubView() {
return newtab;
});
const copy = Docs.Create.DockDocument(newtabs, json, { title: incrementTitleCopy(StrCast(doc.title)) });
- return DashboardView.openDashboard(await copy);
+ DashboardView.SetupDashboardTrails(copy);
+ return DashboardView.openDashboard(copy);
}
@action
@@ -444,7 +460,7 @@ export class CollectionDockingView extends CollectionSubView() {
.map(id => DocServer.GetCachedRefField(id))
.filter(f => f)
.map(f => f as Doc);
- const changesMade = this.props.Document.dockcingConfig !== json;
+ const changesMade = this.props.Document.dockingConfig !== json;
if (changesMade && !this._flush) {
UndoManager.RunInBatch(() => {
this.props.Document.dockingConfig = json;
@@ -455,7 +471,7 @@ export class CollectionDockingView extends CollectionSubView() {
};
tabDestroyed = (tab: any) => {
- if (tab.DashDoc?.type !== DocumentType.KVP) {
+ if (tab.DashDoc && ![DocumentType.KVP, DocumentType.PRES].includes(tab.DashDoc?.type)) {
Doc.AddDocToList(Doc.MyHeaderBar, 'data', tab.DashDoc);
Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true);
}
@@ -465,8 +481,8 @@ export class CollectionDockingView extends CollectionSubView() {
Doc.RemoveDocFromList(dview, fieldKey, tab.DashDoc);
this.tabMap.delete(tab);
tab._disposers && Object.values(tab._disposers).forEach((disposer: any) => disposer?.());
- tab.reactComponents?.forEach((ele: any) => ReactDOM.unmountComponentAtNode(ele));
- setTimeout(this.stateChanged);
+ //tab.reactComponents?.forEach((ele: any) => ReactDOM.unmountComponentAtNode(ele));
+ this.stateChanged();
}
};
tabCreated = (tab: any) => {
@@ -475,6 +491,7 @@ export class CollectionDockingView extends CollectionSubView() {
};
stackCreated = (stack: any) => {
+ stack = stack.header ? stack : stack.origin;
stack.header?.element.on('mousedown', (e: any) => {
const dashboard = Doc.ActiveDashboard;
if (dashboard && e.target === stack.header?.element[0] && e.button === 2) {
@@ -487,7 +504,7 @@ export class CollectionDockingView extends CollectionSubView() {
title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`,
});
this.props.Document.isShared && inheritParentAcls(this.props.Document, docToAdd);
- CollectionDockingView.AddSplit(docToAdd, '', stack);
+ CollectionDockingView.AddSplit(docToAdd, OpenWhereMod.none, stack);
}
});
@@ -497,8 +514,13 @@ export class CollectionDockingView extends CollectionSubView() {
.click(
action(() => {
//if (confirm('really close this?')) {
- if (!stack.parent.parent.isRoot || stack.parent.contentItems.length > 1) {
+ if ((!stack.parent.isRoot && !stack.parent.parent.isRoot) || stack.parent.contentItems.length > 1) {
+ const batch = UndoManager.StartBatch('close stack');
stack.remove();
+ setTimeout(() => {
+ this.stateChanged();
+ batch.end();
+ });
} else {
alert('cant delete the last stack');
}
@@ -525,38 +547,60 @@ export class CollectionDockingView extends CollectionSubView() {
title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`,
});
this.props.Document.isShared && inheritParentAcls(this.props.Document, docToAdd);
- CollectionDockingView.AddSplit(docToAdd, '', stack);
+ CollectionDockingView.AddSplit(docToAdd, OpenWhereMod.none, stack);
}
})
);
};
render() {
- return <div className="collectiondockingview-container" onPointerDown={this.onPointerDown} ref={this._containerRef} />;
+ const href = ImageCast(this.rootDoc.thumb)?.url.href;
+ return this.props.renderDepth > -1 ? (
+ <div>
+ {href ? (
+ <img
+ style={{ background: 'white', top: 0, position: 'absolute' }}
+ src={href} // + '?d=' + (new Date()).getTime()}
+ width={this.props.PanelWidth()}
+ height={this.props.PanelHeight()}
+ />
+ ) : (
+ <p>nested dashboards has no thumbnail</p>
+ )}
+ </div>
+ ) : (
+ <div className="collectiondockingview-container" onPointerDown={this.onPointerDown} ref={this._containerRef} />
+ );
}
}
ScriptingGlobals.add(
function openInLightbox(doc: any) {
- LightboxView.AddDocTab(doc, 'lightbox');
+ LightboxView.AddDocTab(doc, OpenWhere.lightbox);
},
'opens up document in a lightbox',
'(doc: any)'
);
ScriptingGlobals.add(
- function openOnRight(doc: any) {
- return CollectionDockingView.AddSplit(doc, 'right');
+ function openDoc(doc: any, where: OpenWhere) {
+ switch (where) {
+ case OpenWhere.addRight:
+ return CollectionDockingView.AddSplit(doc, OpenWhereMod.right);
+ case OpenWhere.overlay:
+ if (doc === 'repl') OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: 'Scripting REPL' });
+ else Doc.AddDocToList(Doc.MyOverlayDocs, undefined, doc);
+ }
},
- 'opens up document in tab on right side of the screen',
+ 'opens up document in location specified',
'(doc: any)'
);
ScriptingGlobals.add(
- function openInOverlay(doc: any) {
- return Doc.AddDocToList(Doc.MyOverlayDocs, undefined, doc);
+ function openRepl() {
+ return 'openRepl';
},
'opens up document in screen overlay layer',
'(doc: any)'
);
-ScriptingGlobals.add(function useRightSplit(doc: any, shiftKey?: boolean) {
- CollectionDockingView.ReplaceTab(doc, 'right', undefined, shiftKey);
+ScriptingGlobals.add(function useRightSplit(doc: any, addToRightSplit?: boolean) {
+ CollectionDockingView.ReplaceTab(doc, OpenWhereMod.right, undefined, addToRightSplit);
});