import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { returnEmptyFilter, returnFalse, returnZero, setupMoveUpEvents } from '../../../../ClientUtils'; import { emptyFunction } from '../../../../Utils'; import './CollectionSchemaView.scss'; import { EditableView } from '../../EditableView'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { DefaultStyleProvider, returnEmptyDocViewList } from '../../StyleProvider'; import { FieldViewProps } from '../../nodes/FieldView'; import { Doc, returnEmptyDoclist } from '../../../../fields/Doc'; import { dropActionType } from '../../../util/DropActionTypes'; import { Transform } from '../../../util/Transform'; import { SchemaTableCell } from './SchemaTableCell'; import { DocCast } from '../../../../fields/Types'; import { computedFn } from 'mobx-utils'; import { CollectionSchemaView } from './CollectionSchemaView'; import { undoable } from '../../../util/UndoManager'; import { IconButton, Size } from '@dash/components'; export enum SchemaFieldType { Header, Cell, } export interface SchemaColumnHeaderProps { Document: Doc; autoFocus?: boolean; columnKeys: string[]; columnWidths: number[]; columnIndex: number; schemaView: CollectionSchemaView; keysDropdown: React.JSX.Element; //cleanupField: (s: string) => string; isContentActive: (outsideReaction?: boolean | undefined) => boolean | undefined; setSort: (field: string | undefined, desc?: boolean) => void; removeColumn: (index: number) => void; rowHeight: () => number; resizeColumn: (e: React.PointerEvent, index: number, rightSide: boolean) => void; dragColumn: (e: PointerEvent, index: number) => boolean; openContextMenu: (x: number, y: number, index: number) => void; setColRef: (index: number, ref: HTMLDivElement) => void; rootSelected?: () => boolean; columnWidth: () => number; finishEdit?: () => void; // notify container that edit is over (eg. to hide view in DashFieldView) //transform: () => Transform; } @observer export class SchemaColumnHeader extends ObservableReactComponent { private _inputRef: EditableView | null = null; @observable _altTitle: string | undefined = undefined; @observable _showMenuIcon: boolean = false; @computed get fieldKey() { return this._props.columnKeys[this._props.columnIndex]; } 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); }; toggleEditing = (editing: boolean) => { this._inputRef?.setIsEditing(editing); this._inputRef?.setIsFocused(editing); }; @action setupDrag = (e: React.PointerEvent) => { this._props.isContentActive(true) && setupMoveUpEvents(this, e, moveEv => this._props.dragColumn(moveEv, this._props.columnIndex), emptyFunction, emptyFunction); }; renderProps = (props: SchemaColumnHeaderProps) => { const { columnKeys, columnWidth, Document } = props; const fieldKey = columnKeys[props.columnIndex]; const color = 'black'; const fieldProps: FieldViewProps = { childFilters: returnEmptyFilter, childFiltersByRanges: returnEmptyFilter, docViewPath: returnEmptyDocViewList, searchFilterDocs: returnEmptyDoclist, styleProvider: DefaultStyleProvider, isSelected: returnFalse, setHeight: returnFalse, select: emptyFunction, dragAction: dropActionType.move, renderDepth: 1, noSidebar: true, isContentActive: returnFalse, whenChildContentsActiveChanged: emptyFunction, ScreenToLocalTransform: Transform.Identity, focus: emptyFunction, addDocTab: SchemaTableCell.addFieldDoc, pinToPres: returnZero, Document: DocCast(Document.rootDocument, Document)!, fieldKey: fieldKey, PanelWidth: columnWidth, PanelHeight: props.rowHeight, rootSelected: props.rootSelected, }; const readOnly = this.getFinfo(fieldKey)?.readOnly ?? false; const cursor = !readOnly ? 'text' : 'default'; return { color, fieldProps, cursor }; }; @computed get editableView() { const { color, fieldProps } = this.renderProps(this._props); return (
{ SchemaColumnHeader.isDefaultField(this.fieldKey) && this.openKeyDropdown(); this._props.schemaView.deselectAllCells(); }} style={{ color, width: '100%', }}> { 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} inputString={true} inputStringPlaceholder={'Add key'} 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; }, 'edit column header')} />
); } public static isDefaultField = (key: string) => { const defaultPattern = /EmptyColumnKey/; 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') ) } /> ); return toRender; } @action handlePointerEnter = () => { this._showMenuIcon = true; } // prettier-ignore @action handlePointerLeave = () => { this._showMenuIcon = false; } // prettier-ignore @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 ); }} ref={col => { if (col) { this._props.setColRef(this._props.columnIndex, col); } }}>
this._props.resizeColumn(e, this._props.columnIndex, false)} />
{this.editableView}
{this.headerButton}
this._props.resizeColumn(e, this._props.columnIndex, true)} />
); } }