From ded7673796965e9cb9239cfd483a2f1e35abd38b Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Wed, 17 Jul 2024 18:28:05 -0400
Subject: highlighting rows based on layoutpreview hover

---
 src/client/views/nodes/ImageBox.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/client/views/nodes/ImageBox.tsx')

diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index e4b3a1b9b..b7943f503 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -341,7 +341,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     }
 
     @computed get paths() {
-        const field = Cast(this.dataDoc[this.fieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc
+        const field = this.dataDoc[this.fieldKey] instanceof ImageField ? Cast(this.dataDoc[this.fieldKey], ImageField, null) : new ImageField(String(this.dataDoc[this.fieldKey])); // retrieve the primary image URL that is being rendered from the data doc
         const alts = DocListCast(this.dataDoc[this.fieldKey + '_alternates']); // retrieve alternate documents that may be rendered as alternate images
         const defaultUrl = new URL(ClientUtils.prepend('/assets/unknown-file-icon-hi.png'));
         const altpaths =
-- 
cgit v1.2.3-70-g09d2


From 4949c68f38049da55ceaa3e95ea155f38d6a3748 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Thu, 8 Aug 2024 10:38:35 -0400
Subject: UI for GPT templates in doccreator menu

---
 src/client/views/nodes/DataVizBox/DataVizBox.tsx   |  45 -------
 .../views/nodes/DataVizBox/DocCreatorMenu.scss     | 128 ++++++++++++++++--
 .../views/nodes/DataVizBox/DocCreatorMenu.tsx      | 147 ++++++++++++++++-----
 src/client/views/nodes/ImageBox.tsx                |   1 +
 4 files changed, 228 insertions(+), 93 deletions(-)

(limited to 'src/client/views/nodes/ImageBox.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index c5a1da1da..a6d3bfa49 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -568,51 +568,6 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         this.applyLayout(templateInfo, docs);
     }
 
-    generateTemplates = async () => {
-        try {
-            const res = await gptAPICall('Please generate for the fields: Image, Description, Divider, Response', GPTCallType.TEMPLATE);
-
-            if (res) {
-                const templates: {template_type: string, fieldVals: {title: string, tlx: string, tly: string, brx: string, bry: string}[]}[] = JSON.parse(res);
-                this.createGeneratedTemplates(templates, 500, 500);
-                //console.log(res);
-            }
-        } catch (err) {
-            console.error(err);
-        }
-
-    }
-
-    createGeneratedTemplates = (layouts: {template_type: string, fieldVals: {title: string, tlx: string, tly: string, brx: string, bry: string}[]}[], tempWidth: number, tempHeight: number) => { 
-        const mainCollection = this.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
-
-        layouts.forEach(layout => {
-            const fields: Doc[] = layout.fieldVals.map(field => {
-                const left: number = Number(field.tlx) * tempWidth / 2; const top: number = Number(field.tly) * tempHeight / 2; //prettier-ignore
-                const right: number = Number(field.brx) * tempWidth / 2; const bottom: number = Number(field.bry) * tempHeight / 2; //prettier-ignore
-                const height = bottom - top; const width = right - left; //prettier-ignore
-                const doc = !field.title.includes('$$') ? Docs.Create.TextDocument('', { _height: height, _width: width, title: field.title, x: left, y: top, _text_fontSize: `${height/2}` }) : Docs.Create.ImageDocument('', { _height: height, _width: 250, title: field.title.replace(/$$/g, ''), x: left, y: top });
-                return doc;
-            });
-
-            const template = Docs.Create.FreeformDocument(fields, { _height: tempHeight, _width: tempWidth, title: layout.template_type, x: 400, y: 400 });
-            mainCollection.addDocument(template);
-        });
-    }
-
-    createBasicTemplates = (colsToLayout: {width: number, height: number, x: number, y: number, title: string}[]) => {
-        const mainCollection = this.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
-
-        const fields: Doc[] = colsToLayout.map(layout => {
-            const field = Docs.Create.TextDocument('', { _height: layout.height, _width: layout.width, title: layout.title, x: layout.x, y: layout.y });
-            return field;
-        });
-
-        const template = Docs.Create.FreeformDocument(fields, { _height: 500, _width: 500, title: 'template', x: 400, y: 400 })
-
-        mainCollection.addDocument(template);
-    }
-
     /**
      * creates a new dataviz document filter from this one
      *      it appears to the right of this document, with the
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss b/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss
index b3bacb13c..e2b4014bd 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss
@@ -22,14 +22,14 @@
 }
 
 .docCreatorMenu-menu-button {
-    width: 30px;
-    height: 30px;
+    width: 25px;
+    height: 25px;
     background: whitesmoke; 
-    background-color: rgb(34, 34, 37);
+    background-color: rgb(50, 50, 50);
     border-radius: 5px;
     border: 1px solid rgb(180, 180, 180);
     padding: 0px;
-    font-size: 14px;
+    font-size: 13px;
     //box-shadow: 3px 3px rgb(29, 29, 31);
 
     &:hover {
@@ -222,7 +222,7 @@
 
 .docCreatorMenu-option-divider {
     border-top: 1px solid rgb(180, 180, 180);
-    width: 80%;
+    width: 95%;
     margin-top: 10px;
     margin-bottom: 10px;
 }
@@ -256,6 +256,18 @@
 // DocCreatorMenu templates preview CSS
 //--------------------------------------------------------------------------------------------------------------------------------------------
 
+.docCreatorMenu-templates-view {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: flex-start;
+    margin: 5px;
+    margin-top: 0px;
+    width: calc(100% - 10px);
+    height: calc(100% - 30px);
+    border: 1px solid rgb(180, 180, 180);
+    border-radius: 5px;
+}
 
 .docCreatorMenu-preview-container {
     display: grid;
@@ -263,20 +275,18 @@
     grid-template-rows: 140px;
     grid-auto-rows: 141px;
     overflow-y: scroll;
-    margin: 5px;
+    margin: 0px;
     margin-top: 0px;
-    width: calc(100% - 10px);
-    height: calc(100% - 30px);
-    border: 1px solid rgb(180, 180, 180);
-    border-radius: 5px;
+    width: 100%;
+    height: 100%;
 }
 
 .docCreatorMenu-preview-window {
     display: flex;
     justify-content: center;
     align-items: center;
-    width: 125px;
-    height: 125px;
+    width: 113px;
+    height: 113px;
     margin-top: 10px;
     margin-left: 10px;
     border: 1px solid rgb(163, 163, 163);
@@ -295,9 +305,103 @@
 
     &.empty {
         font-size: 35px;
+        flex: 0 0 auto;
+
+        &.GPT {
+            margin-top: 0px;
+        }
+    }
+}
+
+.docCreatorMenu-section {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    position: relative;
+    margin: 0px;
+    width: 100%;
+    height: 250;
+    flex: 0 0 auto;
+}
+
+.docCreatorMenu-GPT-options-container {
+    display: flex;
+    flex-direction: row;
+    justify-content: center;
+    align-items: center;
+    position: relative;
+    width: auto;
+    margin: 0px;
+    margin-top: 5px;
+    padding: 0px;
+}
+
+.docCreatorMenu-GPT-templates-preview {
+    display: flex;
+    flex-direction: row;
+    //justify-content: center;
+    align-items: center;
+    overflow-y: scroll;
+    position: relative;
+    height: 125px;
+    width: calc(100% - 10px);
+    -ms-overflow-style: none; 
+    scrollbar-width: none;
+}
+
+.docCreatorMenu-section-topbar {
+    position: relative;
+    display: flex;
+    flex-direction: row;
+    width: 100%;
+
+    .section-reveal-options {
+        margin: 0px;
+        margin-left: auto;
+        border: 0px;
+        background: none;
+    }
+}
+
+.docCreatorMenu-section-title {
+    border: 1px solid rgb(163, 163, 163);
+    border-top: 0px;
+    border-left: 0px;
+    border-bottom-right-radius: 5px;
+    font-size: 12px;
+    padding: 2px;
+    padding-left: 3px;
+    padding-right: 3px;
+    margin-bottom: 3px;
+}
+
+.docCreatorMenu-GPT-generate {
+    height: 30px;
+    width: 30px;
+    background-color: rgb(176, 229, 149); 
+    border: 1px solid rgb(126, 219, 80);
+    border-radius: 5px;
+    padding: 0px;
+    font-size: 14px;
+    color: white;
+    letter-spacing: 1px;
+    flex: 0 0 auto;
+
+    &:hover {
+        background-color: rgb(129, 223, 83);
+        border: 2px solid rgb(80, 185, 28); 
     }
 }
 
+.docCreatorMenu-GPT-prompt-input {
+    width: 140px;
+    overflow-y: scroll;
+    border: 1px solid rgb(180, 180, 180);
+    background-color: rgb(35, 35, 35);
+    border-radius: 3px;
+}
+
 //------------------------------------------------------------------------------------------------------------------------------------------
 // DocCreatorMenu options CSS
 //--------------------------------------------------------------------------------------------------------------------------------------------
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
index 411257ff7..781cbcb55 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
@@ -3,7 +3,7 @@ import { IReactionDisposer, ObservableMap, action, computed, makeObservable, obs
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { returnAll, returnFalse, setupMoveUpEvents } from '../../../../ClientUtils';
-import { Doc, NumListCast } from '../../../../fields/Doc';
+import { Doc, NumListCast, StrListCast } from '../../../../fields/Doc';
 import { DocCast, ImageCast } from '../../../../fields/Types';
 import { ImageField } from '../../../../fields/URLField';
 import { emptyFunction } from '../../../../Utils';
@@ -17,6 +17,9 @@ import { Id } from '../../../../fields/FieldSymbols';
 import { Colors, IconButton, Size } from 'browndash-components';
 import { MakeTemplate } from '../../../util/DropConverter';
 import { DragManager } from '../../../util/DragManager';
+import { GPTCallType, gptAPICall } from '../../../apis/gpt/GPT';
+import { CollectionFreeFormView } from '../../collections/collectionFreeForm/CollectionFreeFormView';
+import { Docs } from '../../../documents/Documents';
 
 export enum LayoutType {
     Stacked = 'stacked', 
@@ -41,6 +44,10 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
     @observable _layoutPreviewScale: number = 1;
     @observable _savedLayouts: DataVizTemplateLayout[] = [];
 
+    @observable _GPTTemplates: Doc[] | undefined = undefined;
+    @observable _GPTOpt: boolean = false;
+    @observable _userPrompt: string = '';
+
     @observable _pageX: number = 0;
     @observable _pageY: number = 0;
     @observable _indicatorX: number | undefined = undefined;
@@ -105,6 +112,10 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
         }
     }
 
+    @computed get selectedFields(){
+        return StrListCast(this._dataViz?.layoutDoc._dataViz_axes);
+    }
+
     @computed get canMakeDocs(){
         return this._selectedTemplate !== undefined && this._layout !== undefined;
     }
@@ -254,8 +265,8 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
         if (this._initDimensions.y === undefined) this._initDimensions.y = this._pageY;
         const {height, width, x, y} = this._initDimensions;
 
-        this._menuDimensions.width = Math.max(100, scale.x * width);
-        this._menuDimensions.height = Math.max(100, scale.y * height);
+        this._menuDimensions.width = Math.max(300, scale.x * width);
+        this._menuDimensions.height = Math.max(200, scale.y * height);
         this._pageX = x + translation.x;
         this._pageY = y + translation.y;
     };
@@ -293,10 +304,104 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
         && this._layout.columns === layout.columns;
     }
 
+    generateTemplates = async (inputText: string) => {
+        let prompt: string = 'Please generate for the fields:';
+        this.selectedFields?.forEach(field => prompt += ` ${field},`)
+        prompt += ` Additional prompt: ${inputText}`;
+
+        try {
+            const res = await gptAPICall(prompt, GPTCallType.TEMPLATE);
+
+            if (res) {
+                const templates: {template_type: string, fieldVals: {title: string, tlx: string, tly: string, brx: string, bry: string}[]}[] = JSON.parse(res);
+                this.createGeneratedTemplates(templates, 500, 500);
+            }
+        } catch (err) {
+            console.error(err);
+        }
+
+    }
+
+    createGeneratedTemplates = (layouts: {template_type: string, fieldVals: {title: string, tlx: string, tly: string, brx: string, bry: string}[]}[], tempWidth: number, tempHeight: number) => { 
+        const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
+
+        layouts.forEach(layout => {
+            const fields: Doc[] = layout.fieldVals.map(field => {
+                const left: number = Number(field.tlx) * tempWidth / 2;    const top: number = Number(field.tly) * tempHeight / 2; //prettier-ignore
+                const right: number = Number(field.brx) * tempWidth / 2;   const bottom: number = Number(field.bry) * tempHeight / 2; //prettier-ignore
+                const height = bottom - top; 
+                const width = right - left; 
+                const doc = !field.title.includes('$$') ? Docs.Create.TextDocument('', { _height: height, _width: width, title: field.title, x: left, y: top, _text_fontSize: `${height/2}` }) : Docs.Create.ImageDocument('', { _height: height, _width: width, title: field.title.replace(/$$/g, ''), x: left, y: top });
+                return doc;
+            });
+
+            const template = Docs.Create.FreeformDocument(fields, { _height: tempHeight, _width: tempWidth, title: layout.template_type, x: 400, y: 400 });
+            mainCollection.addDocument(template);
+        });
+    }
+
     get templatesPreviewContents(){
         const renderedTemplates: Doc[] = [];
+
+        const GPTOptions = 
+            <div></div>
+
+        
         return (
-            <div className='docCreatorMenu-preview-container'
+            <div className='docCreatorMenu-templates-view'>
+                <div className='docCreatorMenu-section'>
+                    <div className='docCreatorMenu-section-topbar'>
+                        <div className='docCreatorMenu-section-title'>Suggested Templates</div>
+                        <button className='docCreatorMenu-menu-button section-reveal-options' onPointerDown={e => this.setUpButtonClick(e, () => this._GPTOpt = !this._GPTOpt)}>
+                            <FontAwesomeIcon icon='gear'/>
+                        </button>
+                    </div>
+                    <div className='docCreatorMenu-GPT-templates-preview'>
+                        <div className='docCreatorMenu-preview-window empty GPT'></div>
+                        <div className='docCreatorMenu-preview-window empty GPT'></div>
+                        <div className='docCreatorMenu-preview-window empty GPT'></div>
+                        <div className='docCreatorMenu-preview-window empty GPT'></div>
+                    </div>
+                    {this._GPTOpt ? (<div className='docCreatorMenu-GPT-options'>
+                        <div className='docCreatorMenu-GPT-options-container'>
+                            <button className='docCreatorMenu-menu-button' onPointerDown={e => this.setUpButtonClick(e, () => this.generateTemplates(this._userPrompt))}>
+                                <FontAwesomeIcon icon='plus'/>
+                            </button>
+                            <input className='docCreatorMenu-GPT-prompt-input'/>
+                        </div>
+                        {this._GPTOpt ? GPTOptions : null}
+                    </div>) : null}
+                </div>
+                <hr className='docCreatorMenu-option-divider'/>
+                <div className='docCreatorMenu-section'>
+                    <div className='docCreatorMenu-section-topbar'>
+                        <div className='docCreatorMenu-section-title'>Your Templates</div>
+                        <button className='docCreatorMenu-menu-button section-reveal-options' onPointerDown={e => this.setUpButtonClick(e, () => this._GPTOpt = !this._GPTOpt)}>
+                            <FontAwesomeIcon icon='gear'/>
+                        </button>
+                    </div>
+                    <div className='docCreatorMenu-GPT-templates-preview'>
+                        <div className='docCreatorMenu-preview-window empty'
+                        onPointerDown={e => this.setUpButtonClick(e, this.basicTemplateTest)}
+                        >
+                            <FontAwesomeIcon icon='plus' color='rgb(160, 160, 160)'/>
+                        </div>
+                        {this._templateDocs.map(doc => ({icon: ImageCast(doc.icon), doc})).filter(info => info.icon && info.doc).map(info => {
+                        if (renderedTemplates.includes(info.doc)) return undefined;
+                        renderedTemplates.push(info.doc);
+                        return (<div 
+                        className='docCreatorMenu-preview-window'
+                        style={{
+                            border: this._selectedTemplate === info.doc ? `solid 3px ${Colors.MEDIUM_BLUE}` : '',
+                            boxShadow: this._selectedTemplate === info.doc ? `0 0 15px rgba(68, 118, 247, .8)` : ''
+                        }}
+                        onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedTemplate(info.doc)))}>
+                            <img className='docCreatorMenu-preview-image' src={info.icon!.url.href.replace(".png", "_o.png")} />
+                        </div>
+                        )})}
+                    </div>
+                </div>
+                {/* <div className='docCreatorMenu-preview-container'
                 style={{gridTemplateColumns: `repeat(${Math.floor((this._menuDimensions.width - 10) / 140)}, 140px)`}}>
                 {this._templateDocs.map(doc => ({icon: ImageCast(doc.icon), doc})).filter(info => info.icon && info.doc).map(info => {
                     if (renderedTemplates.includes(info.doc)) return undefined;
@@ -316,6 +421,7 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
                 >
                     <FontAwesomeIcon icon='plus' color='rgb(160, 160, 160)'/>
                 </div>
+                </div> */}
             </div>
         );
     }
