From 4b231bbaf21939144ed8639d35f022834a406e59 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 17 Oct 2024 22:02:19 -0400 Subject: changed layout_isFlashcard to layout_flashcardType with value of 'flashcard' to make it easy to search for flashcards. made carousel views able to focus() on a Doc. added ability for carousel and card views to have anchors so they can be pinned and linked. fixed pinning collections to save filters --- src/client/views/collections/CollectionTimeView.tsx | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/client/views/collections/CollectionTimeView.tsx') diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 8a24db330..5738e7ce3 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -147,7 +147,6 @@ export class CollectionTimeView extends CollectionSubView() { return (
Date: Fri, 18 Oct 2024 10:00:01 -0400 Subject: fixed following anchors to collection card/carousel to set the current/selected Doc --- src/client/documents/Documents.ts | 2 +- src/client/views/PinFuncs.ts | 6 +-- src/client/views/ViewBoxInterface.ts | 2 +- .../views/collections/CollectionCardDeckView.tsx | 55 +++++++++------------- .../views/collections/CollectionCarousel3DView.tsx | 10 +--- .../views/collections/CollectionCarouselView.tsx | 10 +--- .../views/collections/CollectionTimeView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/trails/PresBox.tsx | 36 +++++++------- src/fields/ScriptField.ts | 6 +-- 10 files changed, 53 insertions(+), 78 deletions(-) (limited to 'src/client/views/collections/CollectionTimeView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index be3b9c3bb..98e8bc932 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -373,7 +373,7 @@ export class DocumentOptions { config_panY?: NUMt = new NumInfo('panY saved as a view spec', false); config_zoom?: NUMt = new NumInfo('zoom saved as a view spec', false); config_carousel_index?: NUMt = new NumInfo('saved carousel index', false); - config_curDoc?: DOCt = new DocInfo('current doc in a collection view, e.g., cardView'); + config_card_curDoc?: DOCt = new DocInfo('current doc in a collection view, e.g., cardView'); config_viewScale?: NUMt = new NumInfo('viewScale saved as a view Spec', false); presentation_transition?: NUMt = new NumInfo('the time taken for the transition TO a document', false); presentation_duration?: NUMt = new NumInfo('the duration of the slide in presentation view', false); diff --git a/src/client/views/PinFuncs.ts b/src/client/views/PinFuncs.ts index 17964c656..bed473eec 100644 --- a/src/client/views/PinFuncs.ts +++ b/src/client/views/PinFuncs.ts @@ -16,7 +16,7 @@ export interface pinDataTypes { scrollable?: boolean; dataviz?: number[]; pannable?: boolean; - type_collection?: boolean; + collectionType?: boolean; inkable?: boolean; filters?: boolean; pivot?: boolean; @@ -65,7 +65,7 @@ export function PinDocView(pinDocIn: Doc, pinProps: PinProps, targetDoc: Doc) { pinProps.pinData.scrollable || pinProps.pinData.temporal || pinProps.pinData.pannable || - pinProps.pinData.type_collection || + pinProps.pinData.collectionType || pinProps.pinData.clippable || pinProps.pinData.datarange || pinProps.pinData.dataview || @@ -118,7 +118,7 @@ export function PinDocView(pinDocIn: Doc, pinProps: PinProps, targetDoc: Doc) { }) ) ); - if (pinProps.pinData.type_collection) pinDoc.config_type_collection = targetDoc._type_collection; + if (pinProps.pinData.collectionType) pinDoc.config_type_collection = targetDoc._type_collection; if (pinProps.pinData.filters) pinDoc.config_docFilters = ObjectField.MakeCopy(targetDoc.childFilters as ObjectField) ?? new List(); if (pinProps.pinData.pivot) pinDoc.config_pivotField = targetDoc._pivotField; if (pinProps.pinData.pannable) { diff --git a/src/client/views/ViewBoxInterface.ts b/src/client/views/ViewBoxInterface.ts index f66f6062e..b7980d74e 100644 --- a/src/client/views/ViewBoxInterface.ts +++ b/src/client/views/ViewBoxInterface.ts @@ -24,7 +24,7 @@ export abstract class ViewBoxInterface

extends ObservableReactComponent void; // moves contents of collection to parent updateIcon?: (usePanelDimensions?: boolean) => Promise; // updates the icon representation of the document getAnchor?: (addAsAnnotation: boolean, pinData?: PinProps) => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box) - restoreView?: (viewSpec: Doc) => boolean; + restoreView?: (viewSpec: Doc) => boolean; // DEPRECATED: do not use, it will go away. see PresBox.restoreTargetDocView scrollPreview?: (docView: DocumentView, doc: Doc, focusSpeed: number, options: FocusViewOptions) => Opt; // returns the duration of the focus brushView?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number, holdTime: number) => void; // highlight a region of a view (used by freeforms) getView?: (doc: Doc, options: FocusViewOptions) => Promise>; // returns a nested DocumentView for the specified doc or undefined diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx index 729a1585a..beb45f326 100644 --- a/src/client/views/collections/CollectionCardDeckView.tsx +++ b/src/client/views/collections/CollectionCardDeckView.tsx @@ -51,14 +51,13 @@ export class CollectionCardView extends CollectionSubView() { private _textToDoc = new Map(); private _oldWheel: HTMLElement | null = null; private _dropped = false; // set when a card doc has just moved and the drop method has been called - prevents the pointerUp method from hiding doc decorations (which needs to be done when clicking on a card to animate it to front/center) - private _clickScript = () => ScriptField.MakeScript('scriptContext._curDoc=this', { scriptContext: 'any' })!; + private _setCurDocScript = () => ScriptField.MakeScript('scriptContext.layoutDoc._card_curDoc=this', { scriptContext: 'any' })!; @observable _forceChildXf = 0; @observable _hoveredNodeIndex = -1; @observable _docRefs = new ObservableMap(); @observable _maxRowCount = 10; @observable _docDraggedIndex: number = -1; - @observable _curDoc: Doc | undefined = undefined; constructor(props: SubCollectionViewProps) { super(props); @@ -165,10 +164,10 @@ export class CollectionCardView extends CollectionSubView() { /** * When in quiz mode, randomly selects a document */ - quizMode = action(() => { + quizMode = () => { const randomIndex = Math.floor(Math.random() * this.childDocs.length); - this._curDoc = this.childDocs[randomIndex]; - }); + this.layoutDoc._card_curDoc = this.childDocs[randomIndex]; + }; setHoveredNodeIndex = action((index: number) => { if (!SnappingManager.IsDragging) this._hoveredNodeIndex = index; @@ -319,7 +318,7 @@ export class CollectionCardView extends CollectionSubView() { (doc: Doc) => () => this._props.isContentActive?.() === false ? false - : this._props.isDocumentActive?.() && this._curDoc === doc + : this._props.isDocumentActive?.() && this.curDoc() === doc ? true : this._props.childDocumentsActive?.() === false || this.Document.childDocumentsActive === false ? false @@ -347,7 +346,7 @@ export class CollectionCardView extends CollectionSubView() { scriptContext={this} focus={this.focus} onDoubleClickScript={this.onChildDoubleClick} - onClickScript={this._curDoc === doc ? undefined : this._clickScript} + onClickScript={this.curDoc() === doc ? undefined : this._setCurDocScript} dontCenter="y" // Don't center it vertically, because the grid it's in is already doing that and we don't want to do it twice. dragAction={(this.Document.childDragAction ?? this._props.childDragAction) as dropActionType} showTags={BoolCast(this.layoutDoc.showChildTags)} @@ -572,8 +571,8 @@ export class CollectionCardView extends CollectionSubView() { * @param doc doc that will be animated away from center focus */ releaseCurDoc = action(() => { - const selDoc = this._curDoc; - this._curDoc = undefined; + const selDoc = this.curDoc(); + this.layoutDoc._card_curDoc = undefined; const cardDocView = DocumentView.getDocumentView(selDoc, this.DocumentView?.()); if (cardDocView && selDoc) { DocumentView.DeselectView(cardDocView); @@ -590,7 +589,7 @@ export class CollectionCardView extends CollectionSubView() { * turns off the _dropped flag at the end of a drag/drop, or releases the focused Doc if a different Doc is clicked */ cardPointerUp = action((doc: Doc) => { - if (this._curDoc === doc || this._dropped) { + if (this.curDoc() === doc || this._dropped) { this._dropped = false; } else { this.releaseCurDoc(); // NOTE: the onClick script for the card will select the new card (ie, 'doc') @@ -601,28 +600,20 @@ export class CollectionCardView extends CollectionSubView() { const docs = DocListCast(this.Document[this.fieldKey]); if (anchor.type === DocumentType.CONFIG || docs.includes(anchor)) { const foundDoc = DocCast( - anchor.config_curDoc, + anchor.config_card_curDoc, docs.find(doc => doc === DocCast(anchor.annotationOn, anchor)) ); options.didMove = foundDoc !== this.curDoc() ? true : false; - options.didMove && (this._curDoc = foundDoc); + options.didMove && (this.layoutDoc._card_curDoc = foundDoc); } return undefined; }); getAnchor = (addAsAnnotation: boolean) => { - const anchor = Docs.Create.ConfigDocument({ annotationOn: this.Document, config_curDoc: this.curDoc() }); - PinDocView(anchor, { pinData: { type_collection: true, filters: true } }, this.Document); + const anchor = Docs.Create.ConfigDocument({ annotationOn: this.Document, config_card_curDoc: this.curDoc() }); + PinDocView(anchor, { pinData: { collectionType: 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; }; - // pinned / linked anchor doc includes selected rows, graph titles, and graph colors - restoreView = (viewData: Doc) => { - if (viewData.config_curDoc !== undefined && this.curDoc() !== viewData.config_curDoc) { - this._curDoc = DocCast(viewData.config_curDoc); - return true; - } - return false; - }; addDocTab = this.addLinkedDocTab; /** @@ -634,9 +625,9 @@ export class CollectionCardView extends CollectionSubView() { return this.sortedDocs.map((doc, index) => { const cardsInRow = this.cardsInRowThatIncludesCardIndex(index); - const childScreenToLocal = this.childScreenToLocal(doc, index, doc === this._curDoc); + const childScreenToLocal = this.childScreenToLocal(doc, index, doc === this.curDoc()); - const translateToCenterIfActive = () => (doc === this._curDoc ? (cardsInRow / 2 - (index % this._maxRowCount)) * 100 - 50 : 0); + const translateToCenterIfActive = () => (doc === this.curDoc() ? (cardsInRow / 2 - (index % this._maxRowCount)) * 100 - 50 : 0); const aspect = NumCast(doc.height) / NumCast(doc.width, 1); const vscale = Math.max(1,Math.min((this._props.PanelHeight() * 0.95 * this.fitContentScale * this.nativeScaling) / (aspect * this.childPanelWidth()), @@ -645,15 +636,15 @@ export class CollectionCardView extends CollectionSubView() { return (

this.cardPointerUp(doc)} style={{ width: this.childPanelWidth(), height: 'max-content', - transform: `translateY(${this.adjustCardYtoFitArch(doc === this._curDoc, index)}px) + transform: `translateY(${this.adjustCardYtoFitArch(doc === this.curDoc(), index)}px) translateX(calc(${translateToCenterIfActive()}% + ${this.horizontalAdjustmentForPartialRows(index, cardsInRow)}px)) - rotate(${doc !== this._curDoc ? this.rotate(index) : 0}rad) - scale(${doc === this._curDoc ? `${Math.min(hscale, vscale) * 100}%` : this._hoveredNodeIndex === index ? 1.1 : 1})`, + rotate(${doc !== this.curDoc()? this.rotate(index) : 0}rad) + scale(${doc === this.curDoc()? `${Math.min(hscale, vscale) * 100}%` : this._hoveredNodeIndex === index ? 1.1 : 1})`, }} // prettier-ignore onPointerEnter={() => this.setHoveredNodeIndex(index)} onPointerLeave={() => this.setHoveredNodeIndex(-1)}> @@ -671,10 +662,10 @@ export class CollectionCardView extends CollectionSubView() { isContentActive: emptyFunction, ScreenToLocalTransform: this.contentScreenToLocalXf, }); - answered = action(() => { - this._curDoc = this.curDoc ? this.filteredChildDocs()[(this.filteredChildDocs().findIndex(d => d === this.curDoc()) + 1) % (this.filteredChildDocs().length || 1)] : undefined; - }); - curDoc = () => this._curDoc; + answered = () => { + this.layoutDoc._card_curDoc = this.curDoc() ? this.filteredChildDocs()[(this.filteredChildDocs().findIndex(d => d === this.curDoc()) + 1) % (this.filteredChildDocs().length || 1)] : undefined; + }; + curDoc = () => DocCast(this.layoutDoc._card_curDoc); render() { const fitContentScale = this.childCards.length === 0 ? 1 : this.fitContentScale; diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx index 081e2fe5a..61a74dd7a 100644 --- a/src/client/views/collections/CollectionCarousel3DView.tsx +++ b/src/client/views/collections/CollectionCarousel3DView.tsx @@ -103,18 +103,10 @@ export class CollectionCarousel3DView extends CollectionSubView() { }; getAnchor = (addAsAnnotation: boolean) => { const anchor = Docs.Create.ConfigDocument({ annotationOn: this.Document, config_carousel_index: this.layoutDoc._carousel_index as number }); - PinDocView(anchor, { pinData: { type_collection: true, filters: true } }, this.Document); + PinDocView(anchor, { pinData: { collectionType: 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; }; - // pinned / linked anchor doc includes selected rows, graph titles, and graph colors - restoreView = (viewData: Doc) => { - if (viewData.config_carousel_index !== undefined && this.layoutDoc._carousel_index !== viewData.config_carousel_index) { - this.layoutDoc._carousel_index = viewData.config_carousel_index; - return true; - } - return false; - }; addDocTab = this.addLinkedDocTab; @computed get content() { const currentIndex = NumCast(this.layoutDoc._carousel_index); diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index bfb58733d..f714e2a00 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -86,18 +86,10 @@ export class CollectionCarouselView extends CollectionSubView() { getAnchor = (addAsAnnotation: boolean) => { const anchor = Docs.Create.ConfigDocument({ annotationOn: this.Document, config_carousel_index: this.carouselIndex }); - PinDocView(anchor, { pinData: { type_collection: true, filters: true } }, this.Document); + PinDocView(anchor, { pinData: { collectionType: 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; }; - // pinned / linked anchor doc includes selected rows, graph titles, and graph colors - restoreView = (viewData: Doc) => { - if (viewData.config_carousel_index !== undefined && this.layoutDoc._carousel_index !== viewData.config_carousel_index) { - this.layoutDoc._carousel_index = viewData.config_carousel_index; - return true; - } - return false; - }; addDocTab = this.addLinkedDocTab; captionStyleProvider = (doc: Doc | undefined, captionProps: Opt, property: string) => { diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 5738e7ce3..d75c633ac 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -52,7 +52,7 @@ export class CollectionTimeView extends CollectionSubView() { title: ComputedField.MakeFunction(`"${this.pivotField}"])`) as unknown as string, // title can take a functiono or a string annotationOn: this.Document, }); - PinDocView(anchor, { pinData: { type_collection: true, pivot: true, filters: true } }, 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 diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 0241fc2dd..ff711314b 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1743,7 +1743,7 @@ export class CollectionFreeFormView extends CollectionSubView() { if (typeof res === 'string') { const resObj = JSON.parse(res); console.log('Parsed GPT Result ', resObj); - // eslint-disable-next-line no-restricted-syntax for (const key in resObj) { if (resObj[key]) { console.log('typeof property', typeof resObj[key]); @@ -563,11 +562,11 @@ export class PresBox extends ViewBoxBaseComponent() { const datarange = [DocumentType.FUNCPLOT].includes(targetType); const dataview = [DocumentType.INK, DocumentType.COL, DocumentType.IMG, DocumentType.RTF].includes(targetType) && target?.activeFrame === undefined; const poslayoutview = [DocumentType.COL].includes(targetType) && target?.activeFrame === undefined; - const typeCollection = targetType === DocumentType.COL; + const collectionType = targetType === DocumentType.COL; const filters = true; const pivot = true; const dataannos = false; - return { scrollable, pannable, inkable, type_collection: typeCollection, pivot, map, filters, temporal, clippable, dataview, datarange, poslayoutview, dataannos }; + return { scrollable, pannable, inkable, collectionType, pivot, map, filters, temporal, clippable, dataview, datarange, poslayoutview, dataannos }; } @action @@ -575,7 +574,6 @@ export class PresBox extends ViewBoxBaseComponent() { /* empty */ }; @action - // eslint-disable-next-line default-param-last static restoreTargetDocView(bestTargetView: Opt, activeItem: Doc, transTime: number, pinDocLayout: boolean = BoolCast(activeItem.config_pinLayout), pinDataTypes?: dataTypes, targetDoc?: Doc) { const bestTarget = bestTargetView?.Document ?? (targetDoc?.layout_unrendered ? DocCast(targetDoc?.annotationOn) : targetDoc); if (!bestTarget) return undefined; @@ -701,7 +699,19 @@ export class PresBox extends ViewBoxBaseComponent() { changed = true; } } - if ((pinDataTypes?.type_collection && activeItem.config_type_collection !== undefined) || (!pinDataTypes && activeItem.config_type_collection !== undefined)) { + if ((pinDataTypes?.collectionType && activeItem.config_card_curDoc !== undefined) || (!pinDataTypes && activeItem.config_card_curDoc !== undefined)) { + if (bestTarget._card_curDoc !== activeItem.config_card_curDoc) { + bestTarget._card_curDoc = activeItem.config_card_curDoc; + changed = true; + } + } + if ((pinDataTypes?.collectionType && activeItem.config_carousel_index !== undefined) || (!pinDataTypes && activeItem.config_carousel_index !== undefined)) { + if (bestTarget._carousel_index !== activeItem.config_carousel_index) { + bestTarget._carousel_index = activeItem.config_carousel_index; + changed = true; + } + } + if ((pinDataTypes?.collectionType && activeItem.config_type_collection !== undefined) || (!pinDataTypes && activeItem.config_type_collection !== undefined)) { if (bestTarget._type_collection !== activeItem.config_type_collection) { bestTarget._type_collection = activeItem.config_type_collection; changed = true; @@ -1135,7 +1145,6 @@ export class PresBox extends ViewBoxBaseComponent() { return false; } } else if (doc.type !== DocumentType.PRES) { - // eslint-disable-next-line operator-assignment if (!doc.presentation_targetDoc) doc.title = doc.title + ' - Slide'; doc.presentation_targetDoc = doc.createdFrom ?? doc; // dropped document will be a new embedding of an embedded document somewhere else. doc.presentation_movement = PresMovement.Zoom; @@ -1167,8 +1176,7 @@ export class PresBox extends ViewBoxBaseComponent() { const tagDoc = Cast(curDoc.presentation_targetDoc, Doc, null); if (curDoc && curDoc === this.activeItem) return ( - // eslint-disable-next-line react/no-array-index-key -
+
{index + 1}. {StrCast(curDoc.title)}) @@ -1176,15 +1184,13 @@ export class PresBox extends ViewBoxBaseComponent() { ); if (tagDoc) return ( - // eslint-disable-next-line react/no-array-index-key -
+
{index + 1}. {StrCast(curDoc.title)}
); if (curDoc) return ( - // eslint-disable-next-line react/no-array-index-key -
+
{index + 1}. {StrCast(curDoc.title)}
); @@ -1369,7 +1375,6 @@ export class PresBox extends ViewBoxBaseComponent() { const tagDoc = PresBox.targetRenderedDoc(doc); const srcContext = Cast(tagDoc.embedContainer, Doc, null); const labelCreator = (top: number, left: number, edge: number, fontSize: number) => ( - // eslint-disable-next-line react/no-array-index-key
this.selectElement(doc)}>
{index + 1}
@@ -1620,7 +1625,6 @@ export class PresBox extends ViewBoxBaseComponent() { this.updateEffect(this.activeItem.presentation_effect as PresEffect, false, true); this.updateEffect(this.activeItem.presBulletEffect as PresEffect, true, true); this.updateEffectDirection(this.activeItem.presentation_effectDirection as PresEffectDirection, true); - // eslint-disable-next-line camelcase const { presentation_transition: pt, presentation_duration: pd, presentation_hideBefore: ph, presentation_hideAfter: pa } = this.activeItem; array.forEach(curDoc => { curDoc.presentation_transition = pt; @@ -2018,7 +2022,6 @@ export class PresBox extends ViewBoxBaseComponent() {
{this.generatedAnimations.map((elem, i) => (
{ @@ -3046,7 +3049,6 @@ export class PresBox extends ViewBoxBaseComponent() {
{mode !== CollectionViewType.Invalid ? ( deserializeScript(obj as ScriptField)) export class ScriptField extends ObjectField { @serializable @@ -137,7 +138,6 @@ export class ScriptField extends ObjectField { [ToString]() { return this.script.originalScript; } - // eslint-disable-next-line default-param-last public static CompileScript(script: string, params: object = {}, addReturn = false, capturedVariables?: { [name: string]: Doc | string | number | boolean }, transformer?: Transformer) { return CompileScript(script, { params: { @@ -156,13 +156,11 @@ export class ScriptField extends ObjectField { }); } - // eslint-disable-next-line default-param-last public static MakeFunction(script: string, params: object = {}, capturedVariables?: { [name: string]: Doc | string | number | boolean }) { const compiled = ScriptField.CompileScript(script, params, true, capturedVariables); return compiled.compiled ? new ScriptField(compiled) : undefined; } - // eslint-disable-next-line default-param-last public static MakeScript(script: string, params: object = {}, capturedVariables?: { [name: string]: Doc | string | number | boolean }) { const compiled = ScriptField.CompileScript(script, params, false, capturedVariables); return compiled.compiled ? new ScriptField(compiled) : undefined; @@ -186,6 +184,7 @@ export class ScriptField extends ObjectField { } @scriptingGlobal +// eslint-disable-next-line no-use-before-define @Deserializable('computed', (obj: unknown) => deserializeScript(obj as ComputedField)) export class ComputedField extends ScriptField { static undefined = '__undefined'; @@ -229,7 +228,6 @@ export class ComputedField extends ScriptField { [ToValue](doc: Doc) { return ComputedField.useComputed ? { value: this.value(doc) } : undefined; } // prettier-ignore [Copy](): ObjectField { return new ComputedField(this.script, this.setterscript, this.rawscript); } // prettier-ignore - // eslint-disable-next-line default-param-last public static MakeFunction(script: string, params: object = {}, capturedVariables?: { [name: string]: Doc | string | number | boolean }, setterscript?: string) { const compiled = ScriptField.CompileScript(script, params, true, { value: '', ...capturedVariables }); const compiledsetter = setterscript ? ScriptField.CompileScript(setterscript, { ...params, value: 'any' }, false, capturedVariables) : undefined; -- cgit v1.2.3-70-g09d2 From 28792ad2da9f5dfab96f98f34a11136bd1453e0f Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 6 Mar 2025 10:49:20 -0500 Subject: fixed resizing height to be > 10 pixels. split pivotView out of timeView. --- src/client/documents/DocumentTypes.ts | 1 + src/client/util/CurrentUserUtils.ts | 4 +- src/client/views/DocumentDecorations.tsx | 3 +- .../views/collections/CollectionCarouselView.tsx | 2 +- .../views/collections/CollectionPivotView.tsx | 147 +++++++++++++++++++ .../views/collections/CollectionTimeView.tsx | 158 ++------------------- src/client/views/collections/CollectionView.tsx | 7 +- .../CollectionFreeFormLayoutEngines.tsx | 6 +- 8 files changed, 174 insertions(+), 154 deletions(-) create mode 100644 src/client/views/collections/CollectionPivotView.tsx (limited to 'src/client/views/collections/CollectionTimeView.tsx') 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([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 {this.content} - {this.flashCardUI(this.curDoc, this.docViewProps, this.answered)} {this.navButtons}
+ {this.flashCardUI(this.curDoc, this.docViewProps, this.answered)}
); } 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 = undefined; + @observable _viewDefDivClick: Opt = undefined; + @observable _focusPivotField: Opt = 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 ( +
+ +
+ ); + } + + render() { + return ( +
+ {this.contents} +
+ { + this.layoutDoc._pivotField = fieldKey; + }} + placeholder={StrCast(this.layoutDoc._pivotField)} + /> +
+
+ ); + } +} + +// 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 = undefined; - @observable _viewDefDivClick: Opt = undefined; @observable _focusPivotField: Opt = 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([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 ( -
+
); } - 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 ( -
+
{this.contents} - {!this._props.isSelected() || !doTimeline ? null : ( - <> -
-
-
- - )}
+ {!this._props.isSelected() ? null : ( + <> +
+
+
+ + )}
); } } - -// 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() { @@ -105,6 +106,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent; case CollectionViewType.Masonry: return ; case CollectionViewType.Time: return ; + case CollectionViewType.Pivot: return ; case CollectionViewType.Grid: return ; case CollectionViewType.Card: return ; } @@ -126,7 +128,8 @@ export class CollectionView extends ViewBoxAnnotatableComponent 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, pivotDoc: Doc } function toNumber(val: FieldResult) { - 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, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[] /* , engineProps: any */) { @@ -295,7 +295,7 @@ export function computeTimelineLayout(poolData: Map, 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); -- cgit v1.2.3-70-g09d2