import React = require("react"); import { library } from '@fortawesome/fontawesome-svg-core'; import { faCog, faPlus, faSortDown, faSortUp, faTable } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, untracked } from "mobx"; import { observer } from "mobx-react"; import ReactTable, { CellInfo, Column, ComponentPropsGetterR, Resize, SortingRule } from "react-table"; import "react-table/react-table.css"; import { Doc, DocListCast, Field, Opt } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; import { ComputedField } from "../../../new_fields/ScriptField"; import { Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types"; import { Docs, DocumentOptions } from "../../documents/Documents"; import { DocumentType } from "../../documents/DocumentTypes"; import { Gateway } from "../../northstar/manager/Gateway"; import { CompileScript, Transformer, ts } from "../../util/Scripting"; import { Transform } from "../../util/Transform"; import { undoBatch } from "../../util/UndoManager"; import { COLLECTION_BORDER_WIDTH } from '../../views/globalCssVariables.scss'; import { ContextMenu } from "../ContextMenu"; import '../DocumentDecorations.scss'; import { CellProps, CollectionSchemaCell, CollectionSchemaCheckboxCell, CollectionSchemaDocCell, CollectionSchemaNumberCell, CollectionSchemaStringCell } from "./CollectionSchemaCells"; import { CollectionSchemaAddColumnHeader, CollectionSchemaHeader } from "./CollectionSchemaHeaders"; import { MovableColumn, MovableRow } from "./CollectionSchemaMovableTableHOC"; import "./CollectionSchemaView.scss"; import { CollectionSubView } from "./CollectionSubView"; import { CollectionView } from "./CollectionView"; import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView"; library.add(faCog, faPlus, faSortUp, faSortDown); library.add(faTable); // bcz: need to add drag and drop of rows and columns. This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657 export enum ColumnType { Any, Number, String, Boolean, Doc, } // this map should be used for keys that should have a const type of value const columnTypes: Map = new Map([ ["title", ColumnType.String], ["x", ColumnType.Number], ["y", ColumnType.Number], ["width", ColumnType.Number], ["height", ColumnType.Number], ["nativeWidth", ColumnType.Number], ["nativeHeight", ColumnType.Number], ["isPrototype", ColumnType.Boolean], ["page", ColumnType.Number], ["curPage", ColumnType.Number], ["currentTimecode", ColumnType.Number], ["zIndex", ColumnType.Number] ]); @observer export class CollectionSchemaView extends CollectionSubView(doc => doc) { private _mainCont?: HTMLDivElement; private _startPreviewWidth = 0; private DIVIDER_WIDTH = 4; @observable previewScript: string = ""; @observable previewDoc: Doc | undefined = undefined; @observable private _node: HTMLDivElement | null = null; @observable private _focusedTable: Doc = this.props.Document; @computed get previewWidth() { return () => NumCast(this.props.Document.schemaPreviewWidth); } @computed get previewHeight() { return () => this.props.PanelHeight() - 2 * this.borderWidth; } @computed get tableWidth() { return this.props.PanelWidth() - 2 * this.borderWidth - this.DIVIDER_WIDTH - this.previewWidth(); } @computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); } private createTarget = (ele: HTMLDivElement) => { this._mainCont = ele; super.CreateDropTarget(ele); } isFocused = (doc: Doc): boolean => this.props.isSelected() && doc === this._focusedTable; @action setFocused = (doc: Doc) => this._focusedTable = doc; @action setPreviewDoc = (doc: Doc) => this.previewDoc = doc; @undoBatch @action setPreviewScript = (script: string) => this.previewScript = script //toggles preview side-panel of schema @action toggleExpander = () => { this.props.Document.schemaPreviewWidth = this.previewWidth() === 0 ? Math.min(this.tableWidth / 3, 200) : 0; } onDividerDown = (e: React.PointerEvent) => { this._startPreviewWidth = this.previewWidth(); e.stopPropagation(); e.preventDefault(); document.addEventListener("pointermove", this.onDividerMove); document.addEventListener('pointerup', this.onDividerUp); } @action onDividerMove = (e: PointerEvent): void => { const nativeWidth = this._mainCont!.getBoundingClientRect(); const minWidth = 40; const maxWidth = 1000; const movedWidth = this.props.ScreenToLocalTransform().transformDirection(nativeWidth.right - e.clientX, 0)[0]; const width = movedWidth < minWidth ? minWidth : movedWidth > maxWidth ? maxWidth : movedWidth; this.props.Document.schemaPreviewWidth = width; } @action onDividerUp = (e: PointerEvent): void => { document.removeEventListener("pointermove", this.onDividerMove); document.removeEventListener('pointerup', this.onDividerUp); if (this._startPreviewWidth === this.previewWidth()) { this.toggleExpander(); } } onPointerDown = (e: React.PointerEvent): void => { if (e.button === 0 && !e.altKey && !e.ctrlKey && !e.metaKey) { if (this.props.isSelected(true)) e.stopPropagation(); else { this.props.select(false); } } } @computed get previewDocument(): Doc | undefined { return this.previewDoc ? (this.previewScript && this.previewScript !== "this" ? FieldValue(Cast(this.previewDoc[this.previewScript], Doc)) : this.previewDoc) : undefined; } getPreviewTransform = (): Transform => { return this.props.ScreenToLocalTransform().translate(- this.borderWidth - this.DIVIDER_WIDTH - this.tableWidth, - this.borderWidth); } @computed get dividerDragger() { return this.previewWidth() === 0 ? (null) :
; } @computed get previewPanel() { const layoutDoc = this.previewDocument ? Doc.expandTemplateLayout(this.previewDocument, this.props.DataDoc) : undefined; return
; } @computed get schemaTable() { return ; } @computed public get schemaToolbar() { return
Show Preview
; } render() { return
this.props.active(true) && e.stopPropagation()} onDrop={e => this.onDrop(e, {})} ref={this.createTarget}> {this.schemaTable}
{this.dividerDragger} {!this.previewWidth() ? (null) : this.previewPanel}
; } } export interface SchemaTableProps { Document: Doc; // child doc dataDoc?: Doc; PanelHeight: () => number; PanelWidth: () => number; childDocs?: Doc[]; CollectionView: Opt; ContainingCollectionView: Opt; ContainingCollectionDoc: Opt; fieldKey: string; renderDepth: number; deleteDocument: (document: Doc) => boolean; addDocument: (document: Doc) => boolean; moveDocument: (document: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean; ScreenToLocalTransform: () => Transform; active: (outsideReaction: boolean) => boolean; onDrop: (e: React.DragEvent, options: DocumentOptions, completed?: (() => void) | undefined) => void; addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean; pinToPres: (document: Doc) => void; isSelected: (outsideReaction?: boolean) => boolean; isFocused: (document: Doc) => boolean; setFocused: (document: Doc) => void; setPreviewDoc: (document: Doc) => void; } @observer export class SchemaTable extends React.Component { private DIVIDER_WIDTH = 4; @observable _headerIsEditing: boolean = false; @observable _cellIsEditing: boolean = false; @observable _focusedCell: { row: number, col: number } = { row: 0, col: 0 }; @observable _openCollections: Array = []; @computed get previewWidth() { return () => NumCast(this.props.Document.schemaPreviewWidth); } @computed get previewHeight() { return () => this.props.PanelHeight() - 2 * this.borderWidth; } @computed get tableWidth() { return this.props.PanelWidth() - 2 * this.borderWidth - this.DIVIDER_WIDTH - this.previewWidth(); } @computed get columns() { return Cast(this.props.Document.schemaColumns, listSpec(SchemaHeaderField), []); } set columns(columns: SchemaHeaderField[]) { this.props.Document.schemaColumns = new List(columns); } @computed get childDocs() { if (this.props.childDocs) return this.props.childDocs; const doc = this.props.dataDoc ? this.props.dataDoc : this.props.Document; return DocListCast(doc[this.props.fieldKey]); } set childDocs(docs: Doc[]) { const doc = this.props.dataDoc ? this.props.dataDoc : this.props.Document; doc[this.props.fieldKey] = new List(docs); } @computed get textWrappedRows() { return Cast(this.props.Document.textwrappedSchemaRows, listSpec("string"), []); } set textWrappedRows(textWrappedRows: string[]) { this.props.Document.textwrappedSchemaRows = new List(textWrappedRows); } @computed get resized(): { id: string, value: number }[] { return this.columns.reduce((resized, shf) => { (shf.width > -1) && resized.push({ id: shf.heading, value: shf.width }); return resized; }, [] as { id: string, value: number }[]); } @computed get sorted(): SortingRule[] { return this.columns.reduce((sorted, shf) => { shf.desc && sorted.push({ id: shf.heading, desc: shf.desc }); return sorted; }, [] as SortingRule[]); } @computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); } @computed get tableColumns(): Column[] { const possibleKeys = this.documentKeys.filter(key => this.columns.findIndex(existingKey => existingKey.heading.toUpperCase() === key.toUpperCase()) === -1); const columns: Column[] = []; const tableIsFocused = this.props.isFocused(this.props.Document); const focusedRow = this._focusedCell.row; const focusedCol = this._focusedCell.col; const isEditable = !this._headerIsEditing; if (this.childDocs.reduce((found, doc) => found || doc.type === "collection", false)) { columns.push( { expander: true, Header: "", width: 30, Expander: (rowInfo) => { if (rowInfo.original.type === "collection") { if (rowInfo.isExpanded) return
this.onCloseCollection(rowInfo.original)}>
; if (!rowInfo.isExpanded) return
this.onExpandCollection(rowInfo.original)}>
; } else { return null; } } } ); } const cols = this.columns.map(col => { const header = c.heading)} keyType={this.getColumnType(col)} typeConst={columnTypes.get(col.heading) !== undefined} onSelect={this.changeColumns} setIsEditing={this.setHeaderIsEditing} deleteColumn={this.deleteColumn} setColumnType={this.setColumnType} setColumnSort={this.setColumnSort} setColumnColor={this.setColumnColor} />; return { Header: , accessor: (doc: Doc) => doc ? doc[col.heading] : 0, id: col.heading, Cell: (rowProps: CellInfo) => { const rowIndex = rowProps.index; const columnIndex = this.columns.map(c => c.heading).indexOf(rowProps.column.id!); const isFocused = focusedRow === rowIndex && focusedCol === columnIndex && tableIsFocused; const props: CellProps = { row: rowIndex, col: columnIndex, rowProps: rowProps, isFocused: isFocused, changeFocusedCellByIndex: this.changeFocusedCellByIndex, CollectionView: this.props.CollectionView, ContainingCollection: this.props.ContainingCollectionView, Document: this.props.Document, fieldKey: this.props.fieldKey, renderDepth: this.props.renderDepth, addDocTab: this.props.addDocTab, pinToPres: this.props.pinToPres, moveDocument: this.props.moveDocument, setIsEditing: this.setCellIsEditing, isEditable: isEditable, setPreviewDoc: this.props.setPreviewDoc, setComputed: this.setComputed, getField: this.getField, }; const colType = this.getColumnType(col); if (colType === ColumnType.Number) return ; if (colType === ColumnType.String) return ; if (colType === ColumnType.Boolean) return ; if (colType === ColumnType.Doc) return ; return ; }, minWidth: 200, }; }); columns.push(...cols); columns.push({ Header: , accessor: (doc: Doc) => 0, id: "add", Cell: (rowProps: CellInfo) => <>, width: 28, resizable: false }); return columns; } constructor(props: SchemaTableProps) { super(props); // convert old schema columns (list of strings) into new schema columns (list of schema header fields) const oldSchemaColumns = Cast(this.props.Document.schemaColumns, listSpec("string"), []); if (oldSchemaColumns && oldSchemaColumns.length && typeof oldSchemaColumns[0] !== "object") { const newSchemaColumns = oldSchemaColumns.map(i => typeof i === "string" ? new SchemaHeaderField(i, "#f1efeb") : i); this.props.Document.schemaColumns = new List(newSchemaColumns); } } componentDidMount() { document.addEventListener("keydown", this.onKeyDown); } componentWillUnmount() { document.removeEventListener("keydown", this.onKeyDown); } tableAddDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => { return Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before); } private getTrProps: ComponentPropsGetterR = (state, rowInfo) => { return !rowInfo ? {} : { ScreenToLocalTransform: this.props.ScreenToLocalTransform, addDoc: this.tableAddDoc, removeDoc: this.props.deleteDocument, rowInfo, rowFocused: !this._headerIsEditing && rowInfo.index === this._focusedCell.row && this.props.isFocused(this.props.Document), textWrapRow: this.toggleTextWrapRow, rowWrapped: this.textWrappedRows.findIndex(id => rowInfo.original[Id] === id) > -1 }; } private getTdProps: ComponentPropsGetterR = (state, rowInfo, column, instance) => { if (!rowInfo || column) return {}; const row = rowInfo.index; //@ts-ignore const col = this.columns.map(c => c.heading).indexOf(column!.id); const isFocused = this._focusedCell.row === row && this._focusedCell.col === col && this.props.isFocused(this.props.Document); // TODO: editing border doesn't work :( return { style: { border: !this._headerIsEditing && isFocused ? "2px solid rgb(255, 160, 160)" : "1px solid #f1efeb" } }; } @action onCloseCollection = (collection: Doc): void => { const index = this._openCollections.findIndex(col => col === collection[Id]); if (index > -1) this._openCollections.splice(index, 1); } @action onExpandCollection = (collection: Doc) => this._openCollections.push(collection[Id]); @action setCellIsEditing = (isEditing: boolean) => this._cellIsEditing = isEditing; @action setHeaderIsEditing = (isEditing: boolean) => this._headerIsEditing = isEditing; onPointerDown = (e: React.PointerEvent): void => { this.props.setFocused(this.props.Document); if (e.button === 0 && !e.altKey && !e.ctrlKey && !e.metaKey && this.props.isSelected(true)) { e.stopPropagation(); } } @action onKeyDown = (e: KeyboardEvent): void => { if (!this._cellIsEditing && !this._headerIsEditing && this.props.isFocused(this.props.Document)) {// && this.props.isSelected(true)) { const direction = e.key === "Tab" ? "tab" : e.which === 39 ? "right" : e.which === 37 ? "left" : e.which === 38 ? "up" : e.which === 40 ? "down" : ""; this._focusedCell = this.changeFocusedCellByDirection(direction, this._focusedCell.row, this._focusedCell.col); const pdoc = FieldValue(this.childDocs[this._focusedCell.row]); pdoc && this.props.setPreviewDoc(pdoc); } } changeFocusedCellByDirection = (direction: string, curRow: number, curCol: number) => { switch (direction) { case "tab": return { row: (curRow + 1 === this.childDocs.length ? 0 : curRow + 1), col: curCol + 1 === this.columns.length ? 0 : curCol + 1 }; case "right": return { row: curRow, col: curCol + 1 === this.columns.length ? curCol : curCol + 1 }; case "left": return { row: curRow, col: curCol === 0 ? curCol : curCol - 1 }; case "up": return { row: curRow === 0 ? curRow : curRow - 1, col: curCol }; case "down": return { row: curRow + 1 === this.childDocs.length ? curRow : curRow + 1, col: curCol }; } return this._focusedCell; } @action changeFocusedCellByIndex = (row: number, col: number): void => { if (this._focusedCell.row !== row || this._focusedCell.col !== col) { this._focusedCell = { row: row, col: col }; } this.props.setFocused(this.props.Document); } @undoBatch createRow = () => { const newDoc = Docs.Create.TextDocument("", { title: "", _width: 100, _height: 30 }); this.props.addDocument(newDoc); } @undoBatch @action createColumn = () => { let index = 0; let found = this.columns.findIndex(col => col.heading.toUpperCase() === "New field".toUpperCase()) > -1; while (found) { index++; found = this.columns.findIndex(col => col.heading.toUpperCase() === ("New field (" + index + ")").toUpperCase()) > -1; } this.columns.push(new SchemaHeaderField(`New field ${index ? "(" + index + ")" : ""}`, "#f1efeb")); } @undoBatch @action deleteColumn = (key: string) => { const columns = this.columns; if (columns === undefined) { this.columns = new List([]); } else { const index = columns.map(c => c.heading).indexOf(key); if (index > -1) { columns.splice(index, 1); this.columns = columns; } } } @undoBatch @action changeColumns = (oldKey: string, newKey: string, addNew: boolean) => { const columns = this.columns; if (columns === undefined) { this.columns = new List([new SchemaHeaderField(newKey, "f1efeb")]); } else { if (addNew) { columns.push(new SchemaHeaderField(newKey, "f1efeb")); this.columns = columns; } else { const index = columns.map(c => c.heading).indexOf(oldKey); if (index > -1) { const column = columns[index]; column.setHeading(newKey); columns[index] = column; this.columns = columns; } } } } getColumnType = (column: SchemaHeaderField): ColumnType => { // added functionality to convert old column type stuff to new column type stuff -syip if (column.type && column.type !== 0) { return column.type; } if (columnTypes.get(column.heading)) { column.type = columnTypes.get(column.heading)!; return columnTypes.get(column.heading)!; } const typesDoc = FieldValue(Cast(this.props.Document.schemaColumnTypes, Doc)); if (!typesDoc) { column.type = ColumnType.Any; return ColumnType.Any; } column.type = NumCast(typesDoc[column.heading]); return NumCast(typesDoc[column.heading]); } @undoBatch setColumnType = (columnField: SchemaHeaderField, type: ColumnType): void => { if (columnTypes.get(columnField.heading)) return; const columns = this.columns; const index = columns.indexOf(columnField); if (index > -1) { columnField.setType(NumCast(type)); columns[index] = columnField; this.columns = columns; } // const typesDoc = FieldValue(Cast(this.props.Document.schemaColumnTypes, Doc)); // if (!typesDoc) { // let newTypesDoc = new Doc(); // newTypesDoc[key] = type; // this.props.Document.schemaColumnTypes = newTypesDoc; // return; // } else { // typesDoc[key] = type; // } } @undoBatch setColumnColor = (columnField: SchemaHeaderField, color: string): void => { const columns = this.columns; const index = columns.indexOf(columnField); if (index > -1) { columnField.setColor(color); columns[index] = columnField; this.columns = columns; // need to set the columns to trigger rerender } } @action setColumns = (columns: SchemaHeaderField[]) => this.columns = columns @undoBatch reorderColumns = (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columnsValues: SchemaHeaderField[]) => { const columns = [...columnsValues]; const oldIndex = columns.indexOf(toMove); const relIndex = columns.indexOf(relativeTo); const newIndex = (oldIndex > relIndex && !before) ? relIndex + 1 : (oldIndex < relIndex && before) ? relIndex - 1 : relIndex; if (oldIndex === newIndex) return; columns.splice(newIndex, 0, columns.splice(oldIndex, 1)[0]); this.columns = columns; } @undoBatch @action setColumnSort = (columnField: SchemaHeaderField, descending: boolean | undefined) => { const columns = this.columns; const index = columns.findIndex(c => c.heading === columnField.heading); const column = columns[index]; column.setDesc(descending); columns[index] = column; this.columns = columns; } get documentKeys() { const docs = this.childDocs; const keys: { [key: string]: boolean } = {}; // bcz: ugh. this is untracked since otherwise a large collection of documents will blast the server for all their fields. // then as each document's fields come back, we update the documents _proxies. Each time we do this, the whole schema will be // invalidated and re-rendered. This workaround will inquire all of the document fields before the options button is clicked. // then by the time the options button is clicked, all of the fields should be in place. If a new field is added while this menu // is displayed (unlikely) it won't show up until something else changes. //TODO Types untracked(() => docs.map(doc => Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => keys[key] = false)))); this.columns.forEach(key => keys[key.heading] = true); return Array.from(Object.keys(keys)); } @undoBatch @action toggleTextwrap = async () => { const textwrappedRows = Cast(this.props.Document.textwrappedSchemaRows, listSpec("string"), []); if (textwrappedRows.length) { this.props.Document.textwrappedSchemaRows = new List([]); } else { const docs = DocListCast(this.props.Document[this.props.fieldKey]); const allRows = docs instanceof Doc ? [docs[Id]] : docs.map(doc => doc[Id]); this.props.Document.textwrappedSchemaRows = new List(allRows); } } @action toggleTextWrapRow = (doc: Doc): void => { const textWrapped = this.textWrappedRows; const index = textWrapped.findIndex(id => doc[Id] === id); index > -1 ? textWrapped.splice(index, 1) : textWrapped.push(doc[Id]); this.textWrappedRows = textWrapped; } @computed get reactTable() { const children = this.childDocs; const hasCollectionChild = children.reduce((found, doc) => found || doc.type === "collection", false); const expandedRowsList = this._openCollections.map(col => children.findIndex(doc => doc[Id] === col).toString()); const expanded = {}; //@ts-ignore expandedRowsList.forEach(row => expanded[row] = true); const rerender = [...this.textWrappedRows]; // TODO: get component to rerender on text wrap change without needign to console.log :(((( return (row.original.type !== "collection") ? (null) :
} />; } onResizedChange = (newResized: Resize[], event: any) => { const columns = this.columns; newResized.forEach(resized => { const index = columns.findIndex(c => c.heading === resized.id); const column = columns[index]; column.setWidth(resized.value); columns[index] = column; }); this.columns = columns; } onContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 // ContextMenu.Instance.addItem({ description: "Make DB", event: this.makeDB, icon: "table" }); ContextMenu.Instance.addItem({ description: "Toggle text wrapping", event: this.toggleTextwrap, icon: "table" }) } } @action makeDB = async () => { let csv: string = this.columns.reduce((val, col) => val + col + ",", ""); csv = csv.substr(0, csv.length - 1) + "\n"; const self = this; this.childDocs.map(doc => { csv += self.columns.reduce((val, col) => val + (doc[col.heading] ? doc[col.heading]!.toString() : "0") + ",", ""); csv = csv.substr(0, csv.length - 1) + "\n"; }); csv.substring(0, csv.length - 1); const dbName = StrCast(this.props.Document.title); const res = await Gateway.Instance.PostSchema(csv, dbName); if (self.props.CollectionView && self.props.CollectionView.props.addDocument) { const schemaDoc = await Docs.Create.DBDocument("https://www.cs.brown.edu/" + dbName, { title: dbName }, { dbDoc: self.props.Document }); if (schemaDoc) { //self.props.CollectionView.props.addDocument(schemaDoc, false); self.props.Document.schemaDoc = schemaDoc; } } } getField = (row: number, col?: number) => { const docs = this.childDocs; row = row % docs.length; while (row < 0) row += docs.length; const columns = this.columns; const doc = docs[row]; if (col === undefined) { return doc; } if (col >= 0 && col < columns.length) { const column = this.columns[col].heading; return doc[column]; } return undefined; } createTransformer = (row: number, col: number): Transformer => { const self = this; const captures: { [name: string]: Field } = {}; const transformer: ts.TransformerFactory = context => { return root => { function visit(node: ts.Node) { node = ts.visitEachChild(node, visit, context); if (ts.isIdentifier(node)) { const isntPropAccess = !ts.isPropertyAccessExpression(node.parent) || node.parent.expression === node; const isntPropAssign = !ts.isPropertyAssignment(node.parent) || node.parent.name !== node; if (isntPropAccess && isntPropAssign) { if (node.text === "$r") { return ts.createNumericLiteral(row.toString()); } else if (node.text === "$c") { return ts.createNumericLiteral(col.toString()); } else if (node.text === "$") { if (ts.isCallExpression(node.parent)) { // captures.doc = self.props.Document; // captures.key = self.props.fieldKey; } } } } return node; } return ts.visitNode(root, visit); }; }; // const getVars = () => { // return { capturedVariables: captures }; // }; return { transformer, /*getVars*/ }; } setComputed = (script: string, doc: Doc, field: string, row: number, col: number): boolean => { script = `const $ = (row:number, col?:number) => { if(col === undefined) { return (doc as any)[key][row + ${row}]; } return (doc as any)[key][row + ${row}][(doc as any).schemaColumns[col + ${col}].heading]; } return ${script}`; const compiled = CompileScript(script, { params: { this: Doc.name }, capturedVariables: { doc: this.props.Document, key: this.props.fieldKey }, typecheck: true, transformer: this.createTransformer(row, col) }); if (compiled.compiled) { doc[field] = new ComputedField(compiled); return true; } return false; } render() { return
this.props.active(true) && e.stopPropagation()} onDrop={e => this.props.onDrop(e, {})} onContextMenu={this.onContextMenu} > {this.reactTable}
this.createRow()}>+ new
; } }