aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/collectionSchema
diff options
context:
space:
mode:
authorNathan-SR <144961007+Nathan-SR@users.noreply.github.com>2024-03-22 22:11:37 -0400
committerNathan-SR <144961007+Nathan-SR@users.noreply.github.com>2024-03-22 22:11:37 -0400
commit3c5bc5b89c3158c6c1dce02f99aa0c08d24dcb39 (patch)
tree99bed6d83f5a01ff2654cd4fb635ea5c48bcc820 /src/client/views/collections/collectionSchema
parent26d7e045c5b0a9a29612e68d976e35c0e7e23d00 (diff)
parenta974aa4e6573c8becf93f78610406747fec14c1c (diff)
Merge branch 'master' into nathan-starter
Diffstat (limited to 'src/client/views/collections/collectionSchema')
-rw-r--r--src/client/views/collections/collectionSchema/CollectionSchemaView.scss149
-rw-r--r--src/client/views/collections/collectionSchema/CollectionSchemaView.tsx84
-rw-r--r--src/client/views/collections/collectionSchema/SchemaTableCell.tsx29
3 files changed, 142 insertions, 120 deletions
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index fed4e89cf..ac0bd2378 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -38,91 +38,97 @@
background: yellow;
}
}
+ }
- .schema-column-menu,
- .schema-filter-menu {
- background: $light-gray;
- position: absolute;
- min-width: 200px;
- max-width: 400px;
- display: flex;
- flex-direction: column;
- align-items: flex-start;
- z-index: 1;
-
- .schema-key-search-input {
- width: calc(100% - 20px);
- margin: 10px;
- }
+ .schema-preview-divider {
+ height: 100%;
+ background: black;
+ cursor: ew-resize;
+ }
+}
- .schema-search-result {
- cursor: pointer;
- padding: 5px 10px;
- width: 100%;
+.schema-column-menu,
+.schema-filter-menu {
+ background: $light-gray;
+ position: relative;
+ min-width: 200px;
+ max-width: 400px;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ z-index: 1;
- &:hover {
- background-color: $medium-gray;
- }
+ .schema-key-search-input {
+ width: calc(100% - 20px);
+ margin: 10px;
+ }
- .schema-search-result-type,
- .schema-search-result-desc {
- color: $dark-gray;
- font-size: $body-text;
- }
- }
+ .schema-search-result {
+ cursor: pointer;
+ padding: 5px 10px;
+ width: 100%;
- .schema-key-search,
- .schema-new-key-options {
- width: 100%;
- display: flex;
- flex-direction: column;
- align-items: flex-start;
- }
+ &:hover {
+ background-color: $medium-gray;
+ }
+ .schema-search-result-type {
+ font-family: 'Courier New', Courier, monospace;
+ }
- .schema-new-key-options {
- margin: 10px;
- .schema-key-warning {
- color: red;
- font-weight: normal;
- align-self: center;
- }
- }
+ .schema-search-result-type,
+ .schema-search-result-desc {
+ color: $dark-gray;
+ font-size: $body-text;
+ }
+ .schema-search-result-desc {
+ font-style: italic;
+ }
+ }
- .schema-key-list {
- width: 100%;
- max-height: 300px;
- overflow-y: auto;
- }
+ .schema-key-search,
+ .schema-new-key-options {
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ }
- .schema-key-type-option {
- margin: 2px 0px;
+ .schema-new-key-options {
+ margin: 10px;
+ .schema-key-warning {
+ color: red;
+ font-weight: normal;
+ align-self: center;
+ }
+ }
- input {
- margin-right: 5px;
- }
- }
+ .schema-key-list {
+ width: 100%;
+ max-height: 300px;
+ overflow-y: auto;
+ }
- .schema-key-default-val {
- margin: 5px 0;
- }
+ .schema-key-type-option {
+ margin: 2px 0px;
- .schema-column-menu-button {
- cursor: pointer;
- padding: 2px 5px;
- background: $medium-blue;
- border-radius: 9999px;
- color: $white;
- width: fit-content;
- margin: 5px;
- align-self: center;
- }
+ input {
+ margin-right: 5px;
}
}
- .schema-preview-divider {
- height: 100%;
- background: black;
- cursor: ew-resize;
+ .schema-key-default-val {
+ margin: 5px 0;
+ }
+
+ .schema-column-menu-button {
+ cursor: pointer;
+ padding: 2px 5px;
+ background: $medium-blue;
+ border-radius: 9999px;
+ color: $white;
+ width: fit-content;
+ margin: 5px;
+ align-self: center;
}
}
@@ -133,6 +139,7 @@
.row-menu {
display: flex;
justify-content: center;
+ cursor: pointer;
}
}
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 71938d13e..631ad7132 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,31 +1,33 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, makeObservable, observable, ObservableMap, observe } from 'mobx';
+import { Popup, PopupTrigger, Type } from 'browndash-components';
+import { ObservableMap, action, computed, makeObservable, observable, observe } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
+import { emptyFunction, returnEmptyDoclist, returnEmptyString, returnFalse, returnIgnore, returnNever, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../Utils';
import { Doc, DocListCast, Field, NumListCast, Opt, StrListCast } from '../../../../fields/Doc';
+import { DocData } from '../../../../fields/DocSymbols';
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, returnEmptyDoclist, returnEmptyString, returnFalse, returnIgnore, returnNever, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../Utils';
-import { Docs, DocumentOptions, DocUtils, FInfo } from '../../../documents/Documents';
+import { DocUtils, Docs, DocumentOptions, FInfo } from '../../../documents/Documents';
import { DocumentManager } from '../../../util/DocumentManager';
import { DragManager, dropActionType } from '../../../util/DragManager';
import { SelectionManager } from '../../../util/SelectionManager';
-import { undoable, undoBatch } from '../../../util/UndoManager';
+import { SettingsManager } from '../../../util/SettingsManager';
+import { undoBatch, undoable } from '../../../util/UndoManager';
import { ContextMenu } from '../../ContextMenu';
import { EditableView } from '../../EditableView';
+import { ObservableReactComponent } from '../../ObservableReactComponent';
+import { DefaultStyleProvider, StyleProp } from '../../StyleProvider';
import { Colors } from '../../global/globalEnums';
import { DocumentView } from '../../nodes/DocumentView';
-import { FocusViewOptions, FieldViewProps } from '../../nodes/FieldView';
+import { FieldViewProps, FocusViewOptions } from '../../nodes/FieldView';
import { KeyValueBox } from '../../nodes/KeyValueBox';
-import { ObservableReactComponent } from '../../ObservableReactComponent';
-import { DefaultStyleProvider, StyleProp } from '../../StyleProvider';
import { CollectionSubView } from '../CollectionSubView';
import './CollectionSchemaView.scss';
import { SchemaColumnHeader } from './SchemaColumnHeader';
import { SchemaRowBox } from './SchemaRowBox';
-import { faLessThanEqual } from '@fortawesome/free-solid-svg-icons';
const { default: { SCHEMA_NEW_NODE_HEIGHT } } = require('../../global/globalCssVariables.module.scss'); // prettier-ignore
export enum ColumnType {
@@ -165,7 +167,7 @@ export class CollectionSchemaView extends CollectionSubView() {
(change as any).added.forEach((doc: Doc) => // for each document added
Doc.GetAllPrototypes(doc.value as Doc).forEach(proto => // for all of its prototypes (and itself)
Object.keys(proto).forEach(action(key => // check if any of its keys are new, and add them
- !this.fieldInfos.get(key) && this.fieldInfos.set(key, new FInfo(key, key === 'author'))))));
+ !this.fieldInfos.get(key) && this.fieldInfos.set(key, new FInfo("-no description-", key === 'author'))))));
break;
case 'update': //let oldValue = change.oldValue; // fill this in if the entire child list will ever be reassigned with a new list
}
@@ -294,7 +296,7 @@ export class CollectionSchemaView extends CollectionSubView() {
};
@action
- addNewKey = (key: string, defaultVal: any) => this.childDocs.forEach(doc => (doc[key] = defaultVal));
+ addNewKey = (key: string, defaultVal: any) => this.childDocs.forEach(doc => (doc[DocData][key] = defaultVal));
@undoBatch
removeColumn = (index: number) => {
@@ -747,6 +749,7 @@ export class CollectionSchemaView extends CollectionSubView() {
} else {
this.setKey(this._menuValue, this._newFieldDefault);
}
+ this._columnMenuIndex = undefined;
})}>
done
</div>
@@ -754,12 +757,12 @@ export class CollectionSchemaView extends CollectionSubView() {
);
}
- onPassiveWheel = (e: WheelEvent) => {
+ onKeysPassiveWheel = (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();
+ if (!this._oldKeysWheel.scrollTop && e.deltaY <= 0) e.preventDefault();
e.stopPropagation();
};
- _oldWheel: any;
+ _oldKeysWheel: any;
@computed get keysDropdown() {
return (
<div className="schema-key-search">
@@ -774,9 +777,9 @@ export class CollectionSchemaView extends CollectionSubView() {
<div
className="schema-key-list"
ref={r => {
- this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
- this._oldWheel = r;
- r?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
+ this._oldKeysWheel?.removeEventListener('wheel', this.onKeysPassiveWheel);
+ this._oldKeysWheel = r;
+ r?.addEventListener('wheel', this.onKeysPassiveWheel, { passive: false });
}}>
{this._menuKeys.map(key => (
<div
@@ -787,14 +790,14 @@ export class CollectionSchemaView extends CollectionSubView() {
}}>
<p>
<span className="schema-search-result-key">
- {key}
- {this.fieldInfos.get(key)!.fieldType ? ', ' : ''}
+ <b>{key}</b>
+ {this.fieldInfos.get(key)!.fieldType ? ':' : ''}
</span>
<span className="schema-search-result-type" style={{ color: this.fieldInfos.get(key)!.readOnly ? 'red' : 'inherit' }}>
{this.fieldInfos.get(key)!.fieldType}
</span>
+ <span className="schema-search-result-desc">&nbsp;&nbsp;{this.fieldInfos.get(key)!.description}</span>
</p>
- <p className="schema-search-result-desc">{this.fieldInfos.get(key)!.description}</p>
</div>
))}
</div>
@@ -806,16 +809,17 @@ export class CollectionSchemaView extends CollectionSubView() {
const x = this._columnMenuIndex! == -1 ? 0 : this.displayColumnWidths.reduce((total, curr, index) => total + (index < this._columnMenuIndex! ? curr : 0), CollectionSchemaView._rowMenuWidth);
return (
<div className="schema-column-menu" style={{ left: x, minWidth: CollectionSchemaView._minColWidth }}>
- <input className="schema-key-search-input" type="text" value={this._menuValue} onKeyDown={this.onSearchKeyDown} onChange={this.updateKeySearch} onPointerDown={e => e.stopPropagation()} />
+ <input className="schema-key-search-input" type="text" onKeyDown={this.onSearchKeyDown} onChange={this.updateKeySearch} onPointerDown={e => e.stopPropagation()} />
+ {this._makeNewField ? this.newFieldMenu : this.keysDropdown}
+ </div>
+ );
+ }
+ get renderKeysMenu() {
+ console.log('RNDERMENUT:' + this._columnMenuIndex);
+ return (
+ <div className="schema-column-menu" style={{ left: 0, minWidth: CollectionSchemaView._minColWidth }}>
+ <input className="schema-key-search-input" type="text" onKeyDown={this.onSearchKeyDown} onChange={this.updateKeySearch} onPointerDown={e => e.stopPropagation()} />
{this._makeNewField ? this.newFieldMenu : this.keysDropdown}
- <div
- className="schema-column-menu-button"
- onPointerDown={action(e => {
- e.stopPropagation();
- this.closeColumnMenu();
- })}>
- cancel
- </div>
</div>
);
}
@@ -899,6 +903,8 @@ export class CollectionSchemaView extends CollectionSubView() {
isContentActive = () => this._props.isSelected() || this._props.isContentActive();
screenToLocal = () => this.ScreenToLocalBoxXf().translate(-this.tableWidth, 0);
previewWidthFunc = () => this.previewWidth;
+ onPassiveWheel = (e: WheelEvent) => e.stopPropagation();
+ _oldWheel: any;
render() {
return (
<div className="collectionSchemaView" ref={(ele: HTMLDivElement | null) => this.createDashEventsTarget(ele)} onDrop={this.onExternalDrop.bind(this)}>
@@ -907,15 +913,23 @@ export class CollectionSchemaView extends CollectionSubView() {
className="schema-table"
style={{ width: `calc(100% - ${this.previewWidth}px)` }}
onWheel={e => this._props.isContentActive() && e.stopPropagation()}
- ref={r => {
- // prevent wheel events from passively propagating up through containers
- r?.addEventListener('wheel', (e: WheelEvent) => {}, { passive: false });
+ ref={ele => {
+ // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
+ this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
+ (this._oldWheel = ele)?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
}}>
<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" />
- </div>
+ <Popup
+ placement="right"
+ background={SettingsManager.userBackgroundColor}
+ color={SettingsManager.userColor}
+ toggle={<FontAwesomeIcon onPointerDown={e => this.openColumnMenu(-1, true)} icon="plus" />}
+ trigger={PopupTrigger.CLICK}
+ type={Type.TERT}
+ isOpen={this._columnMenuIndex !== -1 ? false : undefined}
+ popup={this.renderKeysMenu}
+ />
</div>
{this.columnKeys.map((key, index) => (
<SchemaColumnHeader
@@ -936,7 +950,7 @@ export class CollectionSchemaView extends CollectionSubView() {
/>
))}
</div>
- {this._columnMenuIndex !== undefined && this.renderColumnMenu}
+ {this._columnMenuIndex !== undefined && this._columnMenuIndex !== -1 && this.renderColumnMenu}
{this._filterColumnIndex !== undefined && this.renderFilterMenu}
<CollectionSchemaViewDocs schema={this} childDocs={this.sortedDocsFunc} rowHeight={this.rowHeightFunc} setRef={(ref: HTMLDivElement | null) => (this._tableContentRef = ref)} />
{this.layoutDoc.chromeHidden ? null : (
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 1c4520ae2..734345255 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -1,8 +1,11 @@
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Popup, Size, Type } from 'browndash-components';
import { action, computed, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import { extname } from 'path';
import * as React from 'react';
import DatePicker from 'react-datepicker';
+import 'react-datepicker/dist/react-datepicker.css';
import Select from 'react-select';
import { Utils, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, returnZero } from '../../../../Utils';
import { DateField } from '../../../../fields/DateField';
@@ -12,6 +15,8 @@ import { BoolCast, Cast, DateCast, DocCast, FieldValue, StrCast } from '../../..
import { ImageField } from '../../../../fields/URLField';
import { FInfo, FInfoFieldType } from '../../../documents/Documents';
import { DocFocusOrOpen } from '../../../util/DocumentManager';
+import { dropActionType } from '../../../util/DragManager';
+import { SettingsManager } from '../../../util/SettingsManager';
import { Transform } from '../../../util/Transform';
import { undoBatch, undoable } from '../../../util/UndoManager';
import { EditableView } from '../../EditableView';
@@ -24,12 +29,7 @@ import { KeyValueBox } from '../../nodes/KeyValueBox';
import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
import { ColumnType, FInfotoColType } from './CollectionSchemaView';
import './CollectionSchemaView.scss';
-import 'react-datepicker/dist/react-datepicker.css';
-import { Popup, Size, Type } from 'browndash-components';
-import { IconLookup, faCaretDown } from '@fortawesome/free-solid-svg-icons';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { SettingsManager } from '../../../util/SettingsManager';
-import { dropActionType } from '../../../util/DragManager';
+import { SnappingManager } from '../../../util/SnappingManager';
export interface SchemaTableCellProps {
Document: Doc;
@@ -132,14 +132,14 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
contents={undefined}
fieldContents={fieldProps}
editing={this.selected ? undefined : false}
- GetValue={() => Field.toKeyValueString(this._props.Document, this._props.fieldKey)}
+ GetValue={() => Field.toKeyValueString(this._props.Document, this._props.fieldKey, SnappingManager.MetaKey)}
SetValue={undoable((value: string, shiftDown?: boolean, enterKey?: boolean) => {
if (shiftDown && enterKey) {
this._props.setColumnValues(this._props.fieldKey.replace(/^_/, ''), value);
- } /*else {
- this._props.setSelectedColumnValues(this._props.fieldKey.replace(/^_/, ''), value);
- }*/
- const ret = KeyValueBox.SetField(this._props.Document, this._props.fieldKey.replace(/^_/, ''), value);
+ this._props.finishEdit?.();
+ return true;
+ }
+ const ret = KeyValueBox.SetField(this._props.Document, this._props.fieldKey.replace(/^_/, ''), value, Doc.IsDataProto(this._props.Document) ? true : undefined);
this._props.finishEdit?.();
return ret;
}, 'edit schema cell')}
@@ -354,8 +354,7 @@ export class SchemaBoolCell extends ObservableReactComponent<SchemaTableCellProp
onChange={undoBatch((value: React.ChangeEvent<HTMLInputElement> | undefined) => {
if ((value?.nativeEvent as any).shiftKey) {
this._props.setColumnValues(this._props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + value?.target?.checked.toString());
- }
- KeyValueBox.SetField(this._props.Document, this._props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + value?.target?.checked.toString());
+ } else KeyValueBox.SetField(this._props.Document, this._props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + value?.target?.checked.toString());
})}
/>
<EditableView
@@ -366,8 +365,10 @@ export class SchemaBoolCell extends ObservableReactComponent<SchemaTableCellProp
SetValue={undoBatch((value: string, shiftDown?: boolean, enterKey?: boolean) => {
if (shiftDown && enterKey) {
this._props.setColumnValues(this._props.fieldKey.replace(/^_/, ''), value);
+ this._props.finishEdit?.();
+ return true;
}
- const set = KeyValueBox.SetField(this._props.Document, this._props.fieldKey.replace(/^_/, ''), value);
+ const set = KeyValueBox.SetField(this._props.Document, this._props.fieldKey.replace(/^_/, ''), value, Doc.IsDataProto(this._props.Document) ? true : undefined);
this._props.finishEdit?.();
return set;
})}