diff options
| author | bobzel <zzzman@gmail.com> | 2024-10-04 21:35:22 -0400 |
|---|---|---|
| committer | bobzel <zzzman@gmail.com> | 2024-10-04 21:35:22 -0400 |
| commit | 9323ad30103b474e95610e97eb92916a0cf71f7b (patch) | |
| tree | 72f20d339139018bde242121eaba16e9e939c93b /src/client/views/collections/collectionSchema | |
| parent | 2e883e481fa2064983bcd16425118c1abb55cedb (diff) | |
more lint fixes to schema view changes.
Diffstat (limited to 'src/client/views/collections/collectionSchema')
4 files changed, 385 insertions, 336 deletions
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 0076caaf8..aef97e723 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -1,12 +1,11 @@ -/* eslint-disable no-restricted-syntax */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { IconButton, Popup, PopupTrigger, Size, Type } from 'browndash-components'; -import { IReactionDisposer, ObservableMap, action, autorun, computed, makeObservable, observable, observe, override, reaction, runInAction } from 'mobx'; +import { IconButton, Size } from 'browndash-components'; +import { IReactionDisposer, Lambda, ObservableMap, action, computed, makeObservable, observable, observe, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { ClientUtils, returnEmptyString, returnFalse, returnIgnore, returnNever, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../ClientUtils'; import { emptyFunction } from '../../../../Utils'; -import { Doc, DocListCast, Field, FieldType, IdToDoc, NumListCast, Opt, StrListCast } from '../../../../fields/Doc'; +import { Doc, DocListCast, Field, FieldType, NumListCast, Opt, StrListCast } from '../../../../fields/Doc'; import { DocData } from '../../../../fields/DocSymbols'; import { Id } from '../../../../fields/FieldSymbols'; import { List } from '../../../../fields/List'; @@ -14,10 +13,13 @@ import { ColumnType } from '../../../../fields/SchemaHeaderField'; import { BoolCast, NumCast, StrCast } from '../../../../fields/Types'; import { DocUtils } from '../../../documents/DocUtils'; import { Docs, DocumentOptions, FInfo } from '../../../documents/Documents'; +import { DocumentManager } from '../../../util/DocumentManager'; import { DragManager } from '../../../util/DragManager'; import { dropActionType } from '../../../util/DropActionTypes'; +import { SnappingManager } from '../../../util/SnappingManager'; import { undoBatch, undoable } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; +import { ContextMenuProps } from '../../ContextMenuItem'; import { EditableView } from '../../EditableView'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { StyleProp } from '../../StyleProp'; @@ -28,25 +30,23 @@ import { FieldViewProps } from '../../nodes/FieldView'; import { FocusViewOptions } from '../../nodes/FocusViewOptions'; import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView'; import './CollectionSchemaView.scss'; +import { SchemaCellField } from './SchemaCellField'; import { SchemaColumnHeader } from './SchemaColumnHeader'; import { SchemaRowBox } from './SchemaRowBox'; -import { ContextMenuProps } from '../../ContextMenuItem'; -import { DocumentManager } from '../../../util/DocumentManager'; -import { SchemaCellField } from './SchemaCellField'; -import { SnappingManager } from '../../../util/SnappingManager'; /** * The schema view offers a spreadsheet-like interface for users to interact with documents. Within the schema, - * each doc is represented by its own row. Each column represents a field, for example the author or title fields. + * each doc is represented by its own row. Each column represents a field, for example the author or title fields. * Users can apply varoius filters and sorts to columns to change what is displayed. The schemaview supports equations for * cell linking. - * + * * This class supports the main functionality for choosing which docs to render in the view, applying visual - * updates to rows and columns (such as user dragging or sort-related highlighting), applying edits to multiple cells + * updates to rows and columns (such as user dragging or sort-related highlighting), applying edits to multiple cells * at once, and applying filters and sorts to columns. It contains SchemaRowBoxes (which themselves contain SchemaTableCells, * and SchemaCellFields) and SchemaColumnHeaders. */ +// eslint-disable-next-line @typescript-eslint/no-require-imports const { SCHEMA_NEW_NODE_HEIGHT } = require('../../global/globalCssVariables.module.scss'); // prettier-ignore export const FInfotoColType: { [key: string]: ColumnType } = { @@ -63,7 +63,7 @@ const defaultColumnKeys: string[] = ['title', 'type', 'author', 'author_date', ' @observer export class CollectionSchemaView extends CollectionSubView() { - private _keysDisposer: any; + private _keysDisposer?: Lambda; private _disposers: { [name: string]: IReactionDisposer } = {}; private _previewRef: HTMLDivElement | null = null; private _makeNewColumn: boolean = false; @@ -71,13 +71,14 @@ export class CollectionSchemaView extends CollectionSubView() { private _tableContentRef: HTMLDivElement | null = null; private _menuTarget = React.createRef<HTMLDivElement>(); 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<string, string[]>(); @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<string>(currKeys); + this.layoutDoc.schema_columnKeys = new List<string>(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<any> = []; - 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 ( - <div className="schema-column-menu" style={{ left: x, maxWidth: `${Math.max(this._colEles[this._columnMenuIndex ?? 0].offsetWidth, 150)}px` }}> + <div className="schema-column-menu" style={{ left: x, maxWidth: `${Math.max(this._colEles[this._columnMenuIndex ?? 0].offsetWidth, 150)}px` }}> {this.keysDropdown} </div> ); @@ -1095,13 +1100,7 @@ export class CollectionSchemaView extends CollectionSubView() { } return ( <div key={key} className="schema-filter-option"> - <input - type="checkbox" - onPointerDown={e => e.stopPropagation()} - onClick={e => e.stopPropagation()} - onChange={e => Doc.setDocFilter(this.Document, columnKey, key, e.target.checked ? 'check' : 'remove')} - checked={bool} - /> + <input type="checkbox" onPointerDown={e => e.stopPropagation()} onClick={e => e.stopPropagation()} onChange={e => Doc.setDocFilter(this.Document, columnKey, key, e.target.checked ? 'check' : 'remove')} checked={bool} /> <span style={{ paddingLeft: 4 }}>{key}</span> </div> ); @@ -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 ( - <div className="schema-filter-menu" style={{ left: x, maxWidth: `${Math.max(this._colEles[this._columnMenuIndex ?? 0].offsetWidth, 150)}px`}}> + <div className="schema-filter-menu" style={{ left: x, maxWidth: `${Math.max(this._colEles[this._columnMenuIndex ?? 0].offsetWidth, 150)}px` }}> <input className="schema-filter-input" type="text" value={this._filterSearchValue} onKeyDown={this.onFilterKeyDown} onChange={this.updateFilterSearch} onPointerDown={e => e.stopPropagation()} /> {this.renderFilterOptions} <div @@ -1129,13 +1128,13 @@ export class CollectionSchemaView extends CollectionSubView() { @action setColDrag = (beingDragged: boolean) => { this._colBeingDragged = beingDragged; !beingDragged && this.removeDragHighlight(); - } + }; @action updateMouseCoordinates = (e: React.PointerEvent<HTMLDivElement>) => { 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<HTMLDivElement>) => { @@ -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<Doc>)?.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 ( - <div className="collectionSchemaView" ref={(ele: HTMLDivElement | null) => this.createDashEventsTarget(ele)} - onDrop={this.onExternalDrop.bind(this)} - onPointerMove={e => this.onPointerMove(e)} - onPointerDown={() => {this.closeNewColumnMenu(); this.setColDrag(false)}}> + <div + className="collectionSchemaView" + ref={(ele: HTMLDivElement | null) => this.createDashEventsTarget(ele)} + onDrop={this.onExternalDrop.bind(this)} + onPointerMove={e => this.onPointerMove(e)} + onPointerDown={() => { + this.closeNewColumnMenu(); + this.setColDrag(false); + }}> <div ref={this._menuTarget} style={{ background: 'red', top: 0, left: 0, position: 'absolute', zIndex: 10000 }} /> <div className="schema-table" @@ -1310,30 +1313,29 @@ export class CollectionSchemaView extends CollectionSubView() { <div className="schema-header-row" style={{ height: this.rowHeightFunc() }}> <div className="row-menu" style={{ width: CollectionSchemaView._rowMenuWidth }}> <IconButton - tooltip="Add a new key" - icon={ <FontAwesomeIcon icon="plus" size='lg'/>} - 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={<FontAwesomeIcon icon="plus" size="lg" />} + size={Size.XSMALL} + color={'black'} + onPointerDown={e => + setupMoveUpEvents( + this, + e, + returnFalse, + emptyFunction, + undoable(clickEv => { + clickEv.stopPropagation(); + this.addColumn(); + }, 'add key to schema') + ) + } /> </div> {this.columnKeys.map((key, index) => ( <SchemaColumnHeader - // eslint-disable-next-line react/no-array-index-key //cleanupField={this.cleanupComputedField} ref={r => 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<CollectionSchemaV return ( <DocumentView key={this._props.doc[Id]} - // eslint-disable-next-line react/jsx-props-no-spreading {...this._props.schema._props} containerViewPath={this._props.schema.childContainerViewPath} LayoutTemplate={this._props.schema._props.childLayoutTemplate} @@ -1498,4 +1499,4 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP </div> ); } -}
\ 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<SchemaColumnHeaderProps> { - private _inputRef: EditableView | null = null; @observable _altTitle: string | undefined = undefined; @observable _showMenuIcon: boolean = false; @@ -58,18 +57,26 @@ export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHea return this._props.columnKeys[this._props.columnIndex]; } - constructor(props: SchemaColumnHeaderProps){ + constructor(props: SchemaColumnHeaderProps) { super(props); makeObservable(this); } - + getFinfo = computedFn((fieldKey: string) => 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<SchemaColumnHea const cursor = !readOnly ? 'text' : 'default'; const pointerEvents: 'all' | 'none' = 'all'; return { color, fieldProps, cursor, pointerEvents }; - } + }; @computed get editableView() { - const { color, fieldProps, pointerEvents } = this.renderProps(this._props); - - return <div className='schema-column-edit-wrapper' onPointerUp={() => { - SchemaColumnHeader.isDefaultField(this.fieldKey) && this.openKeyDropdown(); - this._props.schemaView.deselectAllCells(); - }} - style={{ - color, - width: '100%', - pointerEvents, - }}> - <EditableView - ref={r => {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 ( + <div + className="schema-column-edit-wrapper" + onPointerUp={() => { + 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, + }}> + <EditableView + ref={r => { + 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')} + /> </div> + ); } 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) ? - (<IconButton - icon={ <FontAwesomeIcon icon="trash" size='sm'/>} - 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') - ) - } - />) - : (<IconButton - icon={ <FontAwesomeIcon icon="caret-down" size='lg'/>} - 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) ? ( + <IconButton + icon={<FontAwesomeIcon icon="trash" size="sm" />} + 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') + ) + } + /> + ) : ( + <IconButton + icon={<FontAwesomeIcon icon="caret-down" size="lg" />} + 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 ( - <div - className="schema-column-header" - style={{ - width: this._props.columnWidths[this._props.columnIndex], - }} - onPointerEnter={() => {this.handlePointerEnter()}} - onPointerLeave={() => {this.handlePointerLeave()}} - onPointerDown={e => { - this.setupDrag(e); - setupMoveUpEvents( - this, - e, - () => {return this._inputRef?.setIsEditing(false) ?? false}, - emptyFunction, - emptyFunction, - ); - } + <div + className="schema-column-header" + style={{ + width: this._props.columnWidths[this._props.columnIndex], + }} + onPointerEnter={() => { + 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); - } - }}> - <div className="schema-column-resizer left" onPointerDown={e => this._props.resizeColumn(e, this._props.columnIndex, false)} /> + }}> + <div className="schema-column-resizer left" onPointerDown={e => this._props.resizeColumn(e, this._props.columnIndex, false)} /> - <div className="schema-header-text">{this.editableView}</div> + <div className="schema-header-text">{this.editableView}</div> - <div className="schema-header-menu"> - <div className="schema-header-button" style={{opacity: this.displayButton ? '1.0' : '0.0'}}> - {this.headerButton} - </div> - </div> - - <div className="schema-column-resizer right" onPointerDown={e => this._props.resizeColumn(e, this._props.columnIndex, true)} /> + <div className="schema-header-menu"> + <div className="schema-header-button" style={{ opacity: this.displayButton ? '1.0' : '0.0' }}> + {this.headerButton} + </div> </div> + + <div className="schema-column-resizer right" onPointerDown={e => this._props.resizeColumn(e, this._props.columnIndex, true)} /> + </div> ); } -}
\ 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<SchemaRowBoxProps>() { 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<SchemaRowBoxProps>() { // 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<SchemaRowBoxProps>() { 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<SchemaRowBoxProps>() { <div className="schema-row" onPointerDown={e => 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<SchemaRowBoxProps>() { style={{ width: CollectionSchemaView._rowMenuWidth, pointerEvents: !this._props.isContentActive() ? 'none' : undefined, - backgroundColor: this.menuBackgroundColor + backgroundColor: this.menuBackgroundColor, }}> <IconButton tooltip="Open actions menu" - icon={ <FontAwesomeIcon icon="caret-right" size='lg'/>} + icon={<FontAwesomeIcon icon="caret-right" size="lg" />} size={Size.XSMALL} color={'black'} onPointerDown={e => @@ -146,14 +154,16 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() { emptyFunction, undoable(clickEv => { clickEv.stopPropagation(); - this.openContextMenu(e.clientX, e.clientY) + this.openContextMenu(e.clientX, e.clientY); }, 'open actions menu') ) } /> - <div className="row-menu-infos"> - {this.menuInfos.map(icn => <FontAwesomeIcon className="row-infos-icon" icon={icn} size='2xs' />)} - </div> + <div className="row-menu-infos"> + {this.menuInfos.map(icn => ( + <FontAwesomeIcon key={icn.toString()} className="row-infos-icon" icon={icn} size="2xs" /> + ))} + </div> </div> <div className="row-cells"> {this.schemaView?.columnKeys?.map((key, index) => ( @@ -192,4 +202,4 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() { </div> ); } -}
\ 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<SchemaTableCellProps> { - // private _fieldRef: SchemaCellField | null = null; private _submittedValue: string = ''; @@ -96,9 +90,11 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro get lockedInteraction(){return (this.isDefault || this._props.Document._lockedSchemaEditing);} // prettier-ignore - get backgroundColor(){ - if (this.lockedInteraction) {return '#F5F5F5'} - return '' + get backgroundColor() { + if (this.lockedInteraction) { + return '#F5F5F5'; + } + return ''; } static addFieldDoc = (docs: Doc | Doc[] /* , where: OpenWhere */) => { @@ -110,7 +106,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro let protoCount = 0; let doc: Doc | undefined = Document; while (doc) { - if (Object.keys(doc).includes(fieldKey.replace(/^_/, ''))) break; + if (Object.keys(doc).includes(fieldKey.replace(/^_/, ''))) break; protoCount++; doc = DocCast(doc.proto); } @@ -149,28 +145,40 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro adjustSelfReference = (field: string) => { 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<SchemaTableCellPro this._props.finishEdit?.(); return true; } - const hasNoLayout = Doc.IsDataProto(fieldProps.Document) ? true : undefined; // the "delegate" is a a data document so never write to it's proto + const hasNoLayout = Doc.IsDataProto(fieldProps.Document) ? true : undefined; // the "delegate" is a a data document so never write to it's proto const ret = Doc.SetField(fieldProps.Document, this._props.fieldKey.replace(/^_/, ''), value, hasNoLayout); this._submittedValue = value; this._props.finishEdit?.(); @@ -245,8 +253,8 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro const sides: Array<string | undefined> = []; 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<SchemaTableCellPro className="schema-table-cell" onContextMenu={e => 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<SchemaTableCellPro } else !selectedCell(this._props) && this._props.selectCell(this._props.Document, this._props.col, shift, ctrl); } })} - 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}}> + 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} </div> ); @@ -524,4 +538,4 @@ export class SchemaEnumerationCell extends ObservableReactComponent<SchemaTableC </div> ); } -}
\ No newline at end of file +} |
