aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ClientUtils.ts5
-rw-r--r--src/client/documents/DocUtils.ts2
-rw-r--r--src/client/documents/Documents.ts3
-rw-r--r--src/client/util/DocumentManager.ts8
-rw-r--r--src/client/util/LinkManager.ts2
-rw-r--r--src/client/util/Scripting.ts8
-rw-r--r--src/client/util/SelectionManager.ts1
-rw-r--r--src/client/views/ContextMenu.tsx5
-rw-r--r--src/client/views/ContextMenuItem.tsx3
-rw-r--r--src/client/views/EditableView.tsx40
-rw-r--r--src/client/views/FieldsDropdown.tsx4
-rw-r--r--src/client/views/Main.tsx2
-rw-r--r--src/client/views/MainView.tsx6
-rw-r--r--src/client/views/PropertiesView.tsx2
-rw-r--r--src/client/views/ScriptingRepl.scss2
-rw-r--r--src/client/views/ScriptingRepl.tsx3
-rw-r--r--src/client/views/collections/CollectionCalendarView.tsx99
-rw-r--r--src/client/views/collections/CollectionCardDeckView.tsx199
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx3
-rw-r--r--src/client/views/collections/CollectionSubView.tsx2
-rw-r--r--src/client/views/collections/CollectionView.tsx2
-rw-r--r--src/client/views/collections/collectionSchema/CollectionSchemaView.tsx327
-rw-r--r--src/client/views/collections/collectionSchema/SchemaCellField.tsx21
-rw-r--r--src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx198
-rw-r--r--src/client/views/collections/collectionSchema/SchemaRowBox.tsx48
-rw-r--r--src/client/views/collections/collectionSchema/SchemaTableCell.tsx82
-rw-r--r--src/client/views/global/globalScripts.ts1
-rw-r--r--src/client/views/nodes/DataVizBox/DataVizBox.tsx177
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx438
-rw-r--r--src/client/views/nodes/DataVizBox/components/TableBox.tsx18
-rw-r--r--src/client/views/nodes/DocumentIcon.tsx10
-rw-r--r--src/client/views/nodes/DocumentView.tsx4
-rw-r--r--src/client/views/nodes/FieldView.tsx5
-rw-r--r--src/client/views/nodes/LabelBox.tsx4
-rw-r--r--src/client/views/nodes/calendarBox/CalendarBox.tsx2
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx17
36 files changed, 816 insertions, 937 deletions
diff --git a/src/ClientUtils.ts b/src/ClientUtils.ts
index 8ecbc55bf..3066499d8 100644
--- a/src/ClientUtils.ts
+++ b/src/ClientUtils.ts
@@ -317,7 +317,7 @@ export namespace ClientUtils {
}
export function lightenRGB(rVal: number, gVal: number, bVal: number, percent: number): [number, number, number] {
- const amount = 1 + percent/100;
+ const amount = 1 + percent / 100;
const r = rVal * amount;
const g = gVal * amount;
const b = bVal * amount;
@@ -347,8 +347,6 @@ export namespace ClientUtils {
return undefined;
}
-
-
export function GetClipboardText(): string {
const textArea = document.createElement('textarea');
document.body.appendChild(textArea);
@@ -725,7 +723,6 @@ export function UpdateIcon(
const newDiv = docViewContent.cloneNode(true) as HTMLDivElement;
newDiv.style.width = width.toString();
newDiv.style.height = height.toString();
- console.log('width: ' + newDiv.style.width)
replaceCanvases(docViewContent, newDiv);
const htmlString = new XMLSerializer().serializeToString(newDiv);
const nativeWidth = width;
diff --git a/src/client/documents/DocUtils.ts b/src/client/documents/DocUtils.ts
index 0699ea09f..1130a9ae8 100644
--- a/src/client/documents/DocUtils.ts
+++ b/src/client/documents/DocUtils.ts
@@ -1,5 +1,3 @@
-/* eslint-disable prefer-destructuring */
-/* eslint-disable default-param-last */
/* eslint-disable no-use-before-define */
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { saveAs } from 'file-saver';
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 38a4258b9..0a7047128 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -18,7 +18,6 @@ import { PointData } from '../../pen-gestures/GestureTypes';
import { DocServer } from '../DocServer';
import { dropActionType } from '../util/DropActionTypes';
import { CollectionViewType, DocumentType } from './DocumentTypes';
-import { MarkType } from 'prosemirror-model';
class EmptyBox {
public static LayoutString() {
@@ -229,7 +228,7 @@ export class DocumentOptions {
_lockedPosition?: BOOLt = new BoolInfo("lock the x,y coordinates of the document so that it can't be dragged");
_lockedTransform?: BOOLt = new BoolInfo('lock the freeform_panx,freeform_pany and scale parameters of the document so that it be panned/zoomed');
_childrenSharedWithSchema?: BOOLt = new BoolInfo("whether this document's children are displayed in its parent schema view", false);
- _lockedSchemaEditing?: BOOLt = new BoolInfo("", false);
+ _lockedSchemaEditing?: BOOLt = new BoolInfo('', false);
dataViz_title?: string;
dataViz_line?: string;
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 966731656..4ab2e8d05 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -142,13 +142,7 @@ export class DocumentManager {
}
public getDocViewIndex(target: Doc): number {
- const docViewArray = DocumentManager.Instance.DocumentViews;
- for (let i = 0; i < docViewArray.length; ++i){
- if (docViewArray[i].Document == target){
- return i;
- }
- }
- return -1;
+ return DocumentManager.Instance.DocumentViews.findIndex(dv => dv.Document === target);
}
public getLightboxDocumentView = (toFind: Doc): DocumentView | undefined => {
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index bbf8d9c11..e11482572 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -260,7 +260,7 @@ export function UPDATE_SERVER_CACHE() {
Doc.MyDockedBtns.linearView_IsOpen && console.log('Set cached docs = ');
const isFiltered = filtered.filter(doc => !Doc.IsSystem(doc));
const strings = isFiltered.map(doc => StrCast(doc.title) + ' ' + (Doc.IsDataProto(doc) ? '(data)' : '(embedding)'));
- //Doc.MyDockedBtns.linearView_IsOpen && strings.sort().forEach((str, i) => console.log(i.toString() + ' ' + str));
+ Doc.MyDockedBtns.linearView_IsOpen && strings.sort().forEach((str, i) => console.log(i.toString() + ' ' + str));
rp.post(ClientUtils.prepend('/setCacheDocumentIds'), {
body: {
diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts
index 3ba3ff4b5..b1db0bf39 100644
--- a/src/client/util/Scripting.ts
+++ b/src/client/util/Scripting.ts
@@ -81,6 +81,7 @@ function Run(script: string | undefined, customParams: string[], diagnostics: ts
if (!options.editable) {
batch = Doc.MakeReadOnly();
}
+
const result = compiledFunction.apply(thisParam, params).apply(thisParam, argsArray);
batch?.end();
return { success: true, result };
@@ -177,13 +178,8 @@ function forEachNode(node: ts.Node, onEnter: Traverser, onExit?: Traverser, inde
);
}
-// ScriptField.CompileScript(value, {}, true, undefined, DocumentIconContainer.getTransformer());
-// //addreturn = true
-// //capturedvariables = undefined
-// //
-
export function CompileScript(script: string, options: ScriptOptions = {}): CompileResult {
- const captured = options.capturedVariables ?? {};
+ const captured = options.capturedVariables ?? {};
const signature = Object.keys(captured).reduce((p, v) => {
const formatCapture = (obj: FieldType | undefined) => `${v}=${obj instanceof RefField ? 'XXX' : obj?.toString()}`;
const captureVal = captured[v];
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index c39d8ebc7..1ab84421c 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -58,7 +58,6 @@ export class SelectionManager {
});
public static DeselectAll = (except?: Doc): void => {
-
const found = this.Instance.SelectedViews.find(dv => dv.Document === except);
runInAction(() => {
if (LinkManager.Instance) {
diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx
index 98087e224..4b67ef704 100644
--- a/src/client/views/ContextMenu.tsx
+++ b/src/client/views/ContextMenu.tsx
@@ -1,6 +1,3 @@
-/* eslint-disable react/no-array-index-key */
-/* eslint-disable react/jsx-props-no-spreading */
-/* eslint-disable default-param-last */
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, IReactionDisposer, makeObservable, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
@@ -277,4 +274,4 @@ export class ContextMenu extends ObservableReactComponent<{ noexpand?: boolean }
this._selectedIndex = Math.min(this.flatItems.length - 1, this._selectedIndex);
}
};
-} \ No newline at end of file
+}
diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx
index 610032225..6f8f41bdd 100644
--- a/src/client/views/ContextMenuItem.tsx
+++ b/src/client/views/ContextMenuItem.tsx
@@ -1,4 +1,3 @@
-/* eslint-disable react/jsx-props-no-spreading */
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, makeObservable, observable, runInAction } from 'mobx';
@@ -95,4 +94,4 @@ export class ContextMenuItem extends ObservableReactComponent<ContextMenuProps &
const submenu = this._items.map(prop => <ContextMenuItem {...prop} key={prop.description} closeMenu={this._props.closeMenu} />);
return this.props.event || this._props.noexpand ? this.renderItem(submenu) : <div className="contextMenu-inlineMenu">{submenu}</div>;
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index 9974fc63b..898a98c98 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -7,7 +7,6 @@ import { DocumentIconContainer } from './nodes/DocumentIcon';
import { FieldView, FieldViewProps } from './nodes/FieldView';
import { ObservableReactComponent } from './ObservableReactComponent';
import { OverlayView } from './OverlayView';
-import { Padding } from 'browndash-components';
import { SchemaFieldType } from './collections/collectionSchema/SchemaColumnHeader';
export interface EditableProps {
@@ -91,7 +90,7 @@ export class EditableView extends ObservableReactComponent<EditableProps> {
this._overlayDisposer?.();
this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
this._props.highlightCells?.(this._props.GetValue() ?? '');
- }
+ }
});
} else {
this._overlayDisposer?.();
@@ -201,7 +200,7 @@ export class EditableView extends ObservableReactComponent<EditableProps> {
}
}
};
-
+
@action
finalizeEdit(value: string, shiftDown: boolean, lostFocus: boolean, enterKey: boolean) {
if (this._props.SetValue(value, shiftDown, enterKey)) {
@@ -236,12 +235,11 @@ export class EditableView extends ObservableReactComponent<EditableProps> {
setIsEditing = (value: boolean) => {
this._editing = value;
return this._editing;
- }
+ };
renderEditor() {
return this._props.autosuggestProps ? (
<Autosuggest
- // eslint-disable-next-line react/jsx-props-no-spreading
{...this._props.autosuggestProps.autosuggestProps}
inputProps={{
className: 'editableView-input',
@@ -255,11 +253,11 @@ export class EditableView extends ObservableReactComponent<EditableProps> {
onChange: this._props.autosuggestProps.onChange,
}}
/>
- ) : ( this._props.oneLine !== false && this._props.GetValue()?.toString().indexOf('\n') === -1 ? (
+ ) : this._props.oneLine !== false && this._props.GetValue()?.toString().indexOf('\n') === -1 ? (
<input
- className="editableView-input"
+ className="editableView-input"
ref={r => { this._inputref = r; }} // prettier-ignore
- style={{ display: this._props.display, overflow: 'auto', fontSize: this._props.fontSize, minWidth: 20, background: this._props.background}}
+ style={{ display: this._props.display, overflow: 'auto', fontSize: this._props.fontSize, minWidth: 20, background: this._props.background }}
placeholder={this._props.placeholder}
onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true, false)}
defaultValue={this._props.GetValue()}
@@ -285,7 +283,7 @@ export class EditableView extends ObservableReactComponent<EditableProps> {
onClick={this.stopPropagation}
onPointerUp={this.stopPropagation}
/>
- ));
+ );
}
staticDisplay = () => {
@@ -300,24 +298,24 @@ export class EditableView extends ObservableReactComponent<EditableProps> {
// eslint-disable-next-line jsx-a11y/no-autofocus
/>
} else {
- toDisplay = (<span className='editableView-static'
- style={{
- fontStyle: this._props.fontStyle,
- fontSize: this._props.fontSize
- }}>
- {
- // eslint-disable-next-line react/jsx-props-no-spreading
- this._props.fieldContents ? <FieldView {...this._props.fieldContents} /> : this.props.contents ? this._props.contents?.valueOf() : '' as any
- }
- </span>)
+ toDisplay = (
+ <span
+ className="editableView-static"
+ style={{
+ fontStyle: this._props.fontStyle,
+ fontSize: this._props.fontSize,
+ }}>
+ {this._props.fieldContents ? <FieldView {...this._props.fieldContents} /> : (this.props.contents ?? '')}
+ </span>
+ );
}
return toDisplay;
- }
+ };
render() {
const gval = this._props.GetValue()?.replace(/\n/g, '\\r\\n');
- if ((this._editing && gval !== undefined)) {
+ if (this._editing && gval !== undefined) {
return this._props.sizeToContent ? (
<div style={{ display: 'grid', minWidth: 100 }}>
<div style={{ display: 'inline-block', position: 'relative', height: 0, width: '100%', overflow: 'hidden' }}>{this.renderEditor()}</div>
diff --git a/src/client/views/FieldsDropdown.tsx b/src/client/views/FieldsDropdown.tsx
index 176ac96b6..407031b40 100644
--- a/src/client/views/FieldsDropdown.tsx
+++ b/src/client/views/FieldsDropdown.tsx
@@ -34,7 +34,7 @@ export class FieldsDropdown extends ObservableReactComponent<fieldsDropdownProps
makeObservable(this);
}
- @computed get allDescendantDocs() { //!!!
+ @computed get allDescendantDocs() {
const allDocs = new Set<Doc>();
SearchUtil.foreachRecursiveDoc([this._props.Document], (depth, doc) => allDocs.add(doc));
return Array.from(allDocs);
@@ -57,7 +57,7 @@ export class FieldsDropdown extends ObservableReactComponent<fieldsDropdownProps
const filteredOptions = ['author', ...(this._newField ? [this._newField] : []), ...(this._props.addedFields ?? []), ...this.fieldsOfDocuments.filter(facet => facet[0] === facet.charAt(0).toUpperCase())];
Object.entries(DocOptions)
- .filter(opts => opts[1].filterable) //!!!
+ .filter(opts => opts[1].filterable)
.forEach((pair: [string, FInfo]) => filteredOptions.push(pair[0]));
const options = filteredOptions.sort().map(facet => ({ value: facet, label: facet }));
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 73d2872d1..17eea585a 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -18,7 +18,6 @@ import { TrackMovements } from '../util/TrackMovements';
import { KeyManager } from './GlobalKeyHandler';
import { InkingStroke } from './InkingStroke';
import { MainView } from './MainView';
-import { CollectionCalendarView } from './collections/CollectionCalendarView';
import { CollectionDockingView } from './collections/CollectionDockingView';
import { CollectionView } from './collections/CollectionView';
import { TabDocView } from './collections/TabDocView';
@@ -128,7 +127,6 @@ FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0, message: 'cache' };
CollectionFreeFormView,
CollectionDockingView,
CollectionSchemaView,
- CollectionCalendarView,
CollectionView,
WebBox,
KeyValueBox,
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 6feb6bd16..fc159d96b 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -41,6 +41,7 @@ import { DashboardView } from './DashboardView';
import { DictationOverlay } from './DictationOverlay';
import { DocumentDecorations } from './DocumentDecorations';
import { GestureOverlay } from './GestureOverlay';
+import { InkTranscription } from './InkTranscription';
import { LightboxView } from './LightboxView';
import './MainView.scss';
import { ObservableReactComponent } from './ObservableReactComponent';
@@ -57,6 +58,7 @@ import { ImageLabelHandler } from './collections/collectionFreeForm/ImageLabelHa
import { MarqueeOptionsMenu } from './collections/collectionFreeForm/MarqueeOptionsMenu';
import { CollectionLinearView } from './collections/collectionLinear';
import { LinkMenu } from './linking/LinkMenu';
+import { DocCreatorMenu } from './nodes/DataVizBox/DocCreatorMenu';
import { SchemaCSVPopUp } from './nodes/DataVizBox/SchemaCSVPopUp';
import { DocButtonState } from './nodes/DocumentLinksButton';
import { DocumentView, DocumentViewInternal } from './nodes/DocumentView';
@@ -73,10 +75,8 @@ import GenerativeFill from './nodes/generativeFill/GenerativeFill';
import { PresBox } from './nodes/trails';
import { AnchorMenu } from './pdf/AnchorMenu';
import { GPTPopup } from './pdf/GPTPopup/GPTPopup';
-import { TopBar } from './topbar/TopBar';
-import { DocCreatorMenu } from './nodes/DataVizBox/DocCreatorMenu';
import { SmartDrawHandler } from './smartdraw/SmartDrawHandler';
-import { InkTranscription } from './InkTranscription';
+import { TopBar } from './topbar/TopBar';
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { LEFT_MENU_WIDTH, TOPBAR_HEIGHT } = require('./global/globalCssVariables.module.scss'); // prettier-ignore
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 69c46052e..c6dccb4fb 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -884,7 +884,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
@computed get borderColor() {
const doc = this.selectedDoc;
const layoutDoc = doc ? Doc.Layout(doc) : doc;
- return StrCast(layoutDoc);
+ return StrCast(layoutDoc.color);
}
set borderColor(value) { this.selectedDoc && (this.selectedDoc[DocData].color = value || undefined); } // prettier-ignore
diff --git a/src/client/views/ScriptingRepl.scss b/src/client/views/ScriptingRepl.scss
index 5fe176920..adc82238e 100644
--- a/src/client/views/ScriptingRepl.scss
+++ b/src/client/views/ScriptingRepl.scss
@@ -35,8 +35,6 @@
opacity: 0.3;
}
-
-
.scriptingObject-icon {
padding: 3px;
cursor: pointer;
diff --git a/src/client/views/ScriptingRepl.tsx b/src/client/views/ScriptingRepl.tsx
index 2de867746..e413c13e2 100644
--- a/src/client/views/ScriptingRepl.tsx
+++ b/src/client/views/ScriptingRepl.tsx
@@ -1,4 +1,3 @@
-/* eslint-disable react/no-array-index-key */
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
@@ -182,7 +181,7 @@ export class ScriptingRepl extends ObservableReactComponent<object> {
this.maybeScrollToBottom();
return;
}
- const result = undoable(() => script.run({}, e => this.commands.push({ command: this.commandString, result: e as string })), 'run:' + this.commandString)();
+ const result = undoable(() => script.run({}, err => this.commands.push({ command: this.commandString, result: err })), 'run:' + this.commandString)();
if (result.success) {
this.commands.push({ command: this.commandString, result: result.result });
this.commandsHistory.push(this.commandString);
diff --git a/src/client/views/collections/CollectionCalendarView.tsx b/src/client/views/collections/CollectionCalendarView.tsx
deleted file mode 100644
index 0ea9f8ebc..000000000
--- a/src/client/views/collections/CollectionCalendarView.tsx
+++ /dev/null
@@ -1,99 +0,0 @@
-import { computed, makeObservable } from 'mobx';
-import { observer } from 'mobx-react';
-import * as React from 'react';
-import { emptyFunction } from '../../../Utils';
-import { dateRangeStrToDates, returnTrue } from '../../../ClientUtils';
-import { Doc, DocListCast } from '../../../fields/Doc';
-import { StrCast } from '../../../fields/Types';
-import { CollectionStackingView } from './CollectionStackingView';
-import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
-
-@observer
-export class CollectionCalendarView extends CollectionSubView() {
- constructor(props: SubCollectionViewProps) {
- super(props);
- makeObservable(this);
- }
-
- componentDidMount(): void {}
-
- componentWillUnmount(): void {}
-
- @computed get allCalendars() {
- return this.childDocs; // returns a list of docs (i.e. calendars)
- }
-
- removeCalendar = () => {};
-
- addCalendar = (/* doc: Doc | Doc[], annotationKey?: string | undefined */): boolean =>
- // bring up calendar modal with option to create a calendar
- true;
-
- _stackRef = React.createRef<CollectionStackingView>();
-
- panelHeight = () => this._props.PanelHeight() - 40; // this should be the height of the stacking view. For now, it's the hieight of the calendar view minus 40 to allow for a title
-
- // most recent calendar should come first
- sortByMostRecentDate = (calendarA: Doc, calendarB: Doc) => {
- const aDateRangeStr = StrCast(DocListCast(calendarA.data).lastElement()?.date_range);
- const bDateRangeStr = StrCast(DocListCast(calendarB.data).lastElement()?.date_range);
-
- const { start: aFromDate, end: aToDate } = dateRangeStrToDates(aDateRangeStr);
- const { start: bFromDate, end: bToDate } = dateRangeStrToDates(bDateRangeStr);
-
- if (aFromDate > bFromDate) {
- return -1; // a comes first
- }
- if (aFromDate < bFromDate) {
- return 1; // b comes first
- }
- // start dates are the same
- if (aToDate > bToDate) {
- return -1; // a comes first
- }
- if (aToDate < bToDate) {
- return 1; // b comes first
- }
- return 0; // same start and end dates
- };
-
- screenToLocalTransform = () =>
- this._props
- .ScreenToLocalTransform()
- .translate(Doc.NativeWidth(this.Document), 0)
- .scale(this._props.NativeDimScaling?.() || 1);
-
- get calendarsKey() {
- return this._props.fieldKey;
- }
-
- render() {
- return (
- <div className="collectionCalendarView">
- <CollectionStackingView
- // eslint-disable-next-line react/jsx-props-no-spreading
- {...this._props}
- setContentViewBox={emptyFunction}
- ref={this._stackRef}
- PanelHeight={this.panelHeight}
- PanelWidth={this._props.PanelWidth}
- sortFunc={this.sortByMostRecentDate}
- setHeight={undefined}
- isAnnotationOverlay={false}
- // select={emptyFunction} What does this mean?
- isAnyChildContentActive={returnTrue} // ??
- dontCenter="y"
- // childDocumentsActive={}
- // whenChildContentsActiveChanged={}
- childHideDecorationTitle={false}
- removeDocument={this.removeDocument} // will calendar automatically be removed from myCalendars
- moveDocument={this.moveDocument}
- addDocument={this.addCalendar}
- ScreenToLocalTransform={this.screenToLocalTransform}
- renderDepth={this._props.renderDepth + 1}
- fieldKey={this.calendarsKey}
- />
- </div>
- );
- }
-}
diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx
index 101cc8082..a9ab9de26 100644
--- a/src/client/views/collections/CollectionCardDeckView.tsx
+++ b/src/client/views/collections/CollectionCardDeckView.tsx
@@ -2,7 +2,6 @@ import { IReactionDisposer, ObservableMap, action, computed, makeObservable, obs
import { observer } from 'mobx-react';
import * as React from 'react';
import { ClientUtils, DashColor, returnFalse, returnZero } from '../../../ClientUtils';
-import { emptyFunction } from '../../../Utils';
import { Doc } from '../../../fields/Doc';
import { DocData } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
@@ -13,7 +12,6 @@ import { gptImageLabel } from '../../apis/gpt/GPT';
import { DocumentType } from '../../documents/DocumentTypes';
import { DragManager } from '../../util/DragManager';
import { dropActionType } from '../../util/DropActionTypes';
-import { SelectionManager } from '../../util/SelectionManager';
import { SnappingManager } from '../../util/SnappingManager';
import { Transform } from '../../util/Transform';
import { undoable } from '../../util/UndoManager';
@@ -23,12 +21,12 @@ import { DocumentView } from '../nodes/DocumentView';
import { GPTPopup, GPTPopupMode } from '../pdf/GPTPopup/GPTPopup';
import './CollectionCardDeckView.scss';
import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
+import { computedFn } from 'mobx-utils';
enum cardSortings {
Time = 'time',
Type = 'type',
Color = 'color',
- Custom = 'custom',
Chat = 'chat',
Tag = 'tag',
None = '',
@@ -46,14 +44,13 @@ export class CollectionCardView extends CollectionSubView() {
private _dropDisposer?: DragManager.DragDropDisposer;
private _disposers: { [key: string]: IReactionDisposer } = {};
private _textToDoc = new Map<string, Doc>();
- private _dropped = false; // indicate when a card doc has just moved;
+ private _dropped = false; // set when a card doc has just moved and the drop method has been called - prevents the pointerUp method from hiding doc decorations (which needs to be done when clicking on a card to animate it to front/center)
@observable _forceChildXf = 0;
@observable _hoveredNodeIndex = -1;
@observable _docRefs = new ObservableMap<Doc, DocumentView>();
@observable _maxRowCount = 10;
@observable _docDraggedIndex: number = -1;
- @observable overIndex: number = -1;
static imageUrlToBase64 = async (imageUrl: string): Promise<string> => {
try {
@@ -101,7 +98,6 @@ export class CollectionCardView extends CollectionSubView() {
componentDidMount() {
this._props.setContentViewBox?.(this);
- // Reaction to cardSort changes
this._disposers.sort = reaction(
() => GPTPopup.Instance.visible,
isVis => {
@@ -135,8 +131,7 @@ export class CollectionCardView extends CollectionSubView() {
}
/**
- * The child documents to be rendered-- either all of them except the Links or the docs in the currently active
- * custom group
+ * The child documents to be rendered-- everything other than ink/link docs (which are marks as being svg's)
*/
@computed get childDocsWithoutLinks() {
return this.childDocs.filter(l => !l.layout_isSvg);
@@ -155,8 +150,7 @@ export class CollectionCardView extends CollectionSubView() {
*/
quizMode = () => {
const randomIndex = Math.floor(Math.random() * this.childDocs.length);
- SelectionManager.DeselectAll();
- DocumentView.SelectView(DocumentView.getDocumentView(this.childDocs[randomIndex]), false);
+ DocumentView.getDocumentView(this.childDocs[randomIndex])?.select(false);
};
/**
@@ -168,29 +162,15 @@ export class CollectionCardView extends CollectionSubView() {
@action
setHoveredNodeIndex = (index: number) => {
- if (!DocumentView.SelectedDocs().includes(this.childDocs[index])) {
- this._hoveredNodeIndex = index;
- }
+ if (!SnappingManager.IsDragging) this._hoveredNodeIndex = index;
};
- /**
- * Translates the hovered node to the center of the screen
- * @param index
- * @returns
- */
- translateHover = (index: number) => (this._hoveredNodeIndex === index && !DocumentView.SelectedDocs().includes(this.childDocs[index]) ? -50 : 0);
-
- isSelected = (index: number) => DocumentView.SelectedDocs().includes(this.childDocs[index]);
-
- /**
- * Returns all the documents except the one that's currently selected
- */
- inactiveDocs = () => this.childDocsWithoutLinks.filter(d => !DocumentView.SelectedDocs().includes(d));
+ isSelected = (doc: Doc) => this._docRefs.get(doc)?.IsSelected;
childPanelWidth = () => NumCast(this.layoutDoc.childPanelWidth, this._props.PanelWidth() / 2);
childPanelHeight = () => this._props.PanelHeight() * this.fitContentScale;
onChildDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick);
- isContentActive = () => this._props.isSelected() || this._props.isContentActive() || this._props.isAnyChildContentActive();
- isChildContentActive = () => !!this.isContentActive();
+ isContentActive = () => this._props.isSelected() || this._props.isContentActive() || this.isAnyChildContentActive();
+ isAnyChildContentActive = this._props.isAnyChildContentActive;
/**
* Returns the degree to rotate a card dependind on the amount of cards in their row and their index in said row
@@ -202,13 +182,14 @@ export class CollectionCardView extends CollectionSubView() {
if (amCards == 1) return 0;
const possRotate = -30 + index * (30 / ((amCards - (amCards % 2)) / 2));
- const stepMag = Math.abs(-30 + (amCards / 2 - 1) * (30 / ((amCards - (amCards % 2)) / 2)));
-
- if (amCards % 2 === 0 && possRotate === 0) {
- return possRotate + Math.abs(-30 + (index - 1) * (30 / (amCards / 2)));
- }
- if (amCards % 2 === 0 && index > (amCards + 1) / 2) {
- return possRotate + stepMag;
+ if (amCards % 2 === 0) {
+ if (possRotate === 0) {
+ return possRotate + Math.abs(-30 + (index - 1) * (30 / (amCards / 2)));
+ }
+ if (index > (amCards + 1) / 2) {
+ const stepMag = Math.abs(-30 + (amCards / 2 - 1) * (30 / ((amCards - (amCards % 2)) / 2)));
+ return possRotate + stepMag;
+ }
}
return possRotate;
@@ -274,22 +255,13 @@ export class CollectionCardView extends CollectionSubView() {
/**
* Checks to see if a card is being dragged and calls the appropriate methods if so
- * @param e the current pointer event
*/
-
@action
onPointerMove = (x: number, y: number) => {
this._docDraggedIndex = DragManager.docsBeingDragged.length ? this.findCardDropIndex(x, y) : -1;
};
/**
- * Handles external drop of images/PDFs etc from outside Dash.
- */
- onExternalDrop = async (e: React.DragEvent): Promise<void> => {
- super.onExternalDrop(e, {});
- };
-
- /**
* Resets all the doc dragging vairables once a card is dropped
* @param e
* @param de drop event
@@ -326,7 +298,7 @@ export class CollectionCardView extends CollectionSubView() {
}
/**
- * Used to determine how to sort cards based on tags. The lestmost tags are given lower values while cards to the right are
+ * Used to determine how to sort cards based on tags. The leftmost tags are given lower values while cards to the right are
* given higher values. Decimals are used to determine placement for cards with multiple tags
* @param doc the doc whose value is being determined
* @returns its value based on its tags
@@ -352,24 +324,14 @@ export class CollectionCardView extends CollectionSubView() {
docs.sort((docA, docB) => {
const [typeA, typeB] = (() => {
switch (sortType) {
- case cardSortings.Time:
- return [DateCast(docA.author_date)?.date ?? Date.now(), DateCast(docB.author_date)?.date ?? Date.now()];
- case cardSortings.Color: {
- const d1 = DashColor(StrCast(docA.backgroundColor));
- const d2 = DashColor(StrCast(docB.backgroundColor));
- return [d1.hsv().hue(), d2.hsv().hue()];
- }
- case cardSortings.Tag:
- return [this.tagValue(docA) ?? 9999, this.tagValue(docB) ?? 9999];
- case cardSortings.Chat:
- return [NumCast(docA.chatIndex) ?? 9999, NumCast(docB.chatIndex) ?? 9999];
- default:
- return [StrCast(docA.type), StrCast(docB.type)];
+ default:
+ case cardSortings.Type: return [StrCast(docA.type), StrCast(docB.type)];
+ case cardSortings.Chat: return [NumCast(docA.chatIndex, 9999), NumCast(docB.chatIndex,9999)];
+ case cardSortings.Time: return [DateCast(docA.author_date)?.date ?? Date.now(), DateCast(docB.author_date)?.date ?? Date.now()];
+ case cardSortings.Color:return [DashColor(StrCast(docA.backgroundColor)).hsv().hue(), DashColor(StrCast(docB.backgroundColor)).hsv().hue()];
}
- })();
-
- const out = typeA < typeB ? -1 : typeA > typeB ? 1 : 0;
- return isDesc ? out : -out;
+ })(); //prettier-ignore
+ return (typeA < typeB ? -1 : typeA > typeB ? 1 : 0) * (isDesc ? 1 : -1);
});
if (dragIndex !== -1) {
const draggedDoc = DragManager.docsBeingDragged[0];
@@ -382,6 +344,15 @@ export class CollectionCardView extends CollectionSubView() {
return docs;
};
+ isChildContentActive = () =>
+ this._props.isContentActive?.() === false
+ ? false
+ : this._props.isDocumentActive?.() && (this._props.childDocumentsActive?.() || BoolCast(this.Document.childDocumentsActive))
+ ? true
+ : this._props.childDocumentsActive?.() === false || this.Document.childDocumentsActive === false
+ ? false
+ : undefined;
+
displayDoc = (doc: Doc, screenToLocalTransform: () => Transform) => (
<DocumentView
{...this._props}
@@ -396,13 +367,14 @@ export class CollectionCardView extends CollectionSubView() {
LayoutTemplateString={this._props.childLayoutString}
containerViewPath={this.childContainerViewPath}
ScreenToLocalTransform={screenToLocalTransform} // makes sure the box wrapper thing is in the right spot
- isContentActive={emptyFunction}
isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive}
PanelWidth={this.childPanelWidth}
PanelHeight={this.childPanelHeight}
dontCenter="y" // Don't center it vertically, because the grid it's in is already doing that and we don't want to do it twice.
dragAction={(this.Document.childDragAction ?? this._props.childDragAction) as dropActionType}
showTags={BoolCast(this.layoutDoc.showChildTags)}
+ whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
+ isContentActive={this.isChildContentActive}
dontHideOnDrag
/>
);
@@ -416,13 +388,11 @@ export class CollectionCardView extends CollectionSubView() {
if (this.sortedDocs.length < this._maxRowCount) {
return this.sortedDocs.length;
}
- // 13 - 3 = 10
const totalCards = this.sortedDocs.length;
// if 9 or less
if (index < totalCards - (totalCards % this._maxRowCount)) {
return this._maxRowCount;
}
- // (3)
return totalCards % this._maxRowCount;
};
/**
@@ -443,17 +413,17 @@ export class CollectionCardView extends CollectionSubView() {
/**
* Determines how far to translate a card in the y direction depending on its index, whether or not its being hovered, or if it's selected
* @param isHovered
- * @param isSelected
+ * @param isActive
* @param realIndex
* @param amCards
* @param calcRowIndex
* @returns
*/
- calculateTranslateY = (isHovered: boolean, isSelected: boolean, realIndex: number, amCards: number, calcRowIndex: number) => {
+ calculateTranslateY = (isHovered: boolean, isActive: boolean, realIndex: number, amCards: number, calcRowIndex: number) => {
const rowHeight = (this._props.PanelHeight() * this.fitContentScale) / this.numRows;
const rowIndex = Math.trunc(realIndex / this._maxRowCount);
const rowToCenterShift = this.numRows / 2 - rowIndex;
- if (isSelected) return rowToCenterShift * rowHeight - rowHeight / 2;
+ if (isActive) return rowToCenterShift * rowHeight - rowHeight / 2;
if (amCards == 1) return 50 * this.fitContentScale;
return this.translateY(amCards, calcRowIndex, realIndex);
};
@@ -576,15 +546,43 @@ export class CollectionCardView extends CollectionSubView() {
await this.childPairStringListAndUpdateSortDesc();
};
+ childScreenToLocal = computedFn((doc: Doc, index: number, calcRowIndex: number, isSelected: boolean, amCards: number) => () => {
+ // need to explicitly trigger an invalidation since we're reading everything from the Dom
+ this._forceChildXf;
+ this._props.ScreenToLocalTransform();
+
+ const dref = this._docRefs.get(doc);
+ const { translateX, translateY, scale } = ClientUtils.GetScreenTransform(dref?.ContentDiv);
+ if (!scale) return new Transform(0, 0, 0);
+
+ return new Transform(-translateX + (dref?.centeringX || 0) * scale,
+ -translateY + (dref?.centeringY || 0) * scale, 1)
+ .scale(1 / scale).rotate(!isSelected ? -this.rotate(amCards, calcRowIndex) : 0); // prettier-ignore
+ });
+
+ cardPointerUp = action((doc: Doc) => {
+ // if a card doc has just moved, or a card is selected and in front, then ignore this event
+ if (this.isSelected(doc) || this._dropped) {
+ this._dropped = false;
+ } else {
+ // otherwise, turn off documentDecorations becase we're in a selection transition and want to avoid artifacts.
+ // Turn them back on when the animation has completed and the render and backend structures are in synch
+ SnappingManager.SetIsResizing(doc[Id]);
+ setTimeout(
+ action(() => {
+ SnappingManager.SetIsResizing(undefined);
+ this._forceChildXf++;
+ }),
+ 1000
+ );
+ }
+ });
+
/**
* Actually renders all the cards
*/
@computed get renderCards() {
- const sortedDocs = this.sortedDocs;
- const anySelected = this.childDocs.some(doc => DocumentView.SelectedDocs().includes(doc));
- const isEmpty = this.childDocsWithoutLinks.length === 0;
-
- if (isEmpty) {
+ if (!this.childDocsWithoutLinks.length) {
return (
<span className="no-card-span" style={{ width: ` ${this._props.PanelWidth()}px`, height: ` ${this._props.PanelHeight()}px` }}>
Sorry ! There are no cards in this group
@@ -593,31 +591,18 @@ export class CollectionCardView extends CollectionSubView() {
}
// Map sorted documents to their rendered components
- return sortedDocs.map((doc, index) => {
- const realIndex = sortedDocs.indexOf(doc);
+ return this.sortedDocs.map((doc, index) => {
+ const realIndex = this.sortedDocs.indexOf(doc);
const calcRowIndex = this.overflowIndexCalc(realIndex);
const amCards = this.overflowAmCardsCalc(realIndex);
const view = DocumentView.getDocumentView(doc, this.DocumentView?.());
- const isSelected = view?.ComponentView?.isAnyChildContentActive?.() || view?.IsSelected ? true : false;
- const childScreenToLocal = () => {
- // need to explicitly trigger an invalidation since we're reading everything from the Dom
- this._forceChildXf;
- this._props.ScreenToLocalTransform();
-
- const dref = this._docRefs.get(doc);
- const { translateX, translateY, scale } = ClientUtils.GetScreenTransform(dref?.ContentDiv);
- if (!scale) return new Transform(0, 0, 0);
-
- return new Transform(-translateX + (dref?.centeringX || 0) * scale,
- -translateY + (dref?.centeringY || 0) * scale, 1)
- .scale(1 / scale).rotate(!isSelected ? -this.rotate(amCards, calcRowIndex) : 0); // prettier-ignore
- };
+ const childScreenToLocal = this.childScreenToLocal(doc, index, calcRowIndex, !!view?.IsContentActive, amCards);
const translateIfSelected = () => {
const indexInRow = index % this._maxRowCount;
const rowIndex = Math.trunc(index / this._maxRowCount);
- const rowCenterIndex = Math.min(this._maxRowCount, sortedDocs.length - rowIndex * this._maxRowCount) / 2;
+ const rowCenterIndex = Math.min(this._maxRowCount, this.sortedDocs.length - rowIndex * this._maxRowCount) / 2;
return (rowCenterIndex - indexInRow) * 100 - 50;
};
const aspect = NumCast(doc.height) / NumCast(doc.width, 1);
@@ -627,33 +612,18 @@ export class CollectionCardView extends CollectionSubView() {
return (
<div
key={doc[Id]}
- className={`card-item${isSelected ? '-active' : anySelected ? '-inactive' : ''}`}
- onPointerUp={action(() => {
- // if a card doc has just moved, or a card is selected and in front, then ignore this event
- if (DocumentView.SelectedDocs().includes(doc) || this._dropped) {
- this._dropped = false;
- } else {
- // otherwise, turn off documentDecorations becase we're in a selection transition and want to avoid artifacts.
- // Turn them back on when the animation has completed and the render and backend structures are in synch
- SnappingManager.SetIsResizing(doc[Id]);
- setTimeout(
- action(() => {
- SnappingManager.SetIsResizing(undefined);
- this._forceChildXf++;
- }),
- 1000
- );
- }
- })}
+ className={`card-item${view?.IsContentActive ? '-active' : this.isAnyChildContentActive() ? '-inactive' : ''}`}
+ onPointerUp={() => this.cardPointerUp(doc)}
style={{
width: this.childPanelWidth(),
height: 'max-content',
- transform: `translateY(${this.calculateTranslateY(this._hoveredNodeIndex === index, isSelected, realIndex, amCards, calcRowIndex)}px)
- translateX(calc(${isSelected ? translateIfSelected() : 0}% + ${this.translateOverflowX(realIndex, amCards)}px))
- rotate(${!isSelected ? this.rotate(amCards, calcRowIndex) : 0}deg)
- scale(${isSelected ? `${Math.min(hscale, vscale) * 100}%` : this._hoveredNodeIndex === index ? 1.05 : 1})`,
+ transform: `translateY(${this.calculateTranslateY(this._hoveredNodeIndex === index, !!view?.IsContentActive, realIndex, amCards, calcRowIndex)}px)
+ translateX(calc(${view?.IsContentActive ? translateIfSelected() : 0}% + ${this.translateOverflowX(realIndex, amCards)}px))
+ rotate(${!view?.IsContentActive ? this.rotate(amCards, calcRowIndex) : 0}deg)
+ scale(${view?.IsContentActive ? `${Math.min(hscale, vscale) * 100}%` : this._hoveredNodeIndex === index ? 1.1 : 1})`,
}} // prettier-ignore
- onPointerEnter={() => !SnappingManager.IsDragging && this.setHoveredNodeIndex(index)}>
+ onPointerEnter={() => this.setHoveredNodeIndex(index)}
+ onPointerLeave={() => this.setHoveredNodeIndex(-1)}>
{this.displayDoc(doc, childScreenToLocal)}
</div>
);
@@ -680,8 +650,7 @@ export class CollectionCardView extends CollectionSubView() {
...(!isEmpty && { transform: `scale(${1 / this.fitContentScale})` }),
...(!isEmpty && { height: `${100 * this.fitContentScale}%` }),
gridAutoRows: `${100 / this.numRows}%`,
- }}
- onMouseLeave={() => this.setHoveredNodeIndex(-1)}>
+ }}>
{this.renderCards}
</div>
</div>
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 74cf580c9..8b3a699ed 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -165,7 +165,7 @@ export class CollectionCarouselView extends CollectionSubView() {
NativeWidth={returnZero}
NativeHeight={returnZero}
fitWidth={this._props.childLayoutFitWidth}
- showTags={true}
+ showTags={BoolCast(this.layoutDoc.showChildTags)}
containerViewPath={this.childContainerViewPath}
setContentViewBox={undefined}
ScreenToLocalTransform={this.childScreenToLocalXf}
@@ -178,6 +178,7 @@ export class CollectionCarouselView extends CollectionSubView() {
LayoutTemplate={this._props.childLayoutTemplate}
LayoutTemplateString={this._props.childLayoutString}
TemplateDataDocument={DocCast(Doc.Layout(doc).resolvedDataDoc)}
+ xPadding={35}
PanelHeight={this.panelHeight}
/>
);
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 5d32482c3..581201a20 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -296,7 +296,7 @@ export function CollectionSubView<X>() {
return false;
}
- protected async onExternalDrop(e: React.DragEvent, options: DocumentOptions, completed?: (docs: Doc[]) => void) {
+ protected async onExternalDrop(e: React.DragEvent, options: DocumentOptions = {}, completed?: (docs: Doc[]) => void) {
if (e.ctrlKey) {
e.stopPropagation(); // bcz: this is a hack to stop propagation when dropping an image on a text document with shift+ctrl
return;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index c9e934448..7418d4360 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -1,4 +1,3 @@
-/* eslint-disable react/jsx-props-no-spreading */
import { IReactionDisposer, makeObservable, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
@@ -16,7 +15,6 @@ import { ContextMenuProps } from '../ContextMenuItem';
import { ViewBoxAnnotatableComponent } from '../DocComponent';
import { FieldView } from '../nodes/FieldView';
import { OpenWhere } from '../nodes/OpenWhere';
-import { CollectionCalendarView } from './CollectionCalendarView';
import { CollectionCardView } from './CollectionCardDeckView';
import { CollectionCarousel3DView } from './CollectionCarousel3DView';
import { CollectionCarouselView } from './CollectionCarouselView';
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 0076caaf8..aef97e723 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1,12 +1,11 @@
-/* eslint-disable no-restricted-syntax */
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { IconButton, Popup, PopupTrigger, Size, Type } from 'browndash-components';
-import { IReactionDisposer, ObservableMap, action, autorun, computed, makeObservable, observable, observe, override, reaction, runInAction } from 'mobx';
+import { IconButton, Size } from 'browndash-components';
+import { IReactionDisposer, Lambda, ObservableMap, action, computed, makeObservable, observable, observe, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { ClientUtils, returnEmptyString, returnFalse, returnIgnore, returnNever, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../ClientUtils';
import { emptyFunction } from '../../../../Utils';
-import { Doc, DocListCast, Field, FieldType, IdToDoc, NumListCast, Opt, StrListCast } from '../../../../fields/Doc';
+import { Doc, DocListCast, Field, FieldType, NumListCast, Opt, StrListCast } from '../../../../fields/Doc';
import { DocData } from '../../../../fields/DocSymbols';
import { Id } from '../../../../fields/FieldSymbols';
import { List } from '../../../../fields/List';
@@ -14,10 +13,13 @@ import { ColumnType } from '../../../../fields/SchemaHeaderField';
import { BoolCast, NumCast, StrCast } from '../../../../fields/Types';
import { DocUtils } from '../../../documents/DocUtils';
import { Docs, DocumentOptions, FInfo } from '../../../documents/Documents';
+import { DocumentManager } from '../../../util/DocumentManager';
import { DragManager } from '../../../util/DragManager';
import { dropActionType } from '../../../util/DropActionTypes';
+import { SnappingManager } from '../../../util/SnappingManager';
import { undoBatch, undoable } from '../../../util/UndoManager';
import { ContextMenu } from '../../ContextMenu';
+import { ContextMenuProps } from '../../ContextMenuItem';
import { EditableView } from '../../EditableView';
import { ObservableReactComponent } from '../../ObservableReactComponent';
import { StyleProp } from '../../StyleProp';
@@ -28,25 +30,23 @@ import { FieldViewProps } from '../../nodes/FieldView';
import { FocusViewOptions } from '../../nodes/FocusViewOptions';
import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView';
import './CollectionSchemaView.scss';
+import { SchemaCellField } from './SchemaCellField';
import { SchemaColumnHeader } from './SchemaColumnHeader';
import { SchemaRowBox } from './SchemaRowBox';
-import { ContextMenuProps } from '../../ContextMenuItem';
-import { DocumentManager } from '../../../util/DocumentManager';
-import { SchemaCellField } from './SchemaCellField';
-import { SnappingManager } from '../../../util/SnappingManager';
/**
* The schema view offers a spreadsheet-like interface for users to interact with documents. Within the schema,
- * each doc is represented by its own row. Each column represents a field, for example the author or title fields.
+ * each doc is represented by its own row. Each column represents a field, for example the author or title fields.
* Users can apply varoius filters and sorts to columns to change what is displayed. The schemaview supports equations for
* cell linking.
- *
+ *
* This class supports the main functionality for choosing which docs to render in the view, applying visual
- * updates to rows and columns (such as user dragging or sort-related highlighting), applying edits to multiple cells
+ * updates to rows and columns (such as user dragging or sort-related highlighting), applying edits to multiple cells
* at once, and applying filters and sorts to columns. It contains SchemaRowBoxes (which themselves contain SchemaTableCells,
* and SchemaCellFields) and SchemaColumnHeaders.
*/
+// eslint-disable-next-line @typescript-eslint/no-require-imports
const { SCHEMA_NEW_NODE_HEIGHT } = require('../../global/globalCssVariables.module.scss'); // prettier-ignore
export const FInfotoColType: { [key: string]: ColumnType } = {
@@ -63,7 +63,7 @@ const defaultColumnKeys: string[] = ['title', 'type', 'author', 'author_date', '
@observer
export class CollectionSchemaView extends CollectionSubView() {
- private _keysDisposer: any;
+ private _keysDisposer?: Lambda;
private _disposers: { [name: string]: IReactionDisposer } = {};
private _previewRef: HTMLDivElement | null = null;
private _makeNewColumn: boolean = false;
@@ -71,13 +71,14 @@ export class CollectionSchemaView extends CollectionSubView() {
private _tableContentRef: HTMLDivElement | null = null;
private _menuTarget = React.createRef<HTMLDivElement>();
private _headerRefs: SchemaColumnHeader[] = [];
- private _eqHighlightColors: Array<[{r: number, g: number, b: number}, {r: number, g: number, b: number}]> = [];
+ private _eqHighlightColors: Array<[{ r: number; g: number; b: number }, { r: number; g: number; b: number }]> = [];
+ private _oldWheel: HTMLDivElement | null = null;
constructor(props: SubCollectionViewProps) {
super(props);
makeObservable(this);
const lightenedColor = (r: number, g: number, b:number) => { const lightened = ClientUtils.lightenRGB(r, g, b, 165); return {r: lightened[0], g: lightened[1], b: lightened[2]}} // prettier-ignore
- const colors = (r: number, g: number, b: number): [any, any] => {return [{r: r, g: g, b: b}, lightenedColor(r, g, b)]} // prettier-ignore
+ const colors = (r: number, g: number, b: number):[{r:number,g:number,b:number},{r:number,g:number,b:number}] => ([{r, g, b}, lightenedColor(r, g, b)]); // prettier-ignore
this._eqHighlightColors.push(colors(70, 150, 50));
this._eqHighlightColors.push(colors(180, 70, 20));
this._eqHighlightColors.push(colors(70, 50, 150));
@@ -122,8 +123,8 @@ export class CollectionSchemaView extends CollectionSubView() {
@observable _highlightedCellsInfo: Array<[doc: Doc, field: string]> = [];
@observable _cellHighlightColors: ObservableMap = new ObservableMap<string, string[]>();
@observable _containedDocs: Doc[] = []; //all direct children of the schema
- @observable _referenceSelectMode: {enabled: boolean, currEditing: SchemaCellField | undefined} = {enabled: false, currEditing: undefined}
-
+ @observable _referenceSelectMode: { enabled: boolean; currEditing: SchemaCellField | undefined } = { enabled: false, currEditing: undefined };
+
// target HTMLelement portal for showing a popup menu to edit cell values.
public get MenuTarget() {
return this._menuTarget.current;
@@ -217,15 +218,17 @@ export class CollectionSchemaView extends CollectionSubView() {
true
);
this._disposers.docdata = reaction(
- () => DocListCast(this.dataDoc[this.fieldKey]),
- (docs) => this._containedDocs = docs,
- {fireImmediately: true}
- )
+ () => DocListCast(this.dataDoc[this.fieldKey]),
+ docs => (this._containedDocs = docs),
+ { fireImmediately: true }
+ );
this._disposers.sortHighlight = reaction(
- () => [this.sortField, this._containedDocs, this._selectedDocs, this._highlightedCellsInfo],
- () => {this.sortField && setTimeout(() => this.highlightSortedColumn())},
- {fireImmediately: true}
- )
+ () => [this.sortField, this._containedDocs, this._selectedDocs, this._highlightedCellsInfo],
+ () => {
+ this.sortField && setTimeout(() => this.highlightSortedColumn());
+ },
+ { fireImmediately: true }
+ );
}
componentWillUnmount() {
@@ -239,8 +242,8 @@ export class CollectionSchemaView extends CollectionSubView() {
removeDoc = (doc: Doc) => {
this.removeDocument(doc);
- this._containedDocs = this._containedDocs.filter(d => d !== doc)
- }
+ this._containedDocs = this._containedDocs.filter(d => d !== doc);
+ };
rowIndex = (doc: Doc) => this.docsWithDrag.docs.indexOf(doc);
@@ -301,7 +304,9 @@ export class CollectionSchemaView extends CollectionSubView() {
}
break;
case 'Backspace': {
- undoable(() => {this._selectedDocs.forEach(d => this._containedDocs.includes(d) && this.removeDoc(d));}, 'delete schema row');
+ undoable(() => {
+ this._selectedDocs.forEach(d => this._containedDocs.includes(d) && this.removeDoc(d));
+ }, 'delete schema row');
break;
}
case 'Escape': {
@@ -319,7 +324,7 @@ export class CollectionSchemaView extends CollectionSubView() {
addRow = (doc: Doc | Doc[]) => this.addDocument(doc);
@undoBatch
- changeColumnKey = (index: number, newKey: string, defaultVal?: any) => {
+ changeColumnKey = (index: number, newKey: string, defaultVal?: FieldType) => {
if (!this.documentKeys.includes(newKey)) this.addNewKey(newKey, defaultVal);
const currKeys = this.columnKeys.slice(); // copy the column key array first, then change it.
@@ -328,9 +333,10 @@ export class CollectionSchemaView extends CollectionSubView() {
};
@undoBatch
- addColumn = (index: number = 0, key?: string, defaultVal?: any) => {
+ addColumn = (index: number = 0, keyIn?: string, defaultVal?: FieldType) => {
+ let key = keyIn;
if (key && !this.documentKeys.includes(key)) this.addNewKey(key, defaultVal);
-
+
const newColWidth = this.tableWidth / (this.storedColumnWidths.length + 1);
const currWidths = this.storedColumnWidths.slice();
currWidths.splice(index, 0, newColWidth);
@@ -345,11 +351,11 @@ export class CollectionSchemaView extends CollectionSubView() {
};
@action
- addNewKey = (key: string, defaultVal: any) => {
+ addNewKey = (key: string, defaultVal: FieldType | undefined) => {
this.childDocs.forEach(doc => {
doc[DocData][key] = defaultVal;
});
- }
+ };
@undoBatch
removeColumn = (index: number) => {
@@ -365,13 +371,13 @@ export class CollectionSchemaView extends CollectionSubView() {
const currKeys = this.columnKeys.slice();
currKeys.splice(index, 1);
- this.layoutDoc.schema_columnKeys = new List<string>(currKeys);
+ this.layoutDoc.schema_columnKeys = new List<string>(currKeys);
this._colEles.splice(index, 1);
};
@action
- startResize = (e: any, index: number, rightSide: boolean) => {
+ startResize = (e: React.PointerEvent, index: number, rightSide: boolean) => {
this._displayColumnWidths = this.storedColumnWidths;
setupMoveUpEvents(this, e, moveEv => this.resizeColumn(moveEv, index, rightSide), this.finishResize, emptyFunction);
};
@@ -384,8 +390,8 @@ export class CollectionSchemaView extends CollectionSubView() {
let change = e.movementX;
- if (rightSide && (index !== this._displayColumnWidths.length - 1)) {
- growing = change < 0 ? index + 1: index;
+ if (rightSide && index !== this._displayColumnWidths.length - 1) {
+ growing = change < 0 ? index + 1 : index;
shrinking = change < 0 ? index : index + 1;
} else if (index !== 0) {
growing = change < 0 ? index : index - 1;
@@ -432,7 +438,7 @@ export class CollectionSchemaView extends CollectionSubView() {
this.closeNewColumnMenu();
this._headerRefs.forEach(ref => ref.toggleEditing(false));
this._draggedColIndex = index;
- this.setColDrag(true);
+ this.setColDrag(true);
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]));
@@ -446,7 +452,7 @@ export class CollectionSchemaView extends CollectionSubView() {
* @returns column index
*/
findColDropIndex = (mouseX: number) => {
- const xOffset: number = this._props.ScreenToLocalTransform().inverse().transformPoint(0,0)[0] + CollectionSchemaView._rowMenuWidth;
+ const xOffset: number = this._props.ScreenToLocalTransform().inverse().transformPoint(0, 0)[0] + CollectionSchemaView._rowMenuWidth;
let index: number | undefined;
this.displayColumnWidths.reduce((total, curr, i) => {
if (total <= mouseX && total + curr >= mouseX) {
@@ -507,12 +513,7 @@ export class CollectionSchemaView extends CollectionSubView() {
this._colEles.forEach((colRef, i) => {
const edgeStyle = i === index ? `solid 2px ${Colors.MEDIUM_BLUE}` : '';
const sorted = i === this.columnKeys.indexOf(this.sortField);
- const cellEles = [
- colRef,
- ...this.docsWithDrag.docs
- .filter(doc => (i !== this._selectedCol || !this._selectedDocs.includes(doc)) && !sorted)
- .map(doc => this._rowEles.get(doc).children[1].children[i]),
- ];
+ const cellEles = [colRef, ...this.docsWithDrag.docs.filter(doc => (i !== this._selectedCol || !this._selectedDocs.includes(doc)) && !sorted).map(doc => this._rowEles.get(doc).children[1].children[i])];
cellEles.forEach(ele => {
if (sorted || this.highlightedCells.includes(ele)) return;
ele.style.borderTop = ele === cellEles[0] ? edgeStyle : '';
@@ -533,14 +534,14 @@ export class CollectionSchemaView extends CollectionSubView() {
this.childDocs.forEach(doc => {
const cell = this._rowEles.get(doc).children[1].children[i];
- if (!(this._selectedDocs.includes(doc) && i === this._selectedCol) && !(this.highlightedCells.includes(cell)) && cell) {
+ if (!(this._selectedDocs.includes(doc) && i === this._selectedCol) && !this.highlightedCells.includes(cell) && cell) {
cell.style.borderLeft = '';
cell.style.borderRight = '';
cell.style.borderBottom = '';
}
});
});
- }
+ };
/**
* Applies a gradient highlight to a sorted column. The direction of the gradient depends
@@ -552,10 +553,10 @@ export class CollectionSchemaView extends CollectionSubView() {
let index = -1;
const highlightColors: string[] = [];
const rowCount: number = this._containedDocs.length + 1;
- if (field || this.sortField){
+ if (field || this.sortField) {
index = this.columnKeys.indexOf(field || this.sortField);
- const increment: number = 110/rowCount;
- for (let i = 1; i <= rowCount; ++i){
+ const increment: number = 110 / rowCount;
+ for (let i = 1; i <= rowCount; ++i) {
const adjColor = ClientUtils.lightenRGB(16, 66, 230, increment * i);
highlightColors.push(`solid 2px rgb(${adjColor[0]}, ${adjColor[1]}, ${adjColor[2]})`);
}
@@ -564,25 +565,20 @@ export class CollectionSchemaView extends CollectionSubView() {
this._colEles.forEach((colRef, i) => {
const highlight: boolean = i === index;
const desc: boolean = descending || this.sortDesc;
- const cellEles = [
- colRef,
- ...this.docsWithDrag.docs
- .filter(doc => (i !== this._selectedCol || !this._selectedDocs.includes(doc)))
- .map(doc => this._rowEles.get(doc).children[1].children[i]),
- ];
+ const cellEles = [colRef, ...this.docsWithDrag.docs.filter(doc => i !== this._selectedCol || !this._selectedDocs.includes(doc)).map(doc => this._rowEles.get(doc).children[1].children[i])];
const cellCount = cellEles.length;
- for (let ele = 0; ele < cellCount; ++ele){
+ for (let ele = 0; ele < cellCount; ++ele) {
const currCell = cellEles[ele];
if (this.highlightedCells.includes(currCell)) continue;
- const style = highlight ? desc ? `${highlightColors[cellCount - 1 - ele]}` : `${highlightColors[ele]}` : '';
+ const style = highlight ? (desc ? `${highlightColors[cellCount - 1 - ele]}` : `${highlightColors[ele]}`) : '';
currCell.style.borderLeft = style;
currCell.style.borderRight = style;
}
- cellEles[0].style.borderTop = highlight ? desc ? `${highlightColors[cellCount - 1]}` : `${highlightColors[0]}` : '';
- if (!(this._selectedDocs.includes(this.docsWithDrag.docs[this.docsWithDrag.docs.length - 1]) && this._selectedCol === index) && !this.highlightedCells.includes(cellEles[cellCount - 1])) cellEles[cellCount - 1].style.borderBottom = highlight ? desc ? `${highlightColors[0]}` : `${highlightColors[cellCount - 1]}` : '';
+ cellEles[0].style.borderTop = highlight ? (desc ? `${highlightColors[cellCount - 1]}` : `${highlightColors[0]}`) : '';
+ if (!(this._selectedDocs.includes(this.docsWithDrag.docs[this.docsWithDrag.docs.length - 1]) && this._selectedCol === index) && !this.highlightedCells.includes(cellEles[cellCount - 1]))
+ cellEles[cellCount - 1].style.borderBottom = highlight ? (desc ? `${highlightColors[0]}` : `${highlightColors[cellCount - 1]}`) : '';
});
-
- }
+ };
/**
* Gets the html element representing a cell so that styles can be applied on it.
@@ -594,35 +590,40 @@ export class CollectionSchemaView extends CollectionSubView() {
const index = this.columnKeys.indexOf(fieldKey);
const cell = this._rowEles.get(doc).children[1].children[index];
return cell;
- }
+ };
/**
* Given text in a cell, find references to other cells (for equations).
* @param text the text in the cell
- * @returns the html cell elements referenced in the text.
+ * @returns the html cell elements referenced in the text.
*/
findCellRefs = (text: string) => {
const pattern = /(this|d(\d+))\.(\w+)/g;
- interface Match { docRef: string; field: string; }
+ interface Match {
+ docRef: string;
+ field: string;
+ }
const matches: Match[] = [];
let match: RegExpExecArray | null;
while ((match = pattern.exec(text)) !== null) {
- const docRef = match[1] === 'this' ? match[1] : match[2];
+ const docRef = match[1] === 'this' ? match[1] : match[2];
matches.push({ docRef, field: match[3] });
}
- const cells: Array<any> = [];
- matches.forEach((match: Match) => {
- const {docRef, field} = match;
+ const cells: [Doc, string][] = [];
+ matches.forEach((m: Match) => {
+ const { docRef, field } = m;
const docView = DocumentManager.Instance.DocumentViews[Number(docRef)];
const doc = docView?.Document ?? undefined;
- if (this.columnKeys.includes(field) && this._containedDocs.includes(doc)) {cells.push([doc, field])}
- })
+ if (this.columnKeys.includes(field) && this._containedDocs.includes(doc)) {
+ cells.push([doc, field]);
+ }
+ });
return cells;
- }
+ };
/**
* Determines whether the rows above or below a given row have been
@@ -636,7 +637,7 @@ export class CollectionSchemaView extends CollectionSubView() {
const selectedBelow: boolean = this._selectedDocs.includes(docs[index + 1]);
const selectedAbove: boolean = this._selectedDocs.includes(docs[index - 1]);
return [selectedAbove, selectedBelow];
- }
+ };
@action
removeCellHighlights = () => {
@@ -649,9 +650,10 @@ export class CollectionSchemaView extends CollectionSubView() {
if (this.selectionOverlap(doc)[0]) cell.style.borderTop = '';
if (this.selectionOverlap(doc)[1]) cell.style.borderBottom = '';
} else cell.style.border = '';
- cell.style.backgroundColor = '';});
+ cell.style.backgroundColor = '';
+ });
this._highlightedCellsInfo = [];
- }
+ };
restoreCellHighlights = () => {
this._highlightedCellsInfo.forEach(info => {
@@ -665,10 +667,10 @@ export class CollectionSchemaView extends CollectionSubView() {
cell.style.borderRight = color;
cell.style.borderBottom = color;
});
- }
+ };
/**
- * Highlights cells based on equation text in the cell currently being edited.
+ * Highlights cells based on equation text in the cell currently being edited.
* Does not highlight selected cells (that's done directly in SchemaTableCell).
* @param text the equation
*/
@@ -682,7 +684,7 @@ export class CollectionSchemaView extends CollectionSubView() {
const info = this._highlightedCellsInfo[i];
const color = this._eqHighlightColors[i % 10];
const colorStrings = [`solid 2px rgb(${color[0].r}, ${color[0].g}, ${color[0].b})`, `rgb(${color[1].r}, ${color[1].g}, ${color[1].b})`];
- const doc = info[0];
+ const doc = info[0];
const field = info[1];
const key = `${doc[Id]}_${field}`;
const cell = this.getCellElement(doc, field);
@@ -690,7 +692,7 @@ export class CollectionSchemaView extends CollectionSubView() {
cell.style.border = colorStrings[0];
cell.style.backgroundColor = colorStrings[1];
}
- }
+ };
//Used in SchemaRowBox
@action
@@ -718,7 +720,6 @@ export class CollectionSchemaView extends CollectionSubView() {
this.deselectAllCells();
};
-
selectRow = (doc: Doc, lastSelected: Doc) => {
const index = this.rowIndex(doc);
const lastSelectedRow = this.rowIndex(lastSelected);
@@ -737,12 +738,12 @@ export class CollectionSchemaView extends CollectionSubView() {
if (!doc) return;
const docIndex = DocumentView.getDocViewIndex(doc);
const field = this.columnKeys[col];
- const refToAdd = `d${docIndex}.${field}`
- const editedField = this._referenceSelectMode.currEditing ? this._referenceSelectMode.currEditing as SchemaCellField : null;
+ const refToAdd = `d${docIndex}.${field}`;
+ const editedField = this._referenceSelectMode.currEditing ? (this._referenceSelectMode.currEditing as SchemaCellField) : null;
editedField?.insertText(refToAdd, true);
editedField?.setupRefSelect(false);
return;
- }
+ };
@action
selectCell = (doc: Doc, col: number, shiftKey: boolean, ctrlKey: boolean) => {
@@ -787,7 +788,9 @@ export class CollectionSchemaView extends CollectionSubView() {
@action
onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
if (de.complete.columnDragData) {
- setTimeout(() => {this.setColDrag(false);});
+ setTimeout(() => {
+ this.setColDrag(false);
+ });
e.stopPropagation();
return true;
}
@@ -849,9 +852,9 @@ export class CollectionSchemaView extends CollectionSubView() {
};
@action
- setKey = (key: string, defaultVal?: any, index?: number) => {
+ setKey = (key: string, defaultVal?: string, index?: number) => {
if (this.columnKeys.includes(key)) return;
-
+
if (this._makeNewColumn) {
this.addColumn(this.columnKeys.indexOf(key), key, defaultVal);
this._makeNewColumn = false;
@@ -861,14 +864,14 @@ export class CollectionSchemaView extends CollectionSubView() {
};
/**
- * Used in SchemaRowBox to set
- * @param key
- * @param value
- * @returns
+ * Used in SchemaRowBox to set
+ * @param key
+ * @param value
+ * @returns
*/
setCellValues = (key: string, value: string) => {
- if (this._selectedCells.length === 1) this.docs.forEach(doc => !doc._lockedSchemaEditing && Doc.SetField(doc, key, value));
- else this._selectedCells.forEach(doc => !doc._lockedSchemaEditing && Doc.SetField(doc, key, value));
+ if (this._selectedCells.length === 1) this.docs.forEach(doc => !doc._lockedSchemaEditing && Doc.SetField(doc, key, value));
+ else this._selectedCells.forEach(doc => !doc._lockedSchemaEditing && Doc.SetField(doc, key, value));
return true;
};
@@ -912,34 +915,36 @@ export class CollectionSchemaView extends CollectionSubView() {
const cm = ContextMenu.Instance;
cm.clearItems();
- const fieldSortedAsc = (this.sortField === this.columnKeys[index] && !this.sortDesc);
- const fieldSortedDesc = (this.sortField === this.columnKeys[index] && this.sortDesc);
- const revealOptions = cm.findByDescription('Sort column')
- const sortOptions: ContextMenuProps[] = revealOptions && revealOptions && 'subitems' in revealOptions ? revealOptions.subitems ?? [] : [];
+ const fieldSortedAsc = this.sortField === this.columnKeys[index] && !this.sortDesc;
+ const fieldSortedDesc = this.sortField === this.columnKeys[index] && this.sortDesc;
+ const revealOptions = cm.findByDescription('Sort column');
+ const sortOptions: ContextMenuProps[] = revealOptions && revealOptions && 'subitems' in revealOptions ? (revealOptions.subitems ?? []) : [];
sortOptions.push({
- description: 'Sort A-Z',
+ description: 'Sort A-Z',
event: () => {
- this.setColumnSort(undefined);
+ this.setColumnSort(undefined);
const field = this.columnKeys[index];
this._containedDocs = this.sortDocs(field, false);
setTimeout(() => {
this.highlightSortedColumn(field, false);
- setTimeout(() => this.highlightSortedColumn(), 480);
+ setTimeout(() => this.highlightSortedColumn(), 480);
}, 20);
- },
- icon: 'arrow-down-a-z',});
+ },
+ icon: 'arrow-down-a-z',
+ });
sortOptions.push({
- description: 'Sort Z-A',
+ description: 'Sort Z-A',
event: () => {
- this.setColumnSort(undefined);
+ this.setColumnSort(undefined);
const field = this.columnKeys[index];
this._containedDocs = this.sortDocs(field, true);
setTimeout(() => {
this.highlightSortedColumn(field, true);
- setTimeout(() => this.highlightSortedColumn(), 480);
+ setTimeout(() => this.highlightSortedColumn(), 480);
}, 20);
- },
- icon: 'arrow-up-z-a'});
+ },
+ icon: 'arrow-up-z-a',
+ });
sortOptions.push({
description: 'Persistent Sort A-Z',
event: () => {
@@ -964,7 +969,7 @@ export class CollectionSchemaView extends CollectionSubView() {
}
},
icon: fieldSortedDesc ? 'lock' : 'lock-open'}); // prettier-ignore
-
+
cm.addItem({
description: `Change field`,
event: () => this.openNewColumnMenu(index, false),
@@ -975,12 +980,12 @@ export class CollectionSchemaView extends CollectionSubView() {
event: () => this.openFilterMenu(index),
icon: 'filter',
});
- cm.addItem({
- description: 'Sort column',
- addDivider: false,
- noexpand: true,
- subitems: sortOptions,
- icon: 'sort'
+ cm.addItem({
+ description: 'Sort column',
+ addDivider: false,
+ noexpand: true,
+ subitems: sortOptions,
+ icon: 'sort',
});
cm.addItem({
description: 'Add column to left',
@@ -1068,7 +1073,7 @@ export class CollectionSchemaView extends CollectionSubView() {
@computed get renderColumnMenu() {
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, maxWidth: `${Math.max(this._colEles[this._columnMenuIndex ?? 0].offsetWidth, 150)}px` }}>
+ <div className="schema-column-menu" style={{ left: x, maxWidth: `${Math.max(this._colEles[this._columnMenuIndex ?? 0].offsetWidth, 150)}px` }}>
{this.keysDropdown}
</div>
);
@@ -1095,13 +1100,7 @@ export class CollectionSchemaView extends CollectionSubView() {
}
return (
<div key={key} className="schema-filter-option">
- <input
- type="checkbox"
- onPointerDown={e => e.stopPropagation()}
- onClick={e => e.stopPropagation()}
- onChange={e => Doc.setDocFilter(this.Document, columnKey, key, e.target.checked ? 'check' : 'remove')}
- checked={bool}
- />
+ <input type="checkbox" onPointerDown={e => e.stopPropagation()} onClick={e => e.stopPropagation()} onChange={e => Doc.setDocFilter(this.Document, columnKey, key, e.target.checked ? 'check' : 'remove')} checked={bool} />
<span style={{ paddingLeft: 4 }}>{key}</span>
</div>
);
@@ -1111,7 +1110,7 @@ export class CollectionSchemaView extends CollectionSubView() {
@computed get renderFilterMenu() {
const x = this.displayColumnWidths.reduce((total, curr, index) => total + (index < this._filterColumnIndex! ? curr : 0), CollectionSchemaView._rowMenuWidth);
return (
- <div className="schema-filter-menu" style={{ left: x, maxWidth: `${Math.max(this._colEles[this._columnMenuIndex ?? 0].offsetWidth, 150)}px`}}>
+ <div className="schema-filter-menu" style={{ left: x, maxWidth: `${Math.max(this._colEles[this._columnMenuIndex ?? 0].offsetWidth, 150)}px` }}>
<input className="schema-filter-input" type="text" value={this._filterSearchValue} onKeyDown={this.onFilterKeyDown} onChange={this.updateFilterSearch} onPointerDown={e => e.stopPropagation()} />
{this.renderFilterOptions}
<div
@@ -1129,13 +1128,13 @@ export class CollectionSchemaView extends CollectionSubView() {
@action setColDrag = (beingDragged: boolean) => {
this._colBeingDragged = beingDragged;
!beingDragged && this.removeDragHighlight();
- }
+ };
@action updateMouseCoordinates = (e: React.PointerEvent<HTMLDivElement>) => {
const prevX = this._mouseCoordinates.x;
const prevY = this._mouseCoordinates.y;
this._mouseCoordinates = { x: e.clientX, y: e.clientY, prevX: prevX, prevY: prevY };
- }
+ };
@action
onPointerMove = (e: React.PointerEvent<HTMLDivElement>) => {
@@ -1158,9 +1157,9 @@ export class CollectionSchemaView extends CollectionSubView() {
/**
* Gets docs contained by collections within the schema. Currently defunct.
- * @param doc
- * @param displayed
- * @returns
+ * @param doc
+ * @param displayed
+ * @returns
*/
// subCollectionDocs = (doc: Doc, displayed: boolean) => {
// const childDocs = DocListCast(doc[Doc.LayoutFieldKey(doc)]);
@@ -1203,8 +1202,7 @@ export class CollectionSchemaView extends CollectionSubView() {
subDocs.forEach(t => {
const docFieldKey = Doc.LayoutFieldKey(t);
const isSubDocAnnotatable = t[docFieldKey] instanceof List && !(t[docFieldKey] as List<Doc>)?.some(ele => !(ele instanceof Doc));
- notFiltered =
- notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && ((!childDocFilters.length && !childFiltersByRanges.length) || DocUtils.FilterDocs([t], childDocFilters, childFiltersByRanges, d).length));
+ notFiltered = notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && ((!childDocFilters.length && !childFiltersByRanges.length) || DocUtils.FilterDocs([t], childDocFilters, childFiltersByRanges, d).length));
DocListCast(t[isSubDocAnnotatable ? docFieldKey + '_annotations' : docFieldKey]).forEach(newdoc => newarray.push(newdoc));
isSubDocAnnotatable && DocListCast(t[docFieldKey + '_sidebar']).forEach(newdoc => newarray.push(newdoc));
});
@@ -1231,19 +1229,19 @@ export class CollectionSchemaView extends CollectionSubView() {
// docsFromChildren = docsFromChildren.concat(docsNotAlreadyDisplayed);
// });
- return this.filteredDocs;;
+ return this.filteredDocs;
}
/**
- * Sorts docs first alphabetically and then numerically.
+ * Sorts docs first alphabetically and then numerically.
* @param field the column being sorted
* @param desc whether the sort is ascending or descending
* @param persistent whether the sort is applied persistently or is one-shot
- * @returns
+ * @returns
*/
sortDocs = (field: string, desc: boolean, persistent?: boolean) => {
const numbers: Doc[] = [];
- const strings: Doc[] = [];
+ const strings: Doc[] = [];
this.docs.forEach(doc => {
if (!isNaN(Number(Field.toString(doc[field] as FieldType)))) numbers.push(doc);
@@ -1253,25 +1251,26 @@ export class CollectionSchemaView extends CollectionSubView() {
const sortedNums = numbers.sort((numOne, numTwo) => {
const numA = Number(Field.toString(numOne[field] as FieldType));
const numB = Number(Field.toString(numTwo[field] as FieldType));
- return desc? numA - numB : numB - numA;
+ return desc ? numA - numB : numB - numA;
});
- const collator = new Intl.Collator(undefined, {sensitivity: 'base'});
+ const collator = new Intl.Collator(undefined, { sensitivity: 'base' });
let sortedStrings;
- if (!desc) {sortedStrings = strings.slice().sort((docA, docB) => collator.compare(Field.toString(docA[field] as FieldType), Field.toString(docB[field] as FieldType)));
+ if (!desc) {
+ sortedStrings = strings.slice().sort((docA, docB) => collator.compare(Field.toString(docA[field] as FieldType), Field.toString(docB[field] as FieldType)));
} else sortedStrings = strings.slice().sort((docB, docA) => collator.compare(Field.toString(docA[field] as FieldType), Field.toString(docB[field] as FieldType)));
const sortedDocs = desc ? sortedNums.concat(sortedStrings) : sortedStrings.concat(sortedNums);
if (!persistent) this._containedDocs = sortedDocs;
return sortedDocs;
- }
-
+ };
+
/**
* Returns all docs minus those currently being dragged by the user.
*/
@computed get docsWithDrag() {
let docs = this.docs.slice();
- if (this.sortField){
+ if (this.sortField) {
const field = StrCast(this.layoutDoc.sortField);
const desc = BoolCast(this.layoutDoc.sortDesc); // is this an ascending or descending sort
docs = this.sortDocs(field, desc, true);
@@ -1290,13 +1289,17 @@ export class CollectionSchemaView extends CollectionSubView() {
previewWidthFunc = () => this.previewWidth;
onPassiveWheel = (e: WheelEvent) => e.stopPropagation();
displayedDocsFunc = () => this.docsWithDrag.docs;
- _oldWheel: any;
render() {
return (
- <div className="collectionSchemaView" ref={(ele: HTMLDivElement | null) => this.createDashEventsTarget(ele)}
- onDrop={this.onExternalDrop.bind(this)}
- onPointerMove={e => this.onPointerMove(e)}
- onPointerDown={() => {this.closeNewColumnMenu(); this.setColDrag(false)}}>
+ <div
+ className="collectionSchemaView"
+ ref={(ele: HTMLDivElement | null) => this.createDashEventsTarget(ele)}
+ onDrop={this.onExternalDrop.bind(this)}
+ onPointerMove={e => this.onPointerMove(e)}
+ onPointerDown={() => {
+ this.closeNewColumnMenu();
+ this.setColDrag(false);
+ }}>
<div ref={this._menuTarget} style={{ background: 'red', top: 0, left: 0, position: 'absolute', zIndex: 10000 }} />
<div
className="schema-table"
@@ -1310,30 +1313,29 @@ export class CollectionSchemaView extends CollectionSubView() {
<div className="schema-header-row" style={{ height: this.rowHeightFunc() }}>
<div className="row-menu" style={{ width: CollectionSchemaView._rowMenuWidth }}>
<IconButton
- tooltip="Add a new key"
- icon={ <FontAwesomeIcon icon="plus" size='lg'/>}
- size={Size.XSMALL}
- color={'black'}
- onPointerDown={e =>
- setupMoveUpEvents(
- this,
- e,
- returnFalse,
- emptyFunction,
- undoable(clickEv => {
- clickEv.stopPropagation();
- this.addColumn()
- }, 'add key to schema')
- )
- }
+ tooltip="Add a new key"
+ icon={<FontAwesomeIcon icon="plus" size="lg" />}
+ size={Size.XSMALL}
+ color={'black'}
+ onPointerDown={e =>
+ setupMoveUpEvents(
+ this,
+ e,
+ returnFalse,
+ emptyFunction,
+ undoable(clickEv => {
+ clickEv.stopPropagation();
+ this.addColumn();
+ }, 'add key to schema')
+ )
+ }
/>
</div>
{this.columnKeys.map((key, index) => (
<SchemaColumnHeader
- // eslint-disable-next-line react/no-array-index-key
//cleanupField={this.cleanupComputedField}
ref={r => r && this._headerRefs.push(r)}
- keysDropdown={(this.keysDropdown)}
+ keysDropdown={this.keysDropdown}
schemaView={this}
columnWidth={() => CollectionSchemaView._minColWidth} //TODO: update
Document={this.Document}
@@ -1445,7 +1447,6 @@ class CollectionSchemaViewDoc extends ObservableReactComponent<CollectionSchemaV
return (
<DocumentView
key={this._props.doc[Id]}
- // eslint-disable-next-line react/jsx-props-no-spreading
{...this._props.schema._props}
containerViewPath={this._props.schema.childContainerViewPath}
LayoutTemplate={this._props.schema._props.childLayoutTemplate}
@@ -1498,4 +1499,4 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
</div>
);
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index dab494c0e..5a64ecc62 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -27,6 +27,7 @@ export interface SchemaCellFieldProps {
oneLine?: boolean;
Document: Doc;
fieldKey: string;
+ // eslint-disable-next-line no-use-before-define
refSelectModeInfo: { enabled: boolean; currEditing: SchemaCellField | undefined };
highlightCells?: (text: string) => void;
GetValue(): string | undefined;
@@ -154,8 +155,8 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
}
}
- matches.forEach((match: string) => {
- chunkedText = chunkedText.replace(match, this.generateSpan(match, cells.get(match)));
+ matches.forEach(m => {
+ chunkedText = chunkedText.replace(m, this.generateSpan(m, cells.get(m)));
});
return chunkedText;
@@ -301,13 +302,14 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
setTimeout(() => this.setupRefSelect(this.refSelectConditionMet), 0);
break;
case ' ':
- e.stopPropagation();
- let cursorPos = 0;
- if (this.cursorPosition !== null) cursorPos = this.cursorPosition + 1;
- setTimeout(() => {
- this.setContent(this._unrenderedContent);
- setTimeout(() => this.setCursorPosition(cursorPos));
- }, 0);
+ {
+ e.stopPropagation();
+ const cursorPos = this.cursorPosition !== null ? this.cursorPosition + 1 : 0;
+ setTimeout(() => {
+ this.setContent(this._unrenderedContent);
+ setTimeout(() => this.setCursorPosition(cursorPos));
+ }, 0);
+ }
break;
case 'u': // for some reason 'u' otherwise exits the editor
e.stopPropagation();
@@ -318,7 +320,6 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
case 'Control':
case ':': // prettier-ignore
break;
- // eslint-disable-next-line no-fallthrough
default:
break;
}
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index 207e1deac..9ffdd812f 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -1,4 +1,3 @@
-/* eslint-disable react/no-unused-prop-types */
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
@@ -21,7 +20,8 @@ import { undoable } from '../../../util/UndoManager';
import { IconButton, Size } from 'browndash-components';
export enum SchemaFieldType {
- Header, Cell
+ Header,
+ Cell,
}
export interface SchemaColumnHeaderProps {
@@ -49,7 +49,6 @@ export interface SchemaColumnHeaderProps {
@observer
export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHeaderProps> {
-
private _inputRef: EditableView | null = null;
@observable _altTitle: string | undefined = undefined;
@observable _showMenuIcon: boolean = false;
@@ -58,18 +57,26 @@ export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHea
return this._props.columnKeys[this._props.columnIndex];
}
- constructor(props: SchemaColumnHeaderProps){
+ constructor(props: SchemaColumnHeaderProps) {
super(props);
makeObservable(this);
}
-
+
getFinfo = computedFn((fieldKey: string) => this._props.schemaView?.fieldInfos.get(fieldKey));
- setColumnValues = (field: string, defaultValue: string) => {this._props.schemaView?.setKey(field, defaultValue, this._props.columnIndex);}
- @action updateAlt = (newAlt: string) => {this._altTitle = newAlt};
- updateKeyDropdown = (value: string) => {this._props.schemaView.updateKeySearch(value)};
- openKeyDropdown = () => {!this._props.schemaView._colBeingDragged && this._props.schemaView.openNewColumnMenu(this._props.columnIndex, false)};
+ setColumnValues = (field: string, defaultValue: string) => {
+ this._props.schemaView?.setKey(field, defaultValue, this._props.columnIndex);
+ };
+ @action updateAlt = (newAlt: string) => {
+ this._altTitle = newAlt;
+ };
+ updateKeyDropdown = (value: string) => {
+ this._props.schemaView.updateKeySearch(value);
+ };
+ openKeyDropdown = () => {
+ !this._props.schemaView._colBeingDragged && this._props.schemaView.openNewColumnMenu(this._props.columnIndex, false);
+ };
toggleEditing = (editing: boolean) => {
- this._inputRef?.setIsEditing(editing);
+ this._inputRef?.setIsEditing(editing);
this._inputRef?.setIsFocused(editing);
};
@@ -110,10 +117,10 @@ export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHea
const cursor = !readOnly ? 'text' : 'default';
const pointerEvents: 'all' | 'none' = 'all';
return { color, fieldProps, cursor, pointerEvents };
- }
+ };
@computed get editableView() {
- const { color, fieldProps, pointerEvents } = this.renderProps(this._props);
+ const { color, fieldProps, pointerEvents } = this.renderProps(this._props);
return <div className='schema-column-edit-wrapper' onPointerUp={() => {
SchemaColumnHeader.isDefaultField(this.fieldKey) && this.openKeyDropdown();
@@ -143,107 +150,116 @@ export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHea
else return this.fieldKey;
}}
SetValue={undoable((value: string, shiftKey?: boolean, enterKey?: boolean) => {
- if (enterKey) { // if shift & enter, set value of each cell in column
+ if (enterKey) {
+ // if shift & enter, set value of each cell in column
this.setColumnValues(value, '');
this._altTitle = undefined;
this._props.finishEdit?.();
return true;
}
- this._props.finishEdit?.();
+ this._props.finishEdit?.();
return true;
- }, 'edit column header')}
- />
+ }, 'edit column header')}/>
</div>
}
public static isDefaultField = (key: string) => {
const defaultPattern = /EmptyColumnKey/;
- const isDefault: boolean = (defaultPattern.exec(key) != null);
+ const isDefault: boolean = defaultPattern.exec(key) != null;
return isDefault;
- }
+ };
- get headerButton(){
- const toRender = SchemaColumnHeader.isDefaultField(this.fieldKey) ?
- (<IconButton
- icon={ <FontAwesomeIcon icon="trash" size='sm'/>}
- size={Size.XSMALL}
- color={'black'}
- onPointerDown={e =>
- setupMoveUpEvents(
- this,
- e,
- returnFalse,
- emptyFunction,
- undoable(clickEv => {
- clickEv.stopPropagation();
- this._props.schemaView.removeColumn(this._props.columnIndex);
- }, 'open column menu')
- )
- }
- />)
- : (<IconButton
- icon={ <FontAwesomeIcon icon="caret-down" size='lg'/>}
- size={Size.XSMALL}
- color={'black'}
- onPointerDown={e =>
- setupMoveUpEvents(
- this,
- e,
- returnFalse,
- emptyFunction,
- undoable(clickEv => {
- clickEv.stopPropagation();
- this._props.openContextMenu(e.clientX, e.clientY, this._props.columnIndex)
- }, 'open column menu')
- )
- }
- />)
+ get headerButton() {
+ const toRender = SchemaColumnHeader.isDefaultField(this.fieldKey) ? (
+ <IconButton
+ icon={<FontAwesomeIcon icon="trash" size="sm" />}
+ size={Size.XSMALL}
+ color={'black'}
+ onPointerDown={e =>
+ setupMoveUpEvents(
+ this,
+ e,
+ returnFalse,
+ emptyFunction,
+ undoable(clickEv => {
+ clickEv.stopPropagation();
+ this._props.schemaView.removeColumn(this._props.columnIndex);
+ }, 'open column menu')
+ )
+ }
+ />
+ ) : (
+ <IconButton
+ icon={<FontAwesomeIcon icon="caret-down" size="lg" />}
+ size={Size.XSMALL}
+ color={'black'}
+ onPointerDown={e =>
+ setupMoveUpEvents(
+ this,
+ e,
+ returnFalse,
+ emptyFunction,
+ undoable(clickEv => {
+ clickEv.stopPropagation();
+ this._props.openContextMenu(e.clientX, e.clientY, this._props.columnIndex);
+ }, 'open column menu')
+ )
+ }
+ />
+ );
return toRender;
}
- @action handlePointerEnter = () => this._showMenuIcon = true;
- @action handlePointerLeave = () => this._showMenuIcon = false;
+ @action handlePointerEnter = () => { this._showMenuIcon = true; } // prettier-ignore
+ @action handlePointerLeave = () => { this._showMenuIcon = false; } // prettier-ignore
- @computed get displayButton() {return this._showMenuIcon;}
+ @computed get displayButton() {
+ return this._showMenuIcon;
+ }
render() {
return (
- <div
- className="schema-column-header"
- style={{
- width: this._props.columnWidths[this._props.columnIndex],
- }}
- onPointerEnter={() => {this.handlePointerEnter()}}
- onPointerLeave={() => {this.handlePointerLeave()}}
- onPointerDown={e => {
- this.setupDrag(e);
- setupMoveUpEvents(
- this,
- e,
- () => {return this._inputRef?.setIsEditing(false) ?? false},
- emptyFunction,
- emptyFunction,
- );
- }
+ <div
+ className="schema-column-header"
+ style={{
+ width: this._props.columnWidths[this._props.columnIndex],
+ }}
+ onPointerEnter={() => {
+ this.handlePointerEnter();
+ }}
+ onPointerLeave={() => {
+ this.handlePointerLeave();
+ }}
+ onPointerDown={e => {
+ this.setupDrag(e);
+ setupMoveUpEvents(
+ this,
+ e,
+ () => {
+ return this._inputRef?.setIsEditing(false) ?? false;
+ },
+ emptyFunction,
+ emptyFunction
+ );
+ }}
+ ref={col => {
+ if (col) {
+ this._props.setColRef(this._props.columnIndex, col);
}
- ref={col => {
- if (col) {
- this._props.setColRef(this._props.columnIndex, col);
- }
- }}>
- <div className="schema-column-resizer left" onPointerDown={e => this._props.resizeColumn(e, this._props.columnIndex, false)} />
-
- <div className="schema-header-text">{this.editableView}</div>
-
- <div className="schema-header-menu">
- <div className="schema-header-button" style={{opacity: this.displayButton ? '1.0' : '0.0'}}>
- {this.headerButton}
- </div>
- </div>
-
- <div className="schema-column-resizer right" onPointerDown={e => this._props.resizeColumn(e, this._props.columnIndex, true)} />
+ }}>
+ <div className="schema-column-resizer left" onPointerDown={e => this._props.resizeColumn(e, this._props.columnIndex, false)} />
+
+ <div className="schema-header-text">{this.editableView}</div>
+
+ <div className="schema-header-menu">
+ <div className="schema-header-button" style={{ opacity: this.displayButton ? '1.0' : '0.0' }}>
+ {this.headerButton}
+ </div>
</div>
+
+ <div className="schema-column-resizer right" onPointerDown={e => this._props.resizeColumn(e, this._props.columnIndex, true)} />
+ </div>
);
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index a8a4ef2c2..6ffb0865a 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -21,7 +21,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core';
/**
* The SchemaRowBox renders a doc as a row of cells, with each cell representing
- * one field value of the doc. It mostly handles communication from the SchemaView
+ * one field value of the doc. It mostly handles communication from the SchemaView
* to each SchemaCell, passing down necessary functions are props.
*/
@@ -59,7 +59,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
ContextMenu.Instance.clearItems();
ContextMenu.Instance.addItem({
description: this.Document._lockedSchemaEditing ? 'Unlock field editing' : 'Lock field editing',
- event: () => this.Document._lockedSchemaEditing = !this.Document._lockedSchemaEditing,
+ event: () => (this.Document._lockedSchemaEditing = !this.Document._lockedSchemaEditing),
icon: this.Document._lockedSchemaEditing ? 'lock-open' : 'lock',
});
ContextMenu.Instance.addItem({
@@ -78,17 +78,19 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
// ContextMenu.Instance.addItem({
// description: this.Document._childrenSharedWithSchema ? 'Remove children from schema' : 'Add children to schema',
// event: () => {
- // this.Document._childrenSharedWithSchema = !this.Document._childrenSharedWithSchema;
+ // this.Document._childrenSharedWithSchema = !this.Document._childrenSharedWithSchema;
// },
// icon: this.Document._childrenSharedWithSchema ? 'minus' : 'plus',
// });
// }
ContextMenu.Instance.displayMenu(x, y, undefined, false);
- }
+ };
- @computed get menuBackgroundColor(){
- if (this.Document._lockedSchemaEditing) {return '#F5F5F5'}
- return ''
+ @computed get menuBackgroundColor() {
+ if (this.Document._lockedSchemaEditing) {
+ return '#F5F5F5';
+ }
+ return '';
}
@computed get menuInfos() {
@@ -98,22 +100,28 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
return infos;
}
- isolatedSelection = (doc: Doc) => {return this.schemaView?.selectionOverlap(doc)};
+ isolatedSelection = (doc: Doc) => {
+ return this.schemaView?.selectionOverlap(doc);
+ };
setCursorIndex = (mouseY: number) => this.schemaView?.setRelCursorIndex(mouseY);
selectedCol = () => this.schemaView._selectedCol;
getFinfo = computedFn((fieldKey: string) => this.schemaView?.fieldInfos.get(fieldKey));
selectCell = (doc: Doc, col: number, shift: boolean, ctrl: boolean) => this.schemaView?.selectCell(doc, col, shift, ctrl);
deselectCell = () => this.schemaView?.deselectAllCells();
selectedCells = () => this.schemaView?._selectedDocs;
- setColumnValues = (field: any, value: any) => this.schemaView?.setCellValues(field, value) ?? false;
+ setColumnValues = (field: string, value: string) => this.schemaView?.setCellValues(field, value) ?? false;
columnWidth = computedFn((index: number) => () => this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth);
computeRowIndex = () => this.schemaView?.rowIndex(this.Document);
highlightCells = (text: string) => this.schemaView?.highlightCells(text);
- selectReference = (doc: Doc, col: number) => {this.schemaView.selectReference(doc, col)}
+ selectReference = (doc: Doc, col: number) => {
+ this.schemaView.selectReference(doc, col);
+ };
eqHighlightFunc = (text: string) => {
const info = this.schemaView.findCellRefs(text);
const cells: HTMLDivElement[] = [];
- info.forEach(info => {cells.push(this.schemaView.getCellElement(info[0], info[1]))})
+ info.forEach(inf => {
+ cells.push(this.schemaView.getCellElement(inf[0], inf[1]));
+ });
return cells;
};
render() {
@@ -121,7 +129,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
<div
className="schema-row"
onPointerDown={e => this.setCursorIndex(e.clientY)}
- style={{ height: this._props.PanelHeight()}}
+ style={{ height: this._props.PanelHeight() }}
ref={(row: HTMLDivElement | null) => {
row && this.schemaView?.addRowRef?.(this.Document, row);
this._ref = row;
@@ -131,11 +139,11 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
style={{
width: CollectionSchemaView._rowMenuWidth,
pointerEvents: !this._props.isContentActive() ? 'none' : undefined,
- backgroundColor: this.menuBackgroundColor
+ backgroundColor: this.menuBackgroundColor,
}}>
<IconButton
tooltip="Open actions menu"
- icon={ <FontAwesomeIcon icon="caret-right" size='lg'/>}
+ icon={<FontAwesomeIcon icon="caret-right" size="lg" />}
size={Size.XSMALL}
color={'black'}
onPointerDown={e =>
@@ -146,14 +154,16 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
emptyFunction,
undoable(clickEv => {
clickEv.stopPropagation();
- this.openContextMenu(e.clientX, e.clientY)
+ this.openContextMenu(e.clientX, e.clientY);
}, 'open actions menu')
)
}
/>
- <div className="row-menu-infos">
- {this.menuInfos.map(icn => <FontAwesomeIcon className="row-infos-icon" icon={icn} size='2xs' />)}
- </div>
+ <div className="row-menu-infos">
+ {this.menuInfos.map(icn => (
+ <FontAwesomeIcon key={icn.toString()} className="row-infos-icon" icon={icn} size="2xs" />
+ ))}
+ </div>
</div>
<div className="row-cells">
{this.schemaView?.columnKeys?.map((key, index) => (
@@ -192,4 +202,4 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
</div>
);
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index c05382ce0..f036ff843 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -1,4 +1,3 @@
-/* eslint-disable react/jsx-props-no-spreading */
/* eslint-disable no-use-before-define */
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Popup, Size, Type } from 'browndash-components';
@@ -37,7 +36,7 @@ import { SchemaCellField } from './SchemaCellField';
/**
* SchemaTableCells make up the majority of the visual representation of the SchemaView.
* They are rendered for each cell in the SchemaView, and each represents one field value
- * of a doc. Editing the content of the cell changes the corresponding doc's field value.
+ * of a doc. Editing the content of the cell changes the corresponding doc's field value.
*/
export interface SchemaTableCellProps {
@@ -67,21 +66,16 @@ export interface SchemaTableCellProps {
isolatedSelection: (doc: Doc) => [boolean, boolean];
highlightCells: (text: string) => void;
eqHighlightFunc: (text: string) => HTMLDivElement[] | [];
- refSelectModeInfo: {enabled: boolean, currEditing: SchemaCellField | undefined};
+ refSelectModeInfo: { enabled: boolean; currEditing: SchemaCellField | undefined };
selectReference: (doc: Doc, col: number) => void;
}
function selectedCell(props: SchemaTableCellProps) {
- return (
- props.isRowActive() &&
- props.selectedCol() === props.col &&
- props.selectedCells()?.filter(d => d === props.Document)?.length
- );
+ return props.isRowActive() && props.selectedCol() === props.col && props.selectedCells()?.filter(d => d === props.Document)?.length;
}
@observer
export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellProps> {
-
// private _fieldRef: SchemaCellField | null = null;
private _submittedValue: string = '';
@@ -96,9 +90,11 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
get lockedInteraction(){return (this.isDefault || this._props.Document._lockedSchemaEditing);} // prettier-ignore
- get backgroundColor(){
- if (this.lockedInteraction) {return '#F5F5F5'}
- return ''
+ get backgroundColor() {
+ if (this.lockedInteraction) {
+ return '#F5F5F5';
+ }
+ return '';
}
static addFieldDoc = (docs: Doc | Doc[] /* , where: OpenWhere */) => {
@@ -110,7 +106,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
let protoCount = 0;
let doc: Doc | undefined = Document;
while (doc) {
- if (Object.keys(doc).includes(fieldKey.replace(/^_/, ''))) break;
+ if (Object.keys(doc).includes(fieldKey.replace(/^_/, ''))) break;
protoCount++;
doc = DocCast(doc.proto);
}
@@ -149,28 +145,40 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
adjustSelfReference = (field: string) => {
const modField = field.replace(/\bthis.\b/g, `d${this.docIndex}.`);
return modField;
- }
+ };
// parses a field from the "idToDoc(####)" format to DocumentId (d#) format for readability
cleanupField = (field: string) => {
let modField = field.slice();
let eqSymbol: string = '';
- if (modField.startsWith('=')) {modField = modField.substring(1); eqSymbol += '=';}
- if (modField.startsWith(':=')) {modField = modField.substring(2); eqSymbol += ':=';}
+ if (modField.startsWith('=')) {
+ modField = modField.substring(1);
+ eqSymbol += '=';
+ }
+ if (modField.startsWith(':=')) {
+ modField = modField.substring(2);
+ eqSymbol += ':=';
+ }
const idPattern = /idToDoc\((.*?)\)/g;
let matches;
const results = new Array<[id: string, func: string]>();
- while ((matches = idPattern.exec(field)) !== null) {results.push([matches[0], matches[1].replace(/"/g, '')]); }
- results.forEach((idFuncPair) => {modField = modField.replace(idFuncPair[0], 'd' + (DocumentView.getDocViewIndex(IdToDoc(idFuncPair[1]))).toString());})
+ while ((matches = idPattern.exec(field)) !== null) {
+ results.push([matches[0], matches[1].replace(/"/g, '')]);
+ }
+ results.forEach(idFuncPair => {
+ modField = modField.replace(idFuncPair[0], 'd' + DocumentView.getDocViewIndex(IdToDoc(idFuncPair[1])).toString());
+ });
if (modField.endsWith(';')) modField = modField.substring(0, modField.length - 1);
- const inQuotes = (field: string) => {return ((field.startsWith('`') && field.endsWith('`')) || (field.startsWith("'") && field.endsWith("'")) || (field.startsWith('"') && field.endsWith('"')))}
+ const inQuotes = (strField: string) => {
+ return (strField.startsWith('`') && strField.endsWith('`')) || (strField.startsWith("'") && strField.endsWith("'")) || (strField.startsWith('"') && strField.endsWith('"'));
+ };
if (!inQuotes(this._submittedValue) && inQuotes(modField)) modField = modField.substring(1, modField.length - 1);
return eqSymbol + modField;
- }
+ };
@computed get defaultCellContent() {
const { color, textDecoration, fieldProps, pointerEvents } = SchemaTableCell.renderProps(this._props);
@@ -203,7 +211,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
this._props.finishEdit?.();
return true;
}
- const hasNoLayout = Doc.IsDataProto(fieldProps.Document) ? true : undefined; // the "delegate" is a a data document so never write to it's proto
+ const hasNoLayout = Doc.IsDataProto(fieldProps.Document) ? true : undefined; // the "delegate" is a a data document so never write to it's proto
const ret = Doc.SetField(fieldProps.Document, this._props.fieldKey.replace(/^_/, ''), value, hasNoLayout);
this._submittedValue = value;
this._props.finishEdit?.();
@@ -245,8 +253,8 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
const sides: Array<string | undefined> = [];
sides[0] = selectedCell(this._props) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // left
sides[1] = selectedCell(this._props) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // right
- sides[2] = (!this._props.isolatedSelection(this._props.Document)[0] && selectedCell(this._props)) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // top
- sides[3] = (!this._props.isolatedSelection(this._props.Document)[1] && selectedCell(this._props)) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // bottom
+ sides[2] = !this._props.isolatedSelection(this._props.Document)[0] && selectedCell(this._props) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // top
+ sides[3] = !this._props.isolatedSelection(this._props.Document)[1] && selectedCell(this._props) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // bottom
return sides;
}
@@ -256,9 +264,13 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
className="schema-table-cell"
onContextMenu={e => StopEvent(e)}
onPointerDown={action(e => {
- if (this.lockedInteraction) { e.stopPropagation(); e.preventDefault(); return; }
+ if (this.lockedInteraction) {
+ e.stopPropagation();
+ e.preventDefault();
+ return;
+ }
- if (this._props.refSelectModeInfo.enabled && !selectedCell(this._props)){
+ if (this._props.refSelectModeInfo.enabled && !selectedCell(this._props)) {
e.stopPropagation();
e.preventDefault();
this._props.selectReference(this._props.Document, this._props.col);
@@ -274,14 +286,16 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
} else !selectedCell(this._props) && this._props.selectCell(this._props.Document, this._props.col, shift, ctrl);
}
})}
- style={{ padding: this._props.padding,
- maxWidth: this._props.maxWidth?.(),
- width: this._props.columnWidth() || undefined,
- borderLeft: this.borderColor[0],
- borderRight: this.borderColor[1],
- borderTop: this.borderColor[2],
- borderBottom: this.borderColor[3],
- backgroundColor: this.backgroundColor}}>
+ style={{
+ padding: this._props.padding,
+ maxWidth: this._props.maxWidth?.(),
+ width: this._props.columnWidth() || undefined,
+ borderLeft: this.borderColor[0],
+ borderRight: this.borderColor[1],
+ borderTop: this.borderColor[2],
+ borderBottom: this.borderColor[3],
+ backgroundColor: this.backgroundColor,
+ }}>
{this.isDefault ? '' : this.content}
</div>
);
@@ -524,4 +538,4 @@ export class SchemaEnumerationCell extends ObservableReactComponent<SchemaTableC
</div>
);
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index 962a21dbb..6c3f4eaff 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -84,7 +84,6 @@ ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: b
} else {
const dataKey = Doc.LayoutFieldKey(dv.Document);
const alternate = (dv.layoutDoc[dataKey + '_usePath'] ? '_' + dv.layoutDoc[dataKey + '_usePath'] : '').replace(':hover', '');
- console.log('color: ' + dv.dataDoc[fieldKey + alternate] + ' to set to: ' + color)
dv.layoutDoc[fieldKey + alternate] = undefined;
dv.dataDoc[fieldKey + alternate] = color;
}
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 12196f290..896048ab3 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -1,4 +1,3 @@
-/* eslint-disable react/jsx-props-no-spreading */
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Checkbox } from '@mui/material';
import { Colors, Toggle, ToggleType, Type } from 'browndash-components';
@@ -8,42 +7,36 @@ import * as React from 'react';
import { ClientUtils, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents } from '../../../../ClientUtils';
import { emptyFunction } from '../../../../Utils';
import { Doc, DocListCast, Field, FieldType, NumListCast, Opt, StrListCast } from '../../../../fields/Doc';
+import { AclAdmin, AclAugment, AclEdit } from '../../../../fields/DocSymbols';
import { InkTool } from '../../../../fields/InkField';
import { List } from '../../../../fields/List';
+import { PrefetchProxy } from '../../../../fields/Proxy';
import { Cast, CsvCast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
import { CsvField } from '../../../../fields/URLField';
-import { GetEffectiveAcl, TraceMobx, inheritParentAcls } from '../../../../fields/util';
+import { GetEffectiveAcl, TraceMobx } from '../../../../fields/util';
+import { GPTCallType, gptAPICall } from '../../../apis/gpt/GPT';
import { DocUtils } from '../../../documents/DocUtils';
import { DocumentType } from '../../../documents/DocumentTypes';
import { Docs } from '../../../documents/Documents';
+import { LinkManager } from '../../../util/LinkManager';
import { UndoManager, undoable } from '../../../util/UndoManager';
import { ContextMenu } from '../../ContextMenu';
import { ViewBoxAnnotatableComponent } from '../../DocComponent';
import { MarqueeAnnotator } from '../../MarqueeAnnotator';
import { PinProps } from '../../PinFuncs';
import { SidebarAnnos } from '../../SidebarAnnos';
+import { CollectionFreeFormView } from '../../collections/collectionFreeForm';
import { AnchorMenu } from '../../pdf/AnchorMenu';
import { GPTPopup, GPTPopupMode } from '../../pdf/GPTPopup/GPTPopup';
import { DocumentView } from '../DocumentView';
import { FieldView, FieldViewProps } from '../FieldView';
import { FocusViewOptions } from '../FocusViewOptions';
import './DataVizBox.scss';
+import { Col, DataVizTemplateInfo, DocCreatorMenu, LayoutType, TemplateFieldSize, TemplateFieldType } from './DocCreatorMenu';
import { Histogram } from './components/Histogram';
import { LineChart } from './components/LineChart';
import { PieChart } from './components/PieChart';
import { TableBox } from './components/TableBox';
-import { LinkManager } from '../../../util/LinkManager';
-import { Col, DataVizTemplateInfo, DataVizTemplateLayout, DocCreatorMenu, TemplateFieldSize, LayoutType, TemplateFieldType } from './DocCreatorMenu';
-import { CollectionFreeFormView, MarqueeView } from '../../collections/collectionFreeForm';
-import { PrefetchProxy } from '../../../../fields/Proxy';
-import { AclAdmin, AclAugment, AclEdit } from '../../../../fields/DocSymbols';
-import { template } from 'lodash';
-import { data } from 'jquery';
-import { listSpec } from '../../../../fields/Schema';
-import { ObjectField } from '../../../../fields/ObjectField';
-import { Id } from '../../../../fields/FieldSymbols';
-import { GPTCallType, gptAPICall } from '../../../apis/gpt/GPT';
-import { TbSortDescendingShapes } from 'react-icons/tb';
export enum DataVizView {
TABLE = 'table',
@@ -65,7 +58,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@observable _marqueeing: number[] | undefined = undefined;
@observable _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
@observable _specialHighlightedRow: number | undefined = undefined;
- @observable GPTSummary: ObservableMap<string, {desc?: string, type?: TemplateFieldType, size?: TemplateFieldSize}> | undefined = undefined;
+ @observable GPTSummary: ObservableMap<string, { desc?: string; type?: TemplateFieldType; size?: TemplateFieldSize }> | undefined = undefined;
@observable colsInfo: ObservableMap<string, Col> = new ObservableMap();
@observable _GPTLoading: boolean = false;
@@ -121,12 +114,9 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
const records = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey]).url.href);
this._urlError = false;
return records?.filter(record => Object.keys(record).some(key => record[key])) ?? [];
- } catch (e){
+ } catch {
this._urlError = true;
- const data: { [key: string]: string; }[] = [
- { error: "Data not found"},
- ];
- return data;
+ return [{ error: 'Data not found' }] as { [key: string]: string }[];
}
}
@@ -153,70 +143,73 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@action setSpecialHighlightedRow = (row: number | undefined) => {
this._specialHighlightedRow = row;
- }
+ };
@action setColumnType = (colTitle: string, type: TemplateFieldType) => {
const colInfo = this.colsInfo.get(colTitle);
- if (colInfo) {
+ if (colInfo) {
colInfo.type = type;
} else {
- this.colsInfo.set(colTitle, {title: colTitle, desc: '', type: type, sizes: [TemplateFieldSize.MEDIUM]})
+ this.colsInfo.set(colTitle, { title: colTitle, desc: '', type: type, sizes: [TemplateFieldSize.MEDIUM] });
}
- }
+ };
@action modifyColumnSizes = (colTitle: string, size: TemplateFieldSize, valid: boolean) => {
const column = this.colsInfo.get(colTitle);
- if (column) {
+ if (column) {
if (!valid && column.sizes.includes(size)) {
column.sizes.splice(column.sizes.indexOf(size), 1);
} else if (valid && !column.sizes.includes(size)) {
column.sizes.push(size);
}
} else {
- this.colsInfo.set(colTitle, {title: colTitle, desc: '', type: TemplateFieldType.UNSET, sizes: [size]})
+ this.colsInfo.set(colTitle, { title: colTitle, desc: '', type: TemplateFieldType.UNSET, sizes: [size] });
}
- }
+ };
@action setColumnTitle = (colTitle: string, newTitle: string) => {
const colInfo = this.colsInfo.get(colTitle);
- if (colInfo) {
+ if (colInfo) {
colInfo.title = newTitle;
- console.log(colInfo.title)
+ console.log(colInfo.title);
} else {
- this.colsInfo.set(colTitle, {title: newTitle, desc: '', type: TemplateFieldType.UNSET, sizes: []})
+ this.colsInfo.set(colTitle, { title: newTitle, desc: '', type: TemplateFieldType.UNSET, sizes: [] });
}
- }
+ };
@action setColumnDesc = (colTitle: string, desc: string) => {
const colInfo = this.colsInfo.get(colTitle);
if (colInfo) {
- if (!desc) { colInfo.desc = this.GPTSummary?.get(colTitle)?.desc ?? ''; }
- else { colInfo.desc = desc; }
+ if (!desc) {
+ colInfo.desc = this.GPTSummary?.get(colTitle)?.desc ?? '';
+ } else {
+ colInfo.desc = desc;
+ }
} else {
- this.colsInfo.set(colTitle, {title: colTitle, desc: desc, type: TemplateFieldType.UNSET, sizes: []})
+ this.colsInfo.set(colTitle, { title: colTitle, desc: desc, type: TemplateFieldType.UNSET, sizes: [] });
}
- }
+ };
@action setColumnDefault = (colTitle: string, cont: string) => {
const colInfo = this.colsInfo.get(colTitle);
if (colInfo) {
colInfo.defaultContent = cont;
} else {
- this.colsInfo.set(colTitle, {title: colTitle, desc: '', type: TemplateFieldType.UNSET, sizes: [], defaultContent: cont})
+ this.colsInfo.set(colTitle, { title: colTitle, desc: '', type: TemplateFieldType.UNSET, sizes: [], defaultContent: cont });
}
- }
+ };
@action // pinned / linked anchor doc includes selected rows, graph titles, and graph colors
- restoreView = (data: Doc) => {
+ restoreView = (viewData: Doc) => {
// const changedView = data.config_dataViz && this.dataVizView !== data.config_dataViz && (this.layoutDoc._dataViz = data.config_dataViz);
// const changedAxes = data.config_dataVizAxes && this.axes.join('') !== StrListCast(data.config_dataVizAxes).join('') && (this.layoutDoc._dataViz_axes = new List<string>(StrListCast(data.config_dataVizAxes)));
- this.layoutDoc.dataViz_selectedRows = Field.Copy(data.dataViz_selectedRows);
- this.layoutDoc.dataViz_histogram_barColors = Field.Copy(data.dataViz_histogram_barColors);
- this.layoutDoc.dataViz_histogram_defaultColor = data.dataViz_histogram_defaultColor;
- this.layoutDoc.dataViz_pie_sliceColors = Field.Copy(data.dataViz_pie_sliceColors);
+ this.layoutDoc.dataViz_selectedRows = Field.Copy(viewData.dataViz_selectedRows);
+ this.layoutDoc.dataViz_histogram_barColors = Field.Copy(viewData.dataViz_histogram_barColors);
+ this.layoutDoc.dataViz_histogram_defaultColor = viewData.dataViz_histogram_defaultColor;
+ this.layoutDoc.dataViz_pie_sliceColors = Field.Copy(viewData.dataViz_pie_sliceColors);
Object.keys(this.layoutDoc).forEach(key => {
if (key.startsWith('dataViz_histogram_title') || key.startsWith('dataViz_lineChart_title') || key.startsWith('dataViz_pieChart_title')) {
- this.layoutDoc['_' + key] = data[key];
+ this.layoutDoc['_' + key] = viewData[key];
}
});
return true;
@@ -354,7 +347,9 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
componentDidMount() {
this._props.setContentViewBox?.(this);
- if (!this._urlError) { if (!DataVizBox.dataset.has(CsvCast(this.dataDoc[this.fieldKey]).url.href)) this.fetchData() };
+ if (!this._urlError) {
+ if (!DataVizBox.dataset.has(CsvCast(this.dataDoc[this.fieldKey]).url.href)) this.fetchData();
+ }
this._disposers.datavis = reaction(
() => {
if (this.layoutDoc.dataViz_schemaLive === undefined) this.layoutDoc.dataViz_schemaLive = true;
@@ -516,14 +511,14 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
DocCreatorMenu.Instance.toggleDisplay(x, y);
DocCreatorMenu.Instance.setDataViz(this);
DocCreatorMenu.Instance.setTemplateDocs(this.getPossibleTemplates());
- }
+ };
- specificContextMenu = (x: number, y: number): void => {
+ specificContextMenu = (e: React.MouseEvent) => {
const cm = ContextMenu.Instance;
const options = cm.findByDescription('Options...');
const optionItems = options?.subitems ?? [];
optionItems.push({ description: `Analyze with AI`, event: () => this.askGPT(), icon: 'lightbulb' });
- optionItems.push({ description: `Create documents`, event: () => this.openDocCreatorMenu(x, y), icon: 'table-cells' });
+ optionItems.push({ description: `Create documents`, event: () => this.openDocCreatorMenu(e.pageX, e.pageY), icon: 'table-cells' });
!options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'eye' });
};
@@ -533,19 +528,19 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
GPTPopup.Instance.createFilteredDoc = this.createFilteredDoc;
GPTPopup.Instance.setDataJson('');
GPTPopup.Instance.setMode(GPTPopupMode.DATA);
- const data = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey]).url.href);
- GPTPopup.Instance.setDataJson(JSON.stringify(data));
+ const csvdata = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey]).url.href);
+ GPTPopup.Instance.setDataJson(JSON.stringify(csvdata));
GPTPopup.Instance.generateDataAnalysis();
});
getColSummary = (): string => {
- let possibleIds: number[] = this.records.map((_, index) => index);
+ const possibleIds: number[] = this.records.map((_, index) => index);
for (let i = possibleIds.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[possibleIds[i], possibleIds[j]] = [possibleIds[j], possibleIds[i]];
}
-
+
const rowsToCheck = possibleIds.slice(0, Math.min(10, this.records.length));
let prompt: string = 'Col titles: ';
@@ -553,37 +548,37 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
const cols = Array.from(Object.keys(this.records[0])).filter(header => header !== '' && header !== undefined);
cols.forEach((col, i) => {
- prompt += `Col #${i}: ${col} ------`
- })
+ prompt += `Col #${i}: ${col} ------`;
+ });
- prompt += '----------- Rows: '
+ prompt += '----------- Rows: ';
- rowsToCheck.forEach((row, i) => {
- prompt += `Row #${row}: `
+ rowsToCheck.forEach(row => {
+ prompt += `Row #${row}: `;
cols.forEach(col => {
- prompt += `${col}: ${this.records[row][col]} -----`
- })
- })
+ prompt += `${col}: ${this.records[row][col]} -----`;
+ });
+ });
return prompt;
- }
+ };
updateColDefaults = () => {
- let possibleIds: number[] = this.records.map((_, index) => index);
+ const possibleIds: number[] = this.records.map((_, index) => index);
for (let i = possibleIds.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[possibleIds[i], possibleIds[j]] = [possibleIds[j], possibleIds[i]];
}
-
+
const rowToCheck = possibleIds[0];
const cols = Array.from(Object.keys(this.records[0])).filter(header => header !== '' && header !== undefined);
- cols.forEach(col => {
- this.setColumnDefault(col, `${this.records[rowToCheck][col]}`)
+ cols.forEach(col => {
+ this.setColumnDefault(col, `${this.records[rowToCheck][col]}`);
});
- }
+ };
updateGPTSummary = async () => {
this._GPTLoading = true;
@@ -594,15 +589,12 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
const cols = Array.from(Object.keys(this.records[0])).filter(header => header !== '' && header !== undefined);
cols.forEach(col => {
- if (!this.colsInfo.get(col)) this.colsInfo.set(col, {title: col, desc: '', sizes: [], type: TemplateFieldType.UNSET});
+ if (!this.colsInfo.get(col)) this.colsInfo.set(col, { title: col, desc: '', sizes: [], type: TemplateFieldType.UNSET });
});
try {
- const [res1, res2] = await Promise.all([
- gptAPICall(prompt, GPTCallType.VIZSUM),
- gptAPICall('Info:' + prompt, GPTCallType.VIZSUM2)
- ]);
-
+ const [res1, res2] = await Promise.all([gptAPICall(prompt, GPTCallType.VIZSUM), gptAPICall('Info:' + prompt, GPTCallType.VIZSUM2)]);
+
if (res1) {
this.GPTSummary = new ObservableMap();
const descs: { [col: string]: string } = JSON.parse(res1);
@@ -611,10 +603,10 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
if (!this.colsInfo.get(key)?.desc) this.setColumnDesc(key, val);
}
}
-
+
if (res2) {
!this.GPTSummary && (this.GPTSummary = new ObservableMap());
- const info: { [col: string]: { type: TemplateFieldType, size: TemplateFieldSize } } = JSON.parse(res2);
+ const info: { [col: string]: { type: TemplateFieldType; size: TemplateFieldSize } } = JSON.parse(res2);
for (const [key, val] of Object.entries(info)) {
const colSummary = this.GPTSummary.get(key);
if (colSummary) {
@@ -628,30 +620,29 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
} catch (err) {
console.error(err);
}
-
- }
+ };
getPossibleTemplates = (): Doc[] => {
const linkedDocs: Doc[] = LinkManager.Instance.getAllRelatedLinks(this.Document).map(d => DocCast(LinkManager.getOppositeAnchor(d, this.Document)));
const linkedCollections: Doc[] = linkedDocs.filter(doc => doc.type === 'config').map(doc => DocCast(doc.annotationOn));
const isColumnTitle = (title: string): boolean => {
const colTitles: string[] = Object.keys(this.records[0]);
- for (let i = 0; i < colTitles.length; ++i){
+ for (let i = 0; i < colTitles.length; ++i) {
if (colTitles[i] === title) {
return true;
}
}
return false;
- }
+ };
const isValidTemplate = (collection: Doc) => {
const childDocs = DocListCast(collection[Doc.LayoutFieldKey(collection)]);
- for (let i = 0; i < childDocs.length; ++i){
+ for (let i = 0; i < childDocs.length; ++i) {
if (isColumnTitle(String(childDocs[i].title))) return true;
}
return false;
- }
+ };
return linkedCollections.filter(col => isValidTemplate(col));
- }
+ };
ApplyTemplateTo = (templateDoc: Doc, target: Doc, targetKey: string, titleTarget: string | undefined) => {
if (!Doc.AreProtosEqual(target[targetKey] as Doc, templateDoc)) {
@@ -664,14 +655,14 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
}
}
return target;
- }
+ };
applyLayout = (templateInfo: DataVizTemplateInfo, docs: Doc[]) => {
if (templateInfo.layout.type === LayoutType.Stacked) return;
const columns: number = templateInfo.columns;
const xGap: number = templateInfo.layout.xMargin;
const yGap: number = templateInfo.layout.yMargin;
- const repeat: number = templateInfo.layout.repeat;
+ // const repeat: number = templateInfo.layout.repeat;
const startX: number = templateInfo.referencePos.x;
const startY: number = templateInfo.referencePos.y;
const templWidth = Number(templateInfo.doc._width);
@@ -682,8 +673,8 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
let curX: number = startX;
let curY: number = startY;
- while (docsChanged < docs.length){
- while (i < columns && docsChanged < docs.length){
+ while (docsChanged < docs.length) {
+ while (i < columns && docsChanged < docs.length) {
docs[docsChanged].x = curX;
docs[docsChanged].y = curY;
curX += templWidth + xGap;
@@ -695,27 +686,29 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
curX = startX;
curY += templHeight + yGap;
}
- }
+ };
// @action addSavedLayout = (layout: DataVizTemplateLayout) => {
// const saved = Cast(this.layoutDoc.dataViz_savedTemplates, listSpec('RefField'));
-
+
// }
@action
createDocsFromTemplate = (templateInfo: DataVizTemplateInfo) => {
if (!templateInfo.doc) return;
const mainCollection = this.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
- const fields: string[] = Array.from(Object.keys(this.records[0]));
+ const fields: string[] = Array.from(Object.keys(this.records[0]));
const selectedRows = NumListCast(this.layoutDoc.dataViz_selectedRows);
const docs: Doc[] = selectedRows.map(row => {
- const values: String[] = [];
+ const values: string[] = [];
fields.forEach(col => values.push(this.records[row][col]));
const proto = new Doc();
proto.author = ClientUtils.CurrentUserEmail();
- values.forEach((val, i) => {proto[fields[i]] = val as FieldType});
-
+ values.forEach((val, i) => {
+ proto[fields[i]] = val as FieldType;
+ });
+
const target = Doc.MakeDelegate(proto);
const targetKey = StrCast(templateInfo.doc!.layout_fieldKey, 'layout');
const applied = this.ApplyTemplateTo(templateInfo.doc!, target, targetKey, templateInfo.doc!.title + `${row}`);
@@ -728,7 +721,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
docs.forEach(doc => mainCollection.addDocument(doc));
this.applyLayout(templateInfo, docs);
- }
+ };
/**
* creates a new dataviz document filter from this one
@@ -783,7 +776,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
transform: `scale(${scale})`,
position: 'absolute',
}}
- onContextMenu={(e) => this.specificContextMenu(e.pageX, e.pageY)}
+ onContextMenu={this.specificContextMenu}
onWheel={e => e.stopPropagation()}
ref={this._mainCont}>
<div className="datatype-button">
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
index ad47b7848..6c649bde3 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
@@ -28,6 +28,7 @@ import { DataVizBox } from './DataVizBox';
import './DocCreatorMenu.scss';
import { DefaultStyleProvider, returnEmptyDocViewList } from '../../StyleProvider';
import { Transform } from '../../../util/Transform';
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
export enum LayoutType {
Stacked = 'stacked',
@@ -1621,6 +1622,21 @@ export type Col = {
type: TemplateFieldType;
defaultContent?: string;
};
+export interface FieldOpts {
+ backgroundColor?: string;
+ color?: string;
+ cornerRounding?: number;
+ borderWidth?: string;
+ borderColor?: string;
+ contentXCentering?: 'h-left' | 'h-center' | 'h-right';
+ contentYCentering?: 'top' | 'center' | 'bottom';
+ opacity?: number;
+ rotation?: number;
+ //animation?: boolean;
+ fontBold?: boolean;
+ fontTransform?: 'uppercase' | 'lowercase';
+ fieldViewType?: 'freeform' | 'stacked';
+}
type Field = {
tl: [number, number];
@@ -1667,6 +1683,8 @@ type InkDecoration = {};
type TemplateDecorations = Field | InkDecoration;
+interface TemplateOpts extends FieldOpts {}
+
export interface TemplateDocInfos {
title: string;
height: number;
@@ -1676,178 +1694,6 @@ export interface TemplateDocInfos {
decorations: Field[];
}
-export interface FieldOpts {
- backgroundColor?: string;
- color?: string;
- cornerRounding?: number;
- borderWidth?: string;
- borderColor?: string;
- contentXCentering?: 'h-left' | 'h-center' | 'h-right';
- contentYCentering?: 'top' | 'center' | 'bottom';
- opacity?: number;
- rotation?: number;
- //animation?: boolean;
- fontBold?: boolean;
- fontTransform?: 'uppercase' | 'lowercase';
- fieldViewType?: 'freeform' | 'stacked';
-}
-
-interface TemplateOpts extends FieldOpts {}
-
-export class FieldUtils {
- public static contentFields = (fields: Field[]) => {
- let toRet: Field[] = [];
- fields.forEach(field => {
- if (!field.isDecoration) {
- toRet.push(field);
- }
- toRet = toRet.concat(FieldUtils.contentFields(field.subfields ?? []));
- });
-
- return toRet;
- };
-
- public static calculateFontSize = (contWidth: number, contHeight: number, text: string, uppercase: boolean): number => {
- const words: string[] = text.split(/\s+/).filter(Boolean);
-
- let currFontSize = 1;
- let rowsCount = 1;
- let currTextHeight = currFontSize * rowsCount * 2;
-
- while (currTextHeight <= contHeight) {
- let wordIndex = 0;
- let currentRowWidth = 0;
- let wordsInCurrRow = 0;
- rowsCount = 1;
-
- while (wordIndex < words.length) {
- const word = words[wordIndex];
- const wordWidth = word.length * currFontSize * 0.5;
- //console.log(wordWidth)
-
- if (currentRowWidth + wordWidth <= contWidth) {
- currentRowWidth += wordWidth;
- ++wordsInCurrRow;
- } else {
- if (words.length !== 1 && words.length > wordsInCurrRow) {
- rowsCount++;
- currentRowWidth = wordWidth;
- wordsInCurrRow = 1;
- } else {
- break;
- }
- }
-
- wordIndex++;
- }
-
- currTextHeight = rowsCount * currFontSize * 2;
- //console.log(rowsCount, currFontSize, currTextHeight)
-
- currFontSize += 1;
- }
-
- return currFontSize - 1;
- };
-
- private static getDimensions = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number): { width: number; height: number; coord: { x: number; y: number } } => {
- const l = (coords.tl[0] * parentHeight) / 2;
- const t = coords.tl[1] * parentWidth / 2; //prettier-ignore
- const r = (coords.br[0] * parentHeight) / 2;
- const b = coords.br[1] * parentWidth / 2; //prettier-ignore
- const width = r - l;
- const height = b - t;
- const coord = { x: l, y: t };
- //console.log(coords, parentWidth, parentHeight, height);
- return { width, height, coord };
- };
-
- public static FreeformField = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
- const { width, height, coord } = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
-
- const docWithBasicOpts = Docs.Create.FreeformDocument([], {
- isDefaultTemplateDoc: true,
- _height: height,
- _width: width,
- title: title,
- x: coord.x,
- y: coord.y,
- backgroundColor: opts.backgroundColor ?? '',
- _layout_borderRounding: `${opts.cornerRounding}px` ?? '0px',
- borderColor: opts.borderColor,
- borderWidth: opts.borderWidth,
- opacity: opts.opacity,
- hCentering: opts.contentXCentering,
- _rotation: opts.rotation,
- });
-
- return docWithBasicOpts;
- };
-
- public static TextField = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
- const { width, height, coord } = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
-
- const bool = true;
-
- const docWithBasicOpts = Docs.Create.TextDocument(content, {
- isDefaultTemplateDoc: true,
- _height: height,
- _width: width,
- title: title,
- x: coord.x,
- y: coord.y,
- _text_fontSize: `${FieldUtils.calculateFontSize(width, height, content, true)}`,
- backgroundColor: opts.backgroundColor ?? '',
- text_fontColor: opts.color,
- contentBold: opts.fontBold,
- textTransform: opts.fontTransform,
- color: opts.color,
- _layout_borderRounding: `${opts.cornerRounding}px` ?? '0px',
- borderColor: opts.borderColor,
- borderWidth: opts.borderWidth,
- opacity: opts.opacity,
- hCentering: opts.contentXCentering,
- _rotation: opts.rotation,
- });
-
- docWithBasicOpts._layout_hideScroll = true;
-
- return docWithBasicOpts;
- };
-
- public static ImageField = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
- const { width, height, coord } = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
-
- const doc = Docs.Create.ImageDocument(content, {
- isDefaultTemplateDoc: true,
- _height: height,
- _width: width,
- title: title,
- x: coord.x,
- y: coord.y,
- _layout_fitWidth: false,
- backgroundColor: opts.backgroundColor ?? '',
- _layout_borderRounding: `${opts.cornerRounding}px` ?? '0px',
- borderColor: opts.borderColor,
- borderWidth: opts.borderWidth,
- opacity: opts.opacity,
- _rotation: opts.rotation,
- });
-
- //setTimeout(() => {doc._height = height; doc._width = width}, 10);
-
- return doc;
- };
-
- public static CarouselField = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number, title: string, fields: Doc[]) => {
- const { width, height, coord } = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
-
- const doc = Docs.Create.Carousel3DDocument(fields, { _height: height, _width: width, title: title, x: coord.x, y: coord.y, _text_fontSize: `${height / 2}` });
-
- return doc;
- };
-}
-
export class TemplateLayouts {
public static get allTemplates(): TemplateDocInfos[] {
return Object.values(TemplateLayouts).filter(value => typeof value === 'object' && value !== null && 'title' in value) as TemplateDocInfos[];
@@ -2311,55 +2157,205 @@ export class TemplateLayouts {
},
],
};
+}
+
+export class FieldUtils {
+ public static contentFields = (fields: Field[]) => {
+ let toRet: Field[] = [];
+ fields.forEach(field => {
+ if (!field.isDecoration) {
+ toRet.push(field);
+ }
+ toRet = toRet.concat(FieldUtils.contentFields(field.subfields ?? []));
+ });
+
+ return toRet;
+ };
+
+ public static calculateFontSize = (contWidth: number, contHeight: number, text: string, uppercase: boolean): number => {
+ const words: string[] = text.split(/\s+/).filter(Boolean);
+
+ let currFontSize = 1;
+ let rowsCount = 1;
+ let currTextHeight = currFontSize * rowsCount * 2;
+
+ while (currTextHeight <= contHeight) {
+ let wordIndex = 0;
+ let currentRowWidth = 0;
+ let wordsInCurrRow = 0;
+ rowsCount = 1;
+
+ while (wordIndex < words.length) {
+ const word = words[wordIndex];
+ const wordWidth = word.length * currFontSize * 0.5;
+ //console.log(wordWidth)
+
+ if (currentRowWidth + wordWidth <= contWidth) {
+ currentRowWidth += wordWidth;
+ ++wordsInCurrRow;
+ } else {
+ if (words.length !== 1 && words.length > wordsInCurrRow) {
+ rowsCount++;
+ currentRowWidth = wordWidth;
+ wordsInCurrRow = 1;
+ } else {
+ break;
+ }
+ }
+
+ wordIndex++;
+ }
+
+ currTextHeight = rowsCount * currFontSize * 2;
+ //console.log(rowsCount, currFontSize, currTextHeight)
+
+ currFontSize += 1;
+ }
+
+ return currFontSize - 1;
+ };
- // public static FourField002: TemplateDocInfos = {
- // width: 450,
- // height: 600,
- // fields: [{
- // tl: [-.6, -.9],
- // br: [.6, -.8],
- // types: [FieldType.TEXT],
- // sizes: [FieldSize.TINY]
- // }, {
- // tl: [-.9, -.7],
- // br: [.9, .2],
- // types: [FieldType.TEXT, FieldType.VISUAL],
- // sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE]
- // }, {
- // tl: [-.9, .3],
- // br: [-.05, .9],
- // types: [FieldType.TEXT],
- // sizes: [FieldSize.TINY]
- // }, {
- // tl: [.05, .3],
- // br: [.9, .9],
- // types: [FieldType.TEXT, FieldType.VISUAL],
- // sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE]
- // }]
- // };
-
- // public static TwoFieldPlusCarousel: TemplateDocInfos = {
- // width: 500,
- // height: 600,
- // fields: [{
- // tl: [-.9, -.99],
- // br: [.9, -.7],
- // types: [FieldType.TEXT],
- // sizes: [FieldSize.TINY]
- // }, {
- // tl: [-.9, -.65],
- // br: [.9, .35],
- // types: [],
- // sizes: []
- // }, {
- // tl: [-.9, .4],
- // br: [.9, .95],
- // types: [FieldType.TEXT],
- // sizes: [FieldSize.TINY]
- // }]
- // };
+ private static getDimensions = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number): { width: number; height: number; coord: { x: number; y: number } } => {
+ const l = (coords.tl[0] * parentHeight) / 2;
+ const t = coords.tl[1] * parentWidth / 2; //prettier-ignore
+ const r = (coords.br[0] * parentHeight) / 2;
+ const b = coords.br[1] * parentWidth / 2; //prettier-ignore
+ const width = r - l;
+ const height = b - t;
+ const coord = { x: l, y: t };
+ //console.log(coords, parentWidth, parentHeight, height);
+ return { width, height, coord };
+ };
+
+ public static FreeformField = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
+ const { width, height, coord } = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
+
+ const docWithBasicOpts = Docs.Create.FreeformDocument([], {
+ isDefaultTemplateDoc: true,
+ _height: height,
+ _width: width,
+ title: title,
+ x: coord.x,
+ y: coord.y,
+ backgroundColor: opts.backgroundColor ?? '',
+ _layout_borderRounding: `${opts.cornerRounding ?? 0}px`,
+ borderColor: opts.borderColor,
+ borderWidth: opts.borderWidth,
+ opacity: opts.opacity,
+ hCentering: opts.contentXCentering,
+ _rotation: opts.rotation,
+ });
+
+ return docWithBasicOpts;
+ };
+
+ public static TextField = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
+ const { width, height, coord } = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
+
+ const docWithBasicOpts = Docs.Create.TextDocument(content, {
+ isDefaultTemplateDoc: true,
+ _height: height,
+ _width: width,
+ title: title,
+ x: coord.x,
+ y: coord.y,
+ _text_fontSize: `${FieldUtils.calculateFontSize(width, height, content, true)}`,
+ backgroundColor: opts.backgroundColor ?? '',
+ text_fontColor: opts.color,
+ contentBold: opts.fontBold,
+ textTransform: opts.fontTransform,
+ color: opts.color,
+ _layout_borderRounding: `${opts.cornerRounding ?? 0}px`,
+ borderColor: opts.borderColor,
+ borderWidth: opts.borderWidth,
+ opacity: opts.opacity,
+ hCentering: opts.contentXCentering,
+ _rotation: opts.rotation,
+ });
+
+ docWithBasicOpts._layout_hideScroll = true;
+
+ return docWithBasicOpts;
+ };
+
+ public static ImageField = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
+ const { width, height, coord } = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
+
+ const doc = Docs.Create.ImageDocument(content, {
+ isDefaultTemplateDoc: true,
+ _height: height,
+ _width: width,
+ title: title,
+ x: coord.x,
+ y: coord.y,
+ _layout_fitWidth: false,
+ backgroundColor: opts.backgroundColor ?? '',
+ _layout_borderRounding: `${opts.cornerRounding ?? 0}px`,
+ borderColor: opts.borderColor,
+ borderWidth: opts.borderWidth,
+ opacity: opts.opacity,
+ _rotation: opts.rotation,
+ });
+
+ //setTimeout(() => {doc._height = height; doc._width = width}, 10);
+
+ return doc;
+ };
+
+ public static CarouselField = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number, title: string, fields: Doc[]) => {
+ const { width, height, coord } = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
+
+ const doc = Docs.Create.Carousel3DDocument(fields, { _height: height, _width: width, title: title, x: coord.x, y: coord.y, _text_fontSize: `${height / 2}` });
+
+ return doc;
+ };
}
-// export class ContentField extends Field {
-
-// }
+// public static FourField002: TemplateDocInfos = {
+// width: 450,
+// height: 600,
+// fields: [{
+// tl: [-.6, -.9],
+// br: [.6, -.8],
+// types: [FieldType.TEXT],
+// sizes: [FieldSize.TINY]
+// }, {
+// tl: [-.9, -.7],
+// br: [.9, .2],
+// types: [FieldType.TEXT, FieldType.VISUAL],
+// sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE]
+// }, {
+// tl: [-.9, .3],
+// br: [-.05, .9],
+// types: [FieldType.TEXT],
+// sizes: [FieldSize.TINY]
+// }, {
+// tl: [.05, .3],
+// br: [.9, .9],
+// types: [FieldType.TEXT, FieldType.VISUAL],
+// sizes: [FieldSize.MEDIUM, FieldSize.LARGE, FieldSize.HUGE]
+// }]
+// };
+
+// public static TwoFieldPlusCarousel: TemplateDocInfos = {
+// width: 500,
+// height: 600,
+// fields: [{
+// tl: [-.9, -.99],
+// br: [.9, -.7],
+// types: [FieldType.TEXT],
+// sizes: [FieldSize.TINY]
+// }, {
+// tl: [-.9, -.65],
+// br: [.9, .35],
+// types: [],
+// sizes: []
+// }, {
+// tl: [-.9, .4],
+// br: [.9, .95],
+// types: [FieldType.TEXT],
+// sizes: [FieldSize.TINY]
+// }]
+// };
+// }
+
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index 6cc773da0..fe596bc36 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -1,5 +1,3 @@
-/* eslint-disable jsx-a11y/no-noninteractive-tabindex */
-/* eslint-disable jsx-a11y/no-static-element-interactions */
import { Button, Colors, Type } from 'browndash-components';
import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
@@ -18,6 +16,7 @@ import { DocumentView } from '../../DocumentView';
import { DataVizView } from '../DataVizBox';
import './Chart.scss';
+// eslint-disable-next-line @typescript-eslint/no-require-imports
const { DATA_VIZ_TABLE_ROW_HEIGHT } = require('../../../global/globalCssVariables.module.scss'); // prettier-ignore
interface TableBoxProps {
@@ -416,7 +415,7 @@ export class TableBox extends ObservableReactComponent<TableBoxProps> {
? 'darkred'
: this._props.axes.length > 3 && this._props.axes[1] === col
? 'darkblue'
- : this._props.axes.lastElement() === col || (this._props.axes.length > 3 && this._props.axes[2] === col)
+ : this._props.axes.lastElement() === col || (this._props.axes.length > 3 && this._props.axes[2] === col)
? 'darkcyan'
: undefined,
background: this.settingTitle
@@ -427,7 +426,7 @@ export class TableBox extends ObservableReactComponent<TableBoxProps> {
? '#Fbdbdb'
: this._props.axes.lastElement() === col || (this._props.axes.length > 2 && this._props.axes[1] === col)
? '#c6ebf7'
- : this._props.axes.lastElement() === col || (this._props.axes.length > 3 && this._props.axes[2] === col)
+ : this._props.axes.lastElement() === col || (this._props.axes.length > 3 && this._props.axes[2] === col)
? '#c2f0f4'
: undefined,
fontWeight: 'bolder',
@@ -448,8 +447,15 @@ export class TableBox extends ObservableReactComponent<TableBoxProps> {
className={`tableBox-row ${this.columns[0]}`}
onClick={e => this.tableRowClick(e, rowId)}
style={{
- background: rowId === this._props.specHighlightedRow ? 'lightblue' : NumListCast(this._props.layoutDoc.dataViz_highlitedRows).includes(rowId) ? 'lightYellow' : NumListCast(this._props.layoutDoc.dataViz_selectedRows).includes(rowId) ? 'lightgrey' : '',
- border: rowId === this._props.specHighlightedRow ? `solid 3px ${Colors.MEDIUM_BLUE}` : ''
+ background:
+ rowId === this._props.specHighlightedRow
+ ? 'lightblue'
+ : NumListCast(this._props.layoutDoc.dataViz_highlitedRows).includes(rowId)
+ ? 'lightYellow'
+ : NumListCast(this._props.layoutDoc.dataViz_selectedRows).includes(rowId)
+ ? 'lightgrey'
+ : '',
+ border: rowId === this._props.specHighlightedRow ? `solid 3px ${Colors.MEDIUM_BLUE}` : '',
}}>
{this.columns.map(col => {
let colSelected = false;
diff --git a/src/client/views/nodes/DocumentIcon.tsx b/src/client/views/nodes/DocumentIcon.tsx
index 0b94ae4f7..9769ecb3d 100644
--- a/src/client/views/nodes/DocumentIcon.tsx
+++ b/src/client/views/nodes/DocumentIcon.tsx
@@ -1,5 +1,5 @@
import { Tooltip } from '@mui/material';
-import { action, makeObservable, observable } from 'mobx';
+import { makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { factory } from 'typescript';
@@ -18,14 +18,14 @@ interface DocumentIconProps {
@observer
export class DocumentIcon extends ObservableReactComponent<DocumentIconProps> {
@observable _hovered = false;
- constructor(props: any) {
+ constructor(props: DocumentIconProps) {
super(props);
makeObservable(this);
}
render() {
const { view } = this._props;
- const { left, top, right, bottom } = view.getBounds || { left: 0, top: 0, right: 0, bottom: 0 };
+ const { left, top, bottom } = view.getBounds || { left: 0, top: 0, right: 0, bottom: 0 };
return (
<div
@@ -34,7 +34,7 @@ export class DocumentIcon extends ObservableReactComponent<DocumentIconProps> {
pointerEvents: 'all',
position: 'absolute',
background: SnappingManager.userBackgroundColor,
- transform: `translate(${left}px, ${bottom - (bottom - top)/2}px)`, //**!**
+ transform: `translate(${left}px, ${bottom - (bottom - top) / 2}px)`, //**!**
}}>
<Tooltip title={<div>{StrCast(this._props.view.Document?.title)}</div>}>
<p>d{this._props.index}</p>
@@ -44,7 +44,7 @@ export class DocumentIcon extends ObservableReactComponent<DocumentIconProps> {
}
}
-@observer
+@observer
export class DocumentIconContainer extends React.Component {
public static getTransformer(): Transformer {
const usedDocuments = new Set<number>();
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 4a249838b..428fe5acb 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1161,7 +1161,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
return Math.max(minTextScale, this._props.PanelHeight() / (this.effectiveNativeHeight || 1)); // height-limited or unscaled
}
@computed private get panelWidth() {
- return this.effectiveNativeWidth ? this.effectiveNativeWidth * this.nativeScaling: this._props.PanelWidth();
+ return this.effectiveNativeWidth ? this.effectiveNativeWidth * this.nativeScaling : this._props.PanelWidth();
}
@computed private get panelHeight() {
if (this.effectiveNativeHeight && (!this.layout_fitWidth || !this.layoutDoc.layout_reflowVertical)) {
@@ -1207,6 +1207,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
public set IsSelected(val) { runInAction(() => { this._selected = val; }); } // prettier-ignore
public get IsSelected() { return this._selected; } // prettier-ignore
+ public get IsContentActive(){ return this._docViewInternal?.isContentActive(); } // prettier-ignore
public get topMost() { return this._props.renderDepth === 0; } // prettier-ignore
public get ContentDiv() { return this._docViewInternal?._contentDiv; } // prettier-ignore
public get ComponentView() { return this._docViewInternal?._componentView; } // prettier-ignore
@@ -1472,7 +1473,6 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
render() {
TraceMobx();
- const borderWidth = 50/*Number(StrCast(this.layoutDoc.layout_borderWidth).replace('px', ''))*/;
const xshift = Math.abs(this.Xshift) <= 0.001 ? this._props.PanelWidth() : undefined;
const yshift = Math.abs(this.Yshift) <= 0.001 ? this._props.PanelHeight() : undefined;
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index a0d69d29d..741d63909 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -6,7 +6,6 @@ import { DateField } from '../../../fields/DateField';
import { Doc, Field, FieldType, Opt } from '../../../fields/Doc';
import { List } from '../../../fields/List';
import { ScriptField } from '../../../fields/ScriptField';
-import { WebField } from '../../../fields/URLField';
import { dropActionType } from '../../util/DropActionTypes';
import { Transform } from '../../util/Transform';
import { PinProps } from '../PinFuncs';
@@ -14,9 +13,9 @@ import { ViewBoxInterface } from '../ViewBoxInterface';
import { DocumentView } from './DocumentView';
import { FocusViewOptions } from './FocusViewOptions';
import { OpenWhere } from './OpenWhere';
+import { WebField } from '../../../fields/URLField';
export type FocusFuncType = (doc: Doc, options: FocusViewOptions) => Opt<number>;
-// eslint-disable-next-line no-use-before-define
export type StyleProviderFuncType = (
doc: Opt<Doc>,
// eslint-disable-next-line no-use-before-define
@@ -139,7 +138,7 @@ export class FieldView extends React.Component<FieldViewProps> {
const field = this.fieldval;
// prettier-ignore
if (field instanceof Doc) return <p> <b>{field.title?.toString()}</b></p>;
- if (field === undefined) return <p>{''}</p>;
+ if (field === undefined) return <p />;
if (field instanceof DateField) return <p>{field.date.toLocaleString()}</p>;
if (field instanceof List) return <div> {field.map(f => Field.toString(f)).join(', ')} </div>;
if (field instanceof WebField) return <p>{Field.toString(field.url.href)}</p>;
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index cfcf76b12..8974cccaf 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -2,7 +2,7 @@ import { Property } from 'csstype';
import { action, computed, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-//import * as textfit from 'textfit';
+import * as textfit from 'textfit';
import { Field, FieldType } from '../../../fields/Doc';
import { BoolCast, NumCast, StrCast } from '../../../fields/Types';
import { TraceMobx } from '../../../fields/util';
@@ -96,7 +96,7 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
this._timeout = setTimeout(() => this.fitTextToBox(r));
return textfitParams;
}
- //textfit(r, textfitParams);
+ textfit(r, textfitParams);
}
return textfitParams;
};
diff --git a/src/client/views/nodes/calendarBox/CalendarBox.tsx b/src/client/views/nodes/calendarBox/CalendarBox.tsx
index 678b7dd0b..d38cb5423 100644
--- a/src/client/views/nodes/calendarBox/CalendarBox.tsx
+++ b/src/client/views/nodes/calendarBox/CalendarBox.tsx
@@ -1,4 +1,4 @@
-import { Calendar, DateInput, EventClickArg, EventSourceInput } from '@fullcalendar/core';
+import { Calendar, EventClickArg, EventSourceInput } from '@fullcalendar/core';
import dayGridPlugin from '@fullcalendar/daygrid';
import multiMonthPlugin from '@fullcalendar/multimonth';
import timeGrid from '@fullcalendar/timegrid';
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 730c57794..0d7914a82 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1195,6 +1195,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
if (nh) this.layoutDoc._nativeHeight = scrollHeight;
};
+ @computed get tagsHeight() {
+ return this.DocumentView?.().showTags ? Math.max(0, 20 - Math.max(this._props.yPadding ?? 0, NumCast(this.layoutDoc._yMargin))) * this.ScreenToLocalBoxXf().Scale : 0;
+ }
+
@computed get contentScaling() {
return Doc.NativeAspect(this.Document, this.dataDoc, false) ? this._props.NativeDimScaling?.() || 1 : 1;
}
@@ -1222,9 +1226,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
);
this._disposers.componentHeights = reaction(
// set the document height when one of the component heights changes and layout_autoHeight is on
- () => ({ sidebarHeight: this.sidebarHeight, textHeight: this.textHeight, layoutAutoHeight: this.layout_autoHeight, marginsHeight: this.layout_autoHeightMargins }),
- ({ sidebarHeight, textHeight, layoutAutoHeight, marginsHeight }) => {
- const newHeight = this.contentScaling * (marginsHeight + Math.max(sidebarHeight, textHeight));
+ () => ({ sidebarHeight: this.sidebarHeight, textHeight: this.textHeight, layoutAutoHeight: this.layout_autoHeight, marginsHeight: this.layout_autoHeightMargins, tagsHeight: this.tagsHeight }),
+ ({ sidebarHeight, textHeight, layoutAutoHeight, marginsHeight, tagsHeight }) => {
+ const newHeight = this.contentScaling * (tagsHeight + marginsHeight + Math.max(sidebarHeight, textHeight));
if (
(!Array.from(FormattedTextBox._globalHighlights).includes('Bold Text') || this._props.isSelected()) && //
layoutAutoHeight &&
@@ -1494,7 +1498,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
pdfAnchorId && this.addPdfReference(pdfAnchorId);
}
if (this._props.autoFocus) setTimeout(() => this._editorView!.focus()); // not sure why setTimeout is needed but editing dashFieldView's doesn't work without it.
-
}
// add user mark for any first character that was typed since the user mark that gets set in KeyPress won't have been called yet.
@@ -2005,8 +2008,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
const scale = this._props.NativeDimScaling?.() || 1;
const rounded = StrCast(this.layoutDoc.layout_borderRounding) === '100%' ? '-rounded' : '';
setTimeout(() => !this._props.isContentActive() && FormattedTextBoxComment.textBox === this && FormattedTextBoxComment.Hide);
- const paddingX = NumCast(this.layoutDoc._xMargin, this._props.xPadding || 0);
- const paddingY = NumCast(this.layoutDoc._yMargin, this._props.yPadding || 0);
+ const paddingX = Math.max(this._props.xPadding ?? 0, NumCast(this.layoutDoc._xMargin));
+ const paddingY = Math.max(this._props.yPadding ?? 0, NumCast(this.layoutDoc._yMargin));
const styleFromLayout = styleFromLayoutString(this.Document, this._props, scale); // this converts any expressions in the format string to style props. e.g., <FormattedTextBox height='{this._header_height}px' >
return styleFromLayout?.height === '0px' ? null : (
<div
@@ -2025,6 +2028,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
height: `${100 / scale}%`,
}),
transition: 'inherit',
+ paddingBottom: this.tagsHeight,
// overflowY: this.layoutDoc._layout_autoHeight ? "hidden" : undefined,
color: this.fontColor,
fontSize: this.fontSize,
@@ -2082,7 +2086,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
</div>
</div>
);
-
}
}