diff options
Diffstat (limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx')
-rw-r--r-- | src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx | 156 |
1 files changed, 71 insertions, 85 deletions
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx index 7b28a06a3..7bc1b8064 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx @@ -1,24 +1,22 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Colors } from 'browndash-components'; -import { action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; +import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { IDisposer } from 'mobx-utils'; import * as React from 'react'; import ReactLoading from 'react-loading'; -import { ClientUtils, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents } from '../../../../../ClientUtils'; +import { ClientUtils, returnEmptyFilter, returnFalse, setupMoveUpEvents } from '../../../../../ClientUtils'; import { emptyFunction } from '../../../../../Utils'; -import { Doc, FieldType, NumListCast, StrListCast, returnEmptyDoclist } from '../../../../../fields/Doc'; +import { Doc, NumListCast, StrListCast, returnEmptyDoclist } from '../../../../../fields/Doc'; import { Id } from '../../../../../fields/FieldSymbols'; -import { Cast, DocCast, ImageCast, StrCast } from '../../../../../fields/Types'; +import { ImageCast, StrCast } from '../../../../../fields/Types'; import { ImageField } from '../../../../../fields/URLField'; import { Networking } from '../../../../Network'; import { GPTCallType, gptAPICall, gptImageCall } from '../../../../apis/gpt/GPT'; import { Docs, DocumentOptions } from '../../../../documents/Documents'; import { DragManager } from '../../../../util/DragManager'; -import { MakeTemplate } from '../../../../util/DropConverter'; import { SnappingManager } from '../../../../util/SnappingManager'; import { UndoManager, undoable } from '../../../../util/UndoManager'; -import { LightboxView } from '../../../LightboxView'; import { ObservableReactComponent } from '../../../ObservableReactComponent'; import { CollectionFreeFormView } from '../../../collections/collectionFreeForm/CollectionFreeFormView'; import { DocumentView, DocumentViewInternal } from '../../DocumentView'; @@ -26,14 +24,13 @@ import { FieldViewProps } from '../../FieldView'; import { OpenWhere } from '../../OpenWhere'; import { DataVizBox } from '../DataVizBox'; import './DocCreatorMenu.scss'; -import { DefaultStyleProvider, returnEmptyDocViewList } from '../../../StyleProvider'; +import { DefaultStyleProvider } from '../../../StyleProvider'; import { Transform } from '../../../../util/Transform'; -import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { TemplateFieldSize, TemplateFieldType, TemplateLayouts } from './TemplateBackend'; import { TemplateManager } from './TemplateManager'; import { Template } from './Template'; import { Field, FieldContentType } from './FieldTypes/Field'; -import { TabDocView } from '../../../collections/TabDocView'; +import { IconProp } from '@fortawesome/fontawesome-svg-core'; export enum LayoutType { FREEFORM = 'Freeform', @@ -43,6 +40,29 @@ export enum LayoutType { CARD = 'Card View', } +export interface DataVizTemplateInfo { + doc: Doc; + layout: { type: LayoutType; xMargin: number; yMargin: number; repeat: number }; + columns: number; + referencePos: { x: number; y: number }; +} + +export interface DataVizTemplateLayout { + template: Doc; + docsNumList: number[]; + layout: { type: LayoutType; xMargin: number; yMargin: number; repeat: number }; + columns: number; + rows: number; +} + +export type Col = { + sizes: TemplateFieldSize[]; + desc: string; + title: string; + type: TemplateFieldType; + defaultContent?: string; +}; + @observer export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { static Instance: DocCreatorMenu; @@ -89,8 +109,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { @observable _dragging: boolean = false; @observable _draggingIndicator: boolean = false; @observable _dataViz?: DataVizBox; - @observable _interactionLock: any; - @observable _snapPt: any; + @observable _interactionLock: boolean | undefined; + @observable _snapPt: {x: number, y: number} = {x: 0, y: 0}; @observable _resizeHdlId: string = ''; @observable _resizing: boolean = false; @observable _offset: { x: number; y: number } = { x: 0, y: 0 }; @@ -195,7 +215,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { return bounds; } - setUpButtonClick = (e: any, func: Function) => { + setUpButtonClick = (e: any, func: () => void) => { setupMoveUpEvents( this, e, @@ -250,11 +270,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { } @action - updateSelectedCols = (cols: string[]) => { - this._selectedCols; - }; - - @action toggleDisplay = (x: number, y: number) => { if (this._shouldDisplay) { this._shouldDisplay = false; @@ -302,7 +317,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { this._interactionLock = true; const scaleAspect = {x: scale.x, y: scale.y}; this.resizeView(refPt, scaleAspect, transl); // prettier-ignore - await new Promise<any>(res => { setTimeout(() => { res(this._interactionLock = undefined)})}); + await new Promise<boolean | undefined>(res => { setTimeout(() => { res(this._interactionLock = undefined)})}); }); // prettier-ignore return true; }; @@ -318,7 +333,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { getResizeVals = (thisPt: { x: number; y: number }, dragHdl: string) => { const [w, h] = [this._initDimensions.width, this._initDimensions.height]; - const [moveX, moveY] = [thisPt.x - this._snapPt.x, thisPt.y - this._snapPt.y]; + const [moveX, moveY] = [thisPt.x - this._snapPt!.x, thisPt.y - this._snapPt!.y]; let vals: { scale: { x: number; y: number }; refPt: [number, number]; transl: { x: number; y: number } }; switch (dragHdl) { case 'topLeft': vals = { scale: { x: 1 - moveX / w, y: 1 -moveY / h }, refPt: [this.bounds.r, this.bounds.b], transl: {x: moveX, y: moveY } }; break; @@ -335,7 +350,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { }; resizeView = (refPt: number[], scale: { x: number; y: number }, translation: { x: number; y: number }) => { - const refCent = [refPt[0], refPt[1]]; // fixed reference point for resize (ie, a point that doesn't move) if (this._initDimensions.x === undefined) this._initDimensions.x = this._pageX; if (this._initDimensions.y === undefined) this._initDimensions.y = this._pageY; const { height, width, x, y } = this._initDimensions; @@ -475,8 +489,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { const GPTTextCalls = Object.entries(assignments).filter(([str, col]) => col.type === TemplateFieldType.TEXT && this._userCreatedFields.includes(col)); const GPTIMGCalls = Object.entries(assignments).filter(([str, col]) => col.type === TemplateFieldType.VISUAL && this._userCreatedFields.includes(col)); - let fieldContent: string = template.compiledContent; - if (GPTTextCalls.length) { const promises = GPTTextCalls.map(([str, col]) => { return this.renderGPTTextCall(template, col, Number(str)); @@ -527,7 +539,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { ++this._callCount; const origCount = this._callCount; - let prompt: string = `(${origCount}) ${inputText}`; + const prompt: string = `(${origCount}) ${inputText}`; this._GPTLoading = true; @@ -539,7 +551,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { const brokenDownAssignments: [Template, { [fieldID: number]: Col }][] = []; Object.entries(assignments).forEach(([tempTitle, assignment]) => { - const template = templates.filter(template => template.mainField.getTitle() === tempTitle)[0]; + const template = templates.filter(t => t.mainField.getTitle() === tempTitle)[0]; if (!template) return; const toObj = Object.entries(assignment).reduce( (a, [fieldID, colTitle]) => { @@ -575,9 +587,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { const assignments: [Template, { [field: number]: Col }][] = await this.assignColsToFields(templates, cols); - const renderedTemplatePromises: Promise<Template | undefined>[] = assignments.map(([template, assignments]) => this.applyGPTContentToTemplate(template, assignments)); + const renderedTemplatePromises: Promise<Template | undefined>[] = assignments.map(([template, asns]) => this.applyGPTContentToTemplate(template, asns)); - const renderedTemplates: (Template | undefined)[] = await Promise.all(renderedTemplatePromises); + await Promise.all(renderedTemplatePromises); setTimeout(() => { this.setSuggestedTemplates(templates); @@ -585,16 +597,16 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { }); }; - renderGPTImageCall = async (template: Template, col: Col, fieldNum: number): Promise<boolean> => { - const generateAndLoadImage = async (fieldNum: string, col: Col, prompt: string) => { + renderGPTImageCall = async (template: Template, col: Col, fieldNumber: number): Promise<boolean> => { + const generateAndLoadImage = async (fieldNum: string, column: Col, prompt: string) => { const url = await this.generateGPTImage(prompt); const field: Field = template.getFieldByID(Number(fieldNum)); field.setContent(url ?? '', FieldContentType.IMAGE); - field.setTitle(col.title); + field.setTitle(column.title); }; - let fieldContent: string = template.compiledContent; + const fieldContent: string = template.compiledContent; try { const sysPrompt = @@ -605,7 +617,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { const prompt = await gptAPICall(sysPrompt, GPTCallType.COMPLETEPROMPT); - await generateAndLoadImage(String(fieldNum), col, prompt); + await generateAndLoadImage(String(fieldNumber), col, prompt); } catch (e) { console.log(e); } @@ -632,7 +644,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { const textAssignment = `--- title: ${col.title}, prompt: ${col.desc}, word limit: ${wordLimit(col.sizes[0])} words, assigned field: ${fieldNum} ---`; - let fieldContent: string = template.compiledContent; + const fieldContent: string = template.compiledContent; try { const prompt = fieldContent + textAssignment; @@ -643,10 +655,10 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { const assignments: { [title: string]: { number: string; content: string } } = JSON.parse(res); Object.entries(assignments).forEach(([title, info]) => { const field: Field = template.getFieldByID(Number(info.number)); - const col = this.getColByTitle(title); + const column = this.getColByTitle(title); field.setContent(info.content ?? '', FieldContentType.STRING); - field.setTitle(col.title); + field.setTitle(column.title); }); } } catch (err) { @@ -667,7 +679,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { const selectedRows = NumListCast(dv.layoutDoc.dataViz_selectedRows); const rowContents: { [title: string]: string }[] = selectedRows.map(row => { - let values: { [title: string]: string } = {}; + const values: { [title: string]: string } = {}; fields.forEach(col => { values[col] = dv.records[row][col]; }); @@ -756,7 +768,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { focus={emptyFunction} styleProvider={DefaultStyleProvider} addDocTab={DocumentViewInternal.addDocTabFunc} - // eslint-disable-next-line no-use-before-define pinToPres={() => undefined} childFilters={returnEmptyFilter} childFiltersByRanges={returnEmptyFilter} @@ -786,7 +797,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { } get templatesPreviewContents() { - const renderedTemplates: Doc[] = []; const GPTOptions = <div></div>; @@ -813,6 +823,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { .map(({doc, template}) => ( <div className="docCreatorMenu-preview-window" + key='0' style={{ border: this._selectedTemplate === template ? `solid 3px ${Colors.MEDIUM_BLUE}` : '', boxShadow: this._selectedTemplate === template ? `0 0 15px rgba(68, 118, 247, .8)` : '', @@ -844,7 +855,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { focus={emptyFunction} styleProvider={DefaultStyleProvider} addDocTab={this._props.addDocTab} - // eslint-disable-next-line no-use-before-define pinToPres={() => undefined} childFilters={returnEmptyFilter} childFiltersByRanges={returnEmptyFilter} @@ -882,6 +892,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { .map(({template, doc}) => ( <div className="docCreatorMenu-preview-window" + key='0' style={{ border: this._selectedTemplate === template ? `solid 3px ${Colors.MEDIUM_BLUE}` : '', boxShadow: this._selectedTemplate === template ? `0 0 15px rgba(68, 118, 247, .8)` : '', @@ -913,7 +924,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { focus={emptyFunction} styleProvider={DefaultStyleProvider} addDocTab={this._props.addDocTab} - // eslint-disable-next-line no-use-before-define pinToPres={() => undefined} childFilters={returnEmptyFilter} childFiltersByRanges={returnEmptyFilter} @@ -953,11 +963,11 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { }; get layoutConfigOptions() { - const optionInput = (icon: string, func: Function, def?: number, key?: string, noMargin?: boolean) => { + const optionInput = (icon: string, func: (input: string) => void, def?: number, key?: string, noMargin?: boolean) => { return ( <div className="docCreatorMenu-option-container small no-margin" key={key} style={{ marginTop: noMargin ? '0px' : '' }}> <div className="docCreatorMenu-option-title config layout-config"> - <FontAwesomeIcon icon={icon as any} /> + <FontAwesomeIcon icon={icon as IconProp} /> </div> <input defaultValue={def} onInput={e => func(e.currentTarget.value)} className="docCreatorMenu-input config layout-config" /> </div> @@ -1070,16 +1080,16 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { this._renderedDocCollection = collection; } - layoutPreviewContents = (id?: number) => { + layoutPreviewContents = () => { return this._docsRendering ? ( - <div className="docCreatorMenu-layout-preview-window-wrapper loading" id={String(id) ?? undefined}> + <div className="docCreatorMenu-layout-preview-window-wrapper loading"> <div className="loading-spinner"> <ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} /> </div> </div> ) : !this._renderedDocCollection? null : ( - <div className="docCreatorMenu-layout-preview-window-wrapper" id={String(id) ?? undefined}> + <div className="docCreatorMenu-layout-preview-window-wrapper"> <DocumentView Document={this._renderedDocCollection} isContentActive={emptyFunction} @@ -1094,7 +1104,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { focus={emptyFunction} styleProvider={DefaultStyleProvider} addDocTab={this._props.addDocTab} - // eslint-disable-next-line no-use-before-define pinToPres={() => undefined} childFilters={returnEmptyFilter} childFiltersByRanges={returnEmptyFilter} @@ -1108,7 +1117,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { }; get optionsMenuContents() { - const layoutOption = (option: LayoutType, optStyle?: {}, specialFunc?: Function) => { + const layoutOption = (option: LayoutType, optStyle?: object, specialFunc?: () => void) => { return ( <div className="docCreatorMenu-dropdown-option" @@ -1131,7 +1140,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { return ( <div className="docCreatorMenu-option-container"> <div className={`docCreatorMenu-option-title config ${specClass}`} style={{ width: width * 0.4, height: height }}> - <FontAwesomeIcon icon={icon as any} /> + <FontAwesomeIcon icon={icon as IconProp} /> </div> {manual ? ( <input className={`docCreatorMenu-input config ${specClass}`} style={{ width: width * 0.6, height: height }} /> @@ -1162,13 +1171,13 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { </div> </div> {this._layout.type ? this.layoutConfigOptions : null} - {this.layoutPreviewContents(this._menuDimensions.width * 0.75)} + {this.layoutPreviewContents()} {selectionBox( 60, 20, 'repeat', undefined, - repeatOptions.map(num => <option onPointerDown={e => (this._layout.repeat = num)}>{`${num}x`}</option>) + repeatOptions.map(num => <option key={num} onPointerDown={() => (this._layout.repeat = num)}>{`${num}x`}</option>) )} <hr className="docCreatorMenu-option-divider" /> <div className="docCreatorMenu-general-options-container"> @@ -1333,19 +1342,19 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { const width: number = ref?.width ?? 0; return [ - <div className='docCreatorMenu-resizer top' onPointerDown={this.onResizePointerDown} style={{width: width, left: 0, top: -7}}/>, - <div className='docCreatorMenu-resizer left' onPointerDown={this.onResizePointerDown} style={{height: height, left: -7, top: 0}}/>, - <div className='docCreatorMenu-resizer right' onPointerDown={this.onResizePointerDown} style={{height: height, left: width - 3, top: 0}}/>, - <div className='docCreatorMenu-resizer bottom' onPointerDown={this.onResizePointerDown} style={{width: width, left: 0, top: height - 3}}/>, - <div className='docCreatorMenu-resizer topLeft' onPointerDown={this.onResizePointerDown} style={{left: -10, top: -10, cursor: 'nwse-resize'}}/>, - <div className='docCreatorMenu-resizer topRight' onPointerDown={this.onResizePointerDown} style={{left: width - 5, top: -10, cursor: 'nesw-resize'}}/>, - <div className='docCreatorMenu-resizer bottomLeft' onPointerDown={this.onResizePointerDown} style={{left: -10, top: height - 5, cursor: 'nesw-resize'}}/>, - <div className='docCreatorMenu-resizer bottomRight' onPointerDown={this.onResizePointerDown} style={{left: width - 5, top: height - 5, cursor: 'nwse-resize'}}/>, + <div className='docCreatorMenu-resizer top' key='0' onPointerDown={this.onResizePointerDown} style={{width: width, left: 0, top: -7}}/>, + <div className='docCreatorMenu-resizer left' key='1' onPointerDown={this.onResizePointerDown} style={{height: height, left: -7, top: 0}}/>, + <div className='docCreatorMenu-resizer right' key='2' onPointerDown={this.onResizePointerDown} style={{height: height, left: width - 3, top: 0}}/>, + <div className='docCreatorMenu-resizer bottom' key='3' onPointerDown={this.onResizePointerDown} style={{width: width, left: 0, top: height - 3}}/>, + <div className='docCreatorMenu-resizer topLeft' key='4' onPointerDown={this.onResizePointerDown} style={{left: -10, top: -10, cursor: 'nwse-resize'}}/>, + <div className='docCreatorMenu-resizer topRight' key='5' onPointerDown={this.onResizePointerDown} style={{left: width - 5, top: -10, cursor: 'nesw-resize'}}/>, + <div className='docCreatorMenu-resizer bottomLeft' key='6' onPointerDown={this.onResizePointerDown} style={{left: -10, top: height - 5, cursor: 'nesw-resize'}}/>, + <div className='docCreatorMenu-resizer bottomRight' key='7' onPointerDown={this.onResizePointerDown} style={{left: width - 5, top: height - 5, cursor: 'nwse-resize'}}/>, ]; //prettier-ignore } render() { - const topButton = (icon: string, opt: string, func: Function, tag: string) => { + const topButton = (icon: string, opt: string, func: () => void, tag: string) => { return ( <div className={`top-button-container ${tag} ${opt === this._menuContent ? 'selected' : ''}`}> <div @@ -1357,7 +1366,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { }) ) }> - <FontAwesomeIcon icon={icon as any} /> + <FontAwesomeIcon icon={icon as IconProp} /> </div> </div> ); @@ -1396,11 +1405,11 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { setupMoveUpEvents( this, e, - e => { + event => { this._dragging = true; this._startPos = { x: 0, y: 0 }; - this._startPos.x = e.pageX - (this._ref?.getBoundingClientRect().left ?? 0); - this._startPos.y = e.pageY - (this._ref?.getBoundingClientRect().top ?? 0); + this._startPos.x = event.pageX - (this._ref?.getBoundingClientRect().left ?? 0); + this._startPos.y = event.pageY - (this._ref?.getBoundingClientRect().top ?? 0); document.addEventListener('pointermove', this.onDrag); return true; }, @@ -1426,26 +1435,3 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { ); } } - -export interface DataVizTemplateInfo { - doc: Doc; - layout: { type: LayoutType; xMargin: number; yMargin: number; repeat: number }; - columns: number; - referencePos: { x: number; y: number }; -} - -export interface DataVizTemplateLayout { - template: Doc; - docsNumList: number[]; - layout: { type: LayoutType; xMargin: number; yMargin: number; repeat: number }; - columns: number; - rows: number; -} - -export type Col = { - sizes: TemplateFieldSize[]; - desc: string; - title: string; - type: TemplateFieldType; - defaultContent?: string; -}; |