@@ -546,12 +652,7 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
     }
 
     basicTemplateTest = () => {
-        const temps: {width: number; height: number; x: number; y: number; title: string}[] = [
-            {width: 200, height: 50, x: -100, y: -200, title: 'title'},
-            {width: 300, height: 300, x: -150, y: -100, title: 'image'},
-            {width: 200, height: 50, x: -100, y: -200, title: 'description'},
-        ]
-        this._dataViz?.generateTemplates();
+        this.generateTemplates(this._userPrompt);
         //this._dataViz?.createBasicTemplates(temps);
     }
 
@@ -609,31 +710,6 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
         return (
             <div className='docCreatorMenu'>
                 {!this._shouldDisplay ? undefined : 
-                <>
-                {/* <div className='docCreatorMenu-placement-indicator' 
-                style={{
-                    display: '',
-                    left: this._indicatorX ?? this._pageX + 300,
-                    top: this._indicatorY ?? this._pageY,
-                }}
-                onPointerMove={e => this.onPointerMove(e)}
-                onPointerDown={e =>
-                    setupMoveUpEvents(
-                        this,
-                        e,
-                        (e) => {
-                            this._draggingIndicator = 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);
-                            return true;
-                        },
-                        emptyFunction,
-                        undoable(clickEv => {
-                            clickEv.stopPropagation();
-                        }, 'drag menu')
-                    )
-                }/> */}
                 <div
                     className="docCreatorMenu-cont"
                     ref={r => this._ref = r}
@@ -681,7 +757,6 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
                         </div>
                         {this.renderSelectedViewType}
                 </div>
-                </>
                 }
             </div>
             )
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 92a5a1533..faea05104 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -295,6 +295,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
 
     @computed get nativeSize() {
         TraceMobx();
+        if (this.paths.length && this.paths[0].includes('icon-hi')) return { nativeWidth: NumCast(this.layoutDoc._width), nativeHeight: NumCast(this.layoutDoc._height), nativeOrientation: 0}
         const nativeWidth = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth'], NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth'], 500));
         const nativeHeight = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight'], NumCast(this.layoutDoc[this.fieldKey + '_nativeHeight'], 500));
         const nativeOrientation = NumCast(this.dataDoc[this.fieldKey + '_nativeOrientation'], 1);
