{
let field = props.Document[props.fieldKey];
if (Field.IsField(field)) {
return Field.toScriptString(field);
}
return "";
}}
SetValue={(value: string) => {
let script = CompileScript(value, { addReturn: true, params: { this: Doc.name } });
if (!script.compiled) {
return false;
}
return applyToDoc(props.Document, script.run);
}}
OnFillDown={async (value: string) => {
let script = CompileScript(value, { addReturn: true, params: { this: Doc.name } });
if (!script.compiled) {
return;
}
const run = script.run;
//TODO This should be able to be refactored to compile the script once
const val = await DocListCastAsync(this.props.Document[this.props.fieldKey]);
val && val.forEach(doc => applyToDoc(doc, run));
}}>
);
}
private getTrProps: ComponentPropsGetterR = (state, rowInfo) => {
const that = this;
if (!rowInfo) {
return {};
}
return {
onClick: action((e: React.MouseEvent, handleOriginal: Function) => {
that.props.select(e.ctrlKey);
that._selectedIndex = rowInfo.index;
if (handleOriginal) {
handleOriginal();
}
}),
style: {
background: rowInfo.index === this._selectedIndex ? "lightGray" : "white",
//color: rowInfo.index === this._selectedIndex ? "white" : "black"
}
};
}
private createTarget = (ele: HTMLDivElement) => {
this._mainCont = ele;
super.CreateDropTarget(ele);
}
@action
toggleKey = (key: string) => {
let list = Cast(this.props.Document.schemaColumns, listSpec("string"));
if (list === undefined) {
this.props.Document.schemaColumns = list = new List([key]);
} else {
const index = list.indexOf(key);
if (index === -1) {
list.push(key);
} else {
list.splice(index, 1);
}
}
}
//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();
}
}
onPointerDown = (e: React.PointerEvent): void => {
if (e.button === 0 && !e.altKey && !e.ctrlKey && !e.metaKey) {
if (this.props.isSelected()) e.stopPropagation();
}
}
onWheel = (e: React.WheelEvent): void => {
if (this.props.active()) {
e.stopPropagation();
}
}
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 });
}
}
@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;
}
}
}
@action
addColumn = () => {
this.columns.push(this._newKeyName);
this._newKeyName = "";
}
@action
newKeyChange = (e: React.ChangeEvent) => {
this._newKeyName = e.currentTarget.value;
}
@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;
}
getPreviewTransform = (): Transform => this.props.ScreenToLocalTransform().translate(
- this.borderWidth - this.DIVIDER_WIDTH - this.tableWidth, - this.borderWidth)
get documentKeysCheckList() {
const docs = DocListCast(this.props.Document[this.props.fieldKey]);
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
// 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] = true);
return Array.from(Object.keys(keys)).map(item =>
());
}
get tableOptionsPanel() {
return !this.props.active() ? (null) :
(
Options
Preview Window
Show Preview
Displayed Columns
{this.documentKeysCheckList}
}>
);
}
@computed
get reactTable() {
let previewWidth = this.previewWidth() + 2 * this.borderWidth + this.DIVIDER_WIDTH + 1;
return ;
}
@computed
get dividerDragger() {
return this.previewWidth() === 0 ? (null) :
;
}
@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);
// }
let layoutDoc = this.previewDocument ? Doc.expandTemplateLayout(this.previewDocument, this.props.DataDoc) : undefined;
return