import { IconButton, Size } from '@dash/components'; import { computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import * as React from 'react'; import { returnFalse, setupMoveUpEvents } from '../../../../ClientUtils'; import { emptyFunction } from '../../../../Utils'; import { Doc } from '../../../../fields/Doc'; import { BoolCast } from '../../../../fields/Types'; import { Transform } from '../../../util/Transform'; import { undoable } from '../../../util/UndoManager'; import { ViewBoxBaseComponent } from '../../DocComponent'; import { FieldView, FieldViewProps } from '../../nodes/FieldView'; import { OpenWhere } from '../../nodes/OpenWhere'; import { CollectionSchemaView } from './CollectionSchemaView'; import './CollectionSchemaView.scss'; import { SchemaTableCell } from './SchemaTableCell'; import { ContextMenu } from '../../ContextMenu'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 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 * to each SchemaCell, passing down necessary functions are props. */ interface SchemaRowBoxProps extends FieldViewProps { rowIndex: number; } @observer export class SchemaRowBox extends ViewBoxBaseComponent() { public static LayoutString(fieldKey: string, rowIndex: number) { return FieldView.LayoutString(SchemaRowBox, fieldKey).replace('fieldKey', `rowIndex={${rowIndex}} fieldKey`); } private _ref: HTMLDivElement | null = null; @observable _childrenAddedToSchema: boolean = false; constructor(props: SchemaRowBoxProps) { super(props); makeObservable(this); } bounds = () => this._ref?.getBoundingClientRect(); @computed get schemaView() { return this.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionSchemaView; } @computed get schemaDoc() { return this.schemaView.Document; } componentDidMount(): void { this._props.setContentViewBox?.(this); } openContextMenu = (x: number, y: number) => { ContextMenu.Instance.clearItems(); ContextMenu.Instance.addItem({ description: this.Document._lockedSchemaEditing ? 'Unlock field editing' : 'Lock field editing', event: () => (this.Document._lockedSchemaEditing = !this.Document._lockedSchemaEditing), icon: this.Document._lockedSchemaEditing ? 'lock-open' : 'lock', }); ContextMenu.Instance.addItem({ description: 'Open preview', event: () => this._props.addDocTab(this.Document, OpenWhere.addRight), icon: 'magnifying-glass', }); ContextMenu.Instance.addItem({ description: `Close doc`, event: () => this.schemaView.removeDoc(this.Document), icon: 'minus', }); // Defunct option to add child docs of collections to the main schema // const childDocs = DocListCast(this.Document[Doc.LayoutFieldKey(this.Document)]) // if (this.Document.type === 'collection' && childDocs.length) { // ContextMenu.Instance.addItem({ // description: this.Document._childrenSharedWithSchema ? 'Remove children from schema' : 'Add children to schema', // event: () => { // 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 menuInfos() { const infos: Array = []; if (this.Document._lockedSchemaEditing) infos.push('lock'); if (this.Document._childrenSharedWithSchema) infos.push('star'); return infos; } isolatedSelection = (doc: Doc) => 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: 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); eqHighlightFunc = (text: string) => { const info = this.schemaView.findCellRefs(text); const cells: HTMLDivElement[] = []; info.forEach(inf => { cells.push(this.schemaView.getCellElement(inf[0], inf[1])); }); return cells; }; render() { return (
this.setCursorIndex(e.clientY)} style={{ height: this._props.PanelHeight() }} ref={(row: HTMLDivElement | null) => { row && this.schemaView?.addRowRef?.(this.Document, row); this._ref = row; }}>
} size={Size.XSMALL} color={'black'} onPointerDown={e => setupMoveUpEvents( this, e, returnFalse, emptyFunction, undoable(clickEv => { clickEv.stopPropagation(); this.openContextMenu(e.clientX, e.clientY); }, 'open actions menu') ) } />
{this.menuInfos.map(icn => ( ))}
{this.schemaView?.columnKeys?.map((key, index) => ( { const ind = index === this.schemaView.columnKeys.length - 1 ? this.schemaView.columnKeys.length - 3 : index; const x = this.schemaView?.displayColumnWidths.reduce((p, c, i) => (i <= ind ? p + c : p), 0); const y = (this._props.rowIndex ?? 0) * this._props.PanelHeight(); return new Transform(x + CollectionSchemaView._rowMenuWidth, y, 1); }} /> ))}
); } }