-- 
cgit v1.2.3-70-g09d2


From b4e4cca578747c987efde7fa8c14299790f3ee02 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Wed, 4 Sep 2024 04:14:59 -0400
Subject: stuff

---
 src/client/apis/gpt/GPT.ts                         |   2 +-
 src/client/views/nodes/DataVizBox/DataVizBox.tsx   |   1 +
 .../views/nodes/DataVizBox/DocCreatorMenu.scss     |  15 +-
 .../views/nodes/DataVizBox/DocCreatorMenu.tsx      | 261 ++++++++++++++++-----
 src/client/views/nodes/ImageBox.tsx                |  23 +-
 .../nodes/formattedText/FormattedTextBox.scss      |   1 +
 6 files changed, 232 insertions(+), 71 deletions(-)

(limited to 'src/client/views/nodes/ImageBox.tsx')

diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts
index ba8106c4d..6befad310 100644
--- a/src/client/apis/gpt/GPT.ts
+++ b/src/client/apis/gpt/GPT.ts
@@ -56,7 +56,7 @@ const callTypeMap: { [type: string]: GPTCallOpts } = {
         temp: 0,
         prompt: 'List unique differences between the content of the UserAnswer and Rubric. Before each difference, label it and provide any additional information the UserAnswer missed and explain it in second person without separating it into UserAnswer and Rubric content and additional information. If there are no differences, say correct',
     },
-    template: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'You will be given a list of field descriptions for multiple templates in the format {field #0: “description”}{field #1: “description”}{...}, and a list of column descriptions in the format {“title”: “description}{...}. Your job is to match columns with fields based on their descriptions. Your output should be in the following JSON format: {“Template title”:{“#”: “title”, “#”: “title”, “#”: “title” …}, “Template title”:{“#”: “title”, “#”: “title”, “#”: “title” …}} where “Template title” represents the template,  # represents the field # and “title” the title of the column assigned to it. A filled out example might look like {“fivefield2”:{0:”Name”, 1:”Image”, 2:”Caption”, 3:”Position”, 4:”Stats”}, “fivefield3”:{0:”Image”, 1:”Name”, 2:”Caption”, 3:”Stats”, 4:”Position”}. Include one object for each template. IT IS VERY IMPORTANT THAT YOU ONLY INCLUDE TEXT IN THE FORMAT ABOVE, WITH NO ADDITIONS WHATSOEVER. Do not include extraneous ‘#’ characters, ‘column’ for columns, or ‘template’ for templates: ONLY THE TITLES AND NUMBERS. Do this for each template whose fields are described. The descriptions are as follows:  ' },
+    template: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'You will be given a list of field descriptions for multiple templates in the format {field #0: “description”}{field #1: “description”}{...}, and a list of column descriptions in the format {“title”: “description”}{...}. Your job is to match columns with fields based on their descriptions. Your output should be in the following JSON format: {“Template title”:{“#”: “title”, “#”: “title”, “#”: “title” …}, “Template title”:{“#”: “title”, “#”: “title”, “#”: “title” …}} where “Template title” represents the template,  # represents the field # and “title” the title of the column assigned to it. A filled out example might look like {“fivefield2”:{“0”:”Name”, “1”:”Image”, “2”:”Caption”, “3”:”Position”, “4”:”Stats”}, “fivefield3”:{0:”Image”, 1:”Name”, 2:”Caption”, 3:”Stats”, 4:”Position”}. Include one object for each template. IT IS VERY IMPORTANT THAT YOU ONLY INCLUDE TEXT IN THE FORMAT ABOVE, WITH NO ADDITIONS WHATSOEVER. Do not include extraneous ‘#’ characters, ‘column’ for columns, or ‘template’ for templates: ONLY THE TITLES AND NUMBERS. There should never be one column assigned to more than one field (ie. if the “name” column is assigned to field 1, it can’t be assigned to any other fields) . Do this for each template whose fields are described. The descriptions are as follows:' },
     vizsum: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'Your job is to provide brief descriptions for columns in a dataset based on example rows. Your descriptions should be geared towards how each column’s data might fit together into a visual template. Would they make good titles, main focuses, captions, descriptions, etc. Pay special attention to connections between columns, i.e. is there one column that specifically seems to describe/be related to another more than the rest? You should provide your analysis in JSON format like so: {“col1”:”description”, “col2”:”description”, …}. DO NOT INCLUDE ANY OTHER TEXT, ONLY THE JSON.'},
     vizsum2: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'Your job is to provide structured information on columns in a dataset based on example rows. You will categorize each column in two ways: by type and size. The size categories are as follows: tiny (one or two words), small (a sentence/multiple words), medium (a few sentences), large (a longer paragraph), and huge (a very long or multiple paragraphs). The type categories are as follows: visual (links/file paths to images, pdfs, maps, or any other visual media type), and text (plain text that isn’t a link/file path). Visual media should be assumed to have size “medium” “large” or “huge”. You will give your responses in JSON format, like so: {“title (of column)”:{“type”:”text”, “size”:”small”}, “title (of column)”:{“type”:”visual”, “size”:”medium”}, …}. DO NOT INCLUDE ANY OTHER TEXT, ONLY THE JSON.'} 
 };
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 6888d5f1e..e8235ce1a 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -712,6 +712,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             const targetKey = StrCast(templateInfo.doc!.layout_fieldKey, 'layout');
             const applied = this.ApplyTemplateTo(templateInfo.doc!, target, targetKey, templateInfo.doc!.title + `${row}`);
             target.layout_fieldKey = targetKey;
+
             //this.applyImagesTo(target, fields);
             return applied;
         });
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss b/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss
index c93798979..1f81bf960 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss
@@ -307,8 +307,11 @@
     }
 
     .docCreatorMenu-preview-image{ 
-        width: 105px;
-        height: 105px;
+        background-color: transparent;
+        height: 100px;
+        width: 100px;
+        display: block;
+        object-fit: contain;
         border-radius: 5px;
     }
 
