aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/collections/collectionSchema/CollectionSchemaView.tsx')
-rw-r--r--src/client/views/collections/collectionSchema/CollectionSchemaView.tsx163
1 files changed, 83 insertions, 80 deletions
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index a59d7e5a3..15424de98 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -8,17 +8,16 @@ import { Id } from '../../../../fields/FieldSymbols';
import { List } from '../../../../fields/List';
import { listSpec } from '../../../../fields/Schema';
import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
-import { emptyFunction, returnDefault, returnEmptyDoclist, returnEmptyString, returnFalse, returnIgnore, returnNever, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../Utils';
+import { emptyFunction, returnEmptyDoclist, returnEmptyString, returnFalse, returnIgnore, returnNever, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../Utils';
import { Docs, DocumentOptions, DocUtils, FInfo } from '../../../documents/Documents';
import { DocumentManager } from '../../../util/DocumentManager';
import { DragManager } from '../../../util/DragManager';
import { SelectionManager } from '../../../util/SelectionManager';
-import { undoBatch } from '../../../util/UndoManager';
+import { undoable, undoBatch } from '../../../util/UndoManager';
import { ContextMenu } from '../../ContextMenu';
import { EditableView } from '../../EditableView';
import { Colors } from '../../global/globalEnums';
import { DocFocusOptions, DocumentView } from '../../nodes/DocumentView';
-import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
import { KeyValueBox } from '../../nodes/KeyValueBox';
import { DefaultStyleProvider } from '../../StyleProvider';
import { CollectionSubView } from '../CollectionSubView';
@@ -33,6 +32,7 @@ export enum ColumnType {
Date,
Image,
RTF,
+ Enumeration,
Any,
}
@@ -43,9 +43,10 @@ export const FInfotoColType: { [key: string]: ColumnType } = {
date: ColumnType.Date,
image: ColumnType.Image,
rtf: ColumnType.RTF,
+ enumeration: ColumnType.Enumeration,
};
-const defaultColumnKeys: string[] = ['title', 'type', 'author', 'creationDate', 'text'];
+const defaultColumnKeys: string[] = ['title', 'type', 'author', 'author_date', 'text'];
@observer
export class CollectionSchemaView extends CollectionSubView() {
@@ -55,8 +56,10 @@ export class CollectionSchemaView extends CollectionSubView() {
private _makeNewColumn: boolean = false;
private _documentOptions: DocumentOptions = new DocumentOptions();
private _tableContentRef: HTMLDivElement | null = null;
+ private _menuTarget = React.createRef<HTMLDivElement>();
- public static _rowHeight: number = 50;
+ static _rowHeight: number = 50;
+ static _rowSingleLineHeight: number = 32;
public static _minColWidth: number = 25;
public static _rowMenuWidth: number = 60;
public static _previewDividerWidth: number = 4;
@@ -77,8 +80,13 @@ export class CollectionSchemaView extends CollectionSubView() {
@observable _filterSearchValue: string = '';
@observable _selectedCell: [Doc, number] | undefined;
+ // target HTMLelement portal for showing a popup menu to edit cell values.
+ public get MenuTarget() {
+ return this._menuTarget.current;
+ }
+
@computed get _selectedDocs() {
- return SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.context), this.rootDoc));
+ return SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.embedContainer), this.rootDoc));
}
@computed get documentKeys() {
@@ -86,7 +94,7 @@ export class CollectionSchemaView extends CollectionSubView() {
}
@computed get previewWidth() {
- return NumCast(this.layoutDoc.schemaPreviewWidth);
+ return NumCast(this.layoutDoc.schema_previewWidth);
}
@computed get tableWidth() {
@@ -94,12 +102,12 @@ export class CollectionSchemaView extends CollectionSubView() {
}
@computed get columnKeys() {
- return Cast(this.layoutDoc.columnKeys, listSpec('string'), defaultColumnKeys);
+ return Cast(this.layoutDoc.schema_columnKeys, listSpec('string'), defaultColumnKeys);
}
@computed get storedColumnWidths() {
const widths = NumListCast(
- this.layoutDoc.columnWidths,
+ this.layoutDoc.schema_columnWidths,
this.columnKeys.map(() => (this.tableWidth - CollectionSchemaView._rowMenuWidth) / this.columnKeys.length)
);
@@ -223,7 +231,7 @@ export class CollectionSchemaView extends CollectionSubView() {
@undoBatch
@action
- setSort = (field: string | undefined, desc: boolean = false) => {
+ setColumnSort = (field: string | undefined, desc: boolean = false) => {
this.layoutDoc.sortField = field;
this.layoutDoc.sortDesc = desc;
};
@@ -242,7 +250,7 @@ export class CollectionSchemaView extends CollectionSubView() {
let currKeys = [...this.columnKeys];
currKeys[index] = newKey;
- this.layoutDoc.columnKeys = new List<string>(currKeys);
+ this.layoutDoc.schema_columnKeys = new List<string>(currKeys);
};
@undoBatch
@@ -256,11 +264,11 @@ export class CollectionSchemaView extends CollectionSubView() {
const currWidths = this.storedColumnWidths.slice();
currWidths.splice(0, 0, newColWidth);
const newDesiredTableWidth = currWidths.reduce((w, cw) => w + cw, 0);
- this.layoutDoc.columnWidths = new List<number>(currWidths.map(w => (w / newDesiredTableWidth) * (this.tableWidth - CollectionSchemaView._rowMenuWidth)));
+ this.layoutDoc.schema_columnWidths = new List<number>(currWidths.map(w => (w / newDesiredTableWidth) * (this.tableWidth - CollectionSchemaView._rowMenuWidth)));
let currKeys = this.columnKeys.slice();
currKeys.splice(0, 0, key);
- this.layoutDoc.columnKeys = new List<string>(currKeys);
+ this.layoutDoc.schema_columnKeys = new List<string>(currKeys);
};
@action
@@ -273,11 +281,11 @@ export class CollectionSchemaView extends CollectionSubView() {
const currWidths = this.storedColumnWidths.slice();
currWidths.splice(index, 1);
const newDesiredTableWidth = currWidths.reduce((w, cw) => w + cw, 0);
- this.layoutDoc.columnWidths = new List<number>(currWidths.map(w => (w / newDesiredTableWidth) * (this.tableWidth - CollectionSchemaView._rowMenuWidth)));
+ this.layoutDoc.schema_columnWidths = new List<number>(currWidths.map(w => (w / newDesiredTableWidth) * (this.tableWidth - CollectionSchemaView._rowMenuWidth)));
let currKeys = this.columnKeys.slice();
currKeys.splice(index, 1);
- this.layoutDoc.columnKeys = new List<string>(currKeys);
+ this.layoutDoc.schema_columnKeys = new List<string>(currKeys);
};
@action
@@ -316,7 +324,7 @@ export class CollectionSchemaView extends CollectionSubView() {
@action
finishResize = () => {
- this.layoutDoc.columnWidths = new List<number>(this._displayColumnWidths);
+ this.layoutDoc.schema_columnWidths = new List<number>(this._displayColumnWidths);
this._displayColumnWidths = undefined;
};
@@ -325,20 +333,18 @@ export class CollectionSchemaView extends CollectionSubView() {
moveColumn = (fromIndex: number, toIndex: number) => {
let currKeys = this.columnKeys.slice();
currKeys.splice(toIndex, 0, currKeys.splice(fromIndex, 1)[0]);
- this.layoutDoc.columnKeys = new List<string>(currKeys);
+ this.layoutDoc.schema_columnKeys = new List<string>(currKeys);
let currWidths = this.storedColumnWidths.slice();
currWidths.splice(toIndex, 0, currWidths.splice(fromIndex, 1)[0]);
- this.layoutDoc.columnWidths = new List<number>(currWidths);
+ this.layoutDoc.schema_columnWidths = new List<number>(currWidths);
};
@action
dragColumn = (e: PointerEvent, index: number) => {
const dragData = new DragManager.ColumnDragData(index);
const dragEles = [this._colEles[index]];
- this.childDocs.forEach(doc => {
- dragEles.push(this._rowEles.get(doc).children[1].children[index]);
- });
+ this.childDocs.forEach(doc => dragEles.push(this._rowEles.get(doc).children[1].children[index]));
DragManager.StartColumnDrag(dragEles, dragData, e.x, e.y);
document.removeEventListener('pointermove', this.highlightDropColumn);
@@ -352,24 +358,28 @@ export class CollectionSchemaView extends CollectionSubView() {
return true;
};
- @action
- highlightDropColumn = (e: PointerEvent) => {
- e.stopPropagation();
- const mouseX = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0];
+ findDropIndex = (mouseX: number) => {
let index: number | undefined;
this.displayColumnWidths.reduce((total, curr, i) => {
if (total <= mouseX && total + curr >= mouseX) {
- if (mouseX <= total + curr / 2) index = i;
+ if (mouseX <= total + curr) index = i;
else index = i + 1;
}
return total + curr;
}, CollectionSchemaView._rowMenuWidth);
+ return index;
+ };
+ @action
+ highlightDropColumn = (e: PointerEvent) => {
+ e.stopPropagation();
+ const mouseX = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0];
+ const index = this.findDropIndex(mouseX);
this._colEles.forEach((colRef, i) => {
let leftStyle = '';
let rightStyle = '';
- if (i + 1 === index) rightStyle = `solid 2px ${Colors.MEDIUM_BLUE}`;
- if (i === index && i === 0) leftStyle = `solid 2px ${Colors.MEDIUM_BLUE}`;
+ if (i + 1 === index) rightStyle = `solid 12px ${Colors.MEDIUM_BLUE}`;
+ if (i === index && i === 0) leftStyle = `solid 12px ${Colors.MEDIUM_BLUE}`;
colRef.style.borderLeft = leftStyle;
colRef.style.borderRight = rightStyle;
this.childDocs.forEach(doc => {
@@ -426,15 +436,8 @@ export class CollectionSchemaView extends CollectionSubView() {
if (de.complete.columnDragData) {
e.stopPropagation();
const mouseX = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y)[0];
- let index = de.complete.columnDragData.colIndex;
- this.displayColumnWidths.reduce((total, curr, i) => {
- if (total <= mouseX && total + curr >= mouseX) {
- if (mouseX <= total + curr / 2) index = i;
- else index = i + 1;
- }
- return total + curr;
- }, CollectionSchemaView._rowMenuWidth);
- this.moveColumn(de.complete.columnDragData.colIndex, index);
+ const index = this.findDropIndex(mouseX);
+ this.moveColumn(de.complete.columnDragData.colIndex, index ?? de.complete.columnDragData.colIndex);
this._colEles.forEach((colRef, i) => {
colRef.style.borderLeft = '';
@@ -479,28 +482,15 @@ export class CollectionSchemaView extends CollectionSubView() {
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.layoutDoc.schemaPreviewWidth = width;
+ this.layoutDoc.schema_previewWidth = width;
return false;
};
- @action
- addNewTextDoc = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => {
- if (!value && !forceEmptyNote) return false;
- const newDoc = Docs.Create.TextDocument(value, { title: value, _autoHeight: true });
- FormattedTextBox.SelectOnLoad = newDoc[Id];
- FormattedTextBox.SelectOnLoadChar = forceEmptyNote ? '' : ' ';
- return this.addRow(newDoc) || false;
- };
-
menuCallback = (x: number, y: number) => {
ContextMenu.Instance.clearItems();
- DocUtils.addDocumentCreatorMenuItems(doc => this.addRow(doc), this.addRow, x, y, true);
+ DocUtils.addDocumentCreatorMenuItems(this.addRow, this.addRow, x, y, true);
- ContextMenu.Instance.setDefaultItem('::', (name: string): void => {
- Doc.GetProto(this.props.Document)[name] = '';
- this.addRow(Docs.Create.TextDocument('', { title: name, _autoHeight: true }));
- });
ContextMenu.Instance.displayMenu(x, y, undefined, true);
};
@@ -515,9 +505,9 @@ export class CollectionSchemaView extends CollectionSubView() {
if (found) {
const rect = found.getBoundingClientRect();
const localRect = this.props.ScreenToLocalTransform().transformBounds(rect.left, rect.top, rect.width, rect.height);
- if (localRect.y < CollectionSchemaView._rowHeight || localRect.y + localRect.height > this.props.PanelHeight()) {
+ if (localRect.y < this.rowHeightFunc() || localRect.y + localRect.height > this.props.PanelHeight()) {
let focusSpeed = options.zoomTime ?? 50;
- smoothScroll(focusSpeed, this._tableContentRef!, localRect.y + this._tableContentRef!.scrollTop - CollectionSchemaView._rowHeight, options.easeFunc);
+ smoothScroll(focusSpeed, this._tableContentRef!, localRect.y + this._tableContentRef!.scrollTop - this.rowHeightFunc(), options.easeFunc);
return focusSpeed;
}
}
@@ -620,7 +610,7 @@ export class CollectionSchemaView extends CollectionSubView() {
this._menuKeys = this.documentKeys.filter(value => value.toLowerCase().includes(this._menuValue.toLowerCase()));
};
- getFieldFilters = (field: string) => StrListCast(this.Document._docFilters).filter(filter => filter.split(':')[0] == field);
+ getFieldFilters = (field: string) => StrListCast(this.Document._childFilters).filter(filter => filter.split(':')[0] == field);
removeFieldFilters = (field: string) => {
this.getFieldFilters(field).forEach(filter => Doc.setDocFilter(this.Document, field, filter.split(':')[1], 'remove'));
@@ -696,6 +686,12 @@ export class CollectionSchemaView extends CollectionSubView() {
);
}
+ onPassiveWheel = (e: WheelEvent) => {
+ // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this)
+ if (!this._oldWheel.scrollTop && e.deltaY <= 0) e.preventDefault();
+ e.stopPropagation();
+ };
+ _oldWheel: any;
@computed get keysDropdown() {
return (
<div className="schema-key-search">
@@ -709,16 +705,11 @@ export class CollectionSchemaView extends CollectionSubView() {
</div>
<div
className="schema-key-list"
- ref={r =>
- r?.addEventListener(
- 'wheel', // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this)
- (e: WheelEvent) => {
- if (!r.scrollTop && e.deltaY <= 0) e.preventDefault();
- e.stopPropagation();
- },
- { passive: false }
- )
- }>
+ ref={r => {
+ this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
+ this._oldWheel = r;
+ r?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
+ }}>
{this._menuKeys.map(key => (
<div
className="schema-search-result"
@@ -772,7 +763,7 @@ export class CollectionSchemaView extends CollectionSubView() {
}
});
- const filters = StrListCast(this.Document._docFilters);
+ const filters = StrListCast(this.Document._childFilters);
return keyOptions.map(key => {
let bool = false;
if (filters !== undefined) {
@@ -836,6 +827,7 @@ export class CollectionSchemaView extends CollectionSubView() {
});
return { docs };
}
+ rowHeightFunc = () => (BoolCast(this.layoutDoc._schema_singleLine) ? CollectionSchemaView._rowSingleLineHeight : CollectionSchemaView._rowHeight);
sortedDocsFunc = () => this.sortedDocs;
isContentActive = () => this.props.isSelected() || this.props.isContentActive();
screenToLocal = () => this.props.ScreenToLocalTransform().translate(-this.tableWidth, 0);
@@ -843,6 +835,7 @@ export class CollectionSchemaView extends CollectionSubView() {
render() {
return (
<div className="collectionSchemaView" ref={(ele: HTMLDivElement | null) => this.createDashEventsTarget(ele)} onDrop={this.onExternalDrop.bind(this)}>
+ <div ref={this._menuTarget} style={{ background: 'red', top: 0, left: 0, position: 'absolute', zIndex: 10000 }}></div>
<div
className="schema-table"
onWheel={e => this.props.isContentActive() && e.stopPropagation()}
@@ -850,7 +843,7 @@ export class CollectionSchemaView extends CollectionSubView() {
// prevent wheel events from passively propagating up through containers
r?.addEventListener('wheel', (e: WheelEvent) => {}, { passive: false });
}}>
- <div className="schema-header-row" style={{ height: CollectionSchemaView._rowHeight }}>
+ <div className="schema-header-row" style={{ height: this.rowHeightFunc() }}>
<div className="row-menu" style={{ width: CollectionSchemaView._rowMenuWidth }}>
<div className="schema-header-button" onPointerDown={e => (this._columnMenuIndex === -1 ? this.closeColumnMenu() : this.openColumnMenu(-1, true))}>
<FontAwesomeIcon icon="plus" />
@@ -864,19 +857,28 @@ export class CollectionSchemaView extends CollectionSubView() {
columnWidths={this.displayColumnWidths}
sortField={this.sortField}
sortDesc={this.sortDesc}
- setSort={this.setSort}
+ setSort={this.setColumnSort}
+ rowHeight={this.rowHeightFunc}
removeColumn={this.removeColumn}
resizeColumn={this.startResize}
openContextMenu={this.openContextMenu}
dragColumn={this.dragColumn}
setColRef={this.setColRef}
+ isContentActive={this.props.isContentActive}
/>
))}
</div>
{this._columnMenuIndex !== undefined && this.renderColumnMenu}
{this._filterColumnIndex !== undefined && this.renderFilterMenu}
- <CollectionSchemaViewDocs schema={this} childDocs={this.sortedDocsFunc} setRef={(ref: HTMLDivElement | null) => (this._tableContentRef = ref)} />
- <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} placeholder={"Type ':' for commands"} contents={'+ New Node'} menuCallback={this.menuCallback} height={CollectionSchemaView._newNodeInputHeight} />
+ <CollectionSchemaViewDocs schema={this} childDocs={this.sortedDocsFunc} rowHeight={this.rowHeightFunc} setRef={(ref: HTMLDivElement | null) => (this._tableContentRef = ref)} />
+ <EditableView
+ GetValue={returnEmptyString}
+ SetValue={undoable(value => (value ? this.addRow(Docs.Create.TextDocument(value, { title: value, _layout_autoHeight: true })) : false), 'add text doc')}
+ placeholder={"Type ':' for commands"}
+ contents={'+ New Node'}
+ menuCallback={this.menuCallback}
+ height={CollectionSchemaView._newNodeInputHeight}
+ />
</div>
{this.previewWidth > 0 && <div className="schema-preview-divider" style={{ width: CollectionSchemaView._previewDividerWidth }} onPointerDown={this.onDividerDown}></div>}
{this.previewWidth > 0 && (
@@ -897,8 +899,8 @@ export class CollectionSchemaView extends CollectionSubView() {
isContentActive={returnTrue}
isDocumentActive={returnFalse}
ScreenToLocalTransform={this.screenToLocal}
- docFilters={this.childDocFilters}
- docRangeFilters={this.childDocRangeFilters}
+ childFilters={this.childDocFilters}
+ childFiltersByRanges={this.childDocRangeFilters}
searchFilterDocs={this.searchFilterDocs}
styleProvider={DefaultStyleProvider}
docViewPath={returnEmptyDoclist}
@@ -922,20 +924,20 @@ interface CollectionSchemaViewDocsProps {
schema: CollectionSchemaView;
setRef: (ref: HTMLDivElement | null) => void;
childDocs: () => { docs: Doc[] };
+ rowHeight: () => number;
}
@observer
class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsProps> {
tableWidthFunc = () => this.props.schema.tableWidth;
- rowHeightFunc = () => CollectionSchemaView._rowHeight;
- childScreenToLocal = computedFn((index: number) => () => this.props.schema.props.ScreenToLocalTransform().translate(0, -CollectionSchemaView._rowHeight - index * this.rowHeightFunc()));
+ childScreenToLocal = computedFn((index: number) => () => this.props.schema.props.ScreenToLocalTransform().translate(0, -this.props.rowHeight() - index * this.props.rowHeight()));
render() {
return (
- <div className="schema-table-content" ref={this.props.setRef} style={{ height: `calc(100% - ${CollectionSchemaView._newNodeInputHeight + CollectionSchemaView._rowHeight}px)` }}>
+ <div className="schema-table-content" ref={this.props.setRef} style={{ height: `calc(100% - ${CollectionSchemaView._newNodeInputHeight + this.props.rowHeight()}px)` }}>
{this.props.childDocs().docs.map((doc: Doc, index: number) => {
const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField ? undefined : this.props.schema.props.DataDoc;
return (
- <div className="schema-row-wrapper" style={{ height: CollectionSchemaView._rowHeight }}>
+ <div className="schema-row-wrapper" style={{ height: this.props.rowHeight() }}>
<DocumentView
key={doc[Id]}
{...this.props.schema.props}
@@ -943,17 +945,18 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
LayoutTemplateString={SchemaRowBox.LayoutString(this.props.schema.props.fieldKey)}
Document={doc}
DataDoc={dataDoc}
+ yPadding={index}
renderDepth={this.props.schema.props.renderDepth + 1}
PanelWidth={this.tableWidthFunc}
- PanelHeight={this.rowHeightFunc}
+ PanelHeight={this.props.rowHeight}
styleProvider={DefaultStyleProvider}
waitForDoubleClickToClick={returnNever}
defaultDoubleClick={returnIgnore}
enableDragWhenActive={true}
onClickScriptDisable="always"
focus={this.props.schema.focusDocument}
- docFilters={this.props.schema.childDocFilters}
- docRangeFilters={this.props.schema.childDocRangeFilters}
+ childFilters={this.props.schema.childDocFilters}
+ childFiltersByRanges={this.props.schema.childDocRangeFilters}
searchFilterDocs={this.props.schema.searchFilterDocs}
rootSelected={this.props.schema.rootSelected}
ScreenToLocalTransform={this.childScreenToLocal(index)}
@@ -965,7 +968,7 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
hideTitle={true}
hideDocumentButtonBar={true}
hideLinkAnchors={true}
- fitWidth={returnTrue}
+ layout_fitWidth={returnTrue}
scriptContext={this}
canEmbedOnDrag={true}
/>