aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/CollectionSchemaView.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/collections/CollectionSchemaView.tsx')
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx1062
1 files changed, 743 insertions, 319 deletions
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 119aa7c19..08ab22725 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -1,18 +1,18 @@
import React = require("react");
import { library } from '@fortawesome/fontawesome-svg-core';
-import { faCog, faPlus } from '@fortawesome/free-solid-svg-icons';
+import { faCog, faPlus, faTable, faSortUp, faSortDown } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, observable, trace, untracked } from "mobx";
import { observer } from "mobx-react";
-import ReactTable, { CellInfo, ComponentPropsGetterR, ReactTableDefaults } from "react-table";
+import ReactTable, { CellInfo, ComponentPropsGetterR, ReactTableDefaults, TableCellRenderer, Column, RowInfo } from "react-table";
import "react-table/react-table.css";
import { emptyFunction, returnFalse, returnZero, returnOne } from "../../../Utils";
-import { Doc, DocListCast, DocListCastAsync, Field } from "../../../new_fields/Doc";
+import { Doc, DocListCast, DocListCastAsync, Field, FieldResult, Opt } from "../../../new_fields/Doc";
import { Id } from "../../../new_fields/FieldSymbols";
import { List } from "../../../new_fields/List";
import { listSpec } from "../../../new_fields/Schema";
-import { Cast, FieldValue, NumCast, StrCast, BoolCast } from "../../../new_fields/Types";
-import { Docs } from "../../documents/Documents";
+import { Docs, DocumentOptions } from "../../documents/Documents";
+import { Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types";
import { Gateway } from "../../northstar/manager/Gateway";
import { SetupDrag, DragManager } from "../../util/DragManager";
import { CompileScript, ts, Transformer } from "../../util/Scripting";
@@ -30,29 +30,36 @@ import { CollectionSubView } from "./CollectionSubView";
import { CollectionVideoView } from "./CollectionVideoView";
import { CollectionView } from "./CollectionView";
import { undoBatch } from "../../util/UndoManager";
+import { timesSeries } from "async";
+import { CollectionSchemaHeader, CollectionSchemaAddColumnHeader } from "./CollectionSchemaHeaders";
+import { CellProps, CollectionSchemaCell, CollectionSchemaNumberCell, CollectionSchemaStringCell, CollectionSchemaBooleanCell, CollectionSchemaCheckboxCell, CollectionSchemaDocCell } from "./CollectionSchemaCells";
+import { MovableColumn, MovableRow } from "./CollectionSchemaMovableTableHOC";
+import { SelectionManager } from "../../util/SelectionManager";
+import { DocumentManager } from "../../util/DocumentManager";
+import { ImageBox } from "../nodes/ImageBox";
import { ComputedField } from "../../../new_fields/ScriptField";
+import { SchemaHeaderField, RandomPastel } from "../../../new_fields/SchemaHeaderField";
-library.add(faCog);
-library.add(faPlus);
+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
-
-@observer
-class KeyToggle extends React.Component<{ keyName: string, checked: boolean, toggle: (key: string) => void }> {
- constructor(props: any) {
- super(props);
- }
-
- render() {
- return (
- <div key={this.props.keyName}>
- <input type="checkbox" checked={this.props.checked} onChange={() => this.props.toggle(this.props.keyName)} />
- {this.props.keyName}
- </div>
- );
- }
+export enum ColumnType {
+ Any,
+ Number,
+ String,
+ Boolean,
+ Doc,
+ // Checkbox
}
+// this map should be used for keys that should have a const type of value
+const columnTypes: Map<string, ColumnType> = 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], ["libraryBrush", ColumnType.Boolean], ["zIndex", ColumnType.Number]
+]);
@observer
export class CollectionSchemaView extends CollectionSubView(doc => doc) {
@@ -60,182 +67,384 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
private _startPreviewWidth = 0;
private DIVIDER_WIDTH = 4;
- @observable _columns: Array<string> = ["title", "data", "author"];
- @observable _selectedIndex = 0;
- @observable _columnsPercentage = 0;
- @observable _keys: string[] = [];
- @observable _newKeyName: string = "";
@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 columns() { return Cast(this.props.Document.schemaColumns, listSpec("string"), []); }
@computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); }
- @computed get tableColumns() {
- return this.columns.map(col => {
- const ref = React.createRef<HTMLParagraphElement>();
- return {
- Header: <p ref={ref} onPointerDown={SetupDrag(ref, () => this.onHeaderDrag(col), undefined, "copy")}>{col}</p>,
- accessor: (doc: Doc) => doc ? doc[col] : 0,
- id: col
- };
- });
+
+ private createTarget = (ele: HTMLDivElement) => {
+ this._mainCont = ele;
+ super.CreateDropTarget(ele);
}
- onHeaderDrag = (columnName: string) => {
- let schemaDoc = Cast(this.props.Document.schemaDoc, Doc);
- if (schemaDoc instanceof Doc) {
- let columnDocs = DocListCast(schemaDoc.data);
- if (columnDocs) {
- let ddoc = columnDocs.find(doc => doc.title === columnName);
- if (ddoc) {
- return ddoc;
- }
- }
+ // detectClick = (e: PointerEvent): void => {
+ // if (this._node && this._node.contains(e.target as Node)) {
+ // } else {
+ // this._isOpen = false;
+ // this.props.setIsEditing(false);
+ // }
+ // }
+
+ isFocused = (doc: Doc): boolean => {
+ if (!this.props.isSelected()) return false;
+ return doc === this._focusedTable;
+ }
+
+ @action
+ setFocused = (doc: Doc): void => {
+ this._focusedTable = doc;
+ }
+
+ @action
+ setPreviewDoc = (doc: Doc): void => {
+ this.previewDoc = doc;
+ }
+
+ //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 => {
+ let nativeWidth = this._mainCont!.getBoundingClientRect();
+ this.props.Document.schemaPreviewWidth = Math.min(nativeWidth.right - nativeWidth.left - 40,
+ this.props.ScreenToLocalTransform().transformDirection(nativeWidth.right - e.clientX, 0)[0]);
+ }
+ @action
+ onDividerUp = (e: PointerEvent): void => {
+ document.removeEventListener("pointermove", this.onDividerMove);
+ document.removeEventListener('pointerup', this.onDividerUp);
+ if (this._startPreviewWidth === this.previewWidth()) {
+ this.toggleExpander();
}
- return this.props.Document;
}
- getField(row: number, col?: number) {
- const docs = DocListCast(this.props.Document[this.props.fieldKey]);
- row = row % docs.length;
- while (row < 0) row += docs.length;
- const columns = this.columns;
- const doc = docs[row];
- if (col === undefined) {
- return doc;
+ onPointerDown = (e: React.PointerEvent): void => {
+ if (e.button === 0 && !e.altKey && !e.ctrlKey && !e.metaKey) {
+ if (this.props.isSelected()) e.stopPropagation();
+ else {
+ this.props.select(false);
+ }
}
- if (col >= 0 && col < columns.length) {
- const column = this.columns[col];
- return doc[column];
+ }
+
+ onWheel = (e: React.WheelEvent): void => {
+ if (this.props.active()) {
+ e.stopPropagation();
}
- return undefined;
}
- createTransformer = (row: number, col: number): Transformer => {
- const self = this;
- const captures: { [name: string]: Field } = {};
+ @computed
+ get previewDocument(): Doc | undefined {
+ let selected = this.previewDoc;
+ let pdc = selected ? (this.previewScript && this.previewScript !== "this" ? FieldValue(Cast(selected[this.previewScript], Doc)) : selected) : undefined;
+ return pdc;
+ }
- const transformer: ts.TransformerFactory<ts.SourceFile> = 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;
- }
- }
- }
- }
+ getPreviewTransform = (): Transform => {
+ return this.props.ScreenToLocalTransform().translate(- this.borderWidth - this.DIVIDER_WIDTH - this.tableWidth, - this.borderWidth);
+ }
- return node;
- }
- return ts.visitNode(root, visit);
- };
- };
+ @computed
+ get dividerDragger() {
+ return this.previewWidth() === 0 ? (null) :
+ <div className="collectionSchemaView-dividerDragger" onPointerDown={this.onDividerDown} style={{ width: `${this.DIVIDER_WIDTH}px` }} />;
+ }
- const getVars = () => {
- return { capturedVariables: captures };
- };
+ @computed
+ get previewPanel() {
+ let layoutDoc = this.previewDocument ? Doc.expandTemplateLayout(this.previewDocument, this.props.DataDoc) : undefined;
+ return <div ref={this.createTarget}>
+ <CollectionSchemaPreview
+ Document={layoutDoc}
+ DataDocument={this.previewDocument !== this.props.DataDoc ? this.props.DataDoc : undefined}
+ childDocs={this.childDocs}
+ renderDepth={this.props.renderDepth}
+ width={this.previewWidth}
+ height={this.previewHeight}
+ getTransform={this.getPreviewTransform}
+ CollectionView={this.props.CollectionView}
+ moveDocument={this.props.moveDocument}
+ addDocument={this.props.addDocument}
+ removeDocument={this.props.removeDocument}
+ active={this.props.active}
+ whenActiveChanged={this.props.whenActiveChanged}
+ addDocTab={this.props.addDocTab}
+ setPreviewScript={this.setPreviewScript}
+ previewScript={this.previewScript}
+ />
+ </div>;
+ }
+ @action
+ setPreviewScript = (script: string) => {
+ this.previewScript = script;
+ }
+
+ @computed
+ get schemaTable() {
+ return (
+ <SchemaTable
+ Document={this.props.Document}
+ PanelHeight={this.props.PanelHeight}
+ PanelWidth={this.props.PanelWidth}
+ childDocs={this.childDocs}
+ CollectionView={this.props.CollectionView}
+ ContainingCollectionView={this.props.ContainingCollectionView}
+ fieldKey={this.props.fieldKey}
+ renderDepth={this.props.renderDepth}
+ moveDocument={this.props.moveDocument}
+ ScreenToLocalTransform={this.props.ScreenToLocalTransform}
+ active={this.props.active}
+ onDrop={this.onDrop}
+ addDocTab={this.props.addDocTab}
+ isSelected={this.props.isSelected}
+ isFocused={this.isFocused}
+ setFocused={this.setFocused}
+ setPreviewDoc={this.setPreviewDoc}
+ deleteDocument={this.props.removeDocument}
+ dataDoc={this.props.DataDoc}
+ />
+ );
+ }
- return { transformer, getVars };
+ @computed
+ public get schemaToolbar() {
+ return (
+ <div className="collectionSchemaView-toolbar">
+ <div className="collectionSchemaView-toolbar-item">
+ <div id="preview-schema-checkbox-div"><input type="checkbox" key={"Show Preview"} checked={this.previewWidth() !== 0} onChange={this.toggleExpander} />Show Preview</div>
+ </div>
+ </div>
+ );
}
- 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}];
+ render() {
+ Doc.UpdateDocumentExtensionForField(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey);
+ // if (SelectionManager.SelectedDocuments().length > 0) console.log(StrCast(SelectionManager.SelectedDocuments()[0].Document.title));
+ // if (DocumentManager.Instance.getDocumentView(this.props.Document)) console.log(StrCast(this.props.Document.title), SelectionManager.IsSelected(DocumentManager.Instance.getDocumentView(this.props.Document)!))
+ return (
+ <div className="collectionSchemaView-container"
+ onPointerDown={this.onPointerDown} onWheel={this.onWheel} onDrop={(e: React.DragEvent) => this.onDrop(e, {})} ref={this.createTarget}>
+ {this.schemaTable}
+ {this.dividerDragger}
+ {!this.previewWidth() ? (null) : this.previewPanel}
+ </div>
+ );
+ }
+}
+
+export interface SchemaTableProps {
+ Document: Doc; // child doc
+ dataDoc?: Doc;
+ PanelHeight: () => number;
+ PanelWidth: () => number;
+ childDocs?: Doc[];
+ CollectionView: CollectionView | CollectionPDFView | CollectionVideoView;
+ ContainingCollectionView: Opt<CollectionView | CollectionPDFView | CollectionVideoView>;
+ fieldKey: string;
+ renderDepth: number;
+ deleteDocument: (document: Doc) => boolean;
+ moveDocument: (document: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean) => boolean;
+ ScreenToLocalTransform: () => Transform;
+ // CreateDropTarget: (ele: HTMLDivElement)=> void; // super createdriotarget
+ active: () => boolean;
+ onDrop: (e: React.DragEvent<Element>, options: DocumentOptions, completed?: (() => void) | undefined) => void;
+ addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => void;
+ isSelected: () => boolean;
+ isFocused: (document: Doc) => boolean;
+ setFocused: (document: Doc) => void;
+ setPreviewDoc: (document: Doc) => void;
+}
+
+@observer
+export class SchemaTable extends React.Component<SchemaTableProps> {
+ // private _mainCont?: HTMLDivElement;
+ private DIVIDER_WIDTH = 4;
+
+ @observable _headerIsEditing: boolean = false;
+ @observable _cellIsEditing: boolean = false;
+ @observable _focusedCell: { row: number, col: number } = { row: 0, col: 0 };
+ @observable _sortedColumns: Map<string, { id: string, desc: boolean }> = new Map();
+ @observable _openCollections: Array<string> = [];
+ @observable _textWrappedRows: Array<string> = [];
+ @observable private _node: HTMLDivElement | null = null;
+
+ @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() {
+ console.log("columns");
+ return Cast(this.props.Document.schemaColumns, listSpec(SchemaHeaderField), []);
+ }
+ @computed get childDocs() {
+ if (this.props.childDocs) return this.props.childDocs;
+
+ let doc = this.props.dataDoc ? this.props.dataDoc : this.props.Document;
+ return DocListCast(doc[this.props.fieldKey]);
+ }
+ set childDocs(docs: Doc[]) {
+ let doc = this.props.dataDoc ? this.props.dataDoc : this.props.Document;
+ doc[this.props.fieldKey] = new List<Doc>(docs);
+ }
+ set columns(columns: SchemaHeaderField[]) { this.props.Document.schemaColumns = new List<SchemaHeaderField>(columns); }
+ @computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); }
+ @computed get tableColumns(): Column<Doc>[] {
+ let possibleKeys = this.documentKeys.filter(key => this.columns.findIndex(existingKey => existingKey.heading.toUpperCase() === key.toUpperCase()) === -1);
+ let columns: Column<Doc>[] = [];
+ let tableIsFocused = this.props.isFocused(this.props.Document);
+ let focusedRow = this._focusedCell.row;
+ let focusedCol = this._focusedCell.col;
+ let isEditable = !this._headerIsEditing;// && this.props.isSelected();
+
+ // let cdoc = this.props.dataDoc ? this.props.dataDoc : this.props.Document;
+ // let children = DocListCast(cdoc[this.props.fieldKey]);
+ let children = this.childDocs;
+
+ if (children.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 <div className="collectionSchemaView-expander" onClick={() => this.onCloseCollection(rowInfo.original)}><FontAwesomeIcon icon={"sort-up"} size="sm" /></div>;
+ if (!rowInfo.isExpanded) return <div className="collectionSchemaView-expander" onClick={() => this.onExpandCollection(rowInfo.original)}><FontAwesomeIcon icon={"sort-down"} size="sm" /></div>;
+ } else {
+ return null;
+ }
+ }
}
- return (doc as any)[key][row + ${row}][(doc as any).schemaColumns[col + ${col}]];
- }
- return ${script}`;
- const compiled = CompileScript(script, { params: { this: Doc.name }, typecheck: true, transformer: this.createTransformer(row, col) });
- if (compiled.compiled) {
- doc[field] = new ComputedField(compiled);
- return true;
+ );
}
- return false;
+ let cols = this.columns.map(col => {
+ let header = <CollectionSchemaHeader
+ keyValue={col}
+ possibleKeys={possibleKeys}
+ existingKeys={this.columns.map(c => 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}
+ removeColumnSort={this.removeColumnSort}
+ />;
+
+ return {
+ Header: <MovableColumn columnRenderer={header} columnValue={col} allColumns={this.columns} reorderColumns={this.reorderColumns} ScreenToLocalTransform={this.props.ScreenToLocalTransform} />,
+ accessor: (doc: Doc) => doc ? doc[col.heading] : 0,
+ id: col.heading,
+ Cell: (rowProps: CellInfo) => {
+ let rowIndex = rowProps.index;
+ let columnIndex = this.columns.map(c => c.heading).indexOf(rowProps.column.id!);
+ let isFocused = focusedRow === rowIndex && focusedCol === columnIndex && tableIsFocused;
+
+ let 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,
+ moveDocument: this.props.moveDocument,
+ setIsEditing: this.setCellIsEditing,
+ isEditable: isEditable,
+ setPreviewDoc: this.props.setPreviewDoc,
+ setComputed: this.setComputed,
+ getField: this.getField,
+ };
+
+ let colType = this.getColumnType(col);
+ if (colType === ColumnType.Number) return <CollectionSchemaNumberCell {...props} />;
+ if (colType === ColumnType.String) return <CollectionSchemaStringCell {...props} />;
+ if (colType === ColumnType.Boolean) return <CollectionSchemaCheckboxCell {...props} />;
+ if (colType === ColumnType.Doc) return <CollectionSchemaDocCell {...props} />;
+ return <CollectionSchemaCell {...props} />;
+ },
+ minWidth: 200,
+ };
+ });
+ columns.push(...cols);
+
+ columns.push({
+ Header: <CollectionSchemaAddColumnHeader createColumn={this.createColumn} />,
+ accessor: (doc: Doc) => 0,
+ id: "add",
+ Cell: (rowProps: CellInfo) => <></>,
+ width: 28,
+ resizable: false
+ });
+ return columns;
+ }
+
+ // onHeaderDrag = (columnName: string) => {
+ // let schemaDoc = Cast(this.props.Document.schemaDoc, Doc);
+ // if (schemaDoc instanceof Doc) {
+ // let columnDocs = DocListCast(schemaDoc.data);
+ // if (columnDocs) {
+ // let ddoc = columnDocs.find(doc => doc.title === columnName);
+ // if (ddoc) {
+ // return ddoc;
+ // }
+ // }
+ // }
+ // return this.props.Document;
+ // }
+ constructor(props: SchemaTableProps) {
+ super(props);
+ // convert old schema columns (list of strings) into new schema columns (list of schema header fields)
+ let oldSchemaColumns = Cast(this.props.Document.schemaColumns, listSpec("string"), []);
+ if (oldSchemaColumns && oldSchemaColumns.length && typeof oldSchemaColumns[0] !== "object") {
+ console.log("REMAKING COLUMNs");
+ let newSchemaColumns = oldSchemaColumns.map(i => typeof i === "string" ? new SchemaHeaderField(i, "#f1efeb") : i);
+ this.props.Document.schemaColumns = new List<SchemaHeaderField>(newSchemaColumns);
+ }
}
- renderCell = (rowProps: CellInfo) => {
- let props: FieldViewProps = {
- Document: rowProps.original,
- DataDoc: rowProps.original,
- fieldKey: rowProps.column.id as string,
- fieldExt: "",
- ContainingCollectionView: this.props.CollectionView,
- isSelected: returnFalse,
- select: emptyFunction,
- renderDepth: this.props.renderDepth + 1,
- selectOnLoad: false,
- ScreenToLocalTransform: Transform.Identity,
- focus: emptyFunction,
- active: returnFalse,
- whenActiveChanged: emptyFunction,
- PanelHeight: returnZero,
- PanelWidth: returnZero,
- addDocTab: this.props.addDocTab,
- };
- let fieldContentView = <FieldView {...props} />;
- let reference = React.createRef<HTMLDivElement>();
- let onItemDown = (e: React.PointerEvent) => {
- (!this.props.CollectionView.props.isSelected() ? undefined :
- SetupDrag(reference, () => props.Document, this.props.moveDocument, this.props.Document.schemaDoc ? "copy" : undefined)(e));
- };
- let applyToDoc = (doc: Doc, row: number, column: number, run: (args?: { [name: string]: any }) => any) => {
- const res = run({ this: doc, $r: row, $c: column, $: (r: number = 0, c: number = 0) => this.getField(r + row, c + column) });
- if (!res.success) return false;
- doc[props.fieldKey] = res.result;
+ 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);
+ }
+
+ tableRemoveDoc = (document: Doc): boolean => {
+ // let doc = this.props.dataDoc ? this.props.dataDoc : this.props.Document;
+ // let children = Cast(doc[this.props.fieldKey], listSpec(Doc), []);
+ let children = this.childDocs;
+ if (children.indexOf(document) !== -1) {
+ children.splice(children.indexOf(document), 1);
+ this.childDocs = children;
return true;
- };
- const colIndex = this.columns.indexOf(rowProps.column.id!);
- return (
- <div className="collectionSchemaView-cellContents" onPointerDown={onItemDown} key={props.Document[Id]} ref={reference}>
- <EditableView
- display={"inline"}
- contents={fieldContentView}
- height={Number(MAX_ROW_HEIGHT)}
- GetValue={() => {
- let field = props.Document[props.fieldKey];
- if (Field.IsField(field)) {
- return Field.toScriptString(field);
- }
- return "";
- }}
- SetValue={(value: string) => {
- if (value.startsWith(":=")) {
- return this.setComputed(value.substring(2), props.Document, rowProps.column.id!, rowProps.index, colIndex);
- }
- let script = CompileScript(value, { addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } });
- if (!script.compiled) {
- return false;
- }
- return applyToDoc(props.Document, rowProps.index, colIndex, script.run);
- }}
- OnFillDown={async (value: string) => {
- let script = CompileScript(value, { addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } });
- if (!script.compiled) {
- return;
- }
- const run = script.run;
- const val = await DocListCastAsync(this.props.Document[this.props.fieldKey]);
- val && val.forEach((doc, i) => applyToDoc(doc, i, colIndex, run));
- }}>
- </EditableView>
- </div >
- );
+ }
+ return false;
}
private getTrProps: ComponentPropsGetterR = (state, rowInfo) => {
@@ -244,70 +453,70 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
return {};
}
return {
- onClick: action((e: React.MouseEvent, handleOriginal: Function) => {
- that.props.select(e.ctrlKey);
- that._selectedIndex = rowInfo.index;
+ ScreenToLocalTransform: this.props.ScreenToLocalTransform,
+ addDoc: this.tableAddDoc,
+ removeDoc: this.tableRemoveDoc,
+ // removeDoc: this.props.deleteDocument,
+ rowInfo,
+ rowFocused: !this._headerIsEditing && rowInfo.index === this._focusedCell.row && this.props.isFocused(this.props.Document),
+ textWrapRow: this.textWrapRow,
+ rowWrapped: this._textWrappedRows.findIndex(id => rowInfo.original[Id] === id) > -1
+ };
+ }
- if (handleOriginal) {
- handleOriginal();
- }
- }),
+ private getTdProps: ComponentPropsGetterR = (state, rowInfo, column, instance) => {
+ if (!rowInfo) return {};
+ if (!column) return {};
+
+ let row = rowInfo.index;
+ //@ts-ignore
+ let col = this.columns.map(c => c.heading).indexOf(column!.id);
+ // let col = column ? this.columns.indexOf(column!) : -1;
+ let isFocused = this._focusedCell.row === row && this._focusedCell.col === col && this.props.isFocused(this.props.Document);
+ // let column = this.columns.indexOf(column.id!);
+ return {
style: {
- background: rowInfo.index === this._selectedIndex ? "lightGray" : "white",
- //color: rowInfo.index === this._selectedIndex ? "white" : "black"
+ border: !this._headerIsEditing && isFocused ? "2px solid rgb(255, 160, 160)" : "1px solid #f1efeb"
}
};
}
- private createTarget = (ele: HTMLDivElement) => {
- this._mainCont = ele;
- super.CreateDropTarget(ele);
- }
+ // private createTarget = (ele: HTMLDivElement) => {
+ // this._mainCont = ele;
+ // this.props.CreateDropTarget(ele);
+ // }
+
+ // detectClick = (e: PointerEvent): void => {
+ // if (this._node && this._node.contains(e.target as Node)) {
+ // } else {
+ // this._isOpen = false;
+ // this.props.setIsEditing(false);
+ // }
+ // }
@action
- toggleKey = (key: string) => {
- let list = Cast(this.props.Document.schemaColumns, listSpec("string"));
- if (list === undefined) {
- this.props.Document.schemaColumns = list = new List<string>([key]);
- } else {
- const index = list.indexOf(key);
- if (index === -1) {
- list.push(key);
- } else {
- list.splice(index, 1);
- }
- }
+ onExpandCollection = (collection: Doc): void => {
+ this._openCollections.push(collection[Id]);
}
- //toggles preview side-panel of schema
@action
- toggleExpander = () => {
- this.props.Document.schemaPreviewWidth = this.previewWidth() === 0 ? Math.min(this.tableWidth / 3, 200) : 0;
+ onCloseCollection = (collection: Doc): void => {
+ let index = this._openCollections.findIndex(col => col === collection[Id]);
+ if (index > -1) this._openCollections.splice(index, 1);
}
- 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 => {
- let nativeWidth = this._mainCont!.getBoundingClientRect();
- this.props.Document.schemaPreviewWidth = Math.min(nativeWidth.right - nativeWidth.left - 40,
- this.props.ScreenToLocalTransform().transformDirection(nativeWidth.right - e.clientX, 0)[0]);
+ setCellIsEditing = (isEditing: boolean): void => {
+ this._cellIsEditing = isEditing;
}
+
@action
- onDividerUp = (e: PointerEvent): void => {
- document.removeEventListener("pointermove", this.onDividerMove);
- document.removeEventListener('pointerup', this.onDividerUp);
- if (this._startPreviewWidth === this.previewWidth()) {
- this.toggleExpander();
- }
+ setHeaderIsEditing = (isEditing: boolean): void => {
+ this._headerIsEditing = isEditing;
}
onPointerDown = (e: React.PointerEvent): void => {
+ this.props.setFocused(this.props.Document);
if (e.button === 0 && !e.altKey && !e.ctrlKey && !e.metaKey) {
if (this.props.isSelected()) e.stopPropagation();
}
@@ -319,57 +528,189 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
}
}
- 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 });
+ onKeyDown = (e: KeyboardEvent): void => {
+ if (!this._cellIsEditing && !this._headerIsEditing && this.props.isFocused(this.props.Document)) {// && this.props.isSelected()) {
+ let direction = e.key === "Tab" ? "tab" : e.which === 39 ? "right" : e.which === 37 ? "left" : e.which === 38 ? "up" : e.which === 40 ? "down" : "";
+ this.changeFocusedCellByDirection(direction);
+
+ // let doc = this.props.dataDoc ? this.props.dataDoc : this.props.Document;
+ // let children = Cast(doc[this.props.fieldKey], listSpec(Doc), []);
+ let children = this.childDocs;
+ const pdoc = FieldValue(children[this._focusedCell.row]);
+ pdoc && this.props.setPreviewDoc(pdoc);
}
}
@action
- makeDB = async () => {
- let csv: string = this.columns.reduce((val, col) => val + col + ",", "");
- csv = csv.substr(0, csv.length - 1) + "\n";
- let self = this;
- DocListCast(this.props.Document.data).map(doc => {
- csv += self.columns.reduce((val, col) => val + (doc[col] ? doc[col]!.toString() : "0") + ",", "");
- csv = csv.substr(0, csv.length - 1) + "\n";
- });
- csv.substring(0, csv.length - 1);
- let dbName = StrCast(this.props.Document.title);
- let res = await Gateway.Instance.PostSchema(csv, dbName);
- if (self.props.CollectionView.props.addDocument) {
- let 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;
+ changeFocusedCellByDirection = (direction: string): void => {
+ // let doc = this.props.dataDoc ? this.props.dataDoc : this.props.Document;
+ // let children = Cast(doc[this.props.fieldKey], listSpec(Doc), []);
+ let children = this.childDocs;
+ switch (direction) {
+ case "tab":
+ if (this._focusedCell.col + 1 === this.columns.length && this._focusedCell.row + 1 === children.length) {
+ this._focusedCell = { row: 0, col: 0 };
+ } else if (this._focusedCell.col + 1 === this.columns.length) {
+ this._focusedCell = { row: this._focusedCell.row + 1, col: 0 };
+ } else {
+ this._focusedCell = { row: this._focusedCell.row, col: this._focusedCell.col + 1 };
+ }
+ break;
+ case "right":
+ this._focusedCell = { row: this._focusedCell.row, col: this._focusedCell.col + 1 === this.columns.length ? this._focusedCell.col : this._focusedCell.col + 1 };
+ break;
+ case "left":
+ this._focusedCell = { row: this._focusedCell.row, col: this._focusedCell.col === 0 ? this._focusedCell.col : this._focusedCell.col - 1 };
+ break;
+ case "up":
+ this._focusedCell = { row: this._focusedCell.row === 0 ? this._focusedCell.row : this._focusedCell.row - 1, col: this._focusedCell.col };
+ break;
+ case "down":
+ this._focusedCell = { row: this._focusedCell.row + 1 === children.length ? this._focusedCell.row : this._focusedCell.row + 1, col: this._focusedCell.col };
+ break;
+ }
+ // const pdoc = FieldValue(children[this._focusedCell.row]);
+ // pdoc && this.props.setPreviewDoc(pdoc);
+ }
+
+ @action
+ changeFocusedCellByIndex = (row: number, col: number): void => {
+ // let doc = this.props.dataDoc ? this.props.dataDoc : this.props.Document;
+ // let children = Cast(doc[this.props.fieldKey], listSpec(Doc), []);
+
+ this._focusedCell = { row: row, col: col };
+ this.props.setFocused(this.props.Document);
+
+ // const fdoc = FieldValue(children[this._focusedCell.row]);
+ // fdoc && this.props.setPreviewDoc(fdoc);
+ }
+
+ createRow = () => {
+ // let doc = this.props.dataDoc ? this.props.dataDoc : this.props.Document;
+ // let children = Cast(doc[this.props.fieldKey], listSpec(Doc), []);
+ let children = this.childDocs;
+
+ let newDoc = Docs.Create.TextDocument({ width: 100, height: 30 });
+ let proto = Doc.GetProto(newDoc);
+ proto.title = "";
+ children.push(newDoc);
+ this.childDocs = children;
+ }
+
+ @action
+ createColumn = () => {
+ let index = 0;
+ let found = this.columns.findIndex(col => col.heading.toUpperCase() === "New field".toUpperCase()) > -1;
+ if (!found) {
+ console.log("create column found");
+ this.columns.push(new SchemaHeaderField("New field", "#f1efeb"));
+ return;
+ }
+ while (found) {
+ index++;
+ found = this.columns.findIndex(col => col.heading.toUpperCase() === ("New field (" + index + ")").toUpperCase()) > -1;
+ }
+ console.log("create column new");
+ this.columns.push(new SchemaHeaderField("New field (" + index + ")", "#f1efeb"));
+ }
+
+ @action
+ deleteColumn = (key: string) => {
+ console.log("deleting columnnn");
+ let list = Cast(this.props.Document.schemaColumns, listSpec(SchemaHeaderField));
+ if (list === undefined) {
+ console.log("delete column");
+ this.props.Document.schemaColumns = list = new List<SchemaHeaderField>([]);
+ } else {
+ const index = list.map(c => c.heading).indexOf(key);
+ if (index > -1) {
+ list.splice(index, 1);
}
}
}
@action
- addColumn = () => {
- this.columns.push(this._newKeyName);
- this._newKeyName = "";
+ changeColumns = (oldKey: string, newKey: string, addNew: boolean) => {
+ console.log("changingin columnsdfhs");
+ let list = Cast(this.props.Document.schemaColumns, listSpec(SchemaHeaderField));
+ if (list === undefined) {
+ console.log("change columns new");
+ this.props.Document.schemaColumns = list = new List<SchemaHeaderField>([new SchemaHeaderField(newKey, "f1efeb")]);
+ } else {
+ console.log("change column");
+ if (addNew) {
+ this.columns.push(new SchemaHeaderField(newKey, "f1efeb"));
+ } else {
+ const index = list.map(c => c.heading).indexOf(oldKey);
+ if (index > -1) {
+ list[index] = new SchemaHeaderField(newKey, "f1efeb");
+ }
+ }
+ }
+ }
+
+ 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]);
+ }
+
+ setColumnType = (key: string, type: ColumnType): void => {
+ if (columnTypes.get(key)) return;
+ 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;
+ }
}
@action
- newKeyChange = (e: React.ChangeEvent<HTMLInputElement>) => {
- this._newKeyName = e.currentTarget.value;
+ setColumns = (columns: SchemaHeaderField[]) => {
+ this.columns = columns;
}
- @computed
- get previewDocument(): Doc | undefined {
- const selected = this.childDocs.length > this._selectedIndex ? this.childDocs[this._selectedIndex] : undefined;
- let pdc = selected ? (this.previewScript && this.previewScript !== "this" ? FieldValue(Cast(selected[this.previewScript], Doc)) : selected) : undefined;
- return pdc;
+ reorderColumns = (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columnsValues: SchemaHeaderField[]) => {
+ let columns = [...columnsValues];
+ let oldIndex = columns.indexOf(toMove);
+ let relIndex = columns.indexOf(relativeTo);
+ let 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.setColumns(columns);
}
- getPreviewTransform = (): Transform => this.props.ScreenToLocalTransform().translate(
- - this.borderWidth - this.DIVIDER_WIDTH - this.tableWidth, - this.borderWidth)
+ @action
+ setColumnSort = (column: string, descending: boolean) => {
+ this._sortedColumns.set(column, { id: column, desc: descending });
+ }
+ @action
+ removeColumnSort = (column: string) => {
+ this._sortedColumns.delete(column);
+ }
- get documentKeysCheckList() {
+ get documentKeys() {
const docs = DocListCast(this.props.Document[this.props.fieldKey]);
+
+ // let docs = this.childDocs;
let 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
@@ -379,99 +720,180 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
//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] = true);
- return Array.from(Object.keys(keys)).map(item =>
- (<KeyToggle checked={keys[item]} key={item} keyName={item} toggle={this.toggleKey} />));
- }
-
- get tableOptionsPanel() {
- return !this.props.active() ? (null) :
- (<Flyout
- anchorPoint={anchorPoints.RIGHT_TOP}
- content={<div>
- <div id="schema-options-header"><h5><b>Options</b></h5></div>
- <div id="options-flyout-div">
- <h6 className="schema-options-subHeader">Preview Window</h6>
- <div id="preview-schema-checkbox-div"><input type="checkbox" key={"Show Preview"} checked={this.previewWidth() !== 0} onChange={this.toggleExpander} /> Show Preview </div>
- <h6 className="schema-options-subHeader" >Displayed Columns</h6>
- <ul id="schema-col-checklist" >
- {this.documentKeysCheckList}
- </ul>
- <input value={this._newKeyName} onChange={this.newKeyChange} />
- <button onClick={this.addColumn}><FontAwesomeIcon style={{ color: "white" }} icon="plus" size="lg" /></button>
- </div>
- </div>
- }>
- <button id="schemaOptionsMenuBtn" ><FontAwesomeIcon style={{ color: "white" }} icon="cog" size="sm" /></button>
- </Flyout>);
+ this.columns.forEach(key => keys[key.heading] = true);
+ return Array.from(Object.keys(keys));
+ }
+
+ @action
+ textWrapRow = (doc: Doc): void => {
+ let index = this._textWrappedRows.findIndex(id => doc[Id] === id);
+ if (index > -1) {
+ this._textWrappedRows.splice(index, 1);
+ } else {
+ this._textWrappedRows.push(doc[Id]);
+ }
+
}
@computed
get reactTable() {
- let previewWidth = this.previewWidth() + 2 * this.borderWidth + this.DIVIDER_WIDTH + 1;
- return <ReactTable style={{ position: "relative", float: "left", width: `calc(100% - ${previewWidth}px` }} data={this.childDocs} page={0} pageSize={this.childDocs.length} showPagination={false}
+
+ // let cdoc = this.props.dataDoc ? this.props.dataDoc : this.props.Document;
+ // let children = DocListCast(cdoc[this.props.fieldKey]);
+ let children = this.childDocs;
+
+ let previewWidth = this.previewWidth(); // + 2 * this.borderWidth + this.DIVIDER_WIDTH + 1;
+ let hasCollectionChild = children.reduce((found, doc) => found || doc.type === "collection", false);
+ let expandedRowsList = this._openCollections.map(col => children.findIndex(doc => doc[Id] === col).toString());
+ let expanded = {};
+ //@ts-ignore
+ expandedRowsList.forEach(row => expanded[row] = true);
+ console.log(...[...this._textWrappedRows]); // TODO: get component to rerender on text wrap change without needign to console.log :((((
+
+ return <ReactTable
+ style={{ position: "relative", float: "left", width: `calc(100% - ${previewWidth}px` }}
+ data={children}
+ page={0}
+ pageSize={children.length}
+ showPagination={false}
columns={this.tableColumns}
- column={{ ...ReactTableDefaults.column, Cell: this.renderCell, }}
getTrProps={this.getTrProps}
+ getTdProps={this.getTdProps}
+ sortable={false}
+ TrComponent={MovableRow}
+ sorted={Array.from(this._sortedColumns.values())}
+ expanded={expanded}
+ SubComponent={hasCollectionChild ?
+ row => {
+ if (row.original.type === "collection") {
+ // let childDocs = DocListCast(row.original[this.props.fieldKey]);
+ return <div className="sub"><SchemaTable {...this.props} Document={row.original} childDocs={undefined} /></div>;
+ }
+ }
+ : undefined}
+
/>;
}
- @computed
- get dividerDragger() {
- return this.previewWidth() === 0 ? (null) :
- <div className="collectionSchemaView-dividerDragger" onPointerDown={this.onDividerDown} style={{ width: `${this.DIVIDER_WIDTH}px` }} />;
+ 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" });
+ }
}
+ @action
+ makeDB = async () => {
+ let csv: string = this.columns.reduce((val, col) => val + col + ",", "");
+ csv = csv.substr(0, csv.length - 1) + "\n";
+ let self = this;
+ let cdoc = this.props.dataDoc ? this.props.dataDoc : this.props.Document;
+ // let children = DocListCast(cdoc[this.props.fieldKey]);
+ 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);
+ let dbName = StrCast(this.props.Document.title);
+ let res = await Gateway.Instance.PostSchema(csv, dbName);
+ if (self.props.CollectionView.props.addDocument) {
+ let 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;
+ }
+ }
+ }
- @computed
- get previewPanel() {
- // let layoutDoc = this.previewDocument;
- // let resolvedDataDoc = (layoutDoc !== this.props.DataDoc) ? this.props.DataDoc : undefined;
- // if (layoutDoc && !(Cast(layoutDoc.layout, Doc) instanceof Doc) &&
- // resolvedDataDoc && resolvedDataDoc !== layoutDoc) {
- // // ... so change the layout to be an expanded view of the template layout. This allows the view override the template's properties and be referenceable as its own document.
- // layoutDoc = Doc.expandTemplateLayout(layoutDoc, resolvedDataDoc);
- // }
+ getField = (row: number, col?: number) => {
+ // const docs = DocListCast(this.props.Document[this.props.fieldKey]);
- let layoutDoc = this.previewDocument ? Doc.expandTemplateLayout(this.previewDocument, this.props.DataDoc) : undefined;
- return <div ref={this.createTarget}>
- <CollectionSchemaPreview
- Document={layoutDoc}
- DataDocument={this.previewDocument !== this.props.DataDoc ? this.props.DataDoc : undefined}
- childDocs={this.childDocs}
- renderDepth={this.props.renderDepth}
- width={this.previewWidth}
- height={this.previewHeight}
- getTransform={this.getPreviewTransform}
- CollectionView={this.props.CollectionView}
- moveDocument={this.props.moveDocument}
- addDocument={this.props.addDocument}
- removeDocument={this.props.removeDocument}
- active={this.props.active}
- whenActiveChanged={this.props.whenActiveChanged}
- addDocTab={this.props.addDocTab}
- setPreviewScript={this.setPreviewScript}
- previewScript={this.previewScript}
- />
- </div>;
+ let cdoc = this.props.dataDoc ? this.props.dataDoc : this.props.Document;
+ const docs = DocListCast(cdoc[this.props.fieldKey]);
+ // let 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;
}
- @action
- setPreviewScript = (script: string) => {
- this.previewScript = script;
+
+ createTransformer = (row: number, col: number): Transformer => {
+ const self = this;
+ const captures: { [name: string]: Field } = {};
+
+ const transformer: ts.TransformerFactory<ts.SourceFile> = 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() {
+ // if (SelectionManager.SelectedDocuments().length > 0) console.log(StrCast(SelectionManager.SelectedDocuments()[0].Document.title));
+ // if (DocumentManager.Instance.getDocumentView(this.props.Document)) console.log(StrCast(this.props.Document.title), SelectionManager.IsSelected(DocumentManager.Instance.getDocumentView(this.props.Document)!))
return (
- <div className="collectionSchemaView-container" onPointerDown={this.onPointerDown} onWheel={this.onWheel}
- onDrop={(e: React.DragEvent) => this.onDrop(e, {})} onContextMenu={this.onContextMenu} ref={this.createTarget}>
+ <div className="collectionSchemaView-table" onPointerDown={this.onPointerDown} onWheel={this.onWheel}
+ onDrop={(e: React.DragEvent) => this.props.onDrop(e, {})} onContextMenu={this.onContextMenu} >
{this.reactTable}
- {this.dividerDragger}
- {!this.previewWidth() ? (null) : this.previewPanel}
- {this.tableOptionsPanel}
+ <button onClick={() => this.createRow()}>new row</button>
</div>
);
}
}
+
+
interface CollectionSchemaPreviewProps {
Document?: Doc;
DataDocument?: Doc;
@@ -550,6 +972,8 @@ export class CollectionSchemaPreview extends React.Component<CollectionSchemaPre
}
return undefined;
}
+
+
render() {
let input = this.props.previewScript === undefined ? (null) :
<div ref={this.createTarget}><input className="collectionSchemaView-input" value={this.props.previewScript} onChange={this.onPreviewScriptChange}
@@ -563,7 +987,7 @@ export class CollectionSchemaPreview extends React.Component<CollectionSchemaPre
height: "100%"
}}>
<DocumentView
- DataDoc={this.props.Document.layout instanceof Doc ? this.props.Document : this.props.DataDocument}
+ DataDoc={this.props.DataDocument}
Document={this.props.Document}
fitToBox={this.props.fitToBox}
renderDepth={this.props.renderDepth + 1}