@@ -411,10 +414,16 @@
 }
 
 .section-reveal-options {
-    margin: 0px;
+    margin-top: 0px;
+    margin-bottom: 0px;
+    margin-right: 0px;
     margin-left: auto;
     border: 0px;
     background: none;
+
+    &.float-right {
+        float: right;
+    }
 }
 
 .docCreatorMenu-section-title {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
index e36adc40a..191b387c4 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
@@ -59,7 +59,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     @observable _layoutPreviewScale: number = 1;
     @observable _savedLayouts: DataVizTemplateLayout[] = [];
 
-    @observable _GPTTemplates: Doc[] = [];
+    @observable _suggestedTemplates: Doc[] = [];
     @observable _GPTOpt: boolean = false;
     @observable _userPrompt: string = '';
     @observable _callCount: number = 0;
@@ -99,7 +99,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
     @action setDataViz = (dataViz: DataVizBox) => { this._dataViz = dataViz };
     @action setTemplateDocs = (docs: Doc[]) => {this._templateDocs = docs.map(doc => doc.annotationOn ? DocCast(doc.annotationOn):doc)};
-    @action setGPTTemplates = (docs: Doc[]) => {this._GPTTemplates = docs};
+    @action setGSuggestedTemplates = (docs: Doc[]) => {this._suggestedTemplates = docs};
 
     @computed get docsToRender() {
         return this._selectedTemplate ? NumListCast(this._dataViz?.layoutDoc.dataViz_selectedRows) : [];
@@ -198,7 +198,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         document.addEventListener('pointerdown', this.onPointerDown, true);
         document.addEventListener('pointerup', this.onPointerUp);
         this._disposers.templates = reaction(() => this._templateDocs.slice(), (docs) => docs.map(this.getIcon));
-        this._disposers.gpt = reaction(() => this._GPTTemplates.slice(), (docs) => docs.map(this.getIcon));
+        this._disposers.gpt = reaction(() => this._suggestedTemplates.slice(), (docs) => docs.map(this.getIcon));
         //this._disposers.columns = reaction(() => this._dataViz?.layoutDoc._dataViz_axes, () => {this.generateTemplates('')})
         this._disposers.lightbox = reaction(() => LightboxView.LightboxDoc(), doc => { doc ? this._shouldDisplay && this.closeMenu() : !this._shouldDisplay && this.openMenu()});
         //this._disposers.fields = reaction(() => this._dataViz?.axes, cols => this._selectedCols = cols?.map(col => { return {title: col, type: '', desc: ''}}))
@@ -233,7 +233,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
     @action
     openMenu = () => { 
-        const allTemplates = this._templateDocs.concat(this._GPTTemplates);
+        const allTemplates = this._templateDocs.concat(this._suggestedTemplates);
         this._shouldDisplay = true;
         this.updateIcons(allTemplates);
     };
@@ -357,7 +357,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             const res = await gptAPICall(prompt, GPTCallType.TEMPLATE);
 
             if (res && this._callCount === origCount) {
-                this._GPTTemplates = [];
+                this._suggestedTemplates = [];
                 this._GPTLoading = false;
                 const templates: {template_type: string, fieldVals: {title: string, tlx: string, tly: string, brx: string, bry: string}[]}[] = JSON.parse(res);
                 this.createGeneratedTemplates(templates, 500, 500);
@@ -389,14 +389,14 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             GPTTemplates.push(template);
         });
 
-        setTimeout(() => {this.setGPTTemplates(GPTTemplates); /*GPTTemplates.forEach(template => mainCollection.removeDocument(template))*/}, 100);
+        setTimeout(() => {this.setGSuggestedTemplates(GPTTemplates); /*GPTTemplates.forEach(template => mainCollection.removeDocument(template))*/}, 100);
 
         this.forceUpdate();
     };
 
     editTemplate = (doc: Doc) => {
         //this.closeMenu();
-        DocumentViewInternal.addDocTabFunc(doc, OpenWhere.lightboxAlways);
+        DocumentViewInternal.addDocTabFunc(doc, OpenWhere.addRight);
         DocumentView.DeselectAll();
         Doc.UnBrushDoc(doc);
     };
@@ -419,20 +419,22 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         // const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
         // mainCollection.addDocument(doc);
 
-        const temp = TemplateLayouts.FourField001;
+        // const temp = TemplateLayouts.FourField001;
 
-        const img: Col = {type: TemplateFieldType.VISUAL, title: 'Image', desc: 'description whpoo', size: TemplateFieldSize.LARGE};
-        const capt1: Col = {type: TemplateFieldType.TEXT, title: 'Type', desc: 'description hey', size: TemplateFieldSize.TINY};
-        const capt2: Col = {type: TemplateFieldType.TEXT, title: 'Locality', desc: '', size: TemplateFieldSize.TINY};
-        const desc: Col = {type: TemplateFieldType.TEXT, title: 'Description', desc: '', size: TemplateFieldSize.LARGE};
+        // const img: Col = {type: TemplateFieldType.TEXT, title: 'Type', desc: 'description whpoo', size: TemplateFieldSize.LARGE, defaultContent: ''};
+        // const capt1: Col = {type: TemplateFieldType.TEXT, title: 'Image', desc: 'description hey', size: TemplateFieldSize.TINY};
+        // const capt2: Col = {type: TemplateFieldType.TEXT, title: 'Locality', desc: '', size: TemplateFieldSize.TINY, defaultContent: ''};
+        // const desc: Col = {type: TemplateFieldType.TEXT, title: 'Description', desc: '', size: TemplateFieldSize.LARGE, defaultContent: 'This is a description of a rock. It is kind of long. It is very long. It is gratuitous. This description should be shorter. Oh well. This is a description of a rock. It is kind of long. It is very long. It is gratuitous. This description should be shorter. Oh well. This is a description of a rock. It is kind of long. It is very long. It is gratuitous. This description should be shorter. Oh well.'};
 
         // const assignments = {'0': img, '1': capt1, '2': capt2, '3': desc}
 
         // this.createEmptyTemplate(temp, assignments);
+        // console.log(this.findValidTemplates(this.fieldsInfos, TemplateLayouts.allTemplates));
 
-        this.generatePresetTemplates(this.findValidTemplates(this.fieldsInfos, TemplateLayouts.allTemplates), this.fieldsInfos);
         // console.log(this._dataViz?.colsInfo.get("IMG")?.size, this._dataViz?.colsInfo.get("IMG")?.type)
         // console.log(this.fieldsInfos)
