aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeireann Lindfield Roberts <60007097+geireann@users.noreply.github.com>2022-09-22 13:10:58 -0400
committerGeireann Lindfield Roberts <60007097+geireann@users.noreply.github.com>2022-09-22 13:10:58 -0400
commit1ec9505775315d0ba41b114942ff69d8ceb93e04 (patch)
tree3dde9bb324814b419b4b5a27d9be3c30dd81d993
parent604b3e566eaf762ede05f4a31c459c20d0df020b (diff)
parent40cc7455e853d306ee2750c51308d095dc2970ef (diff)
Merge branch 'master' of https://github.com/brown-dash/Dash-Web
-rw-r--r--src/client/Network.ts11
-rw-r--r--src/client/documents/Documents.ts2
-rw-r--r--src/client/goldenLayout.js13
-rw-r--r--src/client/views/ContextMenu.scss2
-rw-r--r--src/client/views/DashboardView.tsx7
-rw-r--r--src/client/views/DocumentDecorations.tsx25
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx3
-rw-r--r--src/client/views/global/globalCssVariables.scss2
-rw-r--r--src/client/views/nodes/VideoBox.tsx1
-rw-r--r--src/client/views/nodes/trails/PresBox.scss25
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx27
-rw-r--r--src/client/views/topbar/TopBar.tsx87
-rw-r--r--src/fields/Doc.ts2
-rw-r--r--src/server/ApiManagers/UploadManager.ts12
14 files changed, 86 insertions, 133 deletions
diff --git a/src/client/Network.ts b/src/client/Network.ts
index a222b320f..996eb35d8 100644
--- a/src/client/Network.ts
+++ b/src/client/Network.ts
@@ -30,6 +30,17 @@ export namespace Networking {
if (!files.length) {
return [];
}
+ const maxFileSize = 50000000;
+ if (files.some(f => f.size > maxFileSize)) {
+ return new Promise<any>(res =>
+ res([
+ {
+ source: { name: '', type: '', size: 0, toJson: () => ({ name: '', type: '' }) },
+ result: { name: '', message: `max file size (${maxFileSize / 1000000}MB) exceeded` },
+ },
+ ])
+ );
+ }
files.forEach(file => formData.append(Utils.GenerateGuid(), file));
} else {
formData.append(Utils.GenerateGuid(), files);
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 4f652b6e4..029c3033d 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1864,7 +1864,7 @@ export namespace DocUtils {
const {
source: { name, type },
result,
- } = upfiles.lastElement();
+ } = upfiles.lastElement() ?? { source: { name: '', type: '' }, result: { message: 'upload failed' } };
if ((result as any).message) {
if (overwriteDoc) {
overwriteDoc.isLoading = false;
diff --git a/src/client/goldenLayout.js b/src/client/goldenLayout.js
index e5cd50de2..dd11e6466 100644
--- a/src/client/goldenLayout.js
+++ b/src/client/goldenLayout.js
@@ -3263,11 +3263,6 @@
const canDelete = rowOrCol && !rowOrCol.isRoot && (rowOrCol.contentItems.length > 1 || (parRowOrCol && parRowOrCol.contentItems.length > 1)); // bcz: added test for last stack
if (canDelete) {
rowOrCol.removeChild(stack);
- if (rowOrCol.contentItems.length === 1 && parRowOrCol.contentItems.length === 1 && !parRowOrCol.isRoot) {
- saveScrollTops(rowOrCol.contentItems[0].element);
- parRowOrCol.replaceChild(rowOrCol, rowOrCol.contentItems[0]);
- restoreScrollTops(rowOrCol.contentItems[0].element);
- }
}
}
},
@@ -4061,6 +4056,14 @@
lm.items.AbstractContentItem.prototype.removeChild.call(this, contentItem, keepChild);
if (this.contentItems.length === 1 && this.config.isClosable === true) {
+ if (["row","column"].includes(this.contentItems[0].type) || ["row","column"].includes(this.parent.type)) {
+ let parent = this.parent;
+ let correctRowOrCol = this.contentItems[0];
+ saveScrollTops(correctRowOrCol.element);
+ parent.replaceChild(this, correctRowOrCol);
+ restoreScrollTops(correctRowOrCol.element);
+ }
+
// bcz: this has the effect of removing children from the DOM and then re-adding them above where they were before.
// in the case of things like an iFrame with a YouTube video, the video will reload for now reason. So let's try leaving these "empty" rows alone.
// childItem = this.contentItems[0];
diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss
index 1e6a377de..cbe14060a 100644
--- a/src/client/views/ContextMenu.scss
+++ b/src/client/views/ContextMenu.scss
@@ -3,7 +3,7 @@
.contextMenu-cont {
position: absolute;
display: flex;
- z-index: 100000;
+ z-index: $contextMenu-zindex;
box-shadow: 0px 3px 4px rgba(0, 0, 0, 30%);
flex-direction: column;
background: whitesmoke;
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx
index 911b53945..11bb0c6a8 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -370,11 +370,12 @@ export class DashboardView extends React.Component {
system: true,
explainer: 'All of the trails that you have created will appear here.',
};
- dashboardDoc.myTrails = new PrefetchProxy(DocUtils.AssignScripts(Docs.Create.TreeDocument([], reqdOpts), { treeViewChildDoubleClick: 'openPresentation(documentView.rootDoc)' }));
+ const myTrails = DocUtils.AssignScripts(Docs.Create.TreeDocument([], reqdOpts), { treeViewChildDoubleClick: 'openPresentation(documentView.rootDoc)' });
+ dashboardDoc.myTrails = new PrefetchProxy(myTrails);
const contextMenuScripts = [reqdBtnScript.onClick];
- if (Cast(Doc.MyTrails.contextMenuScripts, listSpec(ScriptField), null)?.length !== contextMenuScripts.length) {
- Doc.MyTrails.contextMenuScripts = new List<ScriptField>(contextMenuScripts.map(script => ScriptField.MakeFunction(script)!));
+ if (Cast(myTrails.contextMenuScripts, listSpec(ScriptField), null)?.length !== contextMenuScripts.length) {
+ myTrails.contextMenuScripts = new List<ScriptField>(contextMenuScripts.map(script => ScriptField.MakeFunction(script)!));
}
}
}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 797730c10..4675571c2 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -31,6 +31,7 @@ import { ImageBox } from './nodes/ImageBox';
import React = require('react');
import { IconButton } from 'browndash-components';
import { FaUndo } from 'react-icons/fa';
+import { VideoBox } from './nodes/VideoBox';
@observer
export class DocumentDecorations extends React.Component<{ PanelWidth: number; PanelHeight: number; boundsLeft: number; boundsTop: number }, { value: string }> {
@@ -678,7 +679,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
bounds.b = Math.max(bounds.y, Math.max(topBounds, Math.min(window.innerHeight, bounds.b + this._resizeBorderWidth / 2 + this._linkBoxHeight) - this._resizeBorderWidth / 2 - this._linkBoxHeight));
// Rotation constants: Only allow rotation on ink and images
- const useRotation = seldoc.ComponentView instanceof InkingStroke || seldoc.ComponentView instanceof ImageBox;
+ const useRotation = seldoc.ComponentView instanceof InkingStroke || seldoc.ComponentView instanceof ImageBox || seldoc.ComponentView instanceof VideoBox;
const rotation = NumCast(seldoc.rootDoc._jitterRotation);
const resizerScheme = colorScheme ? 'documentDecorations-resizer' + colorScheme : '';
@@ -721,12 +722,14 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
width: bounds.r - bounds.x + this._resizeBorderWidth + 'px',
height: bounds.b - bounds.y + this._resizeBorderWidth + this._titleHeight + 'px',
}}>
- {hideResizers ? null : (<div className="documentDecorations-topbar">
- {hideDeleteButton ? <div /> : topBtn('close', 'times', undefined, e => this.onCloseClick(true), 'Close')}
- {hideDeleteButton ? <div /> : topBtn('minimize', 'window-maximize', undefined, e => this.onCloseClick(undefined), 'Minimize')}
- {titleArea}
- {hideOpenButton ? null : topBtn('open', 'external-link-alt', this.onMaximizeDown, undefined, 'Open in Tab (ctrl: as alias, shift: in new collection)')}
- </div>)}
+ {hideResizers ? null : (
+ <div className="documentDecorations-topbar">
+ {hideDeleteButton ? <div /> : topBtn('close', 'times', undefined, e => this.onCloseClick(true), 'Close')}
+ {hideDeleteButton ? <div /> : topBtn('minimize', 'window-maximize', undefined, e => this.onCloseClick(undefined), 'Minimize')}
+ {titleArea}
+ {hideOpenButton ? null : topBtn('open', 'external-link-alt', this.onMaximizeDown, undefined, 'Open in Tab (ctrl: as alias, shift: in new collection)')}
+ </div>
+ )}
{hideResizers ? null : (
<>
<div key="tl" className={`documentDecorations-topLeftResizer ${resizerScheme}`} onPointerDown={this.onPointerDown} onContextMenu={e => e.preventDefault()} />
@@ -743,9 +746,11 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
</>
)}
- {useRotation && <div key="rot" className={`documentDecorations-rotation`} onPointerDown={this.onRotateDown} onContextMenu={e => e.preventDefault()}>
- <IconButton icon={<FaUndo/>} isCircle={true} hoverStyle={"lighten"} backgroundColor={Colors.DARK_GRAY} color={Colors.LIGHT_GRAY}/>
- </div>}
+ {useRotation && (
+ <div key="rot" className={`documentDecorations-rotation`} onPointerDown={this.onRotateDown} onContextMenu={e => e.preventDefault()}>
+ <IconButton icon={<FaUndo />} isCircle={true} hoverStyle={'lighten'} backgroundColor={Colors.DARK_GRAY} color={Colors.LIGHT_GRAY} />
+ </div>
+ )}
{useRounding && (
<div
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 25fe5fe43..c6ac5ee0c 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -477,6 +477,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) {
@@ -499,7 +500,7 @@ 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) {
stack.remove();
} else {
alert('cant delete the last stack');
diff --git a/src/client/views/global/globalCssVariables.scss b/src/client/views/global/globalCssVariables.scss
index ac2c04aaa..e68f9abe3 100644
--- a/src/client/views/global/globalCssVariables.scss
+++ b/src/client/views/global/globalCssVariables.scss
@@ -47,7 +47,7 @@ $topbar-height: 37px;
$antimodemenu-height: 36px;
// dragged items
-$contextMenu-zindex: 100000; // context menu shows up over everything
+$contextMenu-zindex: 100002; // context menu shows up over everything
$radialMenu-zindex: 100000; // context menu shows up over everything
// borders
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 4bcd79641..f7f558bb4 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -405,6 +405,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
}
if (Number.isFinite(this.player!.duration)) {
this.rawDuration = this.player!.duration;
+ this.dataDoc[this.fieldKey + '-duration'] = this.rawDuration;
} else this.rawDuration = NumCast(this.dataDoc[this.fieldKey + '-duration']);
});
diff --git a/src/client/views/nodes/trails/PresBox.scss b/src/client/views/nodes/trails/PresBox.scss
index a0a2dd4f8..34df415ac 100644
--- a/src/client/views/nodes/trails/PresBox.scss
+++ b/src/client/views/nodes/trails/PresBox.scss
@@ -1,4 +1,4 @@
-@import "../../global/globalCssVariables";
+@import '../../global/globalCssVariables';
.presBox-cont {
cursor: auto;
@@ -231,8 +231,7 @@
margin-top: 10px;
}
- @media screen and (-webkit-min-device-pixel-ratio:0) {
-
+ @media screen and (-webkit-min-device-pixel-ratio: 0) {
.multiThumb-slider {
display: grid;
background-color: $white;
@@ -289,6 +288,7 @@
height: 10px;
-webkit-appearance: none;
margin-top: -1px;
+ background: transparent;
}
.toolbar-slider::-webkit-slider-thumb {
@@ -330,8 +330,6 @@
}
}
-
-
.slider-headers {
position: relative;
display: grid;
@@ -382,7 +380,6 @@
border-bottom: solid 2px $medium-gray;
}
-
.ribbon-textInput {
border-radius: 2px;
height: 20px;
@@ -467,7 +464,6 @@
font-weight: 500;
position: relative;
-
.ribbon-final-button {
cursor: pointer;
position: relative;
@@ -687,7 +683,6 @@
max-width: 200px;
overflow: visible;
-
.presBox-dropdownOption {
cursor: pointer;
font-size: 11;
@@ -716,7 +711,7 @@
width: 85%;
min-width: max-content;
display: block;
- background: #FFFFFF;
+ background: #ffffff;
border: 0.5px solid #979797;
box-sizing: border-box;
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
@@ -741,7 +736,7 @@
padding-top: 5px;
padding-bottom: 5px;
border: solid 1px $black;
- // overflow: auto;
+ // overflow: auto;
::-webkit-scrollbar {
-webkit-appearance: none;
@@ -953,8 +948,6 @@
min-width: 150px;
}
-
-
select {
background: $dark-gray;
color: $white;
@@ -999,8 +992,6 @@
}
}
-
-
.collectionViewBaseChrome-viewPicker {
min-width: 50;
width: 5%;
@@ -1080,7 +1071,7 @@
position: absolute;
top: 0;
left: 0;
- opacity: 0.1;
+ opacity: 0.5;
transition: all 0.4s;
color: $white;
width: 100%;
@@ -1165,8 +1156,6 @@
.presPanel-button-text:hover {
background-color: $medium-gray;
}
-
-
}
// .miniPres {
@@ -1241,4 +1230,4 @@
// background-color: #5a5a5a;
// }
// }
-// } \ No newline at end of file
+// }
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 40cda4f7e..de19f831d 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -234,8 +234,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
//TODO: al: it seems currently that tempMedia doesn't stop onslidechange after clicking the button; the time the tempmedia stop depends on the start & end time
// TODO: to handle child slides (entering into subtrail and exiting), also the next() and back() functions
// No more frames in current doc and next slide is defined, therefore move to next slide
- nextSlide = (activeNext: Doc) => {
- let nextSelected = this.itemIndex + 1;
+ nextSlide = (slideNum?: number) => {
+ let nextSelected = slideNum ?? this.itemIndex + 1;
this.gotoDocument(nextSelected, this.activeItem);
for (nextSelected = nextSelected + 1; nextSelected < this.childDocs.length; nextSelected++) {
if (this.childDocs[nextSelected].groupWithUp) {
@@ -261,10 +261,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this.nextInternalFrame(targetDoc, activeItem);
} else if (this.childDocs[this.itemIndex + 1] !== undefined) {
// Case 2: No more frames in current doc and next slide is defined, therefore move to next slide
- this.nextSlide(activeNext);
+ const slides = DocListCast(this.rootDoc[StrCast(this.presFieldKey, 'data')]);
+ const curLast = this.selectedArray.size ? Math.max(...Array.from(this.selectedArray).map(d => slides.indexOf(DocCast(d)))) : this.itemIndex;
+ this.nextSlide(curLast + 1);
} else if (this.childDocs[this.itemIndex + 1] === undefined && (this.layoutDoc.presLoop || this.layoutDoc.presStatus === PresStatus.Edit)) {
// Case 3: Last slide and presLoop is toggled ON or it is in Edit mode
- this.gotoDocument(0, this.activeItem);
+ this.nextSlide(0);
}
};
@@ -280,8 +282,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
let prevSelected = this.itemIndex;
// Functionality for group with up
let didZoom = activeItem.presMovement;
- for (; !didZoom && prevSelected > 0 && this.childDocs[prevSelected].groupButton; prevSelected--) {
- didZoom = this.childDocs[prevSelected].presMovement;
+ for (; prevSelected > 0 && this.childDocs[Math.max(0, prevSelected - 1)].groupWithUp; prevSelected--) {
+ didZoom = didZoom === 'none' ? this.childDocs[prevSelected].presMovement : didZoom;
}
if (lastFrame !== undefined && curFrame >= 1) {
// Case 1: There are still other frames and should go through all frames before going to previous slide
@@ -289,7 +291,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
} else if (activeItem && this.childDocs[this.itemIndex - 1] !== undefined) {
// Case 2: There are no other frames so it should go to the previous slide
prevSelected = Math.max(0, prevSelected - 1);
- this.gotoDocument(prevSelected, activeItem);
+ this.nextSlide(prevSelected);
+ this.rootDoc._itemIndex = prevSelected;
if (NumCast(prevTargetDoc.lastFrame) > 0) prevTargetDoc._currentFrame = NumCast(prevTargetDoc.lastFrame);
} else if (this.childDocs[this.itemIndex - 1] === undefined && this.layoutDoc.presLoop) {
// Case 3: Pres loop is on so it should go to the last slide
@@ -1427,7 +1430,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const activeItem: Doc = this.activeItem;
const targetDoc: Doc = this.targetDoc;
const clipStart: number = NumCast(activeItem.clipStart);
- const clipEnd: number = NumCast(activeItem.clipEnd);
+ const clipEnd: number = NumCast(activeItem.clipEnd, NumCast(activeItem[Doc.LayoutFieldKey(activeItem) + '-duration']));
const mediaStopDocInd: number = NumCast(activeItem.mediaStopDoc);
if (activeItem && targetDoc) {
return (
@@ -2458,12 +2461,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<div
className="presPanel-button"
style={{ opacity: presStart ? 0.4 : 1 }}
- onClick={() => {
+ onClick={e => {
this.back();
if (this._presTimer) {
clearTimeout(this._presTimer);
this.layoutDoc.presStatus = PresStatus.Manual;
}
+ e.stopPropagation();
}}>
<FontAwesomeIcon icon={'arrow-left'} />
</div>
@@ -2475,18 +2479,19 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<div
className="presPanel-button"
style={{ opacity: presEnd ? 0.4 : 1 }}
- onClick={() => {
+ onClick={e => {
this.next();
if (this._presTimer) {
clearTimeout(this._presTimer);
this.layoutDoc.presStatus = PresStatus.Manual;
}
+ e.stopPropagation();
}}>
<FontAwesomeIcon icon={'arrow-right'} />
</div>
<div className="presPanel-divider"></div>
<Tooltip title={<div className="dash-tooltip">{'Click to return to 1st slide'}</div>}>
- <div className="presPanel-button" style={{ border: 'solid 1px white' }} onClick={() => this.gotoDocument(0, this.activeItem)}>
+ <div className="presPanel-button" style={{ border: 'solid 1px white' }} onClick={() => this.nextSlide(0)}>
<b>1</b>
</div>
</Tooltip>
diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx
index 7bc7ba3ed..7e728306c 100644
--- a/src/client/views/topbar/TopBar.tsx
+++ b/src/client/views/topbar/TopBar.tsx
@@ -80,8 +80,6 @@ export class TopBar extends React.Component {
* - Taking a snapshot of a dashboard
*/
@computed get topbarCenter() {
- const myDashboards = DocListCast(Doc.MyDashboards.data);
- const activeDashboard = Doc.ActiveDashboard;
// const dashboardItems = myDashboards.map(board => {
// const boardTitle = StrCast(board.title);
// console.log(boardTitle);
@@ -91,10 +89,10 @@ export class TopBar extends React.Component {
// val: board,
// };
// });
- return activeDashboard ? (
+ return Doc.ActiveDashboard ? (
<div className="topbar-center">
<Button
- text={StrCast(activeDashboard.title)}
+ text={StrCast(Doc.ActiveDashboard.title)}
tooltip="Browsing mode for directly navigating to documents"
fontSize={FontSize.SECONDARY}
size={Size.SMALL}
@@ -104,7 +102,7 @@ export class TopBar extends React.Component {
borderRadius={5}
hoverStyle="none"
onClick={(e: React.MouseEvent) => {
- const dashView = activeDashboard && DocumentManager.Instance.getDocumentView(activeDashboard);
+ const dashView = Doc.ActiveDashboard && DocumentManager.Instance.getDocumentView(Doc.ActiveDashboard);
ContextMenu.Instance.addItem({ description: 'Open Dashboard View', event: this.navigateToHome, icon: 'edit' });
ContextMenu.Instance.addItem({
description: 'Snapshot Dashboard',
@@ -119,9 +117,9 @@ export class TopBar extends React.Component {
}}
/>
<Button
- text={GetEffectiveAcl(Doc.GetProto(activeDashboard)) === AclAdmin ? 'Share' : 'View Original'}
+ text={GetEffectiveAcl(Doc.GetProto(Doc.ActiveDashboard)) === AclAdmin ? 'Share' : 'View Original'}
onClick={() => {
- SharingManager.Instance.open(undefined, activeDashboard);
+ SharingManager.Instance.open(undefined, Doc.ActiveDashboard);
}}
type="outline"
fontSize={FontSize.SECONDARY}
@@ -183,81 +181,6 @@ export class TopBar extends React.Component {
);
}
- // render() {
- // const activeDashboard = Doc.ActiveDashboard;
- // return (
- // //TODO:glr Add support for light / dark mode
- // <div style={{ pointerEvents: 'all', background: Colors.DARK_GRAY, borderBottom: Borders.STANDARD }} className="topbar-container">
- // <div className="topbar-inner-container">
- // <div className="topbar-left">
- // {activeDashboard ? (
- // <>
- // <div
- // className="topbar-button-icon"
- // onClick={e => {
- // ContextMenu.Instance.addItem({ description: 'Logout', event: () => window.location.assign(Utils.prepend('/logout')), icon: 'edit' });
- // ContextMenu.Instance.displayMenu(e.clientX + 5, e.clientY + 10);
- // }}>
- // {Doc.CurrentUserEmail}
- // </div>
- // <div className="topbar-button-icon" onClick={this.navigateToHome}>
- // <FontAwesomeIcon icon="home" />
- // </div>
- // </>
- // ) : null}
- // </div>
- // <div className="topbar-center">
- // <div className="topbar-title" onClick={() => activeDashboard && SelectionManager.SelectView(DocumentManager.Instance.getDocumentView(activeDashboard)!, false)}>
- // {activeDashboard ? StrCast(activeDashboard.title) : 'Dash'}
- // </div>
- // <div
- // className="topbar-button-icon"
- // onClick={e => {
- // const dashView = activeDashboard && DocumentManager.Instance.getDocumentView(activeDashboard);
- // ContextMenu.Instance.addItem({ description: 'Open Dashboard View', event: this.navigateToHome, icon: 'edit' });
- // ContextMenu.Instance.addItem({
- // description: 'Snapshot Dashboard',
- // event: async () => {
- // const batch = UndoManager.StartBatch('snapshot');
- // await DashboardView.snapshotDashboard();
- // batch.end();
- // },
- // icon: 'edit',
- // });
- // dashView?.showContextMenu(e.clientX + 20, e.clientY + 30);
- // }}>
- // <FontAwesomeIcon color="white" size="lg" icon="bars" />
- // </div>
- // <Tooltip title={<div className="dash-tooltip">Browsing mode for directly navigating to documents</div>} placement="bottom">
- // <div className="topbar-button-icon" style={{ background: MainView.Instance._exploreMode ? Colors.LIGHT_BLUE : undefined }} onClick={action(() => (MainView.Instance._exploreMode = !MainView.Instance._exploreMode))}>
- // <FontAwesomeIcon color={MainView.Instance._exploreMode ? 'red' : 'white'} icon="eye" size="lg" />
- // </div>
- // </Tooltip>
- // </div>
- // <div className="topbar-right">
- // {Doc.ActiveDashboard ? (
- // <div
- // className="topbar-button-icon"
- // onClick={() => {
- // SharingManager.Instance.open(undefined, activeDashboard);
- // }}>
- // {GetEffectiveAcl(Doc.GetProto(Doc.ActiveDashboard)) === AclAdmin ? 'Share' : 'view original'}
- // </div>
- // ) : null}
- // <div className="topbar-button-icon" onClick={() => ReportManager.Instance.open()}>
- // <MdBugReport />
- // </div>
- // <div className="topbar-button-icon" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/', '_blank')}>
- // <FontAwesomeIcon icon="question-circle" />
- // </div>
- // <div className="topbar-button-icon" onClick={() => SettingsManager.Instance.open()}>
- // <FontAwesomeIcon icon="cog" />
- // </div>
- // </div>
- // </div>
- // </div>
- // );
- // }
render() {
return (
//TODO:glr Add support for light / dark mode
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 74a3d8cf2..a3c742f28 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -239,6 +239,8 @@ export class Doc extends RefField {
return DocCast(Doc.UserDoc().activeDashboard);
}
public static set ActiveDashboard(val: Doc | undefined) {
+ const overlays = Cast(Doc.MyOverlayDocs.data, listSpec(Doc), null);
+ overlays && (overlays.length = 0);
Doc.UserDoc().activeDashboard = val;
}
public static set ActiveTool(tool: InkTool) {
diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts
index 0b6e18743..76cf36d44 100644
--- a/src/server/ApiManagers/UploadManager.ts
+++ b/src/server/ApiManagers/UploadManager.ts
@@ -60,6 +60,18 @@ export default class UploadManager extends ApiManager {
return new Promise<void>(resolve => {
form.parse(req, async (_err, _fields, files) => {
const results: Upload.FileResponse[] = [];
+ if (_err?.message) {
+ results.push({
+ source: {
+ size: 0,
+ path: 'none',
+ name: 'none',
+ type: 'none',
+ toJSON: () => ({ name: 'none', path: '' }),
+ },
+ result: { name: 'failed upload', message: `${_err.message}` },
+ });
+ }
for (const key in files) {
const f = files[key];
if (!Array.isArray(f)) {