diff options
Diffstat (limited to 'src/client/views/DashboardView.tsx')
-rw-r--r-- | src/client/views/DashboardView.tsx | 154 |
1 files changed, 105 insertions, 49 deletions
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index a4f598d1a..fc6a330f7 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -1,9 +1,12 @@ +/* eslint-disable jsx-a11y/no-static-element-interactions */ +/* eslint-disable jsx-a11y/click-events-have-key-events */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Button, ColorPicker, EditableText, Size, Type } from 'browndash-components'; import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { FaPlus } from 'react-icons/fa'; +import { ClientUtils } from '../../ClientUtils'; import { Doc, DocListCast } from '../../fields/Doc'; import { AclPrivate, DocAcl, DocData } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; @@ -12,34 +15,73 @@ import { PrefetchProxy } from '../../fields/Proxy'; import { listSpec } from '../../fields/Schema'; import { ScriptField } from '../../fields/ScriptField'; import { Cast, ImageCast, StrCast } from '../../fields/Types'; -import { normalizeEmail } from '../../fields/util'; +import { SharingPermissions, inheritParentAcls, normalizeEmail } from '../../fields/util'; import { DocServer } from '../DocServer'; -import { Docs, DocumentOptions, DocUtils } from '../documents/Documents'; +import { DocUtils } from '../documents/DocUtils'; +import { Docs, DocumentOptions } from '../documents/Documents'; +import { dropActionType } from '../util/DropActionTypes'; import { HistoryUtil } from '../util/History'; import { ScriptingGlobals } from '../util/ScriptingGlobals'; -import { SettingsManager } from '../util/SettingsManager'; -import { SharingManager } from '../util/SharingManager'; -import { undoable, undoBatch, UndoManager } from '../util/UndoManager'; -import { CollectionDockingView } from './collections/CollectionDockingView'; -import { CollectionView } from './collections/CollectionView'; +import { SnappingManager } from '../util/SnappingManager'; +import { undoBatch, undoable } from '../util/UndoManager'; import { ContextMenu } from './ContextMenu'; import './DashboardView.scss'; -import { Colors } from './global/globalEnums'; import { MainViewModal } from './MainViewModal'; -import { ButtonType } from './nodes/FontIconBox/FontIconBox'; import { ObservableReactComponent } from './ObservableReactComponent'; -import { dropActionType } from '../util/DragManager'; +import { Colors } from './global/globalEnums'; +import { DocumentView } from './nodes/DocumentView'; +import { ButtonType } from './nodes/FontIconBox/FontIconBox'; enum DashboardGroup { MyDashboards, SharedDashboards, } +export type DocConfig = { + doc: Doc; + initialWidth?: number; + path?: Doc[]; +}; + // DashboardView is the view with the dashboard previews, rendered when the app first loads @observer export class DashboardView extends ObservableReactComponent<{}> { public static _urlState: HistoryUtil.DocUrl; + public static makeDocumentConfig(document: Doc, panelName?: string, width?: number, keyValue?: boolean) { + return { + type: 'react-component', + component: 'DocumentFrameRenderer', + title: document.title, + width: width, + props: { + documentId: document[Id], + keyValue, + panelName, // name of tab that can be used to close or replace its contents + }, + }; + } + static StandardCollectionDockingDocument(configs: Array<DocConfig>, options: DocumentOptions, id?: string, type: string = 'row') { + const layoutConfig = { + content: [ + { + type: type, + content: [...configs.map(config => DashboardView.makeDocumentConfig(config.doc, undefined, config.initialWidth))], + }, + ], + }; + const doc = Docs.Create.DockDocument( + configs.map(c => c.doc), + JSON.stringify(layoutConfig), + ClientUtils.CurrentUserEmail() === 'guest' ? options : { acl_Guest: SharingPermissions.View, ...options }, + id + ); + configs.forEach(c => { + Doc.SetContainer(c.doc, doc); + inheritParentAcls(doc, c.doc, false); + }); + return doc; + } constructor(props: any) { super(props); makeObservable(this); @@ -49,10 +91,18 @@ export class DashboardView extends ObservableReactComponent<{}> { @observable private selectedDashboardGroup = DashboardGroup.MyDashboards; @observable private newDashboardName = ''; @observable private newDashboardColor = '#AFAFAF'; - @action abortCreateNewDashboard = () => (this.openModal = false); - @action setNewDashboardName = (name: string) => (this.newDashboardName = name); - @action setNewDashboardColor = (color: string) => (this.newDashboardColor = color); - @action selectDashboardGroup = (group: DashboardGroup) => (this.selectedDashboardGroup = group); + @action abortCreateNewDashboard = () => { + this.openModal = false; + }; + @action setNewDashboardName = (name: string) => { + this.newDashboardName = name; + }; + @action setNewDashboardColor = (color: string) => { + this.newDashboardColor = color; + }; + @action selectDashboardGroup = (group: DashboardGroup) => { + this.selectedDashboardGroup = group; + }; clickDashboard = (e: React.MouseEvent, dashboard: Doc) => { if (this.selectedDashboardGroup === DashboardGroup.SharedDashboards) { @@ -65,7 +115,7 @@ export class DashboardView extends ObservableReactComponent<{}> { getDashboards = (whichGroup: DashboardGroup) => { if (whichGroup === DashboardGroup.MyDashboards) { - return DocListCast(Doc.MyDashboards.data).filter(dashboard => dashboard[DocData].author === Doc.CurrentUserEmail); + return DocListCast(Doc.MyDashboards.data).filter(dashboard => dashboard[DocData].author === ClientUtils.CurrentUserEmail()); } return DocListCast(Doc.MySharedDocs.data_dashboards).filter(doc => doc.dockingConfig); }; @@ -84,11 +134,11 @@ export class DashboardView extends ObservableReactComponent<{}> { <div className="new-dashboard" style={{ - background: SettingsManager.userBackgroundColor, - color: SettingsManager.userColor, + background: SnappingManager.userBackgroundColor, + color: SnappingManager.userColor, }}> <div className="header">Create New Dashboard</div> - <EditableText formLabel="Title" placeholder={this.newDashboardName} type={Type.SEC} color={SettingsManager.userColor} setVal={val => this.setNewDashboardName(val as string)} fillWidth /> + <EditableText formLabel="Title" placeholder={this.newDashboardName} type={Type.SEC} color={SnappingManager.userColor} setVal={val => this.setNewDashboardName(val as string)} fillWidth /> <ColorPicker formLabel="Background" // colorPickerType="github" @@ -98,8 +148,8 @@ export class DashboardView extends ObservableReactComponent<{}> { setSelectedColor={this.setNewDashboardColor} /> <div className="button-bar"> - <Button text="Cancel" color={SettingsManager.userColor} onClick={this.abortCreateNewDashboard} /> - <Button text="Create" color={SettingsManager.userVariantColor} type={Type.TERT} onClick={() => this.createNewDashboard(this.newDashboardName, this.newDashboardColor)} /> + <Button text="Cancel" color={SnappingManager.userColor} onClick={this.abortCreateNewDashboard} /> + <Button text="Create" color={SnappingManager.userVariantColor} type={Type.TERT} onClick={() => this.createNewDashboard(this.newDashboardName, this.newDashboardColor)} /> </div> </div> ); @@ -120,7 +170,7 @@ export class DashboardView extends ObservableReactComponent<{}> { ContextMenu.Instance.addItem({ description: `Share Dashboard`, - event: () => SharingManager.Instance.open(undefined, dashboard), + event: () => DocumentView.ShareOpen(undefined, dashboard), icon: 'edit', }); ContextMenu.Instance.addItem({ @@ -133,15 +183,15 @@ export class DashboardView extends ObservableReactComponent<{}> { }; render() { - const color = SettingsManager.userColor; - const variant = SettingsManager.userVariantColor; + const color = SnappingManager.userColor; + const variant = SnappingManager.userVariantColor; return ( <> <div className="dashboard-view"> <div className="left-menu"> - <Button text="My Dashboards" active={this.selectedDashboardGroup === DashboardGroup.MyDashboards} color={color} align={'flex-start'} onClick={() => this.selectDashboardGroup(DashboardGroup.MyDashboards)} fillWidth /> + <Button text="My Dashboards" active={this.selectedDashboardGroup === DashboardGroup.MyDashboards} color={color} align="flex-start" onClick={() => this.selectDashboardGroup(DashboardGroup.MyDashboards)} fillWidth /> <Button - text={'Shared Dashboards' + ' (' + this.getDashboards(DashboardGroup.SharedDashboards).length + ')'} + text={'Shared Dashboards (' + this.getDashboards(DashboardGroup.SharedDashboards).length + ')'} active={this.selectedDashboardGroup === DashboardGroup.SharedDashboards} color={this.getDashboards(DashboardGroup.SharedDashboards).some(dash => !DocListCast(Doc.MySharedDocs.viewed).includes(dash)) ? 'green' : color} align="flex-start" @@ -156,7 +206,7 @@ export class DashboardView extends ObservableReactComponent<{}> { : this.getDashboards(this.selectedDashboardGroup).map(dashboard => { const href = ImageCast(dashboard.thumb)?.url?.href; const shared = Object.keys(dashboard[DocAcl]) - .filter(key => key !== `acl-${normalizeEmail(Doc.CurrentUserEmail)}` && !['acl-Me', 'acl-Guest'].includes(key)) + .filter(key => key !== `acl_${normalizeEmail(ClientUtils.CurrentUserEmail())}` && !['acl_Me', 'acl_Guest'].includes(key)) .some(key => dashboard[DocAcl][key] !== AclPrivate); return ( <div @@ -166,14 +216,22 @@ export class DashboardView extends ObservableReactComponent<{}> { onContextMenu={e => this.onContextMenu(dashboard, e)} onClick={e => this.clickDashboard(e, dashboard)}> <img + alt="" src={ href ?? 'https://media.istockphoto.com/photos/hot-air-balloons-flying-over-the-botan-canyon-in-turkey-picture-id1297349747?b=1&k=20&m=1297349747&s=170667a&w=0&h=oH31fJty_4xWl_JQ4OIQWZKP8C6ji9Mz7L4XmEnbqRU=' } /> <div className="info"> - <EditableText type={Type.PRIM} color={color} val={StrCast(dashboard.title)} setVal={val => (dashboard[DocData].title = val)} /> - {this.selectedDashboardGroup === DashboardGroup.SharedDashboards && this.isUnviewedSharedDashboard(dashboard) ? <div>unviewed</div> : <div></div>} + <EditableText + type={Type.PRIM} + color={color} + val={StrCast(dashboard.title)} + setVal={val => { + dashboard[DocData].title = val; + }} + /> + {this.selectedDashboardGroup === DashboardGroup.SharedDashboards && this.isUnviewedSharedDashboard(dashboard) ? <div>unviewed</div> : <div />} <div className="more" onPointerDown={e => { @@ -187,7 +245,7 @@ export class DashboardView extends ObservableReactComponent<{}> { <div className="background" style={{ - background: SettingsManager.userColor, + background: SnappingManager.userColor, filter: 'opacity(0.2)', }} /> @@ -201,7 +259,7 @@ export class DashboardView extends ObservableReactComponent<{}> { <div className="background" style={{ - background: SettingsManager.userColor, + background: SnappingManager.userColor, filter: 'opacity(0.2)', }} /> @@ -209,7 +267,7 @@ export class DashboardView extends ObservableReactComponent<{}> { )} </div> </div> - <MainViewModal contents={this.namingInterface} isDisplayed={this.openModal} interactive={true} closeOnExternalClick={this.abortCreateNewDashboard} dialogueBoxStyle={{ width: '400px', height: '180px', color: Colors.LIGHT_GRAY }} /> + <MainViewModal contents={this.namingInterface} isDisplayed={this.openModal} interactive closeOnExternalClick={this.abortCreateNewDashboard} dialogueBoxStyle={{ width: '400px', height: '180px', color: Colors.LIGHT_GRAY }} /> </> ); } @@ -217,9 +275,6 @@ export class DashboardView extends ObservableReactComponent<{}> { public static closeActiveDashboard() { Doc.ActiveDashboard = undefined; } - public static snapshotDashboard() { - return CollectionDockingView.TakeSnapshot(Doc.ActiveDashboard); - } public static openSharedDashboard = (dashboard: Doc) => { Doc.AddDocToList(Doc.MySharedDocs, 'viewed', dashboard); @@ -250,16 +305,17 @@ export class DashboardView extends ObservableReactComponent<{}> { }); if (state.readonly === true || state.readonly === null) { DocServer.Control.makeReadOnly(); - } else if (state.safe) { - if (!state.nro) { - DocServer.Control.makeReadOnly(); - } - CollectionView.SetSafeMode(true); + // } else if (state.safe) { + // if (!state.nro) { + // DocServer.Control.makeReadOnly(); + // } + // CollectionView.SetSafeMode(true); } else if (state.nro || state.nro === null || state.readonly === false) { + /* empty */ } else if (doc.readOnly) { DocServer.Control.makeReadOnly(); } else { - Doc.CurrentUserEmail !== 'guest' && DocServer.Control.makeEditable(); + ClientUtils.CurrentUserEmail() !== 'guest' && DocServer.Control.makeEditable(); } } @@ -278,7 +334,7 @@ export class DashboardView extends ObservableReactComponent<{}> { public static resetDashboard = (dashboard: Doc) => { const config = StrCast(dashboard.dockingConfig); - const matches = config.match(/\"documentId\":\"[a-z0-9-]+\"/g); + const matches = config.match(/"documentId":"[a-z0-9-]+"/g); const docids = matches?.map(m => m.replace('"documentId":"', '').replace('"', '')) ?? []; const components = @@ -372,9 +428,9 @@ export class DashboardView extends ObservableReactComponent<{}> { title: `Untitled Tab 1`, }; - const title = name ? name : `Dashboard ${dashboardCount}`; + const title = name || `Dashboard ${dashboardCount}`; const freeformDoc = Doc.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions); - const dashboardDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600 }], { title: title }, id, 'row'); + const dashboardDoc = DashboardView.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600 }], { title: title }, id, 'row'); Doc.AddDocToList(Doc.MyHeaderBar, 'data', freeformDoc, undefined, undefined, true); dashboardDoc.pane_count = 1; @@ -473,23 +529,23 @@ export class DashboardView extends ObservableReactComponent<{}> { } } +// eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function createNewDashboard() { return DashboardView.createNewDashboard(); }, 'creates a new dashboard when called'); +// eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function shareDashboard(dashboard: Doc) { - SharingManager.Instance.open(undefined, dashboard); + DocumentView.ShareOpen(undefined, dashboard); }, 'opens sharing dialog for Dashboard'); +// eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function removeDashboard(dashboard: Doc) { DashboardView.removeDashboard(dashboard); }, 'Remove Dashboard from Dashboards'); +// eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function resetDashboard(dashboard: Doc) { DashboardView.resetDashboard(dashboard); }, 'move all dashboard tabs to single stack'); +// eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function addToDashboards(dashboard: Doc) { DashboardView.openDashboard(Doc.MakeEmbedding(dashboard)); }, 'adds Dashboard to set of Dashboards'); -ScriptingGlobals.add(async function snapshotDashboard() { - const batch = UndoManager.StartBatch('snapshot'); - await DashboardView.snapshotDashboard(); - batch.end(); -}, 'creates a snapshot copy of a dashboard'); |