+
+        
     };
 
     @action addField = () => {
@@ -492,7 +494,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         const colMatchesField = (col: Col, field : Field) => { return field.sizes?.includes(col.size) && field.types?.includes(col.type) };
 
         const matches: number[][] = Array(template.fields.length).fill([]).map(() => []);
-        console.log(matches)
+
         template.fields.forEach((field, i) => {
             cols.forEach((col, v) => {
                 if (colMatchesField(col, field)) {
@@ -507,11 +509,13 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     maxMatches = (fieldsCt: number, matches: number[][]) => {
         const used: boolean[] = Array(fieldsCt).fill(false);
         const mt: number[] = Array(fieldsCt).fill(-1);
+        console.log(fieldsCt, matches)
 
         const augmentingPath = (v: number): boolean => {
             if (used[v]) return false;
             used[v] = true;
             for (const to of matches[v]) {
+                console.log(mt[to]);
                 if (mt[to] === -1 || augmentingPath(mt[to])) {
                     mt[to] = v;
                     return true;
@@ -538,7 +542,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     findValidTemplates = (cols: Col[], templates: TemplateDocInfos[]) => {
         let validTemplates: any[] = [];
         templates.forEach(template => {
-            const numFields =  template.fields.length;
+            const numFields = template.fields.length;
+            if (!(numFields === cols.length)) return;
             const matches = this.matchesForTemplate(template, cols);
             if (this.maxMatches(numFields, matches) === numFields) {
                 validTemplates.push(template.title);
@@ -546,6 +551,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         })
 
         validTemplates = validTemplates.map(title => TemplateLayouts.fieldByTitle(title));
+
+        console.log(validTemplates);
         return validTemplates;
     };
 
@@ -571,7 +578,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     //     return new Doc;
     // }
 
-    createEmptyTemplate = (template: TemplateDocInfos, assignments: {[field: string]: Col}) => {
+    createEmptyTemplate = (template: TemplateDocInfos, assignments: {[field: string]: Col}): Doc => {
         const fields: Doc[] = [];
 
         Object.entries(assignments).forEach(([f, col]) => {
@@ -618,12 +625,13 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
         const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
         mainCollection.addDocument(renderedTemplate);
+        return renderedTemplate;
     };
 
     compileFieldDescriptions = (templates: TemplateDocInfos[]): string => {
         let descriptions: string = '';
         templates.forEach(template => {
-            descriptions += `----------  Description of template ${template.title}'s fields: `
+            descriptions += `----------  NEW TEMPLATE TO INCLUDE: Description of template ${template.title}'s fields: `
             template.fields.forEach((field, index) => {
                 descriptions += `{Field #${index}: ${field.description}} `
             });
@@ -633,7 +641,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     };
 
     compileColDescriptions = (cols: Col[]): string =>  {
-        let descriptions: string = '';
+        let descriptions: string = ' ------------- COL DESCRIPTIONS START HERE:';
         cols.forEach(col => descriptions += `{title: ${col.title}, size: ${col.size}, type: ${col.type}, descreiption: ${col.desc}} `);
 
         return descriptions;
@@ -648,6 +656,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
         const inputText = fieldDescriptions.concat(colDescriptions);
 
+        console.log(inputText);
         ++this._callCount;
         const origCount = this._callCount;
 
@@ -660,6 +669,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
             if (res && this._callCount === origCount) {
                 this._GPTLoading = false;
+
+                console.log(res);
+
                 const assignments: {[templateTitle: string]: {[field: string]: string}} = JSON.parse(res);
                 const brokenDownAssignments: [TemplateDocInfos, {[field: number]: Col}][] = [];
                 Object.entries(assignments).forEach(([tempTitle, assignment]) => {
@@ -681,11 +693,16 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         return [];
     };
 
-    generatePresetTemplates = async(templates: TemplateDocInfos[], cols: Col[]) => {
+    generatePresetTemplates = async() => {
+        const cols = this.fieldsInfos;
+        const templates = this.findValidTemplates(cols, TemplateLayouts.allTemplates);
         const assignments: [TemplateDocInfos, {[field: number]: Col}][] = await this.assignColsToFields(templates, cols); 
+        const renderedTemplates: Doc[] = [];
         assignments.forEach(([template, assignments]) => {
-            this.createEmptyTemplate(template, assignments);
+            renderedTemplates.push(this.createEmptyTemplate(template, assignments));
         });
+
+        setTimeout(() => {this.setGSuggestedTemplates(renderedTemplates)});
     }
 
     get templatesPreviewContents(){
@@ -699,7 +716,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                 <div className='docCreatorMenu-section' style={{height: this._GPTOpt ? 200 : 200}}>
                         <div className='docCreatorMenu-section-topbar'>
                             <div className='docCreatorMenu-section-title'>Suggested Templates</div>
-                            <button className='docCreatorMenu-menu-button section-reveal-options' onPointerDown={e => this.setUpButtonClick(e, () => this._GPTOpt = !this._GPTOpt)}>
+                            <button className='docCreatorMenu-menu-button section-reveal-options' onPointerDown={e => this.setUpButtonClick(e, () => this._menuContent = 'dashboard')}>
                                 <FontAwesomeIcon icon='gear'/>
                             </button>
                         </div>
@@ -709,7 +726,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                     <ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} />
                                 </div>
                             ) : (
-                            this._GPTTemplates?.map(doc => 
+                            this._suggestedTemplates?.map(doc => 
                                 ({icon: ImageCast(doc.icon), doc})).filter(info => info.icon && info.doc).map(info =>
                                     <div 
                                     className='docCreatorMenu-preview-window'
@@ -730,10 +747,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                         </div>
                         <div className='docCreatorMenu-GPT-options'>
                             <div className='docCreatorMenu-GPT-options-container'>
-                                <button className='docCreatorMenu-menu-button' onPointerDown={e => this.setUpButtonClick(e, () => this.generateTemplates(this._userPrompt))}>
+                                <button className='docCreatorMenu-menu-button' onPointerDown={e => this.setUpButtonClick(e, () => this.generatePresetTemplates())}>
                                     <FontAwesomeIcon icon='arrows-rotate'/>
                                 </button>
-                                <input className='docCreatorMenu-GPT-prompt-input' placeholder='Additional prompt:' onChange={e => this._userPrompt = e.target.value}/>
                             </div>
                             {this._GPTOpt ? GPTOptions : null }
                         </div>
@@ -1036,9 +1052,12 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         return (
         <div className='docCreatorMenu-dashboard-view'>
             <div className='topbar'>
-            <button className='docCreatorMenu-menu-button section-reveal-options' onPointerDown={e => this.setUpButtonClick(e, this.addField)}>
-                <FontAwesomeIcon icon='plus'/>
-            </button>
+                <button className='docCreatorMenu-menu-button section-reveal-options' onPointerDown={e => this.setUpButtonClick(e, this.addField)}>
+                    <FontAwesomeIcon icon='plus'/>
+                </button>
+                <button className='docCreatorMenu-menu-button section-reveal-options float-right' onPointerDown={e => this.setUpButtonClick(e, () => this._menuContent = 'templates')}>
+                    <FontAwesomeIcon icon='arrow-left'/>
+                </button>
             </div>
             {this.fieldsInfos.map((field, index) => 
                 <div className='field-panel' id={`${index}`}>
@@ -1261,12 +1280,12 @@ interface TemplateOpts extends FieldOpts {
 
 export class FieldFuncs {
 
-    private static calculateFontSize = (contWidth: number, contHeight: number, text: string, uppercase: boolean): number => {
+    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 * (uppercase ? 1.25 : 1);
+        let currTextHeight = currFontSize * rowsCount * 2;
     
         while (currTextHeight <= contHeight) {
             let wordIndex = 0;
@@ -1276,7 +1295,8 @@ export class FieldFuncs {
     
             while (wordIndex < words.length) {
                 const word = words[wordIndex];
-                const wordWidth = word.length * currFontSize;
+                const wordWidth = word.length * currFontSize * .5;
+                //console.log(wordWidth)
     
                 if (currentRowWidth + wordWidth <= contWidth) {
                     currentRowWidth += wordWidth;
@@ -1291,11 +1311,11 @@ export class FieldFuncs {
                     }
                 }
     
-                wordIndex++;
+                wordIndex++;    
             }
     
-            currTextHeight = rowsCount * currFontSize * (uppercase ? 1.25 : 1);
-            //console.log(rowsCount, currTextHeight)
+            currTextHeight = rowsCount * currFontSize * 2;
+            //console.log(rowsCount, currFontSize, currTextHeight)
     
             currFontSize += 1;
         }
@@ -1312,6 +1332,7 @@ export class FieldFuncs {
         const width = r - l;
         const height = b - t;
         const coord = {x: l, y: t};
+        console.log(coords, parentWidth, parentHeight, height);
         return {width, height, coord};
     }
 
@@ -1378,6 +1399,7 @@ export class FieldFuncs {
             title: title, 
             x: coord.x, 
             y: coord.y,
+            _layout_fitWidth: false,
             backgroundColor: opts.backgroundColor ?? '',
             _layout_borderRounding: `${opts.cornerRounding}px` ?? '0px',
             borderColor: opts.borderColor,
@@ -1386,6 +1408,8 @@ export class FieldFuncs {
             _rotation: opts.rotation,
         });
 
+        //setTimeout(() => {doc._height = height; doc._width = width}, 10);
+
         return doc;
     }
 
@@ -1415,8 +1439,12 @@ export class TemplateLayouts {
                 return TemplateLayouts.FourField002;
             case 'fourfield3':
                 return TemplateLayouts.FourField003;
+            case 'fourfield4':
+                return TemplateLayouts.FourField004;
             case 'threefield1':
                 return TemplateLayouts.ThreeField001;
+            case 'threefield2':
+                return TemplateLayouts.ThreeField002;
             default:
                 break;
         }
@@ -1427,11 +1455,11 @@ export class TemplateLayouts {
     public static FourField001: TemplateDocInfos = {
         title: 'fourfield1',
         width: 416, 
-        height: 721, 
+        height: 700, 
         opts: {
-            backgroundColor: '#7B8D62',
+            backgroundColor: '#C0B887',
             cornerRounding: 20,
-            borderColor: '#642B00',
+            borderColor: '#6B461F',
             borderWidth: '12',
         },
         fields: [{
@@ -1454,13 +1482,13 @@ export class TemplateLayouts {
             description: 'The main focus of the template; could be an image, long text, etc.',
             opts: {
                 cornerRounding: 20,
-                borderColor: '#642B00',
+                borderColor: '#8F5B25',
                 borderWidth: '6',
                 backgroundColor: '#CECAB9',
             }
         }, {
             tl: [-.8, .2], 
-            br: [.8, .35], 
+            br: [.8, .3],  
             types: [TemplateFieldType.TEXT],
             sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
             description: 'A caption for field #2, very short to short text that contextualizes the content of field #2',
@@ -1474,10 +1502,10 @@ export class TemplateLayouts {
             br: [.87, .96], 
             types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
             sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
-            description: 'A medium-sized field for medium/long text or a secondary image that complements the main focus.',
+            description: 'A medium-sized field for medium/long text.',
             opts: {
                 cornerRounding: 15,
-                borderColor: '#642B00',
+                borderColor: '#8F5B25', 
                 borderWidth: '6',
                 backgroundColor: '#CECAB9',
             }
@@ -1497,28 +1525,28 @@ export class TemplateLayouts {
             br: [.83, -.2], 
             types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
             sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
-            description: '',
+            description: 'A medium to large-sized field suitable for an image or longer text that should be the main focus.',
             opts: {
                 borderWidth: '8',
                 borderColor: '#F8E71C',
             }
         }, {
-            tl: [-.45, -.18], 
-            br: [.45, 0], 
+            tl: [-.65, -.2], 
+            br: [.65, -.02], 
             types: [TemplateFieldType.TEXT],
-            sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
-            description: '',
+            sizes: [TemplateFieldSize.TINY],
+            description: 'A tiny field for just a word or two of plain text.',
             opts: {
                 backgroundColor: 'transparent',
                 color: 'white',
                 contentXCentering: 'h-center'
             }
         }, {
-            tl: [-.45, 0], 
-            br: [.45, .18], 
+            tl: [-.65, 0], 
+            br: [.65, .18], 
             types: [TemplateFieldType.TEXT],
-            sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
-            description: '',
+            sizes: [TemplateFieldSize.TINY],
+            description: 'A tiny field for just a word or two of plain text.',
             opts: {
                 backgroundColor: 'transparent',
                 color: 'white',
@@ -1529,11 +1557,12 @@ export class TemplateLayouts {
             br: [.83, .95], 
             types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
             sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
-            description: '',
+            description: 'A medium to large-sized field suitable for an image or longer text that should be the main focus, or share focus with field 1.',
             opts: {
                 borderWidth: '8',
                 borderColor: '#F8E71C',
-                backgroundColor: '#242425'
+                color: 'white',
+                backgroundColor: '#242425',
             }
         }],
         decorations: [{
@@ -1612,7 +1641,8 @@ export class TemplateLayouts {
             description: '',
             opts: {
                 backgroundColor: 'transparent',
-                color: 'white',
+                color: 'red',
+                fontTransform: 'uppercase',
                 contentXCentering: 'h-left'
             }
         }, {
@@ -1635,6 +1665,72 @@ export class TemplateLayouts {
         }]
     };
 
+    public static FourField004: TemplateDocInfos = {
+        title: 'fourfield4',
+        width: 414, 
+        height: 583, 
+        opts: {
+            backgroundColor: '#6CCAF0',
+            borderColor: '#1088C3',
+            borderWidth: '10'
+        },
+        fields: [{
+            tl: [-.86, -.92], 
+            br: [-.075, -.77], 
+            types: [TemplateFieldType.TEXT],
+            sizes: [TemplateFieldSize.TINY],
+            description: 'A tiny field for just a word or two of plain text.',
+            opts: {
+                backgroundColor: '#E2B4F5',
+                borderWidth: '9',
+                borderColor: '#9222F1',
+                contentXCentering: 'h-center'
+            }
+        }, {
+            tl: [.075, -.92], 
+            br: [.86, -.77], 
+            types: [TemplateFieldType.TEXT],
+            sizes: [TemplateFieldSize.TINY],
+            description: 'A tiny field for just a word or two of plain text.',
+            opts: {
+                backgroundColor: '#F5B4DD',
+                borderWidth: '9',
+                borderColor: '#E260F3',
+                contentXCentering: 'h-center'
+            }
+        }, {
+            tl: [-.81, -.64], 
+            br: [.81, .48], 
+            types: [TemplateFieldType.VISUAL],
+            sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+            description: 'A large to huge field for visual content that is the main content of the template.',
+            opts: {
+                borderWidth: '16',
+                borderColor: '#A2BD77',
+            }
+        }, {
+            tl: [-.86, .6], 
+            br: [.86, .92], 
+            types: [TemplateFieldType.TEXT],
+            sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
+            description: 'A medium to large field for text that describes the visual content above',
+            opts: {
+                borderWidth: '9',
+                borderColor: '#F0D601',
+                backgroundColor: '#F3F57D',
+            }
+        }],
+        decorations: [{
+            tl: [-.852, -.67], 
+            br: [.852, .51], 
+            opts: {
+                backgroundColor: 'transparent',
+                borderColor: '#007C0C',
+                borderWidth: '10',
+            }
+        }]
+    };
+
     public static ThreeField001: TemplateDocInfos = {
         title: 'threefield1',
         width: 575, 
@@ -1646,8 +1742,8 @@ export class TemplateLayouts {
             tl: [-.66, -.747], 
             br: [.66, .247], 
             types: [TemplateFieldType.VISUAL],
-            sizes: [TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
-            description: '',
+            sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+            description: 'A medium to large field for visual content that is the central focus.',
             opts: {
                 borderColor: 'yellow',
                 borderWidth: '8',
@@ -1670,7 +1766,7 @@ export class TemplateLayouts {
             br: [.7, .46], 
             types: [TemplateFieldType.TEXT],
             sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
-            description: '',
+            description: 'A very small text field for one to a few words. A good caption for the image.',
             opts: {
                 backgroundColor: 'transparent',
                 contentXCentering: 'h-center',
@@ -1680,7 +1776,7 @@ export class TemplateLayouts {
             br: [.95, .95], 
             types: [TemplateFieldType.TEXT],
             sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
-            description: '',
+            description: 'A medium to large text field for a thorough description of the image. ',
             opts: {
                 backgroundColor: 'transparent',
                 color: 'white'
@@ -1717,6 +1813,59 @@ export class TemplateLayouts {
         }]
     };
 
+    public static ThreeField002: TemplateDocInfos = {
+        title: 'threefield2',
+        width: 477, 
+        height: 662, 
+        opts: {
+            backgroundColor: '#9E9C95'
+        },
+        fields: [{
+            tl: [-.95, .8], 
+            br: [-.1, .95], 
+            types: [TemplateFieldType.VISUAL],
+            sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+            description: '',
+            opts: {
+                backgroundColor: 'transparent',
+                color: 'white',
+                contentXCentering: 'h-right',
+            }
+        }, {
+            tl: [.1, .8], 
+            br: [.95, .95], 
+            types: [TemplateFieldType.TEXT],
+            sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
+            description: 'A very small text field for one to a few words. The content should represent a general categorization of the image.',
+            opts: {
+                backgroundColor: 'transparent',
+                color: 'red',
+                fontTransform: 'uppercase',
+                fontBold: true,
+                contentXCentering: 'h-left'
+            }
+        }, {
+            tl: [0, -.9], 
+            br: [.85, -.66], 
+            types: [TemplateFieldType.TEXT],
+            sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
+            description: 'A very small text field for one to a few words. The content should contextualize field 2.',
+            opts: {
+                backgroundColor: 'transparent',
+                contentXCentering: 'h-right'
+            }
+        }],
+        decorations: [{
+            tl: [-.025, .8], 
+            br: [.025, .95], 
+            opts: {
+                backgroundColor: '#E0E0DA',
+            }
+        }]
+    };
+
+
+
 //     public static FourField002: TemplateDocInfos = {
 //         width: 450, 
 //         height: 600, 
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index faea05104..53aa7171f 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -123,15 +123,15 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             { fireImmediately: true, delay: 1000 }
         );
         const { layoutDoc } = this;
-        this._disposers.path = reaction(
-            () => ({ nativeSize: this.nativeSize, width: NumCast(this.layoutDoc._width) }),
-            ({ nativeSize, width }) => {
-                if (layoutDoc === this.layoutDoc || !this.layoutDoc._height) {
-                    this.layoutDoc._height = (width * nativeSize.nativeHeight) / nativeSize.nativeWidth;
-                }
-            },
-            { fireImmediately: true }
-        );
+        // this._disposers.path = reaction(
+        //     () => ({ nativeSize: this.nativeSize, width: NumCast(this.layoutDoc._width) }),
+        //     ({ nativeSize, width }) => {
+        //         if (layoutDoc === this.layoutDoc || !this.layoutDoc._height) {
+        //             this.layoutDoc._height = (width * nativeSize.nativeHeight) / nativeSize.nativeWidth;
+        //         }
+        //     },
+        //     { fireImmediately: true }
+        // );
         this._disposers.scroll = reaction(
             () => this.layoutDoc.layout_scrollTop,
             sTop => {
@@ -394,7 +394,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                         alt=""
                         key="paths"
                         src={srcpath}
-                        style={{ transform, transformOrigin }}
+                        style={{ transform, transformOrigin, objectFit: 'fill', height: '100%' }}
                         onError={action(e => {
                             this._error = e.toString();
                         })}
@@ -456,6 +456,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
 
     savedAnnotations = () => this._savedAnnotations;
     render() {
+        console.log('img', this._props.PanelWidth(), this._props.PanelHeight())
         TraceMobx();
         const borderRad = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BorderRounding);
         const borderRadius = borderRad?.includes('px') ? `${Number(borderRad.split('px')[0]) / (this._props.NativeDimScaling?.() || 1)}px` : borderRad;
@@ -475,7 +476,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                 })}
                 style={{
                     width: this._props.PanelWidth() ? undefined : `100%`,
-                    height: this._props.PanelWidth() ? undefined : `100%`,
+                    height: this._props.PanelHeight() ? undefined : `100%`,
                     pointerEvents: this.layoutDoc._lockedPosition ? 'none' : undefined,
                     borderRadius,
                     overflow: this.layoutDoc.layout_fitWidth || this._props.fitWidth?.(this.Document) ? 'auto' : undefined,
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.scss b/src/client/views/nodes/formattedText/FormattedTextBox.scss
index d6fd81f83..72d550c7e 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.scss
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.scss
@@ -79,6 +79,7 @@ audiotag:hover {
     transform-origin: left top;
     top: 0;
     left: 0;
+    
 }
 
 .formattedTextBox-cont {
-- 
cgit v1.2.3-70-g09d2


From 441e1337f22f4bc9f9c6c8dcf643cc72c4d68f21 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Thu, 5 Sep 2024 03:35:51 -0400
Subject: Oh, coding makes me feel like an idiot sometimes... (added += where a
 string was supposed to be updated)

---
 src/client/apis/gpt/GPT.ts                         |  2 +-
 src/client/views/nodes/DataVizBox/DataVizBox.tsx   | 43 +++++++++++++---------
 .../views/nodes/DataVizBox/DocCreatorMenu.tsx      | 24 +++++++-----
 src/client/views/nodes/ImageBox.tsx                |  1 -
 4 files changed, 42 insertions(+), 28 deletions(-)

(limited to 'src/client/views/nodes/ImageBox.tsx')

diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts
index 7351fd0f5..f1d5ab533 100644
--- a/src/client/apis/gpt/GPT.ts
+++ b/src/client/apis/gpt/GPT.ts
@@ -60,7 +60,7 @@ const callTypeMap: { [type: string]: GPTCallOpts } = {
     template: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'You will be given a list of field descriptions for multiple templates in the format {field #0: “description”}{field #1: “description”}{...}, and a list of column descriptions in the format {“title”: “description”}{...}. Your job is to match columns with fields based on their descriptions. Your output should be in the following JSON format: {“Template title”:{“#”: “title”, “#”: “title”, “#”: “title” …}, “Template title”:{“#”: “title”, “#”: “title”, “#”: “title” …}} where “Template title” represents the template,  # represents the field # and “title” the title of the column assigned to it. A filled out example might look like {“fivefield2”:{“0”:”Name”, “1”:”Image”, “2”:”Caption”, “3”:”Position”, “4”:”Stats”}, “fivefield3”:{0:”Image”, 1:”Name”, 2:”Caption”, 3:”Stats”, 4:”Position”}. Include one object for each template. IT IS VERY IMPORTANT THAT YOU ONLY INCLUDE TEXT IN THE FORMAT ABOVE, WITH NO ADDITIONS WHATSOEVER. Do not include extraneous ‘#’ characters, ‘column’ for columns, or ‘template’ for templates: ONLY THE TITLES AND NUMBERS. There should never be one column assigned to more than one field (ie. if the “name” column is assigned to field 1, it can’t be assigned to any other fields) . Do this for each template whose fields are described. The descriptions are as follows:' },
     vizsum: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'Your job is to provide brief descriptions for columns in a dataset based on example rows. Your descriptions should be geared towards how each column’s data might fit together into a visual template. Would they make good titles, main focuses, captions, descriptions, etc. Pay special attention to connections between columns, i.e. is there one column that specifically seems to describe/be related to another more than the rest? You should provide your analysis in JSON format like so: {“col1”:”description”, “col2”:”description”, …}. DO NOT INCLUDE ANY OTHER TEXT, ONLY THE JSON.'},
     vizsum2: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'Your job is to provide structured information on columns in a dataset based on example rows. You will categorize each column in two ways: by type and size. The size categories are as follows: tiny (one or two words), small (a sentence/multiple words), medium (a few sentences), large (a longer paragraph), and huge (a very long or multiple paragraphs). The type categories are as follows: visual (links/file paths to images, pdfs, maps, or any other visual media type), and text (plain text that isn’t a link/file path). Visual media should be assumed to have size “medium” “large” or “huge”. You will give your responses in JSON format, like so: {“title (of column)”:{“type”:”text”, “size”:”small”}, “title (of column)”:{“type”:”visual”, “size”:”medium”}, …}. DO NOT INCLUDE ANY OTHER TEXT, ONLY THE JSON.'},
-    fill: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'Your job is to generate content for fields based on a user prompt and background context given to you. You will be given the content of the other fields present in the format: ---- Field # (field title): content ---- Field # (field title): content ----- (etc.) You will be given info on the columns to generate for in the format ---- title: , prompt: , word limit: , assigned field: ----. For each column, based on the prompt, word limit, and the context of existing fields, you should generate a short response in the following JSON format: {“title” (should be the title from the column description with no additions): {“number”:”#” (where # is the assigned field of the column), “content”:”response” (where response is your response to the prompt in the column info)}}. ONLY INCLUDE THE JSON TEXT WITH NO OTHER ADDED TEXT. The word limit for each column applies only to that column’s response. You should include one object per column you are provided info on.' }  
+    fill: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'Your job is to generate content for fields based on a user prompt and background context given to you. You will be given the content of the other fields present in the format: ---- Field # (field title): content ---- Field # (field title): content ----- (etc.) You will be given info on the columns to generate for in the format ---- title: , prompt: , word limit: , assigned field: ----. For each column, based on the prompt, word limit, and the context of existing fields, you should generate a short response in the following JSON format: {“___”(where ___ is the title from the column description with no additions): {“number”:”#” (where # is the assigned field of the column), “content”:”response” (where response is your response to the prompt in the column info)}}. Here’s another example of the format with only one column: {“position”: {“number”:”2”, “content”:”*your response goes here*”}}. ONLY INCLUDE THE JSON TEXT WITH NO OTHER ADDED TEXT. YOUR RESPONSE MUST BE VALID JSON. The word limit for each column applies only to that column’s response. Do not include speculation or information that you can’t glean from your factual knowledge or the content of the other fields (no description of images you can’t see, for example). You should include one object per column you are provided info on.'}
 };
 let lastCall = '';
 let lastResp = '';
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index e8235ce1a..d9a7d5e3a 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -175,6 +175,15 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         }
     }
 
+    @action setColumnTitle = (colTitle: string, newTitle: string) => {
+        const colInfo = this.colsInfo.get(colTitle);
+        if (colInfo) { 
+            colInfo.title = newTitle;
+        } else {
+            this.colsInfo.set(colTitle, {title: newTitle, desc: '', type: TemplateFieldType.UNSET, size: TemplateFieldSize.MEDIUM})
+        }
+    }
+
     @action setColumnDesc = (colTitle: string, desc: string) => {
         const colInfo = this.colsInfo.get(colTitle);
         if (colInfo) {
@@ -580,33 +589,33 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
 
         const prompt = this.getColSummary();
 
+        console.log(prompt)
+
         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: '', size: TemplateFieldSize.MEDIUM, type: TemplateFieldType.UNSET});
         });
 
         try {
-            const res = await gptAPICall(prompt, GPTCallType.VIZSUM);
-
-            if (res) {
+            const [res1, res2] = await Promise.all([
+                gptAPICall(prompt, GPTCallType.VIZSUM),
+                gptAPICall('Info:' + prompt, GPTCallType.VIZSUM2)
+            ]);
+        
+            if (res1) {
+                console.log(res1);
                 this.GPTSummary = new ObservableMap();
-                const descs: {[col: string]: string} = JSON.parse(res);
+                const descs: { [col: string]: string } = JSON.parse(res1);
                 for (const [key, val] of Object.entries(descs)) {
-                    this.GPTSummary.set(key, {desc: val});
+                    this.GPTSummary.set(key, { desc: val });
                     if (!this.colsInfo.get(key)?.desc) this.setColumnDesc(key, val);
                 }
             }
-        } catch (err) {
-            console.error(err);
-        } 
-
-        try {
-            const res = await gptAPICall('Info:' + prompt, GPTCallType.VIZSUM2);
-
-            if (res) {
+        
+            if (res2) {
                 !this.GPTSummary && (this.GPTSummary = new ObservableMap());
-                const info: {[col: string]: {type: TemplateFieldType, size: TemplateFieldSize}} = JSON.parse(res);
-                console.log(info)
+                const info: { [col: string]: { type: TemplateFieldType, size: TemplateFieldSize } } = JSON.parse(res2);
+                console.log(info);
                 for (const [key, val] of Object.entries(info)) {
                     const colSummary = this.GPTSummary.get(key);
                     if (colSummary) {
@@ -616,11 +625,11 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                         this.setColumnSize(key, val.size);
                     }
                 }
-
             }
         } catch (err) {
             console.error(err);
-        } 
+        }
+        
     }
 
     getPossibleTemplates = (): Doc[] => {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
index 33d9a8827..64152f577 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
@@ -478,6 +478,15 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         }   
     };
 
+    setColTitle = (column: Col, title: string) => {
+        if (this.selectedFields.includes(column.title)) {
+            this._dataViz?.setColumnTitle(column.title, title);
+        } else {
+            column.title = title;
+        }
+        this.forceUpdate();
+    };
+
     setColType = (column: Col, type: TemplateFieldType) => {
         if (this.selectedFields.includes(column.title)) {
             this._dataViz?.setColumnType(column.title, type);
@@ -492,6 +501,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             this._dataViz?.setColumnSize(column.title, size);
         } else {
             column.size = size;
+            console.log(column.size)
         }
         this.forceUpdate();
     };
@@ -501,7 +511,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             this._dataViz?.setColumnDesc(column.title, desc);
         } else {
             column.desc = desc;
-            console.log(column, column.desc)
         }
         this.forceUpdate();
     };
@@ -620,13 +629,12 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         const stringifyGPTInfo = (): string => {
             let string: string = '*** COLUMN INFO:';
             GPTAssignments.forEach(([fieldNum, col]) => {
-                `--- title: ${col.title}, prompt: ${col.desc}, word limit: ${wordLimit(col.size)} words, assigned field: ${fieldNum} ---`
+                string += `--- title: ${col.title}, prompt: ${col.desc}, word limit: ${wordLimit(col.size)} words, assigned field: ${fieldNum} ---`
             });
             return string += ' ***';
         };
 
         const GPTAssignmentString = stringifyGPTInfo();
-        console.log('assignment string', GPTAssignmentString);
 
         let fieldContent: string = '';
 
@@ -682,8 +690,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             return main;
         }
 
-        console.log('field content', fieldContent)
-
         if (GPTAssignments.length) {
             
             try {
@@ -695,7 +701,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                     console.log('response', res);
 
                     const assignments: {[title: string]: {number: string, content: string}} = JSON.parse(res);
-                    console.log('assignments', assignments);
+                    console.log('assignments', GPTAssignments, 'assignment string', GPTAssignmentString, 'field content', fieldContent, 'response', res, 'assignments', assignments);
                     Object.entries(assignments).forEach(([title, info]) => {
                         const field: Field = template.fields[Number(info.number)];
                         const col = this.getColByTitle(title);
@@ -1164,7 +1170,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             {this.fieldsInfos.map((field, index) => 
                 <div className='field-panel' id={`${index}`}>
                     <div className='properties-wrapper'>
-                        <input className='field-property-container' id={`${Math.random() * 100}`} defaultValue={field.title} placeholder={'Enter title'}/>
+                        <input className='field-property-container' id={`${Math.random() * 100}`} defaultValue={field.title} placeholder={'Enter title'}  onChange={(e) => this.setColTitle(field, e.target.value)}/>
                         <div className='field-type-selection-container'>
                             {field.type === TemplateFieldType.UNSET ? <span className='placeholder'>Select media type</span> : null}
                             <span className='type-display'>{field.type === TemplateFieldType.TEXT ? 'Text Field' : field.type === TemplateFieldType.VISUAL ? 'File Field' : ''}</span>
@@ -1175,7 +1181,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                 <div className='text'>File</div>
                             </div>
                         </div>
-                        <input className='field-property-container' id={`${Math.random() * 100}`} placeholder={this._dataViz?.GPTSummary?.get(field.title)?.size} style={{width: field.title === '' ? '30%' : ''}}/>
+                        <input className='field-property-container' id={`${Math.random() * 100}`} placeholder={this._dataViz?.GPTSummary?.get(field.title)?.size} style={{width: field.title === '' ? '30%' : ''} } onChange={(e) => this.setColSize(field, e.target.value as TemplateFieldSize)}/>
                     </div>
                     <textarea className='field-description-container' onChange={(e) => this.setColDesc(field, e.target.value)} defaultValue={field.desc === this._dataViz?.GPTSummary?.get(field.title)?.desc ? '' : field.desc } placeholder={this._dataViz?.GPTSummary?.get(field.title)?.desc ?? 'Add a description to help with template generation.'} /> 
                     <div>
@@ -1434,7 +1440,7 @@ export class FieldFuncs {
         const width = r - l;
         const height = b - t;
         const coord = {x: l, y: t};
-        console.log(coords, parentWidth, parentHeight, height);
+        //console.log(coords, parentWidth, parentHeight, height);
         return {width, height, coord};
     }
 
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 53aa7171f..3e5458888 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -456,7 +456,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
 
     savedAnnotations = () => this._savedAnnotations;
     render() {
-        console.log('img', this._props.PanelWidth(), this._props.PanelHeight())
         TraceMobx();
         const borderRad = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BorderRounding);
         const borderRadius = borderRad?.includes('px') ? `${Number(borderRad.split('px')[0]) / (this._props.NativeDimScaling?.() || 1)}px` : borderRad;
-- 
cgit v1.2.3-70-g09d2


From 6ae5bd63d5355a03dba099a149532e7c6b1fd74a Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Wed, 9 Oct 2024 16:58:33 -0400
Subject: small changes for pull request; removed schema type reference in
 editableview; a couple lint changes

---
 package-lock.json                                      |  6 +++---
 src/client/views/EditableView.tsx                      |  7 ++++---
 .../collectionFreeForm/CollectionFreeFormView.tsx      |  2 +-
 .../collections/collectionSchema/SchemaCellField.tsx   |  4 ++--
 .../collectionSchema/SchemaColumnHeader.tsx            |  3 ++-
 src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx   |  2 +-
 src/client/views/nodes/ImageBox.tsx                    | 18 +++++++++---------
 7 files changed, 22 insertions(+), 20 deletions(-)

(limited to 'src/client/views/nodes/ImageBox.tsx')

diff --git a/package-lock.json b/package-lock.json
index 3b1ea2017..c49821f9d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -17447,9 +17447,9 @@
             }
         },
         "node_modules/dompurify": {
-            "version": "3.1.6",
-            "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz",
-            "integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ=="
+            "version": "3.1.7",
+            "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.7.tgz",
+            "integrity": "sha512-VaTstWtsneJY8xzy7DekmYWEOZcmzIe3Qb3zPd4STve1OBTa+e+WmS1ITQec1fZYXI3HCsOZZiSMpG6oxoWMWQ=="
         },
         "node_modules/domutils": {
             "version": "3.1.0",
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index 9722b2d4b..9974fc63b 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -54,7 +54,8 @@ export interface EditableProps {
     placeholder?: string;
     wrap?: string; // nowrap, pre-wrap, etc
 
-    schemaFieldType?: SchemaFieldType;
+    inputString?: boolean;
+    inputStringPlaceholder?: string;
     prohibitedText?: Array<string>;
     onClick?: () => void;
     updateAlt?: (newAlt: string) => void;
@@ -290,10 +291,10 @@ export class EditableView extends ObservableReactComponent<EditableProps> {
     staticDisplay = () => {
         let toDisplay;
         const gval = this._props.GetValue()?.replace(/\n/g, '\\r\\n');
-        if (this._props.schemaFieldType === SchemaFieldType.Header){
+        if (this._props.inputString){
             toDisplay = <input className="editableView-input"
             value={gval}
-            placeholder='Add key'
+            placeholder={this._props.inputStringPlaceholder}
             readOnly
             style={{ display: this._props.display, overflow: 'auto', pointerEvents: 'none', fontSize: this._props.fontSize, width: '100%', margin: 0, background: this._props.background}}
             // eslint-disable-next-line jsx-a11y/no-autofocus
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 0cc63d632..d2bc8f2c2 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1221,7 +1221,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
      * Function that creates a drawing--a group of ink strokes--to go with the smart draw function.
      */
     @undoBatch
-    createDrawingDoc = (strokeData: [InkData, string, string][], opts: DrawingOptions, gptRes: string) => {
+    createDrawingDoc = (strokeData: [InkData, string, string][], opts: DrawingOptions) => {
         this._drawing = [];
         const xf = this.screenToFreeformContentsXf;
         strokeData.forEach((stroke: [InkData, string, string]) => {
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index 84e7b62bf..dab494c0e 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -5,7 +5,7 @@ import { OverlayView } from '../../OverlayView';
 import { DocumentIconContainer } from '../../nodes/DocumentIcon';
 import React, { FormEvent } from 'react';
 import { FieldView, FieldViewProps } from '../../nodes/FieldView';
-import { ObjectField } from '../../../../fields/ObjectField';
+import { FieldType, ObjectField } from '../../../../fields/ObjectField';
 import { Doc } from '../../../../fields/Doc';
 import { DocumentView } from '../../nodes/DocumentView';
 import DOMPurify from 'dompurify';
@@ -21,7 +21,7 @@ import DOMPurify from 'dompurify';
  */
 
 export interface SchemaCellFieldProps {
-    contents: any;
+    contents: FieldType;
     fieldContents?: FieldViewProps;
     editing?: boolean;
     oneLine?: boolean;
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index c5cdac8af..207e1deac 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -135,7 +135,8 @@ export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHea
                 placeholder={'Add key'}
                 updateAlt={this.updateAlt} // alternate title to display
                 updateSearch={this.updateKeyDropdown}
-                schemaFieldType={SchemaFieldType.Header} 
+                inputString={true}
+                inputStringPlaceholder={'Add key'}
                 GetValue={() => {
                     if (SchemaColumnHeader.isDefaultField(this.fieldKey)) return '';
                     else if (this._altTitle) return this._altTitle;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
index 44f743a97..ad47b7848 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
@@ -943,7 +943,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                     removeDocument={returnFalse}
                     PanelWidth={() => this._menuDimensions.width - 10}
                     PanelHeight={() => this._menuDimensions.height - 60}
-                    ScreenToLocalTransform={Transform.Identity}
+                    ScreenToLocalTransform={() => new Transform(-this._pageX,-this._pageY, 1)}
                     renderDepth={5}
                     whenChildContentsActiveChanged={emptyFunction}
                     focus={emptyFunction}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 226fad977..c156c80e4 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -124,15 +124,15 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             { fireImmediately: true, delay: 1000 }
         );
         const { layoutDoc } = this;
-        // this._disposers.path = reaction(
-        //     () => ({ nativeSize: this.nativeSize, width: NumCast(this.layoutDoc._width) }),
-        //     ({ nativeSize, width }) => {
-        //         if (layoutDoc === this.layoutDoc || !this.layoutDoc._height) {
-        //             this.layoutDoc._height = (width * nativeSize.nativeHeight) / nativeSize.nativeWidth;
-        //         }
-        //     },
-        //     { fireImmediately: true }
-        // );
+        this._disposers.path = reaction(
+            () => ({ nativeSize: this.nativeSize, width: NumCast(this.layoutDoc._width) }),
+            ({ nativeSize, width }) => {
+                if (layoutDoc === this.layoutDoc || !this.layoutDoc._height) {
+                    this.layoutDoc._height = (width * nativeSize.nativeHeight) / nativeSize.nativeWidth;
+                }
+            },
+            { fireImmediately: true }
+        );
         this._disposers.scroll = reaction(
             () => this.layoutDoc.layout_scrollTop,
             sTop => {
-- 
cgit v1.2.3-70-g09d2

