From fbea2a097191f22ae20a609760bd632fc98ca414 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 2 Oct 2024 17:53:50 -0400 Subject: added xMargin for carousel to prevent buttons from overlapping text, etc. Made showing tags an option for carouselViews that needs to be turned on with showChildTags. Gave text boxes extra height when show Tags is on. --- src/client/views/collections/CollectionCarouselView.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index 74cf580c9..8b3a699ed 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -165,7 +165,7 @@ export class CollectionCarouselView extends CollectionSubView() { NativeWidth={returnZero} NativeHeight={returnZero} fitWidth={this._props.childLayoutFitWidth} - showTags={true} + showTags={BoolCast(this.layoutDoc.showChildTags)} containerViewPath={this.childContainerViewPath} setContentViewBox={undefined} ScreenToLocalTransform={this.childScreenToLocalXf} @@ -178,6 +178,7 @@ export class CollectionCarouselView extends CollectionSubView() { LayoutTemplate={this._props.childLayoutTemplate} LayoutTemplateString={this._props.childLayoutString} TemplateDataDocument={DocCast(Doc.Layout(doc).resolvedDataDoc)} + xPadding={35} PanelHeight={this.panelHeight} /> ); -- cgit v1.2.3-70-g09d2 From f63aa4c65f6336c7708c50ced83867702a310240 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 4 Oct 2024 18:39:15 -0400 Subject: cleaning up CardDeckView so that animations work smoothly --- src/client/views/Main.tsx | 2 - .../views/collections/CollectionCalendarView.tsx | 99 ---------- .../views/collections/CollectionCardDeckView.tsx | 199 +++++++++------------ src/client/views/collections/CollectionSubView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 2 - src/client/views/nodes/DocumentView.tsx | 1 + src/client/views/nodes/FieldView.tsx | 3 +- src/client/views/nodes/calendarBox/CalendarBox.tsx | 2 +- 8 files changed, 88 insertions(+), 222 deletions(-) delete mode 100644 src/client/views/collections/CollectionCalendarView.tsx (limited to 'src/client/views/collections') diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 73d2872d1..17eea585a 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -18,7 +18,6 @@ import { TrackMovements } from '../util/TrackMovements'; import { KeyManager } from './GlobalKeyHandler'; import { InkingStroke } from './InkingStroke'; import { MainView } from './MainView'; -import { CollectionCalendarView } from './collections/CollectionCalendarView'; import { CollectionDockingView } from './collections/CollectionDockingView'; import { CollectionView } from './collections/CollectionView'; import { TabDocView } from './collections/TabDocView'; @@ -128,7 +127,6 @@ FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0, message: 'cache' }; CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, - CollectionCalendarView, CollectionView, WebBox, KeyValueBox, diff --git a/src/client/views/collections/CollectionCalendarView.tsx b/src/client/views/collections/CollectionCalendarView.tsx deleted file mode 100644 index 0ea9f8ebc..000000000 --- a/src/client/views/collections/CollectionCalendarView.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import { computed, makeObservable } from 'mobx'; -import { observer } from 'mobx-react'; -import * as React from 'react'; -import { emptyFunction } from '../../../Utils'; -import { dateRangeStrToDates, returnTrue } from '../../../ClientUtils'; -import { Doc, DocListCast } from '../../../fields/Doc'; -import { StrCast } from '../../../fields/Types'; -import { CollectionStackingView } from './CollectionStackingView'; -import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; - -@observer -export class CollectionCalendarView extends CollectionSubView() { - constructor(props: SubCollectionViewProps) { - super(props); - makeObservable(this); - } - - componentDidMount(): void {} - - componentWillUnmount(): void {} - - @computed get allCalendars() { - return this.childDocs; // returns a list of docs (i.e. calendars) - } - - removeCalendar = () => {}; - - addCalendar = (/* doc: Doc | Doc[], annotationKey?: string | undefined */): boolean => - // bring up calendar modal with option to create a calendar - true; - - _stackRef = React.createRef(); - - panelHeight = () => this._props.PanelHeight() - 40; // this should be the height of the stacking view. For now, it's the hieight of the calendar view minus 40 to allow for a title - - // most recent calendar should come first - sortByMostRecentDate = (calendarA: Doc, calendarB: Doc) => { - const aDateRangeStr = StrCast(DocListCast(calendarA.data).lastElement()?.date_range); - const bDateRangeStr = StrCast(DocListCast(calendarB.data).lastElement()?.date_range); - - const { start: aFromDate, end: aToDate } = dateRangeStrToDates(aDateRangeStr); - const { start: bFromDate, end: bToDate } = dateRangeStrToDates(bDateRangeStr); - - if (aFromDate > bFromDate) { - return -1; // a comes first - } - if (aFromDate < bFromDate) { - return 1; // b comes first - } - // start dates are the same - if (aToDate > bToDate) { - return -1; // a comes first - } - if (aToDate < bToDate) { - return 1; // b comes first - } - return 0; // same start and end dates - }; - - screenToLocalTransform = () => - this._props - .ScreenToLocalTransform() - .translate(Doc.NativeWidth(this.Document), 0) - .scale(this._props.NativeDimScaling?.() || 1); - - get calendarsKey() { - return this._props.fieldKey; - } - - render() { - return ( -
- -
- ); - } -} diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx index 101cc8082..a9ab9de26 100644 --- a/src/client/views/collections/CollectionCardDeckView.tsx +++ b/src/client/views/collections/CollectionCardDeckView.tsx @@ -2,7 +2,6 @@ import { IReactionDisposer, ObservableMap, action, computed, makeObservable, obs import { observer } from 'mobx-react'; import * as React from 'react'; import { ClientUtils, DashColor, returnFalse, returnZero } from '../../../ClientUtils'; -import { emptyFunction } from '../../../Utils'; import { Doc } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; @@ -13,7 +12,6 @@ import { gptImageLabel } from '../../apis/gpt/GPT'; import { DocumentType } from '../../documents/DocumentTypes'; import { DragManager } from '../../util/DragManager'; import { dropActionType } from '../../util/DropActionTypes'; -import { SelectionManager } from '../../util/SelectionManager'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; import { undoable } from '../../util/UndoManager'; @@ -23,12 +21,12 @@ import { DocumentView } from '../nodes/DocumentView'; import { GPTPopup, GPTPopupMode } from '../pdf/GPTPopup/GPTPopup'; import './CollectionCardDeckView.scss'; import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; +import { computedFn } from 'mobx-utils'; enum cardSortings { Time = 'time', Type = 'type', Color = 'color', - Custom = 'custom', Chat = 'chat', Tag = 'tag', None = '', @@ -46,14 +44,13 @@ export class CollectionCardView extends CollectionSubView() { private _dropDisposer?: DragManager.DragDropDisposer; private _disposers: { [key: string]: IReactionDisposer } = {}; private _textToDoc = new Map(); - private _dropped = false; // indicate when a card doc has just moved; + 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) @observable _forceChildXf = 0; @observable _hoveredNodeIndex = -1; @observable _docRefs = new ObservableMap(); @observable _maxRowCount = 10; @observable _docDraggedIndex: number = -1; - @observable overIndex: number = -1; static imageUrlToBase64 = async (imageUrl: string): Promise => { try { @@ -101,7 +98,6 @@ export class CollectionCardView extends CollectionSubView() { componentDidMount() { this._props.setContentViewBox?.(this); - // Reaction to cardSort changes this._disposers.sort = reaction( () => GPTPopup.Instance.visible, isVis => { @@ -135,8 +131,7 @@ export class CollectionCardView extends CollectionSubView() { } /** - * The child documents to be rendered-- either all of them except the Links or the docs in the currently active - * custom group + * The child documents to be rendered-- everything other than ink/link docs (which are marks as being svg's) */ @computed get childDocsWithoutLinks() { return this.childDocs.filter(l => !l.layout_isSvg); @@ -155,8 +150,7 @@ export class CollectionCardView extends CollectionSubView() { */ quizMode = () => { const randomIndex = Math.floor(Math.random() * this.childDocs.length); - SelectionManager.DeselectAll(); - DocumentView.SelectView(DocumentView.getDocumentView(this.childDocs[randomIndex]), false); + DocumentView.getDocumentView(this.childDocs[randomIndex])?.select(false); }; /** @@ -168,29 +162,15 @@ export class CollectionCardView extends CollectionSubView() { @action setHoveredNodeIndex = (index: number) => { - if (!DocumentView.SelectedDocs().includes(this.childDocs[index])) { - this._hoveredNodeIndex = index; - } + if (!SnappingManager.IsDragging) this._hoveredNodeIndex = index; }; - /** - * Translates the hovered node to the center of the screen - * @param index - * @returns - */ - translateHover = (index: number) => (this._hoveredNodeIndex === index && !DocumentView.SelectedDocs().includes(this.childDocs[index]) ? -50 : 0); - - isSelected = (index: number) => DocumentView.SelectedDocs().includes(this.childDocs[index]); - - /** - * Returns all the documents except the one that's currently selected - */ - inactiveDocs = () => this.childDocsWithoutLinks.filter(d => !DocumentView.SelectedDocs().includes(d)); + isSelected = (doc: Doc) => this._docRefs.get(doc)?.IsSelected; childPanelWidth = () => NumCast(this.layoutDoc.childPanelWidth, this._props.PanelWidth() / 2); childPanelHeight = () => this._props.PanelHeight() * this.fitContentScale; onChildDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick); - isContentActive = () => this._props.isSelected() || this._props.isContentActive() || this._props.isAnyChildContentActive(); - isChildContentActive = () => !!this.isContentActive(); + isContentActive = () => this._props.isSelected() || this._props.isContentActive() || this.isAnyChildContentActive(); + isAnyChildContentActive = this._props.isAnyChildContentActive; /** * Returns the degree to rotate a card dependind on the amount of cards in their row and their index in said row @@ -202,13 +182,14 @@ export class CollectionCardView extends CollectionSubView() { if (amCards == 1) return 0; const possRotate = -30 + index * (30 / ((amCards - (amCards % 2)) / 2)); - const stepMag = Math.abs(-30 + (amCards / 2 - 1) * (30 / ((amCards - (amCards % 2)) / 2))); - - if (amCards % 2 === 0 && possRotate === 0) { - return possRotate + Math.abs(-30 + (index - 1) * (30 / (amCards / 2))); - } - if (amCards % 2 === 0 && index > (amCards + 1) / 2) { - return possRotate + stepMag; + if (amCards % 2 === 0) { + if (possRotate === 0) { + return possRotate + Math.abs(-30 + (index - 1) * (30 / (amCards / 2))); + } + if (index > (amCards + 1) / 2) { + const stepMag = Math.abs(-30 + (amCards / 2 - 1) * (30 / ((amCards - (amCards % 2)) / 2))); + return possRotate + stepMag; + } } return possRotate; @@ -274,21 +255,12 @@ export class CollectionCardView extends CollectionSubView() { /** * Checks to see if a card is being dragged and calls the appropriate methods if so - * @param e the current pointer event */ - @action onPointerMove = (x: number, y: number) => { this._docDraggedIndex = DragManager.docsBeingDragged.length ? this.findCardDropIndex(x, y) : -1; }; - /** - * Handles external drop of images/PDFs etc from outside Dash. - */ - onExternalDrop = async (e: React.DragEvent): Promise => { - super.onExternalDrop(e, {}); - }; - /** * Resets all the doc dragging vairables once a card is dropped * @param e @@ -326,7 +298,7 @@ export class CollectionCardView extends CollectionSubView() { } /** - * Used to determine how to sort cards based on tags. The lestmost tags are given lower values while cards to the right are + * Used to determine how to sort cards based on tags. The leftmost tags are given lower values while cards to the right are * given higher values. Decimals are used to determine placement for cards with multiple tags * @param doc the doc whose value is being determined * @returns its value based on its tags @@ -352,24 +324,14 @@ export class CollectionCardView extends CollectionSubView() { docs.sort((docA, docB) => { const [typeA, typeB] = (() => { switch (sortType) { - case cardSortings.Time: - return [DateCast(docA.author_date)?.date ?? Date.now(), DateCast(docB.author_date)?.date ?? Date.now()]; - case cardSortings.Color: { - const d1 = DashColor(StrCast(docA.backgroundColor)); - const d2 = DashColor(StrCast(docB.backgroundColor)); - return [d1.hsv().hue(), d2.hsv().hue()]; - } - case cardSortings.Tag: - return [this.tagValue(docA) ?? 9999, this.tagValue(docB) ?? 9999]; - case cardSortings.Chat: - return [NumCast(docA.chatIndex) ?? 9999, NumCast(docB.chatIndex) ?? 9999]; - default: - return [StrCast(docA.type), StrCast(docB.type)]; + default: + case cardSortings.Type: return [StrCast(docA.type), StrCast(docB.type)]; + case cardSortings.Chat: return [NumCast(docA.chatIndex, 9999), NumCast(docB.chatIndex,9999)]; + case cardSortings.Time: return [DateCast(docA.author_date)?.date ?? Date.now(), DateCast(docB.author_date)?.date ?? Date.now()]; + case cardSortings.Color:return [DashColor(StrCast(docA.backgroundColor)).hsv().hue(), DashColor(StrCast(docB.backgroundColor)).hsv().hue()]; } - })(); - - const out = typeA < typeB ? -1 : typeA > typeB ? 1 : 0; - return isDesc ? out : -out; + })(); //prettier-ignore + return (typeA < typeB ? -1 : typeA > typeB ? 1 : 0) * (isDesc ? 1 : -1); }); if (dragIndex !== -1) { const draggedDoc = DragManager.docsBeingDragged[0]; @@ -382,6 +344,15 @@ export class CollectionCardView extends CollectionSubView() { return docs; }; + isChildContentActive = () => + this._props.isContentActive?.() === false + ? false + : this._props.isDocumentActive?.() && (this._props.childDocumentsActive?.() || BoolCast(this.Document.childDocumentsActive)) + ? true + : this._props.childDocumentsActive?.() === false || this.Document.childDocumentsActive === false + ? false + : undefined; + displayDoc = (doc: Doc, screenToLocalTransform: () => Transform) => ( ); @@ -416,13 +388,11 @@ export class CollectionCardView extends CollectionSubView() { if (this.sortedDocs.length < this._maxRowCount) { return this.sortedDocs.length; } - // 13 - 3 = 10 const totalCards = this.sortedDocs.length; // if 9 or less if (index < totalCards - (totalCards % this._maxRowCount)) { return this._maxRowCount; } - // (3) return totalCards % this._maxRowCount; }; /** @@ -443,17 +413,17 @@ export class CollectionCardView extends CollectionSubView() { /** * Determines how far to translate a card in the y direction depending on its index, whether or not its being hovered, or if it's selected * @param isHovered - * @param isSelected + * @param isActive * @param realIndex * @param amCards * @param calcRowIndex * @returns */ - calculateTranslateY = (isHovered: boolean, isSelected: boolean, realIndex: number, amCards: number, calcRowIndex: number) => { + calculateTranslateY = (isHovered: boolean, isActive: boolean, realIndex: number, amCards: number, calcRowIndex: number) => { const rowHeight = (this._props.PanelHeight() * this.fitContentScale) / this.numRows; const rowIndex = Math.trunc(realIndex / this._maxRowCount); const rowToCenterShift = this.numRows / 2 - rowIndex; - if (isSelected) return rowToCenterShift * rowHeight - rowHeight / 2; + if (isActive) return rowToCenterShift * rowHeight - rowHeight / 2; if (amCards == 1) return 50 * this.fitContentScale; return this.translateY(amCards, calcRowIndex, realIndex); }; @@ -576,15 +546,43 @@ export class CollectionCardView extends CollectionSubView() { await this.childPairStringListAndUpdateSortDesc(); }; + childScreenToLocal = computedFn((doc: Doc, index: number, calcRowIndex: number, isSelected: boolean, amCards: number) => () => { + // need to explicitly trigger an invalidation since we're reading everything from the Dom + this._forceChildXf; + this._props.ScreenToLocalTransform(); + + const dref = this._docRefs.get(doc); + const { translateX, translateY, scale } = ClientUtils.GetScreenTransform(dref?.ContentDiv); + if (!scale) return new Transform(0, 0, 0); + + return new Transform(-translateX + (dref?.centeringX || 0) * scale, + -translateY + (dref?.centeringY || 0) * scale, 1) + .scale(1 / scale).rotate(!isSelected ? -this.rotate(amCards, calcRowIndex) : 0); // prettier-ignore + }); + + cardPointerUp = action((doc: Doc) => { + // if a card doc has just moved, or a card is selected and in front, then ignore this event + if (this.isSelected(doc) || this._dropped) { + this._dropped = false; + } else { + // otherwise, turn off documentDecorations becase we're in a selection transition and want to avoid artifacts. + // Turn them back on when the animation has completed and the render and backend structures are in synch + SnappingManager.SetIsResizing(doc[Id]); + setTimeout( + action(() => { + SnappingManager.SetIsResizing(undefined); + this._forceChildXf++; + }), + 1000 + ); + } + }); + /** * Actually renders all the cards */ @computed get renderCards() { - const sortedDocs = this.sortedDocs; - const anySelected = this.childDocs.some(doc => DocumentView.SelectedDocs().includes(doc)); - const isEmpty = this.childDocsWithoutLinks.length === 0; - - if (isEmpty) { + if (!this.childDocsWithoutLinks.length) { return ( Sorry ! There are no cards in this group @@ -593,31 +591,18 @@ export class CollectionCardView extends CollectionSubView() { } // Map sorted documents to their rendered components - return sortedDocs.map((doc, index) => { - const realIndex = sortedDocs.indexOf(doc); + return this.sortedDocs.map((doc, index) => { + const realIndex = this.sortedDocs.indexOf(doc); const calcRowIndex = this.overflowIndexCalc(realIndex); const amCards = this.overflowAmCardsCalc(realIndex); const view = DocumentView.getDocumentView(doc, this.DocumentView?.()); - const isSelected = view?.ComponentView?.isAnyChildContentActive?.() || view?.IsSelected ? true : false; - const childScreenToLocal = () => { - // need to explicitly trigger an invalidation since we're reading everything from the Dom - this._forceChildXf; - this._props.ScreenToLocalTransform(); - - const dref = this._docRefs.get(doc); - const { translateX, translateY, scale } = ClientUtils.GetScreenTransform(dref?.ContentDiv); - if (!scale) return new Transform(0, 0, 0); - - return new Transform(-translateX + (dref?.centeringX || 0) * scale, - -translateY + (dref?.centeringY || 0) * scale, 1) - .scale(1 / scale).rotate(!isSelected ? -this.rotate(amCards, calcRowIndex) : 0); // prettier-ignore - }; + const childScreenToLocal = this.childScreenToLocal(doc, index, calcRowIndex, !!view?.IsContentActive, amCards); const translateIfSelected = () => { const indexInRow = index % this._maxRowCount; const rowIndex = Math.trunc(index / this._maxRowCount); - const rowCenterIndex = Math.min(this._maxRowCount, sortedDocs.length - rowIndex * this._maxRowCount) / 2; + const rowCenterIndex = Math.min(this._maxRowCount, this.sortedDocs.length - rowIndex * this._maxRowCount) / 2; return (rowCenterIndex - indexInRow) * 100 - 50; }; const aspect = NumCast(doc.height) / NumCast(doc.width, 1); @@ -627,33 +612,18 @@ export class CollectionCardView extends CollectionSubView() { return (
{ - // if a card doc has just moved, or a card is selected and in front, then ignore this event - if (DocumentView.SelectedDocs().includes(doc) || this._dropped) { - this._dropped = false; - } else { - // otherwise, turn off documentDecorations becase we're in a selection transition and want to avoid artifacts. - // Turn them back on when the animation has completed and the render and backend structures are in synch - SnappingManager.SetIsResizing(doc[Id]); - setTimeout( - action(() => { - SnappingManager.SetIsResizing(undefined); - this._forceChildXf++; - }), - 1000 - ); - } - })} + className={`card-item${view?.IsContentActive ? '-active' : this.isAnyChildContentActive() ? '-inactive' : ''}`} + onPointerUp={() => this.cardPointerUp(doc)} style={{ width: this.childPanelWidth(), height: 'max-content', - transform: `translateY(${this.calculateTranslateY(this._hoveredNodeIndex === index, isSelected, realIndex, amCards, calcRowIndex)}px) - translateX(calc(${isSelected ? translateIfSelected() : 0}% + ${this.translateOverflowX(realIndex, amCards)}px)) - rotate(${!isSelected ? this.rotate(amCards, calcRowIndex) : 0}deg) - scale(${isSelected ? `${Math.min(hscale, vscale) * 100}%` : this._hoveredNodeIndex === index ? 1.05 : 1})`, + transform: `translateY(${this.calculateTranslateY(this._hoveredNodeIndex === index, !!view?.IsContentActive, realIndex, amCards, calcRowIndex)}px) + translateX(calc(${view?.IsContentActive ? translateIfSelected() : 0}% + ${this.translateOverflowX(realIndex, amCards)}px)) + rotate(${!view?.IsContentActive ? this.rotate(amCards, calcRowIndex) : 0}deg) + scale(${view?.IsContentActive ? `${Math.min(hscale, vscale) * 100}%` : this._hoveredNodeIndex === index ? 1.1 : 1})`, }} // prettier-ignore - onPointerEnter={() => !SnappingManager.IsDragging && this.setHoveredNodeIndex(index)}> + onPointerEnter={() => this.setHoveredNodeIndex(index)} + onPointerLeave={() => this.setHoveredNodeIndex(-1)}> {this.displayDoc(doc, childScreenToLocal)}
); @@ -680,8 +650,7 @@ export class CollectionCardView extends CollectionSubView() { ...(!isEmpty && { transform: `scale(${1 / this.fitContentScale})` }), ...(!isEmpty && { height: `${100 * this.fitContentScale}%` }), gridAutoRows: `${100 / this.numRows}%`, - }} - onMouseLeave={() => this.setHoveredNodeIndex(-1)}> + }}> {this.renderCards} diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 5d32482c3..581201a20 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -296,7 +296,7 @@ export function CollectionSubView() { return false; } - protected async onExternalDrop(e: React.DragEvent, options: DocumentOptions, completed?: (docs: Doc[]) => void) { + protected async onExternalDrop(e: React.DragEvent, options: DocumentOptions = {}, completed?: (docs: Doc[]) => void) { if (e.ctrlKey) { e.stopPropagation(); // bcz: this is a hack to stop propagation when dropping an image on a text document with shift+ctrl return; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index c9e934448..7418d4360 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/jsx-props-no-spreading */ import { IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -16,7 +15,6 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { FieldView } from '../nodes/FieldView'; import { OpenWhere } from '../nodes/OpenWhere'; -import { CollectionCalendarView } from './CollectionCalendarView'; import { CollectionCardView } from './CollectionCardDeckView'; import { CollectionCarousel3DView } from './CollectionCarousel3DView'; import { CollectionCarouselView } from './CollectionCarouselView'; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index d730e661b..81b5f946a 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1206,6 +1206,7 @@ export class DocumentView extends DocComponent() { public set IsSelected(val) { runInAction(() => { this._selected = val; }); } // prettier-ignore public get IsSelected() { return this._selected; } // prettier-ignore + public get IsContentActive(){ return this._docViewInternal?.isContentActive(); } // prettier-ignore public get topMost() { return this._props.renderDepth === 0; } // prettier-ignore public get ContentDiv() { return this._docViewInternal?._contentDiv; } // prettier-ignore public get ComponentView() { return this._docViewInternal?._componentView; } // prettier-ignore diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 683edba16..f6eb4009c 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -6,7 +6,6 @@ import { DateField } from '../../../fields/DateField'; import { Doc, Field, FieldType, Opt } from '../../../fields/Doc'; import { List } from '../../../fields/List'; import { ScriptField } from '../../../fields/ScriptField'; -import { WebField } from '../../../fields/URLField'; import { dropActionType } from '../../util/DropActionTypes'; import { Transform } from '../../util/Transform'; import { PinProps } from '../PinFuncs'; @@ -14,9 +13,9 @@ import { ViewBoxInterface } from '../ViewBoxInterface'; import { DocumentView } from './DocumentView'; import { FocusViewOptions } from './FocusViewOptions'; import { OpenWhere } from './OpenWhere'; +import { WebField } from '../../../fields/URLField'; export type FocusFuncType = (doc: Doc, options: FocusViewOptions) => Opt; -// eslint-disable-next-line no-use-before-define export type StyleProviderFuncType = ( doc: Opt, // eslint-disable-next-line no-use-before-define diff --git a/src/client/views/nodes/calendarBox/CalendarBox.tsx b/src/client/views/nodes/calendarBox/CalendarBox.tsx index 678b7dd0b..d38cb5423 100644 --- a/src/client/views/nodes/calendarBox/CalendarBox.tsx +++ b/src/client/views/nodes/calendarBox/CalendarBox.tsx @@ -1,4 +1,4 @@ -import { Calendar, DateInput, EventClickArg, EventSourceInput } from '@fullcalendar/core'; +import { Calendar, EventClickArg, EventSourceInput } from '@fullcalendar/core'; import dayGridPlugin from '@fullcalendar/daygrid'; import multiMonthPlugin from '@fullcalendar/multimonth'; import timeGrid from '@fullcalendar/timegrid'; -- cgit v1.2.3-70-g09d2 From 9323ad30103b474e95610e97eb92916a0cf71f7b Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 4 Oct 2024 21:35:22 -0400 Subject: more lint fixes to schema view changes. --- src/ClientUtils.ts | 5 +- src/client/util/LinkManager.ts | 2 +- src/client/util/Scripting.ts | 8 +- src/client/util/SelectionManager.ts | 1 - src/client/views/FieldsDropdown.tsx | 4 +- src/client/views/PropertiesView.tsx | 2 +- .../collectionSchema/CollectionSchemaView.tsx | 327 +++++++++++---------- .../collectionSchema/SchemaColumnHeader.tsx | 264 +++++++++-------- .../collections/collectionSchema/SchemaRowBox.tsx | 48 +-- .../collectionSchema/SchemaTableCell.tsx | 82 +++--- src/client/views/global/globalScripts.ts | 1 - src/client/views/nodes/DataVizBox/DataVizBox.tsx | 177 ++++++----- src/client/views/nodes/DocumentIcon.tsx | 10 +- src/client/views/nodes/FieldView.tsx | 2 +- src/client/views/nodes/LabelBox.tsx | 4 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 2 - 16 files changed, 485 insertions(+), 454 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/ClientUtils.ts b/src/ClientUtils.ts index 8ecbc55bf..3066499d8 100644 --- a/src/ClientUtils.ts +++ b/src/ClientUtils.ts @@ -317,7 +317,7 @@ export namespace ClientUtils { } export function lightenRGB(rVal: number, gVal: number, bVal: number, percent: number): [number, number, number] { - const amount = 1 + percent/100; + const amount = 1 + percent / 100; const r = rVal * amount; const g = gVal * amount; const b = bVal * amount; @@ -347,8 +347,6 @@ export namespace ClientUtils { return undefined; } - - export function GetClipboardText(): string { const textArea = document.createElement('textarea'); document.body.appendChild(textArea); @@ -725,7 +723,6 @@ export function UpdateIcon( const newDiv = docViewContent.cloneNode(true) as HTMLDivElement; newDiv.style.width = width.toString(); newDiv.style.height = height.toString(); - console.log('width: ' + newDiv.style.width) replaceCanvases(docViewContent, newDiv); const htmlString = new XMLSerializer().serializeToString(newDiv); const nativeWidth = width; diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index bbf8d9c11..e11482572 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -260,7 +260,7 @@ export function UPDATE_SERVER_CACHE() { Doc.MyDockedBtns.linearView_IsOpen && console.log('Set cached docs = '); const isFiltered = filtered.filter(doc => !Doc.IsSystem(doc)); const strings = isFiltered.map(doc => StrCast(doc.title) + ' ' + (Doc.IsDataProto(doc) ? '(data)' : '(embedding)')); - //Doc.MyDockedBtns.linearView_IsOpen && strings.sort().forEach((str, i) => console.log(i.toString() + ' ' + str)); + Doc.MyDockedBtns.linearView_IsOpen && strings.sort().forEach((str, i) => console.log(i.toString() + ' ' + str)); rp.post(ClientUtils.prepend('/setCacheDocumentIds'), { body: { diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index 3ba3ff4b5..b1db0bf39 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -81,6 +81,7 @@ function Run(script: string | undefined, customParams: string[], diagnostics: ts if (!options.editable) { batch = Doc.MakeReadOnly(); } + const result = compiledFunction.apply(thisParam, params).apply(thisParam, argsArray); batch?.end(); return { success: true, result }; @@ -177,13 +178,8 @@ function forEachNode(node: ts.Node, onEnter: Traverser, onExit?: Traverser, inde ); } -// ScriptField.CompileScript(value, {}, true, undefined, DocumentIconContainer.getTransformer()); -// //addreturn = true -// //capturedvariables = undefined -// // - export function CompileScript(script: string, options: ScriptOptions = {}): CompileResult { - const captured = options.capturedVariables ?? {}; + const captured = options.capturedVariables ?? {}; const signature = Object.keys(captured).reduce((p, v) => { const formatCapture = (obj: FieldType | undefined) => `${v}=${obj instanceof RefField ? 'XXX' : obj?.toString()}`; const captureVal = captured[v]; diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index c39d8ebc7..1ab84421c 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -58,7 +58,6 @@ export class SelectionManager { }); public static DeselectAll = (except?: Doc): void => { - const found = this.Instance.SelectedViews.find(dv => dv.Document === except); runInAction(() => { if (LinkManager.Instance) { diff --git a/src/client/views/FieldsDropdown.tsx b/src/client/views/FieldsDropdown.tsx index 176ac96b6..407031b40 100644 --- a/src/client/views/FieldsDropdown.tsx +++ b/src/client/views/FieldsDropdown.tsx @@ -34,7 +34,7 @@ export class FieldsDropdown extends ObservableReactComponent(); SearchUtil.foreachRecursiveDoc([this._props.Document], (depth, doc) => allDocs.add(doc)); return Array.from(allDocs); @@ -57,7 +57,7 @@ export class FieldsDropdown extends ObservableReactComponent facet[0] === facet.charAt(0).toUpperCase())]; Object.entries(DocOptions) - .filter(opts => opts[1].filterable) //!!! + .filter(opts => opts[1].filterable) .forEach((pair: [string, FInfo]) => filteredOptions.push(pair[0])); const options = filteredOptions.sort().map(facet => ({ value: facet, label: facet })); diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 69c46052e..c6dccb4fb 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -884,7 +884,7 @@ export class PropertiesView extends ObservableReactComponent(); private _headerRefs: SchemaColumnHeader[] = []; - private _eqHighlightColors: Array<[{r: number, g: number, b: number}, {r: number, g: number, b: number}]> = []; + private _eqHighlightColors: Array<[{ r: number; g: number; b: number }, { r: number; g: number; b: number }]> = []; + private _oldWheel: HTMLDivElement | null = null; constructor(props: SubCollectionViewProps) { super(props); makeObservable(this); const lightenedColor = (r: number, g: number, b:number) => { const lightened = ClientUtils.lightenRGB(r, g, b, 165); return {r: lightened[0], g: lightened[1], b: lightened[2]}} // prettier-ignore - const colors = (r: number, g: number, b: number): [any, any] => {return [{r: r, g: g, b: b}, lightenedColor(r, g, b)]} // prettier-ignore + const colors = (r: number, g: number, b: number):[{r:number,g:number,b:number},{r:number,g:number,b:number}] => ([{r, g, b}, lightenedColor(r, g, b)]); // prettier-ignore this._eqHighlightColors.push(colors(70, 150, 50)); this._eqHighlightColors.push(colors(180, 70, 20)); this._eqHighlightColors.push(colors(70, 50, 150)); @@ -122,8 +123,8 @@ export class CollectionSchemaView extends CollectionSubView() { @observable _highlightedCellsInfo: Array<[doc: Doc, field: string]> = []; @observable _cellHighlightColors: ObservableMap = new ObservableMap(); @observable _containedDocs: Doc[] = []; //all direct children of the schema - @observable _referenceSelectMode: {enabled: boolean, currEditing: SchemaCellField | undefined} = {enabled: false, currEditing: undefined} - + @observable _referenceSelectMode: { enabled: boolean; currEditing: SchemaCellField | undefined } = { enabled: false, currEditing: undefined }; + // target HTMLelement portal for showing a popup menu to edit cell values. public get MenuTarget() { return this._menuTarget.current; @@ -217,15 +218,17 @@ export class CollectionSchemaView extends CollectionSubView() { true ); this._disposers.docdata = reaction( - () => DocListCast(this.dataDoc[this.fieldKey]), - (docs) => this._containedDocs = docs, - {fireImmediately: true} - ) + () => DocListCast(this.dataDoc[this.fieldKey]), + docs => (this._containedDocs = docs), + { fireImmediately: true } + ); this._disposers.sortHighlight = reaction( - () => [this.sortField, this._containedDocs, this._selectedDocs, this._highlightedCellsInfo], - () => {this.sortField && setTimeout(() => this.highlightSortedColumn())}, - {fireImmediately: true} - ) + () => [this.sortField, this._containedDocs, this._selectedDocs, this._highlightedCellsInfo], + () => { + this.sortField && setTimeout(() => this.highlightSortedColumn()); + }, + { fireImmediately: true } + ); } componentWillUnmount() { @@ -239,8 +242,8 @@ export class CollectionSchemaView extends CollectionSubView() { removeDoc = (doc: Doc) => { this.removeDocument(doc); - this._containedDocs = this._containedDocs.filter(d => d !== doc) - } + this._containedDocs = this._containedDocs.filter(d => d !== doc); + }; rowIndex = (doc: Doc) => this.docsWithDrag.docs.indexOf(doc); @@ -301,7 +304,9 @@ export class CollectionSchemaView extends CollectionSubView() { } break; case 'Backspace': { - undoable(() => {this._selectedDocs.forEach(d => this._containedDocs.includes(d) && this.removeDoc(d));}, 'delete schema row'); + undoable(() => { + this._selectedDocs.forEach(d => this._containedDocs.includes(d) && this.removeDoc(d)); + }, 'delete schema row'); break; } case 'Escape': { @@ -319,7 +324,7 @@ export class CollectionSchemaView extends CollectionSubView() { addRow = (doc: Doc | Doc[]) => this.addDocument(doc); @undoBatch - changeColumnKey = (index: number, newKey: string, defaultVal?: any) => { + changeColumnKey = (index: number, newKey: string, defaultVal?: FieldType) => { if (!this.documentKeys.includes(newKey)) this.addNewKey(newKey, defaultVal); const currKeys = this.columnKeys.slice(); // copy the column key array first, then change it. @@ -328,9 +333,10 @@ export class CollectionSchemaView extends CollectionSubView() { }; @undoBatch - addColumn = (index: number = 0, key?: string, defaultVal?: any) => { + addColumn = (index: number = 0, keyIn?: string, defaultVal?: FieldType) => { + let key = keyIn; if (key && !this.documentKeys.includes(key)) this.addNewKey(key, defaultVal); - + const newColWidth = this.tableWidth / (this.storedColumnWidths.length + 1); const currWidths = this.storedColumnWidths.slice(); currWidths.splice(index, 0, newColWidth); @@ -345,11 +351,11 @@ export class CollectionSchemaView extends CollectionSubView() { }; @action - addNewKey = (key: string, defaultVal: any) => { + addNewKey = (key: string, defaultVal: FieldType | undefined) => { this.childDocs.forEach(doc => { doc[DocData][key] = defaultVal; }); - } + }; @undoBatch removeColumn = (index: number) => { @@ -365,13 +371,13 @@ export class CollectionSchemaView extends CollectionSubView() { const currKeys = this.columnKeys.slice(); currKeys.splice(index, 1); - this.layoutDoc.schema_columnKeys = new List(currKeys); + this.layoutDoc.schema_columnKeys = new List(currKeys); this._colEles.splice(index, 1); }; @action - startResize = (e: any, index: number, rightSide: boolean) => { + startResize = (e: React.PointerEvent, index: number, rightSide: boolean) => { this._displayColumnWidths = this.storedColumnWidths; setupMoveUpEvents(this, e, moveEv => this.resizeColumn(moveEv, index, rightSide), this.finishResize, emptyFunction); }; @@ -384,8 +390,8 @@ export class CollectionSchemaView extends CollectionSubView() { let change = e.movementX; - if (rightSide && (index !== this._displayColumnWidths.length - 1)) { - growing = change < 0 ? index + 1: index; + if (rightSide && index !== this._displayColumnWidths.length - 1) { + growing = change < 0 ? index + 1 : index; shrinking = change < 0 ? index : index + 1; } else if (index !== 0) { growing = change < 0 ? index : index - 1; @@ -432,7 +438,7 @@ export class CollectionSchemaView extends CollectionSubView() { this.closeNewColumnMenu(); this._headerRefs.forEach(ref => ref.toggleEditing(false)); this._draggedColIndex = index; - this.setColDrag(true); + this.setColDrag(true); const dragData = new DragManager.ColumnDragData(index); const dragEles = [this._colEles[index]]; this.childDocs.forEach(doc => dragEles.push(this._rowEles.get(doc).children[1].children[index])); @@ -446,7 +452,7 @@ export class CollectionSchemaView extends CollectionSubView() { * @returns column index */ findColDropIndex = (mouseX: number) => { - const xOffset: number = this._props.ScreenToLocalTransform().inverse().transformPoint(0,0)[0] + CollectionSchemaView._rowMenuWidth; + const xOffset: number = this._props.ScreenToLocalTransform().inverse().transformPoint(0, 0)[0] + CollectionSchemaView._rowMenuWidth; let index: number | undefined; this.displayColumnWidths.reduce((total, curr, i) => { if (total <= mouseX && total + curr >= mouseX) { @@ -507,12 +513,7 @@ export class CollectionSchemaView extends CollectionSubView() { this._colEles.forEach((colRef, i) => { const edgeStyle = i === index ? `solid 2px ${Colors.MEDIUM_BLUE}` : ''; const sorted = i === this.columnKeys.indexOf(this.sortField); - const cellEles = [ - colRef, - ...this.docsWithDrag.docs - .filter(doc => (i !== this._selectedCol || !this._selectedDocs.includes(doc)) && !sorted) - .map(doc => this._rowEles.get(doc).children[1].children[i]), - ]; + const cellEles = [colRef, ...this.docsWithDrag.docs.filter(doc => (i !== this._selectedCol || !this._selectedDocs.includes(doc)) && !sorted).map(doc => this._rowEles.get(doc).children[1].children[i])]; cellEles.forEach(ele => { if (sorted || this.highlightedCells.includes(ele)) return; ele.style.borderTop = ele === cellEles[0] ? edgeStyle : ''; @@ -533,14 +534,14 @@ export class CollectionSchemaView extends CollectionSubView() { this.childDocs.forEach(doc => { const cell = this._rowEles.get(doc).children[1].children[i]; - if (!(this._selectedDocs.includes(doc) && i === this._selectedCol) && !(this.highlightedCells.includes(cell)) && cell) { + if (!(this._selectedDocs.includes(doc) && i === this._selectedCol) && !this.highlightedCells.includes(cell) && cell) { cell.style.borderLeft = ''; cell.style.borderRight = ''; cell.style.borderBottom = ''; } }); }); - } + }; /** * Applies a gradient highlight to a sorted column. The direction of the gradient depends @@ -552,10 +553,10 @@ export class CollectionSchemaView extends CollectionSubView() { let index = -1; const highlightColors: string[] = []; const rowCount: number = this._containedDocs.length + 1; - if (field || this.sortField){ + if (field || this.sortField) { index = this.columnKeys.indexOf(field || this.sortField); - const increment: number = 110/rowCount; - for (let i = 1; i <= rowCount; ++i){ + const increment: number = 110 / rowCount; + for (let i = 1; i <= rowCount; ++i) { const adjColor = ClientUtils.lightenRGB(16, 66, 230, increment * i); highlightColors.push(`solid 2px rgb(${adjColor[0]}, ${adjColor[1]}, ${adjColor[2]})`); } @@ -564,25 +565,20 @@ export class CollectionSchemaView extends CollectionSubView() { this._colEles.forEach((colRef, i) => { const highlight: boolean = i === index; const desc: boolean = descending || this.sortDesc; - const cellEles = [ - colRef, - ...this.docsWithDrag.docs - .filter(doc => (i !== this._selectedCol || !this._selectedDocs.includes(doc))) - .map(doc => this._rowEles.get(doc).children[1].children[i]), - ]; + const cellEles = [colRef, ...this.docsWithDrag.docs.filter(doc => i !== this._selectedCol || !this._selectedDocs.includes(doc)).map(doc => this._rowEles.get(doc).children[1].children[i])]; const cellCount = cellEles.length; - for (let ele = 0; ele < cellCount; ++ele){ + for (let ele = 0; ele < cellCount; ++ele) { const currCell = cellEles[ele]; if (this.highlightedCells.includes(currCell)) continue; - const style = highlight ? desc ? `${highlightColors[cellCount - 1 - ele]}` : `${highlightColors[ele]}` : ''; + const style = highlight ? (desc ? `${highlightColors[cellCount - 1 - ele]}` : `${highlightColors[ele]}`) : ''; currCell.style.borderLeft = style; currCell.style.borderRight = style; } - cellEles[0].style.borderTop = highlight ? desc ? `${highlightColors[cellCount - 1]}` : `${highlightColors[0]}` : ''; - if (!(this._selectedDocs.includes(this.docsWithDrag.docs[this.docsWithDrag.docs.length - 1]) && this._selectedCol === index) && !this.highlightedCells.includes(cellEles[cellCount - 1])) cellEles[cellCount - 1].style.borderBottom = highlight ? desc ? `${highlightColors[0]}` : `${highlightColors[cellCount - 1]}` : ''; + cellEles[0].style.borderTop = highlight ? (desc ? `${highlightColors[cellCount - 1]}` : `${highlightColors[0]}`) : ''; + if (!(this._selectedDocs.includes(this.docsWithDrag.docs[this.docsWithDrag.docs.length - 1]) && this._selectedCol === index) && !this.highlightedCells.includes(cellEles[cellCount - 1])) + cellEles[cellCount - 1].style.borderBottom = highlight ? (desc ? `${highlightColors[0]}` : `${highlightColors[cellCount - 1]}`) : ''; }); - - } + }; /** * Gets the html element representing a cell so that styles can be applied on it. @@ -594,35 +590,40 @@ export class CollectionSchemaView extends CollectionSubView() { const index = this.columnKeys.indexOf(fieldKey); const cell = this._rowEles.get(doc).children[1].children[index]; return cell; - } + }; /** * Given text in a cell, find references to other cells (for equations). * @param text the text in the cell - * @returns the html cell elements referenced in the text. + * @returns the html cell elements referenced in the text. */ findCellRefs = (text: string) => { const pattern = /(this|d(\d+))\.(\w+)/g; - interface Match { docRef: string; field: string; } + interface Match { + docRef: string; + field: string; + } const matches: Match[] = []; let match: RegExpExecArray | null; while ((match = pattern.exec(text)) !== null) { - const docRef = match[1] === 'this' ? match[1] : match[2]; + const docRef = match[1] === 'this' ? match[1] : match[2]; matches.push({ docRef, field: match[3] }); } - const cells: Array = []; - matches.forEach((match: Match) => { - const {docRef, field} = match; + const cells: [Doc, string][] = []; + matches.forEach((m: Match) => { + const { docRef, field } = m; const docView = DocumentManager.Instance.DocumentViews[Number(docRef)]; const doc = docView?.Document ?? undefined; - if (this.columnKeys.includes(field) && this._containedDocs.includes(doc)) {cells.push([doc, field])} - }) + if (this.columnKeys.includes(field) && this._containedDocs.includes(doc)) { + cells.push([doc, field]); + } + }); return cells; - } + }; /** * Determines whether the rows above or below a given row have been @@ -636,7 +637,7 @@ export class CollectionSchemaView extends CollectionSubView() { const selectedBelow: boolean = this._selectedDocs.includes(docs[index + 1]); const selectedAbove: boolean = this._selectedDocs.includes(docs[index - 1]); return [selectedAbove, selectedBelow]; - } + }; @action removeCellHighlights = () => { @@ -649,9 +650,10 @@ export class CollectionSchemaView extends CollectionSubView() { if (this.selectionOverlap(doc)[0]) cell.style.borderTop = ''; if (this.selectionOverlap(doc)[1]) cell.style.borderBottom = ''; } else cell.style.border = ''; - cell.style.backgroundColor = '';}); + cell.style.backgroundColor = ''; + }); this._highlightedCellsInfo = []; - } + }; restoreCellHighlights = () => { this._highlightedCellsInfo.forEach(info => { @@ -665,10 +667,10 @@ export class CollectionSchemaView extends CollectionSubView() { cell.style.borderRight = color; cell.style.borderBottom = color; }); - } + }; /** - * Highlights cells based on equation text in the cell currently being edited. + * Highlights cells based on equation text in the cell currently being edited. * Does not highlight selected cells (that's done directly in SchemaTableCell). * @param text the equation */ @@ -682,7 +684,7 @@ export class CollectionSchemaView extends CollectionSubView() { const info = this._highlightedCellsInfo[i]; const color = this._eqHighlightColors[i % 10]; const colorStrings = [`solid 2px rgb(${color[0].r}, ${color[0].g}, ${color[0].b})`, `rgb(${color[1].r}, ${color[1].g}, ${color[1].b})`]; - const doc = info[0]; + const doc = info[0]; const field = info[1]; const key = `${doc[Id]}_${field}`; const cell = this.getCellElement(doc, field); @@ -690,7 +692,7 @@ export class CollectionSchemaView extends CollectionSubView() { cell.style.border = colorStrings[0]; cell.style.backgroundColor = colorStrings[1]; } - } + }; //Used in SchemaRowBox @action @@ -718,7 +720,6 @@ export class CollectionSchemaView extends CollectionSubView() { this.deselectAllCells(); }; - selectRow = (doc: Doc, lastSelected: Doc) => { const index = this.rowIndex(doc); const lastSelectedRow = this.rowIndex(lastSelected); @@ -737,12 +738,12 @@ export class CollectionSchemaView extends CollectionSubView() { if (!doc) return; const docIndex = DocumentView.getDocViewIndex(doc); const field = this.columnKeys[col]; - const refToAdd = `d${docIndex}.${field}` - const editedField = this._referenceSelectMode.currEditing ? this._referenceSelectMode.currEditing as SchemaCellField : null; + const refToAdd = `d${docIndex}.${field}`; + const editedField = this._referenceSelectMode.currEditing ? (this._referenceSelectMode.currEditing as SchemaCellField) : null; editedField?.insertText(refToAdd, true); editedField?.setupRefSelect(false); return; - } + }; @action selectCell = (doc: Doc, col: number, shiftKey: boolean, ctrlKey: boolean) => { @@ -787,7 +788,9 @@ export class CollectionSchemaView extends CollectionSubView() { @action onInternalDrop = (e: Event, de: DragManager.DropEvent) => { if (de.complete.columnDragData) { - setTimeout(() => {this.setColDrag(false);}); + setTimeout(() => { + this.setColDrag(false); + }); e.stopPropagation(); return true; } @@ -849,9 +852,9 @@ export class CollectionSchemaView extends CollectionSubView() { }; @action - setKey = (key: string, defaultVal?: any, index?: number) => { + setKey = (key: string, defaultVal?: string, index?: number) => { if (this.columnKeys.includes(key)) return; - + if (this._makeNewColumn) { this.addColumn(this.columnKeys.indexOf(key), key, defaultVal); this._makeNewColumn = false; @@ -861,14 +864,14 @@ export class CollectionSchemaView extends CollectionSubView() { }; /** - * Used in SchemaRowBox to set - * @param key - * @param value - * @returns + * Used in SchemaRowBox to set + * @param key + * @param value + * @returns */ setCellValues = (key: string, value: string) => { - if (this._selectedCells.length === 1) this.docs.forEach(doc => !doc._lockedSchemaEditing && Doc.SetField(doc, key, value)); - else this._selectedCells.forEach(doc => !doc._lockedSchemaEditing && Doc.SetField(doc, key, value)); + if (this._selectedCells.length === 1) this.docs.forEach(doc => !doc._lockedSchemaEditing && Doc.SetField(doc, key, value)); + else this._selectedCells.forEach(doc => !doc._lockedSchemaEditing && Doc.SetField(doc, key, value)); return true; }; @@ -912,34 +915,36 @@ export class CollectionSchemaView extends CollectionSubView() { const cm = ContextMenu.Instance; cm.clearItems(); - const fieldSortedAsc = (this.sortField === this.columnKeys[index] && !this.sortDesc); - const fieldSortedDesc = (this.sortField === this.columnKeys[index] && this.sortDesc); - const revealOptions = cm.findByDescription('Sort column') - const sortOptions: ContextMenuProps[] = revealOptions && revealOptions && 'subitems' in revealOptions ? revealOptions.subitems ?? [] : []; + const fieldSortedAsc = this.sortField === this.columnKeys[index] && !this.sortDesc; + const fieldSortedDesc = this.sortField === this.columnKeys[index] && this.sortDesc; + const revealOptions = cm.findByDescription('Sort column'); + const sortOptions: ContextMenuProps[] = revealOptions && revealOptions && 'subitems' in revealOptions ? (revealOptions.subitems ?? []) : []; sortOptions.push({ - description: 'Sort A-Z', + description: 'Sort A-Z', event: () => { - this.setColumnSort(undefined); + this.setColumnSort(undefined); const field = this.columnKeys[index]; this._containedDocs = this.sortDocs(field, false); setTimeout(() => { this.highlightSortedColumn(field, false); - setTimeout(() => this.highlightSortedColumn(), 480); + setTimeout(() => this.highlightSortedColumn(), 480); }, 20); - }, - icon: 'arrow-down-a-z',}); + }, + icon: 'arrow-down-a-z', + }); sortOptions.push({ - description: 'Sort Z-A', + description: 'Sort Z-A', event: () => { - this.setColumnSort(undefined); + this.setColumnSort(undefined); const field = this.columnKeys[index]; this._containedDocs = this.sortDocs(field, true); setTimeout(() => { this.highlightSortedColumn(field, true); - setTimeout(() => this.highlightSortedColumn(), 480); + setTimeout(() => this.highlightSortedColumn(), 480); }, 20); - }, - icon: 'arrow-up-z-a'}); + }, + icon: 'arrow-up-z-a', + }); sortOptions.push({ description: 'Persistent Sort A-Z', event: () => { @@ -964,7 +969,7 @@ export class CollectionSchemaView extends CollectionSubView() { } }, icon: fieldSortedDesc ? 'lock' : 'lock-open'}); // prettier-ignore - + cm.addItem({ description: `Change field`, event: () => this.openNewColumnMenu(index, false), @@ -975,12 +980,12 @@ export class CollectionSchemaView extends CollectionSubView() { event: () => this.openFilterMenu(index), icon: 'filter', }); - cm.addItem({ - description: 'Sort column', - addDivider: false, - noexpand: true, - subitems: sortOptions, - icon: 'sort' + cm.addItem({ + description: 'Sort column', + addDivider: false, + noexpand: true, + subitems: sortOptions, + icon: 'sort', }); cm.addItem({ description: 'Add column to left', @@ -1068,7 +1073,7 @@ export class CollectionSchemaView extends CollectionSubView() { @computed get renderColumnMenu() { const x = this._columnMenuIndex! === -1 ? 0 : this.displayColumnWidths.reduce((total, curr, index) => total + (index < this._columnMenuIndex! ? curr : 0), CollectionSchemaView._rowMenuWidth); return ( -
+
{this.keysDropdown}
); @@ -1095,13 +1100,7 @@ export class CollectionSchemaView extends CollectionSubView() { } return (
- e.stopPropagation()} - onClick={e => e.stopPropagation()} - onChange={e => Doc.setDocFilter(this.Document, columnKey, key, e.target.checked ? 'check' : 'remove')} - checked={bool} - /> + e.stopPropagation()} onClick={e => e.stopPropagation()} onChange={e => Doc.setDocFilter(this.Document, columnKey, key, e.target.checked ? 'check' : 'remove')} checked={bool} /> {key}
); @@ -1111,7 +1110,7 @@ export class CollectionSchemaView extends CollectionSubView() { @computed get renderFilterMenu() { const x = this.displayColumnWidths.reduce((total, curr, index) => total + (index < this._filterColumnIndex! ? curr : 0), CollectionSchemaView._rowMenuWidth); return ( -
+
e.stopPropagation()} /> {this.renderFilterOptions}
{ this._colBeingDragged = beingDragged; !beingDragged && this.removeDragHighlight(); - } + }; @action updateMouseCoordinates = (e: React.PointerEvent) => { const prevX = this._mouseCoordinates.x; const prevY = this._mouseCoordinates.y; this._mouseCoordinates = { x: e.clientX, y: e.clientY, prevX: prevX, prevY: prevY }; - } + }; @action onPointerMove = (e: React.PointerEvent) => { @@ -1158,9 +1157,9 @@ export class CollectionSchemaView extends CollectionSubView() { /** * Gets docs contained by collections within the schema. Currently defunct. - * @param doc - * @param displayed - * @returns + * @param doc + * @param displayed + * @returns */ // subCollectionDocs = (doc: Doc, displayed: boolean) => { // const childDocs = DocListCast(doc[Doc.LayoutFieldKey(doc)]); @@ -1203,8 +1202,7 @@ export class CollectionSchemaView extends CollectionSubView() { subDocs.forEach(t => { const docFieldKey = Doc.LayoutFieldKey(t); const isSubDocAnnotatable = t[docFieldKey] instanceof List && !(t[docFieldKey] as List)?.some(ele => !(ele instanceof Doc)); - notFiltered = - notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && ((!childDocFilters.length && !childFiltersByRanges.length) || DocUtils.FilterDocs([t], childDocFilters, childFiltersByRanges, d).length)); + notFiltered = notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && ((!childDocFilters.length && !childFiltersByRanges.length) || DocUtils.FilterDocs([t], childDocFilters, childFiltersByRanges, d).length)); DocListCast(t[isSubDocAnnotatable ? docFieldKey + '_annotations' : docFieldKey]).forEach(newdoc => newarray.push(newdoc)); isSubDocAnnotatable && DocListCast(t[docFieldKey + '_sidebar']).forEach(newdoc => newarray.push(newdoc)); }); @@ -1231,19 +1229,19 @@ export class CollectionSchemaView extends CollectionSubView() { // docsFromChildren = docsFromChildren.concat(docsNotAlreadyDisplayed); // }); - return this.filteredDocs;; + return this.filteredDocs; } /** - * Sorts docs first alphabetically and then numerically. + * Sorts docs first alphabetically and then numerically. * @param field the column being sorted * @param desc whether the sort is ascending or descending * @param persistent whether the sort is applied persistently or is one-shot - * @returns + * @returns */ sortDocs = (field: string, desc: boolean, persistent?: boolean) => { const numbers: Doc[] = []; - const strings: Doc[] = []; + const strings: Doc[] = []; this.docs.forEach(doc => { if (!isNaN(Number(Field.toString(doc[field] as FieldType)))) numbers.push(doc); @@ -1253,25 +1251,26 @@ export class CollectionSchemaView extends CollectionSubView() { const sortedNums = numbers.sort((numOne, numTwo) => { const numA = Number(Field.toString(numOne[field] as FieldType)); const numB = Number(Field.toString(numTwo[field] as FieldType)); - return desc? numA - numB : numB - numA; + return desc ? numA - numB : numB - numA; }); - const collator = new Intl.Collator(undefined, {sensitivity: 'base'}); + const collator = new Intl.Collator(undefined, { sensitivity: 'base' }); let sortedStrings; - if (!desc) {sortedStrings = strings.slice().sort((docA, docB) => collator.compare(Field.toString(docA[field] as FieldType), Field.toString(docB[field] as FieldType))); + if (!desc) { + sortedStrings = strings.slice().sort((docA, docB) => collator.compare(Field.toString(docA[field] as FieldType), Field.toString(docB[field] as FieldType))); } else sortedStrings = strings.slice().sort((docB, docA) => collator.compare(Field.toString(docA[field] as FieldType), Field.toString(docB[field] as FieldType))); const sortedDocs = desc ? sortedNums.concat(sortedStrings) : sortedStrings.concat(sortedNums); if (!persistent) this._containedDocs = sortedDocs; return sortedDocs; - } - + }; + /** * Returns all docs minus those currently being dragged by the user. */ @computed get docsWithDrag() { let docs = this.docs.slice(); - if (this.sortField){ + if (this.sortField) { const field = StrCast(this.layoutDoc.sortField); const desc = BoolCast(this.layoutDoc.sortDesc); // is this an ascending or descending sort docs = this.sortDocs(field, desc, true); @@ -1290,13 +1289,17 @@ export class CollectionSchemaView extends CollectionSubView() { previewWidthFunc = () => this.previewWidth; onPassiveWheel = (e: WheelEvent) => e.stopPropagation(); displayedDocsFunc = () => this.docsWithDrag.docs; - _oldWheel: any; render() { return ( -
this.createDashEventsTarget(ele)} - onDrop={this.onExternalDrop.bind(this)} - onPointerMove={e => this.onPointerMove(e)} - onPointerDown={() => {this.closeNewColumnMenu(); this.setColDrag(false)}}> +
this.createDashEventsTarget(ele)} + onDrop={this.onExternalDrop.bind(this)} + onPointerMove={e => this.onPointerMove(e)} + onPointerDown={() => { + this.closeNewColumnMenu(); + this.setColDrag(false); + }}>
} - size={Size.XSMALL} - color={'black'} - onPointerDown={e => - setupMoveUpEvents( - this, - e, - returnFalse, - emptyFunction, - undoable(clickEv => { - clickEv.stopPropagation(); - this.addColumn() - }, 'add key to schema') - ) - } + tooltip="Add a new key" + icon={} + size={Size.XSMALL} + color={'black'} + onPointerDown={e => + setupMoveUpEvents( + this, + e, + returnFalse, + emptyFunction, + undoable(clickEv => { + clickEv.stopPropagation(); + this.addColumn(); + }, 'add key to schema') + ) + } />
{this.columnKeys.map((key, index) => ( r && this._headerRefs.push(r)} - keysDropdown={(this.keysDropdown)} + keysDropdown={this.keysDropdown} schemaView={this} columnWidth={() => CollectionSchemaView._minColWidth} //TODO: update Document={this.Document} @@ -1445,7 +1447,6 @@ class CollectionSchemaViewDoc extends ObservableReactComponent ); } -} \ No newline at end of file +} diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx index c5cdac8af..47918f9c1 100644 --- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx +++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/no-unused-prop-types */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; @@ -21,7 +20,8 @@ import { undoable } from '../../../util/UndoManager'; import { IconButton, Size } from 'browndash-components'; export enum SchemaFieldType { - Header, Cell + Header, + Cell, } export interface SchemaColumnHeaderProps { @@ -49,7 +49,6 @@ export interface SchemaColumnHeaderProps { @observer export class SchemaColumnHeader extends ObservableReactComponent { - private _inputRef: EditableView | null = null; @observable _altTitle: string | undefined = undefined; @observable _showMenuIcon: boolean = false; @@ -58,18 +57,26 @@ export class SchemaColumnHeader extends ObservableReactComponent this._props.schemaView?.fieldInfos.get(fieldKey)); - setColumnValues = (field: string, defaultValue: string) => {this._props.schemaView?.setKey(field, defaultValue, this._props.columnIndex);} - @action updateAlt = (newAlt: string) => {this._altTitle = newAlt}; - updateKeyDropdown = (value: string) => {this._props.schemaView.updateKeySearch(value)}; - openKeyDropdown = () => {!this._props.schemaView._colBeingDragged && this._props.schemaView.openNewColumnMenu(this._props.columnIndex, false)}; + setColumnValues = (field: string, defaultValue: string) => { + this._props.schemaView?.setKey(field, defaultValue, this._props.columnIndex); + }; + @action updateAlt = (newAlt: string) => { + this._altTitle = newAlt; + }; + updateKeyDropdown = (value: string) => { + this._props.schemaView.updateKeySearch(value); + }; + openKeyDropdown = () => { + !this._props.schemaView._colBeingDragged && this._props.schemaView.openNewColumnMenu(this._props.columnIndex, false); + }; toggleEditing = (editing: boolean) => { - this._inputRef?.setIsEditing(editing); + this._inputRef?.setIsEditing(editing); this._inputRef?.setIsFocused(editing); }; @@ -110,139 +117,156 @@ export class SchemaColumnHeader extends ObservableReactComponent { - SchemaColumnHeader.isDefaultField(this.fieldKey) && this.openKeyDropdown(); - this._props.schemaView.deselectAllCells(); - }} - style={{ - color, - width: '100%', - pointerEvents, - }}> - {this._inputRef = r; this._props.autoFocus && r?.setIsFocused(true)}} - oneLine={true} - allowCRs={false} - contents={''} - onClick={this.openKeyDropdown} - fieldContents={fieldProps} - editing={undefined} - placeholder={'Add key'} - updateAlt={this.updateAlt} // alternate title to display - updateSearch={this.updateKeyDropdown} - schemaFieldType={SchemaFieldType.Header} - GetValue={() => { - if (SchemaColumnHeader.isDefaultField(this.fieldKey)) return ''; - else if (this._altTitle) return this._altTitle; - else return this.fieldKey; + const { color, fieldProps, pointerEvents } = this.renderProps(this._props); + + return ( +
{ + SchemaColumnHeader.isDefaultField(this.fieldKey) && this.openKeyDropdown(); + this._props.schemaView.deselectAllCells(); }} - SetValue={undoable((value: string, shiftKey?: boolean, enterKey?: boolean) => { - if (enterKey) { // if shift & enter, set value of each cell in column - this.setColumnValues(value, ''); - this._altTitle = undefined; + style={{ + color, + width: '100%', + pointerEvents, + }}> + { + this._inputRef = r; + this._props.autoFocus && r?.setIsFocused(true); + }} + oneLine={true} + allowCRs={false} + contents={''} + onClick={this.openKeyDropdown} + fieldContents={fieldProps} + editing={undefined} + placeholder={'Add key'} + updateAlt={this.updateAlt} // alternate title to display + updateSearch={this.updateKeyDropdown} + schemaFieldType={SchemaFieldType.Header} + GetValue={() => { + if (SchemaColumnHeader.isDefaultField(this.fieldKey)) return ''; + else if (this._altTitle) return this._altTitle; + else return this.fieldKey; + }} + SetValue={undoable((value: string, shiftKey?: boolean, enterKey?: boolean) => { + if (enterKey) { + // if shift & enter, set value of each cell in column + this.setColumnValues(value, ''); + this._altTitle = undefined; + this._props.finishEdit?.(); + return true; + } this._props.finishEdit?.(); return true; - } - this._props.finishEdit?.(); - return true; - }, 'edit column header')} - /> + }, 'edit column header')} + />
+ ); } public static isDefaultField = (key: string) => { const defaultPattern = /EmptyColumnKey/; - const isDefault: boolean = (defaultPattern.exec(key) != null); + const isDefault: boolean = defaultPattern.exec(key) != null; return isDefault; - } + }; - get headerButton(){ - const toRender = SchemaColumnHeader.isDefaultField(this.fieldKey) ? - (} - size={Size.XSMALL} - color={'black'} - onPointerDown={e => - setupMoveUpEvents( - this, - e, - returnFalse, - emptyFunction, - undoable(clickEv => { - clickEv.stopPropagation(); - this._props.schemaView.removeColumn(this._props.columnIndex); - }, 'open column menu') - ) - } - />) - : (} - size={Size.XSMALL} - color={'black'} - onPointerDown={e => - setupMoveUpEvents( - this, - e, - returnFalse, - emptyFunction, - undoable(clickEv => { - clickEv.stopPropagation(); - this._props.openContextMenu(e.clientX, e.clientY, this._props.columnIndex) - }, 'open column menu') - ) - } - />) + get headerButton() { + const toRender = SchemaColumnHeader.isDefaultField(this.fieldKey) ? ( + } + size={Size.XSMALL} + color={'black'} + onPointerDown={e => + setupMoveUpEvents( + this, + e, + returnFalse, + emptyFunction, + undoable(clickEv => { + clickEv.stopPropagation(); + this._props.schemaView.removeColumn(this._props.columnIndex); + }, 'open column menu') + ) + } + /> + ) : ( + } + size={Size.XSMALL} + color={'black'} + onPointerDown={e => + setupMoveUpEvents( + this, + e, + returnFalse, + emptyFunction, + undoable(clickEv => { + clickEv.stopPropagation(); + this._props.openContextMenu(e.clientX, e.clientY, this._props.columnIndex); + }, 'open column menu') + ) + } + /> + ); return toRender; } - @action handlePointerEnter = () => this._showMenuIcon = true; - @action handlePointerLeave = () => this._showMenuIcon = false; + @action handlePointerEnter = () => { this._showMenuIcon = true; } // prettier-ignore + @action handlePointerLeave = () => { this._showMenuIcon = false; } // prettier-ignore - @computed get displayButton() {return this._showMenuIcon;} + @computed get displayButton() { + return this._showMenuIcon; + } render() { return ( -
{this.handlePointerEnter()}} - onPointerLeave={() => {this.handlePointerLeave()}} - onPointerDown={e => { - this.setupDrag(e); - setupMoveUpEvents( - this, - e, - () => {return this._inputRef?.setIsEditing(false) ?? false}, - emptyFunction, - emptyFunction, - ); - } +
{ + this.handlePointerEnter(); + }} + onPointerLeave={() => { + this.handlePointerLeave(); + }} + onPointerDown={e => { + this.setupDrag(e); + setupMoveUpEvents( + this, + e, + () => { + return this._inputRef?.setIsEditing(false) ?? false; + }, + emptyFunction, + emptyFunction + ); + }} + ref={col => { + if (col) { + this._props.setColRef(this._props.columnIndex, col); } - ref={col => { - if (col) { - this._props.setColRef(this._props.columnIndex, col); - } - }}> -
this._props.resizeColumn(e, this._props.columnIndex, false)} /> + }}> +
this._props.resizeColumn(e, this._props.columnIndex, false)} /> -
{this.editableView}
+
{this.editableView}
-
-
- {this.headerButton} -
-
- -
this._props.resizeColumn(e, this._props.columnIndex, true)} /> +
+
+ {this.headerButton} +
+ +
this._props.resizeColumn(e, this._props.columnIndex, true)} /> +
); } -} \ No newline at end of file +} diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx index a8a4ef2c2..6ffb0865a 100644 --- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx +++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx @@ -21,7 +21,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; /** * The SchemaRowBox renders a doc as a row of cells, with each cell representing - * one field value of the doc. It mostly handles communication from the SchemaView + * one field value of the doc. It mostly handles communication from the SchemaView * to each SchemaCell, passing down necessary functions are props. */ @@ -59,7 +59,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent() { ContextMenu.Instance.clearItems(); ContextMenu.Instance.addItem({ description: this.Document._lockedSchemaEditing ? 'Unlock field editing' : 'Lock field editing', - event: () => this.Document._lockedSchemaEditing = !this.Document._lockedSchemaEditing, + event: () => (this.Document._lockedSchemaEditing = !this.Document._lockedSchemaEditing), icon: this.Document._lockedSchemaEditing ? 'lock-open' : 'lock', }); ContextMenu.Instance.addItem({ @@ -78,17 +78,19 @@ export class SchemaRowBox extends ViewBoxBaseComponent() { // ContextMenu.Instance.addItem({ // description: this.Document._childrenSharedWithSchema ? 'Remove children from schema' : 'Add children to schema', // event: () => { - // this.Document._childrenSharedWithSchema = !this.Document._childrenSharedWithSchema; + // this.Document._childrenSharedWithSchema = !this.Document._childrenSharedWithSchema; // }, // icon: this.Document._childrenSharedWithSchema ? 'minus' : 'plus', // }); // } ContextMenu.Instance.displayMenu(x, y, undefined, false); - } + }; - @computed get menuBackgroundColor(){ - if (this.Document._lockedSchemaEditing) {return '#F5F5F5'} - return '' + @computed get menuBackgroundColor() { + if (this.Document._lockedSchemaEditing) { + return '#F5F5F5'; + } + return ''; } @computed get menuInfos() { @@ -98,22 +100,28 @@ export class SchemaRowBox extends ViewBoxBaseComponent() { return infos; } - isolatedSelection = (doc: Doc) => {return this.schemaView?.selectionOverlap(doc)}; + isolatedSelection = (doc: Doc) => { + return this.schemaView?.selectionOverlap(doc); + }; setCursorIndex = (mouseY: number) => this.schemaView?.setRelCursorIndex(mouseY); selectedCol = () => this.schemaView._selectedCol; getFinfo = computedFn((fieldKey: string) => this.schemaView?.fieldInfos.get(fieldKey)); selectCell = (doc: Doc, col: number, shift: boolean, ctrl: boolean) => this.schemaView?.selectCell(doc, col, shift, ctrl); deselectCell = () => this.schemaView?.deselectAllCells(); selectedCells = () => this.schemaView?._selectedDocs; - setColumnValues = (field: any, value: any) => this.schemaView?.setCellValues(field, value) ?? false; + setColumnValues = (field: string, value: string) => this.schemaView?.setCellValues(field, value) ?? false; columnWidth = computedFn((index: number) => () => this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth); computeRowIndex = () => this.schemaView?.rowIndex(this.Document); highlightCells = (text: string) => this.schemaView?.highlightCells(text); - selectReference = (doc: Doc, col: number) => {this.schemaView.selectReference(doc, col)} + selectReference = (doc: Doc, col: number) => { + this.schemaView.selectReference(doc, col); + }; eqHighlightFunc = (text: string) => { const info = this.schemaView.findCellRefs(text); const cells: HTMLDivElement[] = []; - info.forEach(info => {cells.push(this.schemaView.getCellElement(info[0], info[1]))}) + info.forEach(inf => { + cells.push(this.schemaView.getCellElement(inf[0], inf[1])); + }); return cells; }; render() { @@ -121,7 +129,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent() {
this.setCursorIndex(e.clientY)} - style={{ height: this._props.PanelHeight()}} + style={{ height: this._props.PanelHeight() }} ref={(row: HTMLDivElement | null) => { row && this.schemaView?.addRowRef?.(this.Document, row); this._ref = row; @@ -131,11 +139,11 @@ export class SchemaRowBox extends ViewBoxBaseComponent() { style={{ width: CollectionSchemaView._rowMenuWidth, pointerEvents: !this._props.isContentActive() ? 'none' : undefined, - backgroundColor: this.menuBackgroundColor + backgroundColor: this.menuBackgroundColor, }}> } + icon={} size={Size.XSMALL} color={'black'} onPointerDown={e => @@ -146,14 +154,16 @@ export class SchemaRowBox extends ViewBoxBaseComponent() { emptyFunction, undoable(clickEv => { clickEv.stopPropagation(); - this.openContextMenu(e.clientX, e.clientY) + this.openContextMenu(e.clientX, e.clientY); }, 'open actions menu') ) } /> -
- {this.menuInfos.map(icn => )} -
+
+ {this.menuInfos.map(icn => ( + + ))} +
{this.schemaView?.columnKeys?.map((key, index) => ( @@ -192,4 +202,4 @@ export class SchemaRowBox extends ViewBoxBaseComponent() {
); } -} \ No newline at end of file +} diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx index c05382ce0..f036ff843 100644 --- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/jsx-props-no-spreading */ /* eslint-disable no-use-before-define */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Popup, Size, Type } from 'browndash-components'; @@ -37,7 +36,7 @@ import { SchemaCellField } from './SchemaCellField'; /** * SchemaTableCells make up the majority of the visual representation of the SchemaView. * They are rendered for each cell in the SchemaView, and each represents one field value - * of a doc. Editing the content of the cell changes the corresponding doc's field value. + * of a doc. Editing the content of the cell changes the corresponding doc's field value. */ export interface SchemaTableCellProps { @@ -67,21 +66,16 @@ export interface SchemaTableCellProps { isolatedSelection: (doc: Doc) => [boolean, boolean]; highlightCells: (text: string) => void; eqHighlightFunc: (text: string) => HTMLDivElement[] | []; - refSelectModeInfo: {enabled: boolean, currEditing: SchemaCellField | undefined}; + refSelectModeInfo: { enabled: boolean; currEditing: SchemaCellField | undefined }; selectReference: (doc: Doc, col: number) => void; } function selectedCell(props: SchemaTableCellProps) { - return ( - props.isRowActive() && - props.selectedCol() === props.col && - props.selectedCells()?.filter(d => d === props.Document)?.length - ); + return props.isRowActive() && props.selectedCol() === props.col && props.selectedCells()?.filter(d => d === props.Document)?.length; } @observer export class SchemaTableCell extends ObservableReactComponent { - // private _fieldRef: SchemaCellField | null = null; private _submittedValue: string = ''; @@ -96,9 +90,11 @@ export class SchemaTableCell extends ObservableReactComponent { @@ -110,7 +106,7 @@ export class SchemaTableCell extends ObservableReactComponent { const modField = field.replace(/\bthis.\b/g, `d${this.docIndex}.`); return modField; - } + }; // parses a field from the "idToDoc(####)" format to DocumentId (d#) format for readability cleanupField = (field: string) => { let modField = field.slice(); let eqSymbol: string = ''; - if (modField.startsWith('=')) {modField = modField.substring(1); eqSymbol += '=';} - if (modField.startsWith(':=')) {modField = modField.substring(2); eqSymbol += ':=';} + if (modField.startsWith('=')) { + modField = modField.substring(1); + eqSymbol += '='; + } + if (modField.startsWith(':=')) { + modField = modField.substring(2); + eqSymbol += ':='; + } const idPattern = /idToDoc\((.*?)\)/g; let matches; const results = new Array<[id: string, func: string]>(); - while ((matches = idPattern.exec(field)) !== null) {results.push([matches[0], matches[1].replace(/"/g, '')]); } - results.forEach((idFuncPair) => {modField = modField.replace(idFuncPair[0], 'd' + (DocumentView.getDocViewIndex(IdToDoc(idFuncPair[1]))).toString());}) + while ((matches = idPattern.exec(field)) !== null) { + results.push([matches[0], matches[1].replace(/"/g, '')]); + } + results.forEach(idFuncPair => { + modField = modField.replace(idFuncPair[0], 'd' + DocumentView.getDocViewIndex(IdToDoc(idFuncPair[1])).toString()); + }); if (modField.endsWith(';')) modField = modField.substring(0, modField.length - 1); - const inQuotes = (field: string) => {return ((field.startsWith('`') && field.endsWith('`')) || (field.startsWith("'") && field.endsWith("'")) || (field.startsWith('"') && field.endsWith('"')))} + const inQuotes = (strField: string) => { + return (strField.startsWith('`') && strField.endsWith('`')) || (strField.startsWith("'") && strField.endsWith("'")) || (strField.startsWith('"') && strField.endsWith('"')); + }; if (!inQuotes(this._submittedValue) && inQuotes(modField)) modField = modField.substring(1, modField.length - 1); return eqSymbol + modField; - } + }; @computed get defaultCellContent() { const { color, textDecoration, fieldProps, pointerEvents } = SchemaTableCell.renderProps(this._props); @@ -203,7 +211,7 @@ export class SchemaTableCell extends ObservableReactComponent = []; sides[0] = selectedCell(this._props) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // left sides[1] = selectedCell(this._props) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // right - sides[2] = (!this._props.isolatedSelection(this._props.Document)[0] && selectedCell(this._props)) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // top - sides[3] = (!this._props.isolatedSelection(this._props.Document)[1] && selectedCell(this._props)) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // bottom + sides[2] = !this._props.isolatedSelection(this._props.Document)[0] && selectedCell(this._props) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // top + sides[3] = !this._props.isolatedSelection(this._props.Document)[1] && selectedCell(this._props) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // bottom return sides; } @@ -256,9 +264,13 @@ export class SchemaTableCell extends ObservableReactComponent StopEvent(e)} onPointerDown={action(e => { - if (this.lockedInteraction) { e.stopPropagation(); e.preventDefault(); return; } + if (this.lockedInteraction) { + e.stopPropagation(); + e.preventDefault(); + return; + } - if (this._props.refSelectModeInfo.enabled && !selectedCell(this._props)){ + if (this._props.refSelectModeInfo.enabled && !selectedCell(this._props)) { e.stopPropagation(); e.preventDefault(); this._props.selectReference(this._props.Document, this._props.col); @@ -274,14 +286,16 @@ export class SchemaTableCell extends ObservableReactComponent + style={{ + padding: this._props.padding, + maxWidth: this._props.maxWidth?.(), + width: this._props.columnWidth() || undefined, + borderLeft: this.borderColor[0], + borderRight: this.borderColor[1], + borderTop: this.borderColor[2], + borderBottom: this.borderColor[3], + backgroundColor: this.backgroundColor, + }}> {this.isDefault ? '' : this.content}
); @@ -524,4 +538,4 @@ export class SchemaEnumerationCell extends ObservableReactComponent ); } -} \ No newline at end of file +} diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts index 962a21dbb..6c3f4eaff 100644 --- a/src/client/views/global/globalScripts.ts +++ b/src/client/views/global/globalScripts.ts @@ -84,7 +84,6 @@ ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: b } else { const dataKey = Doc.LayoutFieldKey(dv.Document); const alternate = (dv.layoutDoc[dataKey + '_usePath'] ? '_' + dv.layoutDoc[dataKey + '_usePath'] : '').replace(':hover', ''); - console.log('color: ' + dv.dataDoc[fieldKey + alternate] + ' to set to: ' + color) dv.layoutDoc[fieldKey + alternate] = undefined; dv.dataDoc[fieldKey + alternate] = color; } diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 12196f290..a44014444 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/jsx-props-no-spreading */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Checkbox } from '@mui/material'; import { Colors, Toggle, ToggleType, Type } from 'browndash-components'; @@ -8,42 +7,36 @@ import * as React from 'react'; import { ClientUtils, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents } from '../../../../ClientUtils'; import { emptyFunction } from '../../../../Utils'; import { Doc, DocListCast, Field, FieldType, NumListCast, Opt, StrListCast } from '../../../../fields/Doc'; +import { AclAdmin, AclAugment, AclEdit } from '../../../../fields/DocSymbols'; import { InkTool } from '../../../../fields/InkField'; import { List } from '../../../../fields/List'; +import { PrefetchProxy } from '../../../../fields/Proxy'; import { Cast, CsvCast, DocCast, NumCast, StrCast } from '../../../../fields/Types'; import { CsvField } from '../../../../fields/URLField'; -import { GetEffectiveAcl, TraceMobx, inheritParentAcls } from '../../../../fields/util'; +import { GetEffectiveAcl, TraceMobx } from '../../../../fields/util'; +import { GPTCallType, gptAPICall } from '../../../apis/gpt/GPT'; import { DocUtils } from '../../../documents/DocUtils'; import { DocumentType } from '../../../documents/DocumentTypes'; import { Docs } from '../../../documents/Documents'; +import { LinkManager } from '../../../util/LinkManager'; import { UndoManager, undoable } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; import { ViewBoxAnnotatableComponent } from '../../DocComponent'; import { MarqueeAnnotator } from '../../MarqueeAnnotator'; import { PinProps } from '../../PinFuncs'; import { SidebarAnnos } from '../../SidebarAnnos'; +import { CollectionFreeFormView } from '../../collections/collectionFreeForm'; import { AnchorMenu } from '../../pdf/AnchorMenu'; import { GPTPopup, GPTPopupMode } from '../../pdf/GPTPopup/GPTPopup'; import { DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; import { FocusViewOptions } from '../FocusViewOptions'; import './DataVizBox.scss'; +import { Col, DataVizTemplateInfo, DocCreatorMenu, LayoutType, TemplateFieldSize, TemplateFieldType } from './DocCreatorMenu'; import { Histogram } from './components/Histogram'; import { LineChart } from './components/LineChart'; import { PieChart } from './components/PieChart'; import { TableBox } from './components/TableBox'; -import { LinkManager } from '../../../util/LinkManager'; -import { Col, DataVizTemplateInfo, DataVizTemplateLayout, DocCreatorMenu, TemplateFieldSize, LayoutType, TemplateFieldType } from './DocCreatorMenu'; -import { CollectionFreeFormView, MarqueeView } from '../../collections/collectionFreeForm'; -import { PrefetchProxy } from '../../../../fields/Proxy'; -import { AclAdmin, AclAugment, AclEdit } from '../../../../fields/DocSymbols'; -import { template } from 'lodash'; -import { data } from 'jquery'; -import { listSpec } from '../../../../fields/Schema'; -import { ObjectField } from '../../../../fields/ObjectField'; -import { Id } from '../../../../fields/FieldSymbols'; -import { GPTCallType, gptAPICall } from '../../../apis/gpt/GPT'; -import { TbSortDescendingShapes } from 'react-icons/tb'; export enum DataVizView { TABLE = 'table', @@ -65,7 +58,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { @observable _marqueeing: number[] | undefined = undefined; @observable _savedAnnotations = new ObservableMap(); @observable _specialHighlightedRow: number | undefined = undefined; - @observable GPTSummary: ObservableMap | undefined = undefined; + @observable GPTSummary: ObservableMap | undefined = undefined; @observable colsInfo: ObservableMap = new ObservableMap(); @observable _GPTLoading: boolean = false; @@ -121,12 +114,9 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { const records = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey]).url.href); this._urlError = false; return records?.filter(record => Object.keys(record).some(key => record[key])) ?? []; - } catch (e){ + } catch { this._urlError = true; - const data: { [key: string]: string; }[] = [ - { error: "Data not found"}, - ]; - return data; + return [{ error: 'Data not found' }] as { [key: string]: string }[]; } } @@ -153,70 +143,73 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { @action setSpecialHighlightedRow = (row: number | undefined) => { this._specialHighlightedRow = row; - } + }; @action setColumnType = (colTitle: string, type: TemplateFieldType) => { const colInfo = this.colsInfo.get(colTitle); - if (colInfo) { + if (colInfo) { colInfo.type = type; } else { - this.colsInfo.set(colTitle, {title: colTitle, desc: '', type: type, sizes: [TemplateFieldSize.MEDIUM]}) + this.colsInfo.set(colTitle, { title: colTitle, desc: '', type: type, sizes: [TemplateFieldSize.MEDIUM] }); } - } + }; @action modifyColumnSizes = (colTitle: string, size: TemplateFieldSize, valid: boolean) => { const column = this.colsInfo.get(colTitle); - if (column) { + if (column) { if (!valid && column.sizes.includes(size)) { column.sizes.splice(column.sizes.indexOf(size), 1); } else if (valid && !column.sizes.includes(size)) { column.sizes.push(size); } } else { - this.colsInfo.set(colTitle, {title: colTitle, desc: '', type: TemplateFieldType.UNSET, sizes: [size]}) + this.colsInfo.set(colTitle, { title: colTitle, desc: '', type: TemplateFieldType.UNSET, sizes: [size] }); } - } + }; @action setColumnTitle = (colTitle: string, newTitle: string) => { const colInfo = this.colsInfo.get(colTitle); - if (colInfo) { + if (colInfo) { colInfo.title = newTitle; - console.log(colInfo.title) + console.log(colInfo.title); } else { - this.colsInfo.set(colTitle, {title: newTitle, desc: '', type: TemplateFieldType.UNSET, sizes: []}) + this.colsInfo.set(colTitle, { title: newTitle, desc: '', type: TemplateFieldType.UNSET, sizes: [] }); } - } + }; @action setColumnDesc = (colTitle: string, desc: string) => { const colInfo = this.colsInfo.get(colTitle); if (colInfo) { - if (!desc) { colInfo.desc = this.GPTSummary?.get(colTitle)?.desc ?? ''; } - else { colInfo.desc = desc; } + if (!desc) { + colInfo.desc = this.GPTSummary?.get(colTitle)?.desc ?? ''; + } else { + colInfo.desc = desc; + } } else { - this.colsInfo.set(colTitle, {title: colTitle, desc: desc, type: TemplateFieldType.UNSET, sizes: []}) + this.colsInfo.set(colTitle, { title: colTitle, desc: desc, type: TemplateFieldType.UNSET, sizes: [] }); } - } + }; @action setColumnDefault = (colTitle: string, cont: string) => { const colInfo = this.colsInfo.get(colTitle); if (colInfo) { colInfo.defaultContent = cont; } else { - this.colsInfo.set(colTitle, {title: colTitle, desc: '', type: TemplateFieldType.UNSET, sizes: [], defaultContent: cont}) + this.colsInfo.set(colTitle, { title: colTitle, desc: '', type: TemplateFieldType.UNSET, sizes: [], defaultContent: cont }); } - } + }; @action // pinned / linked anchor doc includes selected rows, graph titles, and graph colors - restoreView = (data: Doc) => { + restoreView = (viewData: Doc) => { // const changedView = data.config_dataViz && this.dataVizView !== data.config_dataViz && (this.layoutDoc._dataViz = data.config_dataViz); // const changedAxes = data.config_dataVizAxes && this.axes.join('') !== StrListCast(data.config_dataVizAxes).join('') && (this.layoutDoc._dataViz_axes = new List(StrListCast(data.config_dataVizAxes))); - this.layoutDoc.dataViz_selectedRows = Field.Copy(data.dataViz_selectedRows); - this.layoutDoc.dataViz_histogram_barColors = Field.Copy(data.dataViz_histogram_barColors); - this.layoutDoc.dataViz_histogram_defaultColor = data.dataViz_histogram_defaultColor; - this.layoutDoc.dataViz_pie_sliceColors = Field.Copy(data.dataViz_pie_sliceColors); + this.layoutDoc.dataViz_selectedRows = Field.Copy(viewData.dataViz_selectedRows); + this.layoutDoc.dataViz_histogram_barColors = Field.Copy(viewData.dataViz_histogram_barColors); + this.layoutDoc.dataViz_histogram_defaultColor = viewData.dataViz_histogram_defaultColor; + this.layoutDoc.dataViz_pie_sliceColors = Field.Copy(viewData.dataViz_pie_sliceColors); Object.keys(this.layoutDoc).forEach(key => { if (key.startsWith('dataViz_histogram_title') || key.startsWith('dataViz_lineChart_title') || key.startsWith('dataViz_pieChart_title')) { - this.layoutDoc['_' + key] = data[key]; + this.layoutDoc['_' + key] = viewData[key]; } }); return true; @@ -354,7 +347,9 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { componentDidMount() { this._props.setContentViewBox?.(this); - if (!this._urlError) { if (!DataVizBox.dataset.has(CsvCast(this.dataDoc[this.fieldKey]).url.href)) this.fetchData() }; + if (!this._urlError) { + if (!DataVizBox.dataset.has(CsvCast(this.dataDoc[this.fieldKey]).url.href)) this.fetchData(); + } this._disposers.datavis = reaction( () => { if (this.layoutDoc.dataViz_schemaLive === undefined) this.layoutDoc.dataViz_schemaLive = true; @@ -516,14 +511,14 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { DocCreatorMenu.Instance.toggleDisplay(x, y); DocCreatorMenu.Instance.setDataViz(this); DocCreatorMenu.Instance.setTemplateDocs(this.getPossibleTemplates()); - } + }; - specificContextMenu = (x: number, y: number): void => { + specificContextMenu = (e: MouseEventHandler) => { const cm = ContextMenu.Instance; const options = cm.findByDescription('Options...'); const optionItems = options?.subitems ?? []; optionItems.push({ description: `Analyze with AI`, event: () => this.askGPT(), icon: 'lightbulb' }); - optionItems.push({ description: `Create documents`, event: () => this.openDocCreatorMenu(x, y), icon: 'table-cells' }); + optionItems.push({ description: `Create documents`, event: () => this.openDocCreatorMenu(e.pageX, e.pageY), icon: 'table-cells' }); !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'eye' }); }; @@ -533,19 +528,19 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { GPTPopup.Instance.createFilteredDoc = this.createFilteredDoc; GPTPopup.Instance.setDataJson(''); GPTPopup.Instance.setMode(GPTPopupMode.DATA); - const data = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey]).url.href); - GPTPopup.Instance.setDataJson(JSON.stringify(data)); + const csvdata = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey]).url.href); + GPTPopup.Instance.setDataJson(JSON.stringify(csvdata)); GPTPopup.Instance.generateDataAnalysis(); }); getColSummary = (): string => { - let possibleIds: number[] = this.records.map((_, index) => index); + const possibleIds: number[] = this.records.map((_, index) => index); for (let i = possibleIds.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [possibleIds[i], possibleIds[j]] = [possibleIds[j], possibleIds[i]]; } - + const rowsToCheck = possibleIds.slice(0, Math.min(10, this.records.length)); let prompt: string = 'Col titles: '; @@ -553,37 +548,37 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { const cols = Array.from(Object.keys(this.records[0])).filter(header => header !== '' && header !== undefined); cols.forEach((col, i) => { - prompt += `Col #${i}: ${col} ------` - }) + prompt += `Col #${i}: ${col} ------`; + }); - prompt += '----------- Rows: ' + prompt += '----------- Rows: '; - rowsToCheck.forEach((row, i) => { - prompt += `Row #${row}: ` + rowsToCheck.forEach(row => { + prompt += `Row #${row}: `; cols.forEach(col => { - prompt += `${col}: ${this.records[row][col]} -----` - }) - }) + prompt += `${col}: ${this.records[row][col]} -----`; + }); + }); return prompt; - } + }; updateColDefaults = () => { - let possibleIds: number[] = this.records.map((_, index) => index); + const possibleIds: number[] = this.records.map((_, index) => index); for (let i = possibleIds.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [possibleIds[i], possibleIds[j]] = [possibleIds[j], possibleIds[i]]; } - + const rowToCheck = possibleIds[0]; const cols = Array.from(Object.keys(this.records[0])).filter(header => header !== '' && header !== undefined); - cols.forEach(col => { - this.setColumnDefault(col, `${this.records[rowToCheck][col]}`) + cols.forEach(col => { + this.setColumnDefault(col, `${this.records[rowToCheck][col]}`); }); - } + }; updateGPTSummary = async () => { this._GPTLoading = true; @@ -594,15 +589,12 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { const cols = Array.from(Object.keys(this.records[0])).filter(header => header !== '' && header !== undefined); cols.forEach(col => { - if (!this.colsInfo.get(col)) this.colsInfo.set(col, {title: col, desc: '', sizes: [], type: TemplateFieldType.UNSET}); + if (!this.colsInfo.get(col)) this.colsInfo.set(col, { title: col, desc: '', sizes: [], type: TemplateFieldType.UNSET }); }); try { - const [res1, res2] = await Promise.all([ - gptAPICall(prompt, GPTCallType.VIZSUM), - gptAPICall('Info:' + prompt, GPTCallType.VIZSUM2) - ]); - + const [res1, res2] = await Promise.all([gptAPICall(prompt, GPTCallType.VIZSUM), gptAPICall('Info:' + prompt, GPTCallType.VIZSUM2)]); + if (res1) { this.GPTSummary = new ObservableMap(); const descs: { [col: string]: string } = JSON.parse(res1); @@ -611,10 +603,10 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { if (!this.colsInfo.get(key)?.desc) this.setColumnDesc(key, val); } } - + if (res2) { !this.GPTSummary && (this.GPTSummary = new ObservableMap()); - const info: { [col: string]: { type: TemplateFieldType, size: TemplateFieldSize } } = JSON.parse(res2); + const info: { [col: string]: { type: TemplateFieldType; size: TemplateFieldSize } } = JSON.parse(res2); for (const [key, val] of Object.entries(info)) { const colSummary = this.GPTSummary.get(key); if (colSummary) { @@ -628,30 +620,29 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { } catch (err) { console.error(err); } - - } + }; getPossibleTemplates = (): Doc[] => { const linkedDocs: Doc[] = LinkManager.Instance.getAllRelatedLinks(this.Document).map(d => DocCast(LinkManager.getOppositeAnchor(d, this.Document))); const linkedCollections: Doc[] = linkedDocs.filter(doc => doc.type === 'config').map(doc => DocCast(doc.annotationOn)); const isColumnTitle = (title: string): boolean => { const colTitles: string[] = Object.keys(this.records[0]); - for (let i = 0; i < colTitles.length; ++i){ + for (let i = 0; i < colTitles.length; ++i) { if (colTitles[i] === title) { return true; } } return false; - } + }; const isValidTemplate = (collection: Doc) => { const childDocs = DocListCast(collection[Doc.LayoutFieldKey(collection)]); - for (let i = 0; i < childDocs.length; ++i){ + for (let i = 0; i < childDocs.length; ++i) { if (isColumnTitle(String(childDocs[i].title))) return true; } return false; - } + }; return linkedCollections.filter(col => isValidTemplate(col)); - } + }; ApplyTemplateTo = (templateDoc: Doc, target: Doc, targetKey: string, titleTarget: string | undefined) => { if (!Doc.AreProtosEqual(target[targetKey] as Doc, templateDoc)) { @@ -664,14 +655,14 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { } } return target; - } + }; applyLayout = (templateInfo: DataVizTemplateInfo, docs: Doc[]) => { if (templateInfo.layout.type === LayoutType.Stacked) return; const columns: number = templateInfo.columns; const xGap: number = templateInfo.layout.xMargin; const yGap: number = templateInfo.layout.yMargin; - const repeat: number = templateInfo.layout.repeat; + // const repeat: number = templateInfo.layout.repeat; const startX: number = templateInfo.referencePos.x; const startY: number = templateInfo.referencePos.y; const templWidth = Number(templateInfo.doc._width); @@ -682,8 +673,8 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { let curX: number = startX; let curY: number = startY; - while (docsChanged < docs.length){ - while (i < columns && docsChanged < docs.length){ + while (docsChanged < docs.length) { + while (i < columns && docsChanged < docs.length) { docs[docsChanged].x = curX; docs[docsChanged].y = curY; curX += templWidth + xGap; @@ -695,27 +686,29 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { curX = startX; curY += templHeight + yGap; } - } + }; // @action addSavedLayout = (layout: DataVizTemplateLayout) => { // const saved = Cast(this.layoutDoc.dataViz_savedTemplates, listSpec('RefField')); - + // } @action createDocsFromTemplate = (templateInfo: DataVizTemplateInfo) => { if (!templateInfo.doc) return; const mainCollection = this.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView; - const fields: string[] = Array.from(Object.keys(this.records[0])); + const fields: string[] = Array.from(Object.keys(this.records[0])); const selectedRows = NumListCast(this.layoutDoc.dataViz_selectedRows); const docs: Doc[] = selectedRows.map(row => { - const values: String[] = []; + const values: string[] = []; fields.forEach(col => values.push(this.records[row][col])); const proto = new Doc(); proto.author = ClientUtils.CurrentUserEmail(); - values.forEach((val, i) => {proto[fields[i]] = val as FieldType}); - + values.forEach((val, i) => { + proto[fields[i]] = val as FieldType; + }); + const target = Doc.MakeDelegate(proto); const targetKey = StrCast(templateInfo.doc!.layout_fieldKey, 'layout'); const applied = this.ApplyTemplateTo(templateInfo.doc!, target, targetKey, templateInfo.doc!.title + `${row}`); @@ -728,7 +721,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { docs.forEach(doc => mainCollection.addDocument(doc)); this.applyLayout(templateInfo, docs); - } + }; /** * creates a new dataviz document filter from this one @@ -783,7 +776,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { transform: `scale(${scale})`, position: 'absolute', }} - onContextMenu={(e) => this.specificContextMenu(e.pageX, e.pageY)} + onContextMenu={this.specificContextMenu} onWheel={e => e.stopPropagation()} ref={this._mainCont}>
diff --git a/src/client/views/nodes/DocumentIcon.tsx b/src/client/views/nodes/DocumentIcon.tsx index 0b94ae4f7..9769ecb3d 100644 --- a/src/client/views/nodes/DocumentIcon.tsx +++ b/src/client/views/nodes/DocumentIcon.tsx @@ -1,5 +1,5 @@ import { Tooltip } from '@mui/material'; -import { action, makeObservable, observable } from 'mobx'; +import { makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { factory } from 'typescript'; @@ -18,14 +18,14 @@ interface DocumentIconProps { @observer export class DocumentIcon extends ObservableReactComponent { @observable _hovered = false; - constructor(props: any) { + constructor(props: DocumentIconProps) { super(props); makeObservable(this); } render() { const { view } = this._props; - const { left, top, right, bottom } = view.getBounds || { left: 0, top: 0, right: 0, bottom: 0 }; + const { left, top, bottom } = view.getBounds || { left: 0, top: 0, right: 0, bottom: 0 }; return (
{ pointerEvents: 'all', position: 'absolute', background: SnappingManager.userBackgroundColor, - transform: `translate(${left}px, ${bottom - (bottom - top)/2}px)`, //**!** + transform: `translate(${left}px, ${bottom - (bottom - top) / 2}px)`, //**!** }}> {StrCast(this._props.view.Document?.title)}
}>

d{this._props.index}

@@ -44,7 +44,7 @@ export class DocumentIcon extends ObservableReactComponent { } } -@observer +@observer export class DocumentIconContainer extends React.Component { public static getTransformer(): Transformer { const usedDocuments = new Set(); diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index ba85bfb68..741d63909 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -138,7 +138,7 @@ export class FieldView extends React.Component { const field = this.fieldval; // prettier-ignore if (field instanceof Doc) return

{field.title?.toString()}

; - if (field === undefined) return

{''}

; + if (field === undefined) return

; if (field instanceof DateField) return

{field.date.toLocaleString()}

; if (field instanceof List) return
{field.map(f => Field.toString(f)).join(', ')}
; if (field instanceof WebField) return

{Field.toString(field.url.href)}

; diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index cfcf76b12..8974cccaf 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -2,7 +2,7 @@ import { Property } from 'csstype'; import { action, computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -//import * as textfit from 'textfit'; +import * as textfit from 'textfit'; import { Field, FieldType } from '../../../fields/Doc'; import { BoolCast, NumCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; @@ -96,7 +96,7 @@ export class LabelBox extends ViewBoxBaseComponent() { this._timeout = setTimeout(() => this.fitTextToBox(r)); return textfitParams; } - //textfit(r, textfitParams); + textfit(r, textfitParams); } return textfitParams; }; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index c1367aa0b..0d7914a82 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1498,7 +1498,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent this._editorView!.focus()); // not sure why setTimeout is needed but editing dashFieldView's doesn't work without it. - } // add user mark for any first character that was typed since the user mark that gets set in KeyPress won't have been called yet. @@ -2087,7 +2086,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent
); - } } -- cgit v1.2.3-70-g09d2 From 695a757e1d5d3469a9871b0760c9dedeb073a489 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 4 Oct 2024 21:45:42 -0400 Subject: from last --- src/client/views/ContextMenu.tsx | 5 +- src/client/views/ContextMenuItem.tsx | 3 +- src/client/views/EditableView.tsx | 57 +++++++++++----------- src/client/views/ScriptingRepl.scss | 2 - .../collectionSchema/SchemaCellField.tsx | 17 ++++--- .../views/nodes/DataVizBox/components/TableBox.tsx | 18 ++++--- 6 files changed, 52 insertions(+), 50 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 98087e224..4b67ef704 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -1,6 +1,3 @@ -/* eslint-disable react/no-array-index-key */ -/* eslint-disable react/jsx-props-no-spreading */ -/* eslint-disable default-param-last */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, IReactionDisposer, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; @@ -277,4 +274,4 @@ export class ContextMenu extends ObservableReactComponent<{ noexpand?: boolean } this._selectedIndex = Math.min(this.flatItems.length - 1, this._selectedIndex); } }; -} \ No newline at end of file +} diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index 610032225..6f8f41bdd 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/jsx-props-no-spreading */ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, makeObservable, observable, runInAction } from 'mobx'; @@ -95,4 +94,4 @@ export class ContextMenuItem extends ObservableReactComponent ); return this.props.event || this._props.noexpand ? this.renderItem(submenu) :
{submenu}
; } -} \ No newline at end of file +} diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index 9722b2d4b..612ecee62 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -7,7 +7,6 @@ import { DocumentIconContainer } from './nodes/DocumentIcon'; import { FieldView, FieldViewProps } from './nodes/FieldView'; import { ObservableReactComponent } from './ObservableReactComponent'; import { OverlayView } from './OverlayView'; -import { Padding } from 'browndash-components'; import { SchemaFieldType } from './collections/collectionSchema/SchemaColumnHeader'; export interface EditableProps { @@ -90,7 +89,7 @@ export class EditableView extends ObservableReactComponent { this._overlayDisposer?.(); this._overlayDisposer = OverlayView.Instance.addElement(, { x: 0, y: 0 }); this._props.highlightCells?.(this._props.GetValue() ?? ''); - } + } }); } else { this._overlayDisposer?.(); @@ -200,7 +199,7 @@ export class EditableView extends ObservableReactComponent { } } }; - + @action finalizeEdit(value: string, shiftDown: boolean, lostFocus: boolean, enterKey: boolean) { if (this._props.SetValue(value, shiftDown, enterKey)) { @@ -235,7 +234,7 @@ export class EditableView extends ObservableReactComponent { setIsEditing = (value: boolean) => { this._editing = value; return this._editing; - } + }; renderEditor() { return this._props.autosuggestProps ? ( @@ -254,11 +253,11 @@ export class EditableView extends ObservableReactComponent { onChange: this._props.autosuggestProps.onChange, }} /> - ) : ( this._props.oneLine !== false && this._props.GetValue()?.toString().indexOf('\n') === -1 ? ( + ) : this._props.oneLine !== false && this._props.GetValue()?.toString().indexOf('\n') === -1 ? ( { this._inputref = r; }} // prettier-ignore - style={{ display: this._props.display, overflow: 'auto', fontSize: this._props.fontSize, minWidth: 20, background: this._props.background}} + style={{ display: this._props.display, overflow: 'auto', fontSize: this._props.fontSize, minWidth: 20, background: this._props.background }} placeholder={this._props.placeholder} onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true, false)} defaultValue={this._props.GetValue()} @@ -284,39 +283,41 @@ export class EditableView extends ObservableReactComponent { onClick={this.stopPropagation} onPointerUp={this.stopPropagation} /> - )); + ); } staticDisplay = () => { let toDisplay; const gval = this._props.GetValue()?.replace(/\n/g, '\\r\\n'); - if (this._props.schemaFieldType === SchemaFieldType.Header){ - toDisplay = + if (this._props.schemaFieldType === SchemaFieldType.Header) { + toDisplay = ( + + ); } else { - toDisplay = ( - { - // eslint-disable-next-line react/jsx-props-no-spreading - this._props.fieldContents ? : this.props.contents ? this._props.contents?.valueOf() : '' as any - } - ) + toDisplay = ( + + {this._props.fieldContents ? : (this.props.contents ?? '')} + + ); } return toDisplay; - } + }; render() { const gval = this._props.GetValue()?.replace(/\n/g, '\\r\\n'); - if ((this._editing && gval !== undefined)) { + if (this._editing && gval !== undefined) { return this._props.sizeToContent ? (
{this.renderEditor()}
diff --git a/src/client/views/ScriptingRepl.scss b/src/client/views/ScriptingRepl.scss index 5fe176920..adc82238e 100644 --- a/src/client/views/ScriptingRepl.scss +++ b/src/client/views/ScriptingRepl.scss @@ -35,8 +35,6 @@ opacity: 0.3; } - - .scriptingObject-icon { padding: 3px; cursor: pointer; diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx index 84e7b62bf..ce41b2758 100644 --- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx +++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx @@ -27,6 +27,7 @@ export interface SchemaCellFieldProps { oneLine?: boolean; Document: Doc; fieldKey: string; + // eslint-disable-next-line no-use-before-define refSelectModeInfo: { enabled: boolean; currEditing: SchemaCellField | undefined }; highlightCells?: (text: string) => void; GetValue(): string | undefined; @@ -301,13 +302,14 @@ export class SchemaCellField extends ObservableReactComponent this.setupRefSelect(this.refSelectConditionMet), 0); break; case ' ': - e.stopPropagation(); - let cursorPos = 0; - if (this.cursorPosition !== null) cursorPos = this.cursorPosition + 1; - setTimeout(() => { - this.setContent(this._unrenderedContent); - setTimeout(() => this.setCursorPosition(cursorPos)); - }, 0); + { + e.stopPropagation(); + const cursorPos = this.cursorPosition !== null ? this.cursorPosition + 1 : 0; + setTimeout(() => { + this.setContent(this._unrenderedContent); + setTimeout(() => this.setCursorPosition(cursorPos)); + }, 0); + } break; case 'u': // for some reason 'u' otherwise exits the editor e.stopPropagation(); @@ -318,7 +320,6 @@ export class SchemaCellField extends ObservableReactComponent { ? 'darkred' : this._props.axes.length > 3 && this._props.axes[1] === col ? 'darkblue' - : this._props.axes.lastElement() === col || (this._props.axes.length > 3 && this._props.axes[2] === col) + : this._props.axes.lastElement() === col || (this._props.axes.length > 3 && this._props.axes[2] === col) ? 'darkcyan' : undefined, background: this.settingTitle @@ -427,7 +426,7 @@ export class TableBox extends ObservableReactComponent { ? '#Fbdbdb' : this._props.axes.lastElement() === col || (this._props.axes.length > 2 && this._props.axes[1] === col) ? '#c6ebf7' - : this._props.axes.lastElement() === col || (this._props.axes.length > 3 && this._props.axes[2] === col) + : this._props.axes.lastElement() === col || (this._props.axes.length > 3 && this._props.axes[2] === col) ? '#c2f0f4' : undefined, fontWeight: 'bolder', @@ -448,8 +447,15 @@ export class TableBox extends ObservableReactComponent { className={`tableBox-row ${this.columns[0]}`} onClick={e => this.tableRowClick(e, rowId)} style={{ - background: rowId === this._props.specHighlightedRow ? 'lightblue' : NumListCast(this._props.layoutDoc.dataViz_highlitedRows).includes(rowId) ? 'lightYellow' : NumListCast(this._props.layoutDoc.dataViz_selectedRows).includes(rowId) ? 'lightgrey' : '', - border: rowId === this._props.specHighlightedRow ? `solid 3px ${Colors.MEDIUM_BLUE}` : '' + background: + rowId === this._props.specHighlightedRow + ? 'lightblue' + : NumListCast(this._props.layoutDoc.dataViz_highlitedRows).includes(rowId) + ? 'lightYellow' + : NumListCast(this._props.layoutDoc.dataViz_selectedRows).includes(rowId) + ? 'lightgrey' + : '', + border: rowId === this._props.specHighlightedRow ? `solid 3px ${Colors.MEDIUM_BLUE}` : '', }}> {this.columns.map(col => { let colSelected = false; -- cgit v1.2.3-70-g09d2 From 2012b3ade1d4644115e3a59cf0a1deec07e23637 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 4 Oct 2024 21:51:25 -0400 Subject: from last --- src/client/views/EditableView.tsx | 1 - src/client/views/ScriptingRepl.tsx | 3 +-- src/client/views/collections/collectionSchema/SchemaCellField.tsx | 4 ++-- 3 files changed, 3 insertions(+), 5 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index 612ecee62..41079045b 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -239,7 +239,6 @@ export class EditableView extends ObservableReactComponent { renderEditor() { return this._props.autosuggestProps ? ( { this.maybeScrollToBottom(); return; } - const result = undoable(() => script.run({}, e => this.commands.push({ command: this.commandString, result: e as string })), 'run:' + this.commandString)(); + const result = undoable(() => script.run({}, err => this.commands.push({ command: this.commandString, result: err })), 'run:' + this.commandString)(); if (result.success) { this.commands.push({ command: this.commandString, result: result.result }); this.commandsHistory.push(this.commandString); diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx index ce41b2758..3924ed087 100644 --- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx +++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx @@ -155,8 +155,8 @@ export class SchemaCellField extends ObservableReactComponent { - chunkedText = chunkedText.replace(match, this.generateSpan(match, cells.get(match))); + matches.forEach(m => { + chunkedText = chunkedText.replace(m, this.generateSpan(m, cells.get(m))); }); return chunkedText; -- cgit v1.2.3-70-g09d2