aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2025-03-06 10:49:20 -0500
committerbobzel <zzzman@gmail.com>2025-03-06 10:49:20 -0500
commit28792ad2da9f5dfab96f98f34a11136bd1453e0f (patch)
treefc77258b694b1bab4e39b8bef313538ff9b9fecd /src
parent1256ea80f4f1feedf9344020d1bb5fbbaf8e21a4 (diff)
fixed resizing height to be > 10 pixels. split pivotView out of timeView.
Diffstat (limited to 'src')
-rw-r--r--src/client/documents/DocumentTypes.ts1
-rw-r--r--src/client/util/CurrentUserUtils.ts4
-rw-r--r--src/client/views/DocumentDecorations.tsx3
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx2
-rw-r--r--src/client/views/collections/CollectionPivotView.tsx147
-rw-r--r--src/client/views/collections/CollectionTimeView.tsx158
-rw-r--r--src/client/views/collections/CollectionView.tsx7
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx6
8 files changed, 174 insertions, 154 deletions
diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index 8aa844c0b..845aa280c 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -61,6 +61,7 @@ export enum CollectionViewType {
Multirow = 'multirow',
NoteTaking = 'notetaking',
Pile = 'pileup',
+ Pivot = 'pivot',
Schema = 'schema',
Stacking = 'stacking',
StackedTimeline = 'stacked timeline',
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 60acd5b21..8736225d0 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -826,7 +826,7 @@ pie title Minerals in my tap water
return [
{ btnList: new List<string>([CollectionViewType.Freeform, CollectionViewType.Card, CollectionViewType.Carousel,CollectionViewType.Carousel3D,
CollectionViewType.Masonry, CollectionViewType.Multicolumn, CollectionViewType.Multirow, CollectionViewType.Linear,
- CollectionViewType.Map, CollectionViewType.NoteTaking, CollectionViewType.Schema, CollectionViewType.Stacking,
+ CollectionViewType.Map, CollectionViewType.NoteTaking, CollectionViewType.Pivot, CollectionViewType.Schema, CollectionViewType.Stacking,
CollectionViewType.Calendar, CollectionViewType.Grid, CollectionViewType.Tree, CollectionViewType.Time, ]),
title: "Perspective", toolTip: "View", btnType: ButtonType.DropdownList, ignoreClick: true, width: 100, scripts: { script: '{ return setView(value, shiftKey, _readOnly_); }'}},
{ title: "Pin", icon: "map-pin", toolTip: "Pin View to Trail", btnType: ButtonType.ClickButton, expertMode: false, width: 30, scripts: { onClick: 'pinWithView(altKey)'}, funcs: {hidden: "IsNoneSelected()"}},
@@ -911,7 +911,7 @@ pie title Minerals in my tap water
CurrentUserUtils.createToolButton(opts), scripts, funcs);
const btnDescs = [// setup reactions to change the highlights on the undo/redo buttons -- would be better to encode this in the undo/redo buttons, but the undo/redo stacks are not wired up that way yet
- { opts: { title: "Replicate",icon:"camera",toolTip: "Copy dashboard layout",btnType: ButtonType.ClickButton, expertMode: true}, scripts: { onClick: `snapshotDashboard()`}},
+ { opts: { title: "Replicate",icon:"camera",toolTip:"Copy dashboard layout",btnType: ButtonType.ClickButton, expertMode: true}, scripts: { onClick: `snapshotDashboard()`}},
{ opts: { title: "Recordings", toolTip: "Workspace Recordings", btnType: ButtonType.DropdownList,expertMode: false, ignoreClick: true, width: 100}, funcs: {hidden: `false`, btnList:`getWorkspaceRecordings()`},scripts: { script: `{ return replayWorkspace(value, _readOnly_); }`, onDragScript: `{ return startRecordingDrag(value); }`}},
{ opts: { title: "Stop Rec",icon: "stop", toolTip: "Stop recording", btnType: ButtonType.ClickButton, expertMode: false}, funcs: {hidden: `!isWorkspaceRecording()`}, scripts: { onClick: `stopWorkspaceRecording()`}},
{ opts: { title: "Play", icon: "play", toolTip: "Play recording", btnType: ButtonType.ClickButton, expertMode: false}, funcs: {hidden: `isWorkspaceReplaying() !== "${mediaState.Paused}"`}, scripts: { onClick: `resumeWorkspaceReplaying(getCurrentRecording())`}},
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index d9b6bdf1a..54e050f9f 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -36,7 +36,6 @@ import { ImageBox } from './nodes/ImageBox';
import { OpenWhere, OpenWhereMod } from './nodes/OpenWhere';
import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
import { TagsView } from './TagsView';
-import { ImageField } from '../../fields/URLField';
interface DocumentDecorationsProps {
PanelWidth: number;
@@ -567,7 +566,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
}
doc._width = Math.max(NumCast(doc._width_min, 25), NumCast(doc._width) * scale.x);
- doc._height = Math.max(NumCast(doc._height_min), NumCast(doc._height) * scale.y);
+ doc._height = Math.max(NumCast(doc._height_min, 10), NumCast(doc._height) * scale.y);
const { deltaX, deltaY } = this.realignRefPt(doc, refCent, initWidth || 1, initHeight || 1);
doc.x = NumCast(doc.x) + deltaX;
doc.y = NumCast(doc.y) + deltaY;
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 87c6e3e5c..a7d217076 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -249,9 +249,9 @@ export class CollectionCarouselView extends CollectionSubView() {
position: 'relative',
}}>
{this.content}
- {this.flashCardUI(this.curDoc, this.docViewProps, this.answered)}
{this.navButtons}
</div>
+ {this.flashCardUI(this.curDoc, this.docViewProps, this.answered)}
</div>
);
}
diff --git a/src/client/views/collections/CollectionPivotView.tsx b/src/client/views/collections/CollectionPivotView.tsx
new file mode 100644
index 000000000..2600c0f57
--- /dev/null
+++ b/src/client/views/collections/CollectionPivotView.tsx
@@ -0,0 +1,147 @@
+import { action, computed, makeObservable, observable, runInAction } from 'mobx';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { returnTrue } from '../../../ClientUtils';
+import { Doc, Opt, StrListCast } from '../../../fields/Doc';
+import { List } from '../../../fields/List';
+import { ObjectField } from '../../../fields/ObjectField';
+import { ComputedField, ScriptField } from '../../../fields/ScriptField';
+import { NumCast, StrCast } from '../../../fields/Types';
+import { Docs } from '../../documents/Documents';
+import { ScriptingGlobals } from '../../util/ScriptingGlobals';
+import { FieldsDropdown } from '../FieldsDropdown';
+import { PinDocView } from '../PinFuncs';
+import { DocumentView } from '../nodes/DocumentView';
+import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
+import './CollectionTimeView.scss';
+import { ViewDefBounds, computePivotLayout } from './collectionFreeForm/CollectionFreeFormLayoutEngines';
+import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
+
+@observer
+export class CollectionPivotView extends CollectionSubView() {
+ _changing = false;
+ @observable _collapsed: boolean = false;
+ @observable _childClickedScript: Opt<ScriptField> = undefined;
+ @observable _viewDefDivClick: Opt<ScriptField> = undefined;
+ @observable _focusPivotField: Opt<string> = undefined;
+
+ constructor(props: SubCollectionViewProps) {
+ super(props);
+ makeObservable(this);
+ }
+
+ componentDidMount() {
+ this._props.setContentViewBox?.(this);
+ runInAction(() => {
+ this._childClickedScript = ScriptField.MakeScript('openInLightbox(this)', { this: Doc.name });
+ this._viewDefDivClick = ScriptField.MakeScript('pivotColumnClick(this,payload)', { payload: 'any' });
+ });
+ }
+
+ get pivotField() {
+ return this._focusPivotField || StrCast(this.layoutDoc._pivotField);
+ }
+
+ getAnchor = (addAsAnnotation: boolean) => {
+ const anchor = Docs.Create.ConfigDocument({
+ title: ComputedField.MakeFunction(`"${this.pivotField}"])`) as unknown as string, // title can take a functiono or a string
+ annotationOn: this.Document,
+ });
+ PinDocView(anchor, { pinData: { collectionType: true, pivot: true, filters: true } }, this.Document);
+ addAsAnnotation && Doc.AddDocToList(this.dataDoc, this.fieldKey + '_annotations', anchor); // when added as an annotation, links to anchors can be found as links to the document even if the anchors are not rendered
+ return anchor;
+ };
+
+ @action
+ scrollPreview = (docView: DocumentView, anchor: Doc /* , focusSpeed: number, options: FocusViewOptions */) => {
+ // if in preview, then override document's fields with view spec
+ this._focusFilters = StrListCast(anchor.config_docFilters);
+ this._focusRangeFilters = StrListCast(anchor.config_docRangeFilters);
+ this._focusPivotField = StrCast(anchor.config_pivotField);
+ return undefined;
+ };
+
+ toggleVisibility = action(() => {
+ this._collapsed = !this._collapsed;
+ });
+
+ goTo = (prevFilterIndex: number) => {
+ this.layoutDoc._pivotField = this.layoutDoc['_prevPivotFields' + prevFilterIndex];
+ this.layoutDoc._childFilters = ObjectField.MakeCopy(this.layoutDoc['_prevDocFilter' + prevFilterIndex] as ObjectField);
+ this.layoutDoc._childFiltersByRanges = ObjectField.MakeCopy(this.layoutDoc['_prevDocRangeFilters' + prevFilterIndex] as ObjectField);
+ this.layoutDoc._prevFilterIndex = prevFilterIndex;
+ };
+
+ @action
+ contentsDown = () => {
+ const prevFilterIndex = NumCast(this.layoutDoc._prevFilterIndex);
+ if (prevFilterIndex > 0) {
+ this.goTo(prevFilterIndex - 1);
+ } else {
+ this.layoutDoc._childFilters = new List([]);
+ }
+ };
+ layoutEngine = () => computePivotLayout.name;
+ @computed get contents() {
+ return (
+ <div className="collectionTimeView-innards" key="timeline" style={{ pointerEvents: this._props.isContentActive() ? undefined : 'none' }} onClick={this.contentsDown}>
+ <CollectionFreeFormView
+ {...this._props}
+ engineProps={{ pivotField: this.pivotField, childFilters: this.childDocFilters, childFiltersByRanges: this.childDocRangeFilters }}
+ fitContentsToBox={returnTrue}
+ childClickScript={this._childClickedScript}
+ viewDefDivClick={this._viewDefDivClick}
+ layoutEngine={this.layoutEngine}
+ />
+ </div>
+ );
+ }
+
+ render() {
+ return (
+ <div className="collectionTimeView-pivot" style={{ width: this._props.PanelWidth(), height: '100%' }}>
+ {this.contents}
+ <div style={{ right: 0, top: 0, position: 'absolute' }}>
+ <FieldsDropdown
+ Document={this.Document}
+ selectFunc={fieldKey => {
+ this.layoutDoc._pivotField = fieldKey;
+ }}
+ placeholder={StrCast(this.layoutDoc._pivotField)}
+ />
+ </div>
+ </div>
+ );
+ }
+}
+
+// eslint-disable-next-line prefer-arrow-callback
+ScriptingGlobals.add(function pivotColumnClick(pivotDoc: Doc, bounds: ViewDefBounds) {
+ const pivotField = StrCast(pivotDoc._pivotField, 'author');
+ let prevFilterIndex = NumCast(pivotDoc._prevFilterIndex);
+ const originalFilter = StrListCast(ObjectField.MakeCopy(pivotDoc._childFilters as ObjectField));
+ pivotDoc['_prevDocFilter' + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._childFilters as ObjectField);
+ pivotDoc['_prevDocRangeFilters' + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._childFiltersByRanges as ObjectField);
+ pivotDoc['_prevPivotFields' + prevFilterIndex] = pivotField;
+ pivotDoc._prevFilterIndex = ++prevFilterIndex;
+ pivotDoc._childFilters = new List();
+ setTimeout(
+ action(() => {
+ const filterVals = bounds.payload as string[];
+ filterVals.map(filterVal => Doc.setDocFilter(pivotDoc, pivotField, filterVal, 'check'));
+ const pivotView = DocumentView.getDocumentView(pivotDoc);
+ if (pivotDoc && pivotView?.ComponentView instanceof CollectionPivotView && filterVals.length === 1) {
+ if (pivotView?.ComponentView.childDocs.length && pivotView.ComponentView.childDocs[0][filterVals[0]]) {
+ pivotDoc._pivotField = filterVals[0];
+ }
+ }
+ const newFilters = StrListCast(pivotDoc._childFilters);
+ if (newFilters.length && originalFilter.length && newFilters.lastElement() === originalFilter.lastElement()) {
+ pivotDoc._prevFilterIndex = --prevFilterIndex;
+ pivotDoc['_prevDocFilter' + prevFilterIndex] = undefined;
+ pivotDoc['_prevDocRangeFilters' + prevFilterIndex] = undefined;
+ pivotDoc['_prevPivotFields' + prevFilterIndex] = undefined;
+ }
+ })
+ );
+});
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index d75c633ac..98bd06221 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -1,33 +1,22 @@
-import { action, computed, makeObservable, observable, runInAction } from 'mobx';
+import { action, computed, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { returnFalse, returnTrue, setupMoveUpEvents } from '../../../ClientUtils';
import { emptyFunction } from '../../../Utils';
import { Doc, Opt, StrListCast } from '../../../fields/Doc';
-import { List } from '../../../fields/List';
-import { ObjectField } from '../../../fields/ObjectField';
-import { listSpec } from '../../../fields/Schema';
-import { ComputedField, ScriptField } from '../../../fields/ScriptField';
-import { Cast, NumCast, StrCast } from '../../../fields/Types';
+import { NumCast, StrCast } from '../../../fields/Types';
import { Docs } from '../../documents/Documents';
-import { ScriptingGlobals } from '../../util/ScriptingGlobals';
-import { ContextMenu } from '../ContextMenu';
-import { ContextMenuProps } from '../ContextMenuItem';
import { FieldsDropdown } from '../FieldsDropdown';
import { PinDocView } from '../PinFuncs';
import { DocumentView } from '../nodes/DocumentView';
import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
import './CollectionTimeView.scss';
-import { ViewDefBounds, computePivotLayout, computeTimelineLayout } from './collectionFreeForm/CollectionFreeFormLayoutEngines';
+import { computeTimelineLayout } from './collectionFreeForm/CollectionFreeFormLayoutEngines';
import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
@observer
export class CollectionTimeView extends CollectionSubView() {
- _changing = false;
- @observable _layoutEngine = computePivotLayout.name;
@observable _collapsed: boolean = false;
- @observable _childClickedScript: Opt<ScriptField> = undefined;
- @observable _viewDefDivClick: Opt<ScriptField> = undefined;
@observable _focusPivotField: Opt<string> = undefined;
constructor(props: SubCollectionViewProps) {
@@ -37,10 +26,6 @@ export class CollectionTimeView extends CollectionSubView() {
componentDidMount() {
this._props.setContentViewBox?.(this);
- runInAction(() => {
- this._childClickedScript = ScriptField.MakeScript('openInLightbox(this)', { this: Doc.name });
- this._viewDefDivClick = ScriptField.MakeScript('pivotColumnClick(this,payload)', { payload: 'any' });
- });
}
get pivotField() {
@@ -49,19 +34,10 @@ export class CollectionTimeView extends CollectionSubView() {
getAnchor = (addAsAnnotation: boolean) => {
const anchor = Docs.Create.ConfigDocument({
- title: ComputedField.MakeFunction(`"${this.pivotField}"])`) as unknown as string, // title can take a functiono or a string
annotationOn: this.Document,
});
PinDocView(anchor, { pinData: { collectionType: true, pivot: true, filters: true } }, this.Document);
-
- if (addAsAnnotation) {
- // when added as an annotation, links to anchors can be found as links to the document even if the anchors are not rendered
- if (Cast(this.dataDoc[this._props.fieldKey + '_annotations'], listSpec(Doc), null) !== undefined) {
- Cast(this.dataDoc[this._props.fieldKey + '_annotations'], listSpec(Doc), []).push(anchor);
- } else {
- this.dataDoc[this._props.fieldKey + '_annotations'] = new List<Doc>([anchor]);
- }
- }
+ addAsAnnotation && Doc.AddDocToList(this.dataDoc, this.fieldKey + '_annotations', anchor); // when added as an annotation, links to anchors can be found as links to the document even if the anchors are not rendered
return anchor;
};
@@ -74,7 +50,6 @@ export class CollectionTimeView extends CollectionSubView() {
return undefined;
};
- layoutEngine = () => this._layoutEngine;
toggleVisibility = action(() => {
this._collapsed = !this._collapsed;
});
@@ -126,105 +101,24 @@ export class CollectionTimeView extends CollectionSubView() {
);
};
- goTo = (prevFilterIndex: number) => {
- this.layoutDoc._pivotField = this.layoutDoc['_prevPivotFields' + prevFilterIndex];
- this.layoutDoc._childFilters = ObjectField.MakeCopy(this.layoutDoc['_prevDocFilter' + prevFilterIndex] as ObjectField);
- this.layoutDoc._childFiltersByRanges = ObjectField.MakeCopy(this.layoutDoc['_prevDocRangeFilters' + prevFilterIndex] as ObjectField);
- this.layoutDoc._prevFilterIndex = prevFilterIndex;
- };
-
- @action
- contentsDown = () => {
- const prevFilterIndex = NumCast(this.layoutDoc._prevFilterIndex);
- if (prevFilterIndex > 0) {
- this.goTo(prevFilterIndex - 1);
- } else {
- this.layoutDoc._childFilters = new List([]);
- }
- };
-
+ layoutEngine = () => computeTimelineLayout.name;
@computed get contents() {
return (
- <div className="collectionTimeView-innards" key="timeline" style={{ pointerEvents: this._props.isContentActive() ? undefined : 'none' }} onClick={this.contentsDown}>
+ <div className="collectionTimeView-innards" key="timeline" style={{ pointerEvents: this._props.isContentActive() ? undefined : 'none' }}>
<CollectionFreeFormView
{...this._props}
engineProps={{ pivotField: this.pivotField, childFilters: this.childDocFilters, childFiltersByRanges: this.childDocRangeFilters }}
fitContentsToBox={returnTrue}
- childClickScript={this._childClickedScript}
- viewDefDivClick={this.layoutEngine() === computeTimelineLayout.name ? undefined : this._viewDefDivClick}
layoutEngine={this.layoutEngine}
/>
</div>
);
}
- public static SyncTimelineToPresentation(doc: Doc) {
- const fieldKey = Doc.LayoutFieldKey(doc);
- doc[fieldKey + '-timelineCur'] = ComputedField.MakeFunction("(activePresentationItem()[this._pivotField || 'year'] || 0)");
- }
- specificMenu = () => {
- const layoutItems: ContextMenuProps[] = [];
- const doc = this.layoutDoc;
-
- layoutItems.push({
- description: 'Force Timeline',
- event: () => {
- doc._forceRenderEngine = computeTimelineLayout.name;
- },
- icon: 'compress-arrows-alt',
- });
- layoutItems.push({
- description: 'Force Pivot',
- event: () => {
- doc._forceRenderEngine = computePivotLayout.name;
- },
- icon: 'compress-arrows-alt',
- });
- layoutItems.push({
- description: 'Auto Time/Pivot layout',
- event: () => {
- doc._forceRenderEngine = undefined;
- },
- icon: 'compress-arrows-alt',
- });
- layoutItems.push({ description: 'Sync with presentation', event: () => CollectionTimeView.SyncTimelineToPresentation(doc), icon: 'compress-arrows-alt' });
-
- ContextMenu.Instance.addItem({ description: 'Options...', subitems: layoutItems, icon: 'eye' });
- };
-
render() {
- let nonNumbers = 0;
- this.childDocs.forEach(doc => {
- const num = NumCast(doc[this.pivotField], Number(StrCast(doc[this.pivotField])));
- if (isNaN(num)) {
- nonNumbers++;
- }
- });
- const forceLayout = StrCast(this.layoutDoc._forceRenderEngine);
- const doTimeline = forceLayout ? forceLayout === computeTimelineLayout.name : nonNumbers / this.childDocs.length < 0.1 && this._props.PanelWidth() / this._props.PanelHeight() > 6;
- if (doTimeline !== (this._layoutEngine === computeTimelineLayout.name)) {
- if (!this._changing) {
- this._changing = true;
- setTimeout(
- action(() => {
- this._layoutEngine = doTimeline ? computeTimelineLayout.name : computePivotLayout.name;
- this._changing = false;
- }),
- 0
- );
- }
- }
-
return (
- <div className={'collectionTimeView' + (doTimeline ? '' : '-pivot')} onContextMenu={this.specificMenu} style={{ width: this._props.PanelWidth(), height: '100%' }}>
+ <div className="collectionTimeView" style={{ width: this._props.PanelWidth(), height: '100%' }}>
{this.contents}
- {!this._props.isSelected() || !doTimeline ? null : (
- <>
- <div className="collectionTimeView-thumb-min collectionTimeView-thumb" key="min" onPointerDown={this.onMinDown} />
- <div className="collectionTimeView-thumb-max collectionTimeView-thumb" key="mid" onPointerDown={this.onMaxDown} />
- <div className="collectionTimeView-thumb-mid collectionTimeView-thumb" key="max" onPointerDown={this.onMidDown} />
- </>
- )}
<div style={{ right: 0, top: 0, position: 'absolute' }}>
<FieldsDropdown
Document={this.Document}
@@ -234,38 +128,14 @@ export class CollectionTimeView extends CollectionSubView() {
placeholder={StrCast(this.layoutDoc._pivotField)}
/>
</div>
+ {!this._props.isSelected() ? null : (
+ <>
+ <div className="collectionTimeView-thumb-min collectionTimeView-thumb" key="min" onPointerDown={this.onMinDown} />
+ <div className="collectionTimeView-thumb-max collectionTimeView-thumb" key="mid" onPointerDown={this.onMaxDown} />
+ <div className="collectionTimeView-thumb-mid collectionTimeView-thumb" key="max" onPointerDown={this.onMidDown} />
+ </>
+ )}
</div>
);
}
}
-
-// eslint-disable-next-line prefer-arrow-callback
-ScriptingGlobals.add(function pivotColumnClick(pivotDoc: Doc, bounds: ViewDefBounds) {
- const pivotField = StrCast(pivotDoc._pivotField, 'author');
- let prevFilterIndex = NumCast(pivotDoc._prevFilterIndex);
- const originalFilter = StrListCast(ObjectField.MakeCopy(pivotDoc._childFilters as ObjectField));
- pivotDoc['_prevDocFilter' + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._childFilters as ObjectField);
- pivotDoc['_prevDocRangeFilters' + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._childFiltersByRanges as ObjectField);
- pivotDoc['_prevPivotFields' + prevFilterIndex] = pivotField;
- pivotDoc._prevFilterIndex = ++prevFilterIndex;
- pivotDoc._childFilters = new List();
- setTimeout(
- action(() => {
- const filterVals = bounds.payload as string[];
- filterVals.map(filterVal => Doc.setDocFilter(pivotDoc, pivotField, filterVal, 'check'));
- const pivotView = DocumentView.getDocumentView(pivotDoc);
- if (pivotDoc && pivotView?.ComponentView instanceof CollectionTimeView && filterVals.length === 1) {
- if (pivotView?.ComponentView.childDocs.length && pivotView.ComponentView.childDocs[0][filterVals[0]]) {
- pivotDoc._pivotField = filterVals[0];
- }
- }
- const newFilters = StrListCast(pivotDoc._childFilters);
- if (newFilters.length && originalFilter.length && newFilters.lastElement() === originalFilter.lastElement()) {
- pivotDoc._prevFilterIndex = --prevFilterIndex;
- pivotDoc['_prevDocFilter' + prevFilterIndex] = undefined;
- pivotDoc['_prevDocRangeFilters' + prevFilterIndex] = undefined;
- pivotDoc['_prevPivotFields' + prevFilterIndex] = undefined;
- }
- })
- );
-});
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index a4900e9d7..7ba8989ce 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -15,12 +15,14 @@ import { ContextMenuProps } from '../ContextMenuItem';
import { ViewBoxAnnotatableComponent } from '../DocComponent';
import { FieldView } from '../nodes/FieldView';
import { OpenWhere } from '../nodes/OpenWhere';
+import { CalendarBox } from '../nodes/calendarBox/CalendarBox';
import { CollectionCardView } from './CollectionCardDeckView';
import { CollectionCarousel3DView } from './CollectionCarousel3DView';
import { CollectionCarouselView } from './CollectionCarouselView';
import { CollectionDockingView } from './CollectionDockingView';
import { CollectionNoteTakingView } from './CollectionNoteTakingView';
import { CollectionPileView } from './CollectionPileView';
+import { CollectionPivotView } from './CollectionPivotView';
import { CollectionStackingView } from './CollectionStackingView';
import { CollectionViewProps, SubCollectionViewProps } from './CollectionSubView';
import { CollectionTimeView } from './CollectionTimeView';
@@ -32,7 +34,6 @@ import { CollectionLinearView } from './collectionLinear';
import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView';
import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView';
import { CollectionSchemaView } from './collectionSchema/CollectionSchemaView';
-import { CalendarBox } from '../nodes/calendarBox/CalendarBox';
@observer
export class CollectionView extends ViewBoxAnnotatableComponent<CollectionViewProps>() {
@@ -105,6 +106,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<CollectionViewPr
case CollectionViewType.NoteTaking: return <CollectionNoteTakingView key="collview" {...props} />;
case CollectionViewType.Masonry: return <CollectionStackingView key="collview" {...props} />;
case CollectionViewType.Time: return <CollectionTimeView key="collview" {...props} />;
+ case CollectionViewType.Pivot: return <CollectionPivotView key="collview" {...props} />;
case CollectionViewType.Grid: return <CollectionGridView key="collview" {...props} />;
case CollectionViewType.Card: return <CollectionCardView key="collview" {...props} />;
}
@@ -126,7 +128,8 @@ export class CollectionView extends ViewBoxAnnotatableComponent<CollectionViewPr
{ description: 'Carousel', event: () => func(CollectionViewType.Carousel), icon: 'columns' },
{ description: '3D Carousel', event: () => func(CollectionViewType.Carousel3D), icon: 'columns' },
{ description: 'Calendar', event: () => func(CollectionViewType.Calendar), icon: 'columns' },
- { description: 'Pivot/Time', event: () => func(CollectionViewType.Time), icon: 'columns' },
+ { description: 'Pivot', event: () => func(CollectionViewType.Pivot), icon: 'columns' },
+ { description: 'Time', event: () => func(CollectionViewType.Time), icon: 'columns' },
{ description: 'Map', event: () => func(CollectionViewType.Map), icon: 'globe-americas' },
{ description: 'Grid', event: () => func(CollectionViewType.Grid), icon: 'th-list' },
];
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index bebdbd731..241a56a88 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -4,7 +4,7 @@ import { Id, ToString } from '../../../../fields/FieldSymbols';
import { ObjectField } from '../../../../fields/ObjectField';
import { RefField } from '../../../../fields/RefField';
import { listSpec } from '../../../../fields/Schema';
-import { Cast, NumCast, StrCast } from '../../../../fields/Types';
+import { Cast, DateCast, NumCast, StrCast } from '../../../../fields/Types';
import { aggregateBounds } from '../../../../Utils';
export interface ViewDefBounds {
@@ -107,7 +107,7 @@ export function computePassLayout(poolData: Map<string, PoolData>, pivotDoc: Doc
}
function toNumber(val: FieldResult<FieldType>) {
- return val === undefined ? undefined : NumCast(val, Number(StrCast(val)));
+ return val === undefined ? undefined : DateCast(val) ? DateCast(val).date.getMilliseconds() : NumCast(val, Number(StrCast(val)));
}
export function computeStarburstLayout(poolData: Map<string, PoolData>, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[] /* , engineProps: any */) {
@@ -295,7 +295,7 @@ export function computeTimelineLayout(poolData: Map<string, PoolData>, pivotDoc:
let minTime = minTimeReq === undefined ? Number.MAX_VALUE : minTimeReq;
let maxTime = maxTimeReq === undefined ? -Number.MAX_VALUE : maxTimeReq;
childPairs.forEach(pair => {
- const num = NumCast(pair.layout[timelineFieldKey], Number(StrCast(pair.layout[timelineFieldKey])));
+ const num = toNumber(pair.layout[timelineFieldKey]) ?? 0;
if (!isNaN(num) && (!minTimeReq || num >= minTimeReq) && (!maxTimeReq || num <= maxTimeReq)) {
!pivotDateGroups.get(num) && pivotDateGroups.set(num, []);
pivotDateGroups.get(num)!.push(pair.layout);