From f92a02ec5d676359cb268a35d30e5bf9886199c1 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Fri, 30 May 2025 03:27:03 -0400
Subject: couple more component refactors

---
 .../Menu/TemplateRenderPreviewWindow.tsx           | 346 +++++++++++++++++++++
 1 file changed, 346 insertions(+)
 create mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateRenderPreviewWindow.tsx

(limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateRenderPreviewWindow.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateRenderPreviewWindow.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateRenderPreviewWindow.tsx
new file mode 100644
index 000000000..219152549
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateRenderPreviewWindow.tsx
@@ -0,0 +1,346 @@
+import { action, computed, makeObservable, observable, runInAction } from "mobx";
+import { observer } from "mobx-react";
+import { ObservableReactComponent } from "../../../../ObservableReactComponent";
+import { DataVizTemplateLayout, DocCreatorMenu, LayoutType } from "../DocCreatorMenu";
+import React from "react";
+import { IconProp } from "@fortawesome/fontawesome-svg-core";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { setupMoveUpEvents, returnFalse, returnEmptyFilter } from "../../../../../../ClientUtils";
+import { emptyFunction } from "../../../../../../Utils";
+import { undoable } from "../../../../../util/UndoManager";
+import ReactLoading from "react-loading";
+import { Doc, NumListCast, returnEmptyDoclist } from "../../../../../../fields/Doc";
+import { StrCast } from "../../../../../../fields/Types";
+import { DefaultStyleProvider } from "../../../../StyleProvider";
+import { DocumentView } from "../../../DocumentView";
+import { Transform } from "../../../../../util/Transform";
+import { Docs, DocumentOptions } from "../../../../../documents/Documents";
+import { Template } from "../Template";
+
+interface TemplatesRenderPreviewWindowProps {
+    menu: DocCreatorMenu;
+}
+
+@observer
+export class TemplatesRenderPreviewWindow extends ObservableReactComponent<TemplatesRenderPreviewWindowProps> {
+
+    @observable private _layout: { type: LayoutType; yMargin: number; xMargin: number; columns?: number; repeat: number } = { type: LayoutType.FREEFORM, yMargin: 10, xMargin: 10, columns: 0, repeat: 0 };
+
+    @observable private renderedDocs: Doc[] = [];
+    @observable private renderedDocCollection: Doc | undefined = undefined;
+
+    @observable private loading: boolean = false;
+
+    constructor(props: TemplatesRenderPreviewWindowProps) {
+        super(props);
+        makeObservable(this);
+        this.updateRenderedPreviewCollection();
+    }
+
+    @computed get canMakeDocs() {
+        return this._props.menu._selectedTemplate !== undefined && this._layout !== undefined;
+    }
+
+    @computed get docsToRender() {
+        if (this._props.menu.DEBUG_MODE) {
+            return [1, 2, 3, 4];
+        } else {
+            return NumListCast(this._props.menu._dataViz?.layoutDoc.dataViz_selectedRows);
+        }
+    }
+
+    @computed get rowsCount() {
+        switch (this._layout.type) {
+            case LayoutType.FREEFORM:
+                return Math.ceil(this.docsToRender.length / (this._layout.columns ?? 1)) ?? 0;
+            case LayoutType.CAROUSEL3D:
+                return 1.8;
+            default:
+                return 1;
+        }
+    }
+
+    @computed get columnsCount() {
+        switch (this._layout.type) {
+            case LayoutType.FREEFORM:
+                return this._layout.columns ?? 0;
+            case LayoutType.CAROUSEL3D:
+                return 3;
+            default:
+                return 1;
+        }
+    }
+
+    @action updateRenderedPreviewCollection = async () => {
+        this.loading = true;
+        this.renderedDocs = await this._props.menu.createDocsForPreview();
+        this.updateRenderedDocCollection();
+    };
+
+    /**
+     * Updates the preview that shows how all docs will be rendered in the chosen collection type.
+    @type the type of collection the docs should render to (ie. freeform, carousel, card)
+     */
+    updateRenderedDocCollection = () => {
+        if (!this.renderedDocs) return;
+
+        const collectionFactory = (): ((docs: Doc[], options: DocumentOptions) => Doc) => {
+            switch (this._layout.type) {
+                case LayoutType.CAROUSEL3D: return Docs.Create.Carousel3DDocument;
+                case LayoutType.FREEFORM:   return Docs.Create.FreeformDocument;
+                case LayoutType.CARD:       return Docs.Create.CardDeckDocument;
+                case LayoutType.MASONRY:    return Docs.Create.MasonryDocument;
+                case LayoutType.CAROUSEL:   return Docs.Create.CarouselDocument;
+                default:                    return Docs.Create.FreeformDocument;
+            } // prettier-ignore
+        };
+
+        const collection = collectionFactory()(this.renderedDocs, {
+            isDefaultTemplateDoc: true,
+            title: 'title',
+            backgroundColor: 'gray',
+            x: 200,
+            y: 200,
+            _width: 4000,
+            _height: 4000,
+        });
+
+        this.applyLayout(collection, this.renderedDocs);
+
+        this.renderedDocCollection = collection;
+
+        this.loading = false;
+
+        this.forceUpdate();
+    };
+
+    @action updateMargin = (input: string, xOrY: 'x' | 'y') => {
+        this._layout[`${xOrY}Margin`] = Number(input);
+        setTimeout(() => {
+            if (!this.renderedDocCollection || !this.renderedDocs) return;
+            this.applyLayout(this.renderedDocCollection, this.renderedDocs);
+        });
+    };
+
+    @action updateColumns = (input: string) => {
+        this._layout.columns = Number(input);
+        this.updateRenderedDocCollection();
+    };
+
+    applyLayout = (collection: Doc, docs: Doc[]) => {
+        const { horizontalSpan, verticalSpan } = this.previewInfo;
+        collection._height = verticalSpan;
+        collection._width = horizontalSpan;
+
+        const columns: number = this._layout.columns ?? this.columnsCount;
+        const xGap: number = this._layout.xMargin;
+        const yGap: number = this._layout.yMargin;
+        const startX: number = -Number(collection._width) / 2;
+        const startY: number = -Number(collection._height) / 2;
+        const docHeight: number = Number(docs[0]._height);
+        const docWidth: number = Number(docs[0]._width);
+
+        if (columns === 0 || docs.length === 0) {
+            return;
+        }
+
+        let i: number = 0;
+        let docsChanged: number = 0;
+        let curX: number = startX;
+        let curY: number = startY;
+
+        while (docsChanged < docs.length) {
+            while (i < columns && docsChanged < docs.length) {
+                docs[docsChanged].x = curX;
+                docs[docsChanged].y = curY;
+                curX += docWidth + xGap;
+                ++docsChanged;
+                ++i;
+            }
+            i = 0;
+            curX = startX;
+            curY += docHeight + yGap;
+        }
+    };
+
+    @computed
+    get previewInfo() {
+        const docHeight: number = Number(this.renderedDocs[0]._height);
+        const docWidth: number = Number(this.renderedDocs[0]._width);
+        const layout = this._layout;
+        return {
+            docHeight: docHeight,
+            docWidth: docWidth,
+            horizontalSpan: (docWidth + layout.xMargin) * this.columnsCount - layout.xMargin,
+            verticalSpan: (docHeight + layout.yMargin) * this.rowsCount - layout.yMargin,
+        };
+    }
+
+    get layoutConfigOptions() {
+        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 IconProp} />
+                    </div>
+                    <input defaultValue={def} onInput={e => func(e.currentTarget.value)} className="docCreatorMenu-input config layout-config" />
+                </div>
+            );
+        };
+
+        switch (this._layout.type) {
+            case LayoutType.FREEFORM:
+                return (
+                    <div className="docCreatorMenu-configuration-bar">
+                        {optionInput('arrows-up-down', (input: string) => this.updateMargin(input, 'y'), this._layout.xMargin, '2')}
+                        {optionInput('arrows-left-right', (input: string) => this.updateMargin(input, 'x'), this._layout.xMargin, '3')}
+                        {optionInput('table-columns', this.updateColumns, this._layout.columns, '4', true)}
+                    </div>
+                );
+            default:
+                break;
+        }
+    }
+
+    layoutPreviewContents = action(() => {
+        return this.loading ? (
+            <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">
+                <DocumentView
+                    Document={this.renderedDocCollection}
+                    isContentActive={emptyFunction}
+                    addDocument={returnFalse}
+                    moveDocument={returnFalse}
+                    removeDocument={returnFalse}
+                    PanelWidth={() => this._props.menu._menuDimensions.width - 80}
+                    PanelHeight={() => this._props.menu._menuDimensions.height - 105}
+                    ScreenToLocalTransform={() => new Transform(-this._props.menu._pageX - 5, -this._props.menu._pageY - 35, 1)}
+                    renderDepth={5}
+                    whenChildContentsActiveChanged={emptyFunction}
+                    focus={emptyFunction}
+                    styleProvider={DefaultStyleProvider}
+                    addDocTab={this._props.menu._props.addDocTab}
+                    pinToPres={() => undefined}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
+                    searchFilterDocs={returnEmptyDoclist}
+                    fitContentsToBox={returnFalse}
+                    fitWidth={returnFalse}
+                    hideDecorations={true}
+                />
+            </div>
+        );
+    });
+
+    selectionBox = (width: number, height: number, icon: string, specClass?: string, options?: JSX.Element[], manual?: boolean): JSX.Element => {
+        return (
+            <div className="docCreatorMenu-option-container">
+                <div className={`docCreatorMenu-option-title config ${specClass}`} style={{ width: width * 0.4, height: height }}>
+                    <FontAwesomeIcon icon={icon as IconProp} />
+                </div>
+                {manual ? (
+                    <input className={`docCreatorMenu-input config ${specClass}`} style={{ width: width * 0.6, height: height }} />
+                ) : (
+                    <select className={`docCreatorMenu-input config ${specClass}`} style={{ width: width * 0.6, height: height }}>
+                        {options}
+                    </select>
+                )}
+            </div>
+        );
+    };
+
+    layoutOption = (option: LayoutType, optStyle?: object, specialFunc?: () => void) => {
+        return (
+            <div
+                className="docCreatorMenu-dropdown-option"
+                style={optStyle}
+                onPointerDown={e =>
+                    this._props.menu.setUpButtonClick(e, () => {
+                        specialFunc?.();
+                        runInAction(() => {
+                            this._layout.type = option;
+                            this.updateRenderedDocCollection();
+                        });
+                    })
+                }>
+                {option}
+            </div>
+        );
+    };
+
+    get optionsMenuContents() {
+
+        const repeatOptions = [0, 1, 2, 3, 4, 5];
+
+        return (
+            <div className="docCreatorMenu-menu-container">
+                <div className="docCreatorMenu-option-container layout">
+                    <div className="docCreatorMenu-dropdown-hoverable">
+                        <div className="docCreatorMenu-option-title">{this._layout.type ? this._layout.type.toUpperCase() : 'Choose Layout'}</div>
+                        <div className="docCreatorMenu-dropdown-content">
+                            {this.layoutOption(LayoutType.FREEFORM, undefined, () => {
+                                if (!this._layout.columns) this._layout.columns = Math.ceil(Math.sqrt(this.docsToRender.length));
+                            })}
+                            {this.layoutOption(LayoutType.CAROUSEL)}
+                            {this.layoutOption(LayoutType.CAROUSEL3D)}
+                            {this.layoutOption(LayoutType.MASONRY)}
+                        </div>
+                    </div>
+                </div>
+                {this._layout.type ? this.layoutConfigOptions : null}
+                {this.layoutPreviewContents()}
+                {this.selectionBox(
+                    60,
+                    20,
+                    'repeat',
+                    undefined,
+                    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">
+                    <button
+                        className="docCreatorMenu-save-layout-button"
+                        onPointerDown={e =>
+                            setupMoveUpEvents(
+                                this,
+                                e,
+                                returnFalse,
+                                emptyFunction,
+                                undoable(clickEv => {
+                                    clickEv.stopPropagation();
+                                    //previous implementation deprecated; return later to add or scrap
+                                    return;
+                                }, 'save layout')
+                            )
+                        }>
+                        <FontAwesomeIcon icon="floppy-disk" />
+                    </button>
+                    <button
+                        className="docCreatorMenu-create-docs-button"
+                        style={{ backgroundColor: this.canMakeDocs ? '' : 'rgb(155, 155, 155)', border: this.canMakeDocs ? '' : 'solid 2px rgb(180, 180, 180)' }}
+                        onPointerDown={e =>
+                            setupMoveUpEvents(
+                                this,
+                                e,
+                                returnFalse,
+                                emptyFunction,
+                                undoable(clickEv => {
+                                    clickEv.stopPropagation();
+                                    this.renderedDocCollection && this._props.menu.addRenderedCollectionToMainview(this.renderedDocCollection);
+                                }, 'make docs')
+                            )
+                        }>
+                        <FontAwesomeIcon icon="plus" />
+                    </button>
+                </div>
+            </div>
+        );
+    }
+
+    render() { return this.optionsMenuContents }
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 312a07364ac8880e74e1b0a911d3e5b380886858 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Fri, 30 May 2025 04:07:22 -0400
Subject: linting

---
 .../DocCreatorMenu/Backend/TemplateManager.ts      |  2 +-
 .../DocCreatorMenu/Backend/TemplateMenuAIUtils.ts  |  6 +----
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   | 31 +++++++---------------
 .../DocCreatorMenu/Menu/ConditionalsTextarea.tsx   |  2 +-
 .../DocCreatorMenu/Menu/DocCreatorMenuButton.tsx   |  3 ++-
 .../DocCreatorMenu/Menu/TemplateEditingWindow.tsx  | 21 +++++++--------
 .../Menu/TemplateMenuFieldOptions.tsx              | 14 +++++-----
 .../DocCreatorMenu/Menu/TemplatePreviewBox.tsx     |  9 +++----
 .../DocCreatorMenu/Menu/TemplatePreviewGrid.tsx    | 15 +++++------
 .../Menu/TemplateRenderPreviewWindow.tsx           |  3 +--
 .../nodes/DataVizBox/DocCreatorMenu/Template.ts    |  9 -------
 .../DocCreatorMenu/TemplateFieldTypes/DataField.ts |  3 +--
 .../TemplateFieldTypes/DynamicField.ts             |  9 ++-----
 .../TemplateFieldTypes/StaticContentField.ts       |  1 -
 .../TemplateFieldTypes/TemplateField.ts            |  3 +--
 15 files changed, 45 insertions(+), 86 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateRenderPreviewWindow.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts
index 6fcca7e30..78235d000 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts
@@ -2,7 +2,7 @@ import { action, makeAutoObservable } from 'mobx';
 import { Col } from '../DocCreatorMenu';
 import { FieldSettings, TemplateField } from '../TemplateFieldTypes/TemplateField';
 import { Template } from '../Template';
-import { Doc, NumListCast } from '../../../../../../fields/Doc';
+import { NumListCast } from '../../../../../../fields/Doc';
 import { DataVizBox } from '../../DataVizBox';
 import { TemplateFieldType } from '../TemplateBackend';
 import { TemplateMenuAIUtils } from './TemplateMenuAIUtils';
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateMenuAIUtils.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateMenuAIUtils.ts
index 9bc2bfce2..162b7a1b1 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateMenuAIUtils.ts
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateMenuAIUtils.ts
@@ -1,5 +1,3 @@
-import { action } from "mobx";
-import { Upload } from "openai/resources";
 import { ClientUtils } from "../../../../../../ClientUtils";
 import { Networking } from "../../../../../Network";
 import { gptImageCall, gptAPICall, GPTCallType } from "../../../../../apis/gpt/GPT";
@@ -7,9 +5,6 @@ import { Col } from "../DocCreatorMenu";
 import { TemplateFieldSize, TemplateFieldType } from "../TemplateBackend";
 import { TemplateField, ViewType } from "../TemplateFieldTypes/TemplateField";
 import { Template } from "../Template";
-import { Doc } from "../../../../../../fields/Doc";
-import { DrawingFillHandler } from "../../../../smartdraw/DrawingFillHandler";
-import { CollectionFreeFormView } from "../../../../collections/collectionFreeForm";
 
 export class TemplateMenuAIUtils {
 
@@ -30,6 +25,7 @@ export class TemplateMenuAIUtils {
     public static renderGPTImageCall = async (template: Template, col: Col, fieldNumber: number): Promise<boolean> => {
         const generateAndLoadImage = async (id: number, prompt: string) => {
             const url = await this.generateGPTImage(prompt);
+            // eslint-disable-next-line
             var field: TemplateField = template.getFieldByID(id);
 
             field.setContent(url ?? '', ViewType.IMG);
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index 9a84e69a9..ebfa3fc65 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -1,44 +1,31 @@
-import { Colors } from '@dash/components';
+
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 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, setupMoveUpEvents } from '../../../../../ClientUtils';
+import { returnFalse, setupMoveUpEvents } from '../../../../../ClientUtils';
 import { emptyFunction } from '../../../../../Utils';
-import { Doc, NumListCast, StrListCast, returnEmptyDoclist } from '../../../../../fields/Doc';
+import { Doc, StrListCast } from '../../../../../fields/Doc';
 import { Id } from '../../../../../fields/FieldSymbols';
-import { ImageCast, StrCast } from '../../../../../fields/Types';
-import { ImageField } from '../../../../../fields/URLField';
-import { Upload } from '../../../../../server/SharedMediaTypes';
-import { Networking } from '../../../../Network';
-import { GPTCallType, gptAPICall, gptImageCall } from '../../../../apis/gpt/GPT';
-import { Docs, DocumentOptions } from '../../../../documents/Documents';
+import { GPTCallType, gptAPICall } from '../../../../apis/gpt/GPT';
 import { DragManager } from '../../../../util/DragManager';
 import { SnappingManager } from '../../../../util/SnappingManager';
-import { Transform } from '../../../../util/Transform';
 import { UndoManager, undoable } from '../../../../util/UndoManager';
 import { ObservableReactComponent } from '../../../ObservableReactComponent';
-import { DefaultStyleProvider } from '../../../StyleProvider';
 import { CollectionFreeFormView } from '../../../collections/collectionFreeForm/CollectionFreeFormView';
-import { DocumentView, DocumentViewInternal } from '../../DocumentView';
+import { DocumentView } from '../../DocumentView';
 import { OpenWhere } from '../../OpenWhere';
 import { DataVizBox } from '../DataVizBox';
 import './DocCreatorMenu.scss';
-import { TemplateField, ViewType } from './TemplateFieldTypes/TemplateField';
+import { ViewType } from './TemplateFieldTypes/TemplateField';
 import { Template } from './Template';
 import { TemplateFieldSize, TemplateFieldType, TemplateLayouts } from './TemplateBackend';
-import { Conditional, TemplateManager } from './Backend/TemplateManager';
-import { DrawingFillHandler } from '../../../smartdraw/DrawingFillHandler';
-import { CgPathIntersect } from 'react-icons/cg';
-import { StaticContentField } from './TemplateFieldTypes/StaticContentField';
+import { TemplateManager } from './Backend/TemplateManager';
 import { TemplateMenuAIUtils } from './Backend/TemplateMenuAIUtils'
 import { TemplatePreviewGrid } from './Menu/TemplatePreviewGrid';
 import { FireflyStructureOptions, TemplateEditingWindow } from './Menu/TemplateEditingWindow';
 import { DocCreatorMenuButton } from './Menu/DocCreatorMenuButton';
-import { ConditionalsTextArea } from './Menu/ConditionalsTextarea';
 import { TemplatesRenderPreviewWindow } from './Menu/TemplateRenderPreviewWindow';
 import { TemplateMenuFieldOptions } from './Menu/TemplateMenuFieldOptions';
 
@@ -500,7 +487,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
     };
 
     generateVariations = async (onDoc: Doc, prompt: string, options: FireflyStructureOptions): Promise<string[]> => {
-        const { numVariations, temperature, useStyleRef } = options;
+        // const { numVariations, temperature, useStyleRef } = options;
         this.variations = [];
         const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
 
@@ -509,7 +496,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
         clone.x = 10000;
         clone.y = 10000;
 
-        await DrawingFillHandler.drawingToImage(clone, 100 - temperature, prompt, useStyleRef ? clone : undefined, this, numVariations)
+        // await DrawingFillHandler.drawingToImage(clone, 100 - temperature, prompt, useStyleRef ? clone : undefined, this, numVariations)
 
         return this.variations;
     }
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/ConditionalsTextarea.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/ConditionalsTextarea.tsx
index 2ca0bde3f..89c2e44ff 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/ConditionalsTextarea.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/ConditionalsTextarea.tsx
@@ -51,7 +51,7 @@ export class ConditionalsTextArea extends ObservableReactComponent<ConditionalsT
                     value={this.props.conditional[this.props.property] ?? ''}
                     onChange={e => {
                         runInAction(() => {
-                        this.props.conditional[this.props.property] = e.target.value as any;
+                        this.props.conditional[this.props.property] = e.target.value as "=" | ">" | "<" | "contains";
                         });
                         this.updateInputWidth();
                     }}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/DocCreatorMenuButton.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/DocCreatorMenuButton.tsx
index 1d8139d40..48d2de4de 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/DocCreatorMenuButton.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/DocCreatorMenuButton.tsx
@@ -9,13 +9,14 @@ import { observer } from "mobx-react";
 
 interface DocCreatorMenuButtonProps {
     icon: IconProp;
+    // eslint-disable-next-line
     function: () => any;
     styles?: string;
 }
 
 @observer
 export class DocCreatorMenuButton extends ObservableReactComponent<DocCreatorMenuButtonProps> {
-
+    // eslint-disable-next-line
     setupButtonClick = (e: React.PointerEvent, func: (...args: any) => void) => {
         setupMoveUpEvents(
             this,
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx
index 3eaed79b6..b50fff9e0 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx
@@ -1,7 +1,6 @@
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, makeAutoObservable, makeObservable, observable, reaction, runInAction } from "mobx";
+import { action, makeObservable, observable, reaction, runInAction } from "mobx";
 import React from "react";
-import { returnFalse, returnEmptyFilter, returnTrue } from "../../../../../../ClientUtils";
+import { returnFalse, returnEmptyFilter } from "../../../../../../ClientUtils";
 import { emptyFunction } from "../../../../../../Utils";
 import { Doc, returnEmptyDoclist } from "../../../../../../fields/Doc";
 import { DefaultStyleProvider } from "../../../../StyleProvider";
@@ -11,14 +10,10 @@ import { TemplatePreviewGrid } from "./TemplatePreviewGrid";
 import { observer } from "mobx-react";
 import { Transform } from "../../../../../util/Transform";
 import { Template } from "../Template";
-import { TemplateMenuAIUtils } from "../Backend/TemplateMenuAIUtils";
 import { ObservableReactComponent } from "../../../../ObservableReactComponent";
 import { IDisposer } from "mobx-utils";
-import { ImageField } from "../../../../../../fields/URLField";
 import { DocCreatorMenuButton } from "./DocCreatorMenuButton";
-import { TbHistory } from "react-icons/tb";
 import { IconProp } from "@fortawesome/fontawesome-svg-core";
-import { docStyle } from "pdfjs-dist/types/web/ui_utils";
 
 export type FireflyStructureOptions = {
     numVariations: number;
@@ -56,7 +51,7 @@ export class FireflyVariationsTab extends ObservableReactComponent<FireflyVariat
         cloneTemplate.setMatteBackground();
         const doc: Doc = cloneTemplate.getRenderedDoc()!;
         this._variationURLs = await this._props.menu.generateVariations(doc, this.prompt, this.fireflyOptions);
-        this._variationURLs.forEach(url => {
+        this._variationURLs.forEach(() => {
             const newTemplate: Template = this._props.template.clone(true);
             this._props.menu._variations.push(newTemplate);
         });
@@ -72,7 +67,9 @@ export class FireflyVariationsTab extends ObservableReactComponent<FireflyVariat
         this.promptInput = node;
     }
 
+    // eslint-disable-next-line
     private optionsButtonOpts: [IconProp, () => any] = ['gear', () => {}];
+    // eslint-disable-next-line
     private previewBoxRightButtonOpts: [IconProp, () => any] = ['gear', () => this.forceUpdate()];
 
     render() {
@@ -93,7 +90,7 @@ export class FireflyVariationsTab extends ObservableReactComponent<FireflyVariat
                         <textarea
                             className="docCreatorMenu-variation-prompt-input-textbox"
                             ref={this.setPromptInputRef}
-                            onChange={e => this.prompt = e.target.value}
+                            onChange={e => { this.prompt = e.target.value }}
                             onInput={() => {
                                 if (this.promptInput !== null) {
                                     this.promptInput.style.height = 'auto';
@@ -108,7 +105,7 @@ export class FireflyVariationsTab extends ObservableReactComponent<FireflyVariat
                         <nav className="options‑menu">
                             <label className="menu‑item switch">
                                 <input type="checkbox" checked={this.fireflyOptions.useStyleRef} 
-                                    onChange={(e) => runInAction(() => this.fireflyOptions.useStyleRef = e.target.checked)}
+                                    onChange={(e) => runInAction(() => { this.fireflyOptions.useStyleRef = e.target.checked })}
                                 />
                                 <span className="slider round"></span>
                                 <span className="firefly-option-label">Use template as style guide</span>
@@ -119,7 +116,7 @@ export class FireflyVariationsTab extends ObservableReactComponent<FireflyVariat
                                     min="1" 
                                     max="5" 
                                     value={this.fireflyOptions.numVariations} 
-                                    onChange={(e) => runInAction(() => this.fireflyOptions.numVariations = Number(e.target.value))}
+                                    onChange={(e) => runInAction(() => { this.fireflyOptions.numVariations = Number(e.target.value) })}
                                 />
                                 <span className="value" id="varVal">{this.fireflyOptions.numVariations}</span>
                             </div>
@@ -129,7 +126,7 @@ export class FireflyVariationsTab extends ObservableReactComponent<FireflyVariat
                                     min="1" 
                                     max="100" 
                                     value={this.fireflyOptions.temperature} 
-                                    onChange={(e) => runInAction(() => this.fireflyOptions.temperature = Number(e.target.value))}
+                                    onChange={(e) => runInAction(() => { this.fireflyOptions.temperature = Number(e.target.value) })}
                                 />
                                 <span className="value" id="tempVal">{this.fireflyOptions.temperature}</span>
                             </div>
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateMenuFieldOptions.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateMenuFieldOptions.tsx
index beda45ac3..a4da54392 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateMenuFieldOptions.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateMenuFieldOptions.tsx
@@ -15,7 +15,7 @@ interface TemplateMenuFieldOptionsProps {
 @observer
 export class TemplateMenuFieldOptions extends ObservableReactComponent<TemplateMenuFieldOptionsProps> {
 
-    @observable _collapsedCols: String[] = []; //any columns whose options panels are hidden
+    @observable _collapsedCols: string[] = []; //any columns whose options panels are hidden
 
     constructor(props: TemplateMenuFieldOptionsProps) {
         super(props);
@@ -43,7 +43,7 @@ export class TemplateMenuFieldOptions extends ObservableReactComponent<TemplateM
     conditionForm = (title: string, parameters?: Conditional, empty: boolean = false) => {
 
         const contentFieldTitles = this._props.menu.fieldsInfos.filter(field => field.type !== TemplateFieldType.DATA).map(field => field.title).concat('Template');
-        var params: Conditional = this.getParams(title, parameters);
+        const params: Conditional = this.getParams(title, parameters);
 
         return (
         <div className='form'>
@@ -56,27 +56,27 @@ export class TemplateMenuFieldOptions extends ObservableReactComponent<TemplateM
                 </div>
                 <input
                     className="form-row-textarea"
-                    onChange={e => runInAction(() => params.condition = e.target.value)}
+                    onChange={e => runInAction(() => { params.condition = e.target.value })}
                     placeholder='value'
                     value={params.condition}
                 />
                 <div className='form-row-plain-text'>then</div>
                 <div className="operator-options-dropdown">
                     <span className="operator-dropdown-current">{params.target ?? 'Own'}</span>
-                    {contentFieldTitles.map(fieldTitle => 
-                        <div className='operator-dropdown-option' onPointerDown={() => {params.target = fieldTitle}}>{fieldTitle === title ? 'Own' : fieldTitle}</div>
+                    {contentFieldTitles.map((fieldTitle, i) => 
+                        <div className='operator-dropdown-option' key={i} onPointerDown={() => {params.target = fieldTitle}}>{fieldTitle === title ? 'Own' : fieldTitle}</div>
                     )}
                 </div>
                 <input
                     className="form-row-textarea"
-                    onChange={e => runInAction(() => params.attribute = e.target.value)}
+                    onChange={e => runInAction(() => { params.attribute = e.target.value })}
                     placeholder='attribute'
                     value={params.attribute}
                 />
                 <div className='form-row-plain-text'>{'becomes'}</div>
                 <input
                     className="form-row-textarea"
-                    onChange={e => runInAction(() => params.value = e.target.value)}
+                    onChange={e => runInAction(() => { params.value = e.target.value })}
                     placeholder='value'
                     value={params.value}
                 />
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewBox.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewBox.tsx
index de2f9e455..dc4c35789 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewBox.tsx
@@ -1,7 +1,7 @@
 import { Colors } from "@dash/components/src";
 import { FontAwesomeIcon} from "@fortawesome/react-fontawesome";
 import { Template } from "../Template";
-import { makeObservable, observable, reaction, runInAction } from "mobx";
+import { makeObservable, observable } from "mobx";
 import React from "react";
 import { ObservableReactComponent } from "../../../../ObservableReactComponent";
 import { DocCreatorMenu } from "../DocCreatorMenu";
@@ -12,15 +12,12 @@ import { returnEmptyFilter, returnFalse } from "../../../../../../ClientUtils";
 import { Transform } from "../../../../../util/Transform";
 import { DefaultStyleProvider } from "../../../../StyleProvider";
 import { Doc, returnEmptyDoclist } from "../../../../../../fields/Doc";
-import { IDisposer } from "mobx-utils";
-import { ImageField } from "../../../../../../fields/URLField";
-import { ImageCast } from "../../../../../../fields/Types";
 import { observer } from "mobx-react";
 
 export interface TemplatePreviewBoxProps {
     template: Template;
-    menu: DocCreatorMenu;
-    leftButtonOpts?: [icon: IconProp, func: (...args: any) => void]
+    menu: DocCreatorMenu; // eslint-disable-next-line
+    leftButtonOpts?: [icon: IconProp, func: (...args: any) => void] // eslint-disable-next-line
     rightButtonOpts?: [icon: IconProp, func: (...args: any) => void]
 }
 
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewGrid.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewGrid.tsx
index d53853c52..da4851f84 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewGrid.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewGrid.tsx
@@ -1,6 +1,4 @@
-import { Colors } from "@dash/components/src";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, makeObservable, observable, runInAction } from "mobx";
+import { makeObservable, runInAction } from "mobx";
 import React from "react";
 import ReactLoading from "react-loading";
 import { Doc } from "../../../../../../fields/Doc";
@@ -18,10 +16,10 @@ export interface SuggestedTemplatesProps {
     loading?: boolean;
     templates: Template[];
     title: string;
-    styles?: string;
-    optionsButtonOpts?: [IconProp, (...args: any) => any];
-    previewBoxLeftButtonOpts?: [IconProp, (...args: any) => any];
-    previewBoxRightButtonOpts?: [IconProp, (...args: any) => any];
+    styles?: string; // eslint-disable-next-line
+    optionsButtonOpts?: [IconProp, (...args: any) => any]; // eslint-disable-next-line
+    previewBoxLeftButtonOpts?: [IconProp, (...args: any) => any]; // eslint-disable-next-line
+    previewBoxRightButtonOpts?: [IconProp, (...args: any) => any]; 
 }
 
 @observer
@@ -46,8 +44,9 @@ export class TemplatePreviewGrid extends ObservableReactComponent<SuggestedTempl
                     (<div className="loading-spinner">
                         <ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} />
                     </div>)
-                    : this.props.templates.map(template => (
+                    : this.props.templates.map((template, i) => (
                         <TemplatePreviewBox 
+                        key={i}
                         template={template} 
                         menu={this.props.menu} 
                         leftButtonOpts={["magnifying-glass", (template: Template) => { this.props.menu.setExpandedView(template); this.forceUpdate(); }]}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateRenderPreviewWindow.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateRenderPreviewWindow.tsx
index 219152549..f281f770e 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateRenderPreviewWindow.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateRenderPreviewWindow.tsx
@@ -1,7 +1,7 @@
 import { action, computed, makeObservable, observable, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import { ObservableReactComponent } from "../../../../ObservableReactComponent";
-import { DataVizTemplateLayout, DocCreatorMenu, LayoutType } from "../DocCreatorMenu";
+import { DocCreatorMenu, LayoutType } from "../DocCreatorMenu";
 import React from "react";
 import { IconProp } from "@fortawesome/fontawesome-svg-core";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
@@ -15,7 +15,6 @@ import { DefaultStyleProvider } from "../../../../StyleProvider";
 import { DocumentView } from "../../../DocumentView";
 import { Transform } from "../../../../../util/Transform";
 import { Docs, DocumentOptions } from "../../../../../documents/Documents";
-import { Template } from "../Template";
 
 interface TemplatesRenderPreviewWindowProps {
     menu: DocCreatorMenu;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
index fd87ae973..7591740e0 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
@@ -4,8 +4,6 @@ import { TemplateFieldType, TemplateLayouts } from './TemplateBackend';
 import { DynamicField } from './TemplateFieldTypes/DynamicField';
 import { FieldSettings, TemplateField, ViewType } from './TemplateFieldTypes/TemplateField';
 import { Conditional } from './Backend/TemplateManager';
-import { ImageField } from '../../../../../fields/URLField';
-import { Doc } from '../../../../../fields/Doc';
 import { TemplateDataField } from './TemplateFieldTypes/DataField';
 
 export class Template {
@@ -72,12 +70,6 @@ export class Template {
 
     setupMainField = (templateInfo: FieldSettings) => TemplateField.CreateField(templateInfo, 1, undefined) as DynamicField;
 
-    printFieldInfo = () => {
-        this.allFields.forEach(field => {
-            const doc = field.renderedDoc;
-        });
-    };
-
     assignColToField = (fieldID: number, col: Col) => {
         const field = this.getFieldByID(fieldID);
         field.setContent(col.defaultContent ?? '', col.type === TemplateFieldType.VISUAL ? ViewType.IMG : ViewType.TEXT);
@@ -102,7 +94,6 @@ export class Template {
         const fieldStatements: Conditional[] = logic[field.getTitle()];
         const content = field.getContent()
         fieldStatements && fieldStatements.forEach(statement => {
-            console.log(statement);
             if (content === statement.condition) {
                 if (statement.target === 'Template') {
                     this._mainField.renderedDoc![statement.attribute] = statement.value;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DataField.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DataField.ts
index aaa475bed..6b4086483 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DataField.ts
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DataField.ts
@@ -1,6 +1,5 @@
 
-import { Template } from "../Template";
-import { TemplateField, ViewType } from "./TemplateField";
+import { ViewType } from "./TemplateField";
 
 export class TemplateDataField {
 
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DynamicField.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DynamicField.ts
index 1576dd240..b9042258b 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DynamicField.ts
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DynamicField.ts
@@ -1,6 +1,5 @@
-import { reaction } from 'mobx';
 import { IDisposer } from 'mobx-utils';
-import { Doc, DocListCast } from '../../../../../../fields/Doc';
+import { Doc } from '../../../../../../fields/Doc';
 import { DocData } from '../../../../../../fields/DocSymbols';
 import { List } from '../../../../../../fields/List';
 import { NumCast } from '../../../../../../fields/Types';
@@ -48,10 +47,7 @@ export class DynamicField extends TemplateField {
 
     addField = (field: TemplateField, layer: number = 0) => {
         if (!this._subfields.includes(field)) {
-            console.log('success')
-            console.log('subs: ', this._subfields)
             this._subfields.splice(layer, 0, field);
-            console.log('subffelds: ', this._subfields)
         }
     };
 
@@ -98,7 +94,6 @@ export class DynamicField extends TemplateField {
         const dynClone = super.makeClone(parent) as DynamicField;
         dynClone._subfields = this.getSubfields.map(field => {
             if (field === this.backgroundField) {
-                console.log('background found')
                 const backgroundField: TemplateField = field.makeClone(dynClone, true);
                 dynClone.makeBackgroundField(backgroundField);
                 return backgroundField;
@@ -113,7 +108,7 @@ export class DynamicField extends TemplateField {
     }
 
     initRenderDoc = (settings: FieldSettings) => {
-        this._disposers.fieldList = reaction(() => DocListCast(this._renderDoc?.[Doc.LayoutFieldKey(this._renderDoc)]), this.handleFieldUpdate);
+        //this._disposers.fieldList = reaction(() => DocListCast(this._renderDoc?.[Doc.LayoutFieldKey(this._renderDoc)]), this.handleFieldUpdate);
         this._subfields = settings.subfields?.map((fieldSettings, index) => {return TemplateField.CreateField(fieldSettings, index, this)}) || [];
         const renderedSubfields = this._subfields.filter(field => field.renderedDoc).map(field => field.renderedDoc!);
         settings.opts.title = settings.title;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/StaticContentField.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/StaticContentField.ts
index 2a8e4f09b..569c43af4 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/StaticContentField.ts
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/StaticContentField.ts
@@ -1,4 +1,3 @@
-import { FontSize } from '@dash/components';
 import { FieldResult } from '../../../../../../fields/Doc';
 import { DocData } from '../../../../../../fields/DocSymbols';
 import { RichTextField } from '../../../../../../fields/RichTextField';
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts
index a1107caf3..c100d1cce 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts
@@ -1,7 +1,6 @@
 /* eslint-disable no-use-before-define */
 import { Doc } from '../../../../../../fields/Doc';
 import { DocumentOptions } from '../../../../../documents/Documents';
-import { Conditional } from '../Backend/TemplateManager';
 import { Col } from '../DocCreatorMenu';
 import { Template } from '../Template';
 import { TemplateFieldSize, TemplateFieldType } from '../TemplateBackend';
@@ -95,7 +94,7 @@ export abstract class TemplateField {
     exchangeFields(newField: TemplateField, oldField: TemplateField) {
         throw new Error('Only DynamicField can exchange fields.' + newField._title + ' ' + oldField._title);
     }
-    // eslint-disable-next-line @typescript-eslint/no-unused-vars
+
     changeFieldType = (newType: ViewType): TemplateField => {
         this._settings.viewType = newType;
         const newField = TemplateField.CreateField(this._settings, this._id, this._parent, true);
-- 
cgit v1.2.3-70-g09d2


From 215f874c5f7f28964a3428909fcee0f667388bae Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 1 Jun 2025 16:07:30 -0400
Subject: a number of fixes to document creator to fix preview of templates and
 templates with images.

---
 src/client/views/collections/TabDocView.tsx        |   4 +-
 .../DocCreatorMenu/Backend/TemplateManager.ts      |  79 ++----
 .../DocCreatorMenu/Backend/TemplateMenuAIUtils.ts  |  34 ++-
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.scss  | 183 +++++++-------
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   | 206 ++++++---------
 .../DocCreatorMenu/Menu/TemplateEditingWindow.tsx  | 277 ++++++++++-----------
 .../Menu/TemplateMenuFieldOptions.tsx              | 252 +++++++++----------
 .../DocCreatorMenu/Menu/TemplatePreviewBox.tsx     | 113 ++++-----
 .../Menu/TemplateRenderPreviewWindow.tsx           |  97 ++++----
 .../nodes/DataVizBox/DocCreatorMenu/Template.ts    | 132 ++++------
 .../TemplateFieldTypes/TemplateField.ts            |   7 +-
 src/client/views/nodes/ImageBox.tsx                |   1 +
 12 files changed, 621 insertions(+), 764 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateRenderPreviewWindow.tsx')

diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index c4373aaa7..897a86e7f 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -584,9 +584,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
     miniMapColor = () => Colors.MEDIUM_GRAY;
     tabView = () => this._view;
     disableMinimap = () => !this._document;
-    whenChildContentActiveChanges = (isActive: boolean) => {
-        this._isAnyChildContentActive = isActive;
-    };
+    whenChildContentActiveChanges = (isActive: boolean) => (this._isAnyChildContentActive = isActive);
     isContentActiveFunc = () => this.isContentActive;
     waitForDoubleClick = () => (SnappingManager.ExploreMode ? 'never' : undefined);
     renderDocView = (doc: Doc) => (
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts
index 78235d000..526fcf9c4 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts
@@ -14,87 +14,64 @@ export type Conditional = {
     target: string;
     attribute: string;
     value: string;
-}
+};
 
 export class TemplateManager {
+    _templates: Template[] = [];
 
-    templates: Template[] = [];
-
-    conditionalFieldLogic: Record<string, Conditional[]> = {};
+    _conditionalFieldLogic: Record<string, Conditional[]> = {};
 
     constructor(templateSettings: FieldSettings[]) {
         makeAutoObservable(this);
-        this.templates = this.initializeTemplates(templateSettings);
+        this._templates = templateSettings.map(settings => new Template(settings));
     }
 
-    initializeTemplates = (templateSettings: FieldSettings[]) => templateSettings.map(settings => {
-        return new Template(settings)});
-
-    getValidTemplates = (cols: Col[]) => this.templates.filter(template => template.isValidTemplate(cols));
+    getValidTemplates = (cols: Col[]) => this._templates.filter(template => template.isValidTemplate(cols));
 
-    addTemplate = (newTemplate: Template) => this.templates.push(newTemplate);
+    addTemplate = (newTemplate: Template) => this._templates.push(newTemplate);
 
     removeTemplate = (template: Template) => {
-        this.templates.splice(this.templates.indexOf(template), 1);
+        if (this._templates.includes(template)) {
+            this._templates.splice(this._templates.indexOf(template), 1);
+        }
         template.cleanup();
     };
 
     addFieldCondition = (fieldTitle: string, condition: Conditional) => {
-        if (this.conditionalFieldLogic[fieldTitle] === undefined) {
-            this.conditionalFieldLogic[fieldTitle] = [condition];
+        if (this._conditionalFieldLogic[fieldTitle] === undefined) {
+            this._conditionalFieldLogic[fieldTitle] = [condition];
         } else {
-            this.conditionalFieldLogic[fieldTitle].push(condition);
+            this._conditionalFieldLogic[fieldTitle].push(condition);
         }
-    }
+    };
 
-    removeFieldCondition = (fieldTitle: string, condition: Conditional) => {
-        if (this.conditionalFieldLogic[fieldTitle]) {
-            this.conditionalFieldLogic[fieldTitle] = this.conditionalFieldLogic[fieldTitle].filter(cond => cond !== condition);
-        }
-    }
+    removeFieldCondition = (fieldTitle: string, condition: Conditional) => (this._conditionalFieldLogic[fieldTitle] = this._conditionalFieldLogic[fieldTitle]?.filter(cond => cond !== condition));
 
-    addDataField = (title: string) => {
-        this.templates.forEach(template => template.addDataField(title));
-    }
+    addDataField = (title: string) => this._templates.forEach(template => template.addDataField(title));
 
-    removeDataField = (title: string) => {
-        this.templates.forEach(template => template.removeDataField(title));
-    }
+    removeDataField = (title: string) => this._templates.forEach(template => template.removeDataField(title));
 
     createDocsFromTemplate = action((dv: DataVizBox, template: Template, cols: Col[], debug: boolean = false) => {
         const csvFields = Array.from(Object.keys(dv.records[0]));
 
-        const processContent = async (content: { [title: string]: string }) => {
+        const processContent = (content: { [title: string]: string }) => {
             const templateCopy = template.clone();
 
             csvFields
                 .filter(title => title)
                 .forEach(title => {
                     const field = templateCopy.getFieldByTitle(title);
-                    field && field.setContent(content[title], field.viewType);
+                    field?.setContent(content[title], field.viewType);
                 });
 
             const gptFunc = (type: TemplateFieldType) => (type === TemplateFieldType.VISUAL ? TemplateMenuAIUtils.renderGPTImageCall : TemplateMenuAIUtils.renderGPTTextCall);
-            const applyGPTContent = async () => {
-                const promises = cols
-                    .filter(field => field.AIGenerated)
-                    .map(field => {
-                        const templateField: TemplateField = templateCopy.getFieldByTitle(field.title) as TemplateField;
-                        if (templateField !== undefined) {
-                            return gptFunc(field.type)(templateCopy, field, templateField.getID);
-                        }
-                        return null; 
-                    })
-                    .filter(p => p !== null);
-            
-                await Promise.all(promises);
-            };
-
-            await applyGPTContent();
-
-            templateCopy.applyConditionalLogic(this.conditionalFieldLogic);
-
-            return templateCopy.getRenderedDoc();
+
+            const generateGptContent = cols
+                .map(field => ({ field, templateField: field?.AIGenerated && templateCopy.getFieldByTitle(field.title) }))
+                .filter(({ templateField }) => templateField instanceof TemplateField)
+                .map(({ field, templateField }) => gptFunc(field.type)(templateCopy, field, (templateField as TemplateField).getID));
+
+            return Promise.all(generateGptContent).then(() => templateCopy.applyConditionalLogic(this._conditionalFieldLogic));
         };
 
         const rowContents = debug
@@ -109,10 +86,6 @@ export class TemplateManager {
                   )
               );
 
-        return Promise.all(rowContents.map(processContent)).then(
-            action(renderedDocs => {
-                return renderedDocs;
-            })
-        );
+        return Promise.all(rowContents.map(processContent));
     });
 }
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateMenuAIUtils.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateMenuAIUtils.ts
index 162b7a1b1..08818dd6c 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateMenuAIUtils.ts
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateMenuAIUtils.ts
@@ -1,13 +1,13 @@
-import { ClientUtils } from "../../../../../../ClientUtils";
-import { Networking } from "../../../../../Network";
-import { gptImageCall, gptAPICall, GPTCallType } from "../../../../../apis/gpt/GPT";
-import { Col } from "../DocCreatorMenu";
-import { TemplateFieldSize, TemplateFieldType } from "../TemplateBackend";
-import { TemplateField, ViewType } from "../TemplateFieldTypes/TemplateField";
-import { Template } from "../Template";
+import { ClientUtils } from '../../../../../../ClientUtils';
+import { Networking } from '../../../../../Network';
+import { gptImageCall, gptAPICall, GPTCallType } from '../../../../../apis/gpt/GPT';
+import { Col } from '../DocCreatorMenu';
+import { TemplateFieldSize, TemplateFieldType } from '../TemplateBackend';
+import { ViewType } from '../TemplateFieldTypes/TemplateField';
+import { Template } from '../Template';
+import { Upload } from '../../../../../../server/SharedMediaTypes';
 
 export class TemplateMenuAIUtils {
-
     public static generateGPTImage = async (prompt: string): Promise<string | undefined> => {
         try {
             const res = await gptImageCall(prompt);
@@ -24,13 +24,10 @@ export class TemplateMenuAIUtils {
 
     public static renderGPTImageCall = async (template: Template, col: Col, fieldNumber: number): Promise<boolean> => {
         const generateAndLoadImage = async (id: number, prompt: string) => {
+            const field = template.getFieldByID(id);
             const url = await this.generateGPTImage(prompt);
-            // eslint-disable-next-line
-            var field: TemplateField = template.getFieldByID(id);
-
-            field.setContent(url ?? '', ViewType.IMG);
-            field = template.getFieldByID(id);
-            field.setTitle(col.title);
+            field?.setContent(url ?? '', ViewType.IMG);
+            field?.setTitle(col.title);
         };
 
         const fieldContent: string = template.compiledContent;
@@ -81,10 +78,10 @@ export class TemplateMenuAIUtils {
             if (res) {
                 const assignments: { [title: string]: { number: string; content: string } } = JSON.parse(res);
                 Object.entries(assignments).forEach(([, /* title */ info]) => {
-                    const field: TemplateField = template.getFieldByID(Number(info.number));
+                    const field = template.getFieldByID(Number(info.number));
 
-                    field.setContent(info.content ?? '', ViewType.TEXT);
-                    field.setTitle(col.title);
+                    field?.setContent(info.content ?? '', ViewType.TEXT);
+                    field?.setTitle(col.title);
                 });
             }
         } catch (err) {
@@ -122,5 +119,4 @@ export class TemplateMenuAIUtils {
 
         return template;
     };
-
-}
\ No newline at end of file
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss
index 463e69c67..6eb7fa96a 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss
@@ -9,10 +9,10 @@
     position: absolute;
     z-index: 1000;
     // box-shadow: 0px 3px 4px rgba(0, 0, 0, 30%);
-    // background: whitesmoke; 
+    // background: whitesmoke;
     // color: black;
     border-radius: 3px;
-}   
+}
 
 .docCreatorMenu-menu {
     display: flex;
@@ -24,7 +24,7 @@
 .docCreatorMenu-menu-button {
     width: 25px;
     height: 25px;
-    background: whitesmoke; 
+    background: whitesmoke;
     background-color: rgb(50, 50, 50);
     border-radius: 5px;
     padding: 0px;
@@ -53,8 +53,8 @@
         position: absolute;
         right: 0px;
     }
-     
-    &.right{
+
+    &.right {
         margin-left: 0px;
         font-size: 12px;
     }
@@ -103,12 +103,12 @@
         }
     }
 
-    &:hover::before{
+    &:hover::before {
         border-bottom: 20px solid rgb(82, 82, 82);
     }
 
     &::before {
-        content: "";
+        content: '';
         position: absolute;
         top: 0;
         left: 0;
@@ -120,7 +120,7 @@
     }
 
     &::after {
-        content: "";    
+        content: '';
         position: absolute;
         top: -1px;
         left: -1px;
@@ -143,7 +143,7 @@
     color: white;
 }
 
-.docCreatorMenu-menu-hr{
+.docCreatorMenu-menu-hr {
     margin-top: 0px;
     margin-bottom: 0px;
     color: rgb(180, 180, 180);
@@ -173,14 +173,14 @@
     align-items: center;
     width: 40px;
     height: 40px;
-    background-color: rgb(99, 148, 238); 
+    background-color: rgb(99, 148, 238);
     border: 2px solid rgb(80, 107, 152);
     border-radius: 5px;
     margin-bottom: 20px;
     font-size: 25px;
 
-    &:hover{
-        background-color: rgb(59, 128, 255);  
+    &:hover {
+        background-color: rgb(59, 128, 255);
         border: 2px solid rgb(53, 80, 127);
     }
 }
@@ -188,7 +188,7 @@
 .docCreatorMenu-create-docs-button {
     width: 40px;
     height: 40px;
-    background-color: rgb(176, 229, 149); 
+    background-color: rgb(176, 229, 149);
     border: 2px solid rgb(126, 219, 80);
     border-radius: 5px;
     padding: 0px;
@@ -199,7 +199,7 @@
 
     &:hover {
         background-color: rgb(129, 223, 83);
-        border: 2px solid rgb(80, 185, 28); 
+        border: 2px solid rgb(80, 185, 28);
     }
 }
 
@@ -230,17 +230,22 @@
     position: absolute;
     background-color: none;
 
-    &.top, &.bottom {
+    &.top,
+    &.bottom {
         height: 10px;
         cursor: ns-resize;
     }
 
-    &.right, &.left {
+    &.right,
+    &.left {
         width: 10px;
         cursor: ew-resize;
     }
 
-    &.topRight, &.topLeft, &.bottomRight, &.bottomLeft {
+    &.topRight,
+    &.topLeft,
+    &.bottomRight,
+    &.bottomLeft {
         height: 15px;
         width: 15px;
         background-color: none;
@@ -263,7 +268,7 @@
     height: calc(100% - 30px);
     border: 1px solid rgb(180, 180, 180);
     border-radius: 5px;
-    -ms-overflow-style: none; 
+    -ms-overflow-style: none;
     scrollbar-width: none;
 }
 
@@ -277,7 +282,7 @@
     height: 100%;
     flex-grow: 1;
 
-    .top-panel{
+    .top-panel {
         width: 100%;
         height: 10px;
     }
@@ -302,13 +307,14 @@
     justify-content: center;
     align-items: center;
     height: 100%;
+    width: 100%;
     aspect-ratio: 1;
     color: none;
     border: 1px solid rgb(163, 163, 163);
     border-radius: 5px;
     box-shadow: 5px 5px rgb(29, 29, 31);
 
-    &:hover{
+    &:hover {
         background-color: rgb(72, 72, 73);
     }
 
@@ -353,20 +359,18 @@
     &:hover .option-button {
         display: block;
     }
-    
 }
 
-.docCreatorMenu-preview-image{ 
+.docCreatorMenu-preview-image {
     background-color: transparent;
     height: 100%;
     display: block;
     object-fit: contain;
     border-radius: 5px;
-
 }
 
 .docCreatorMenu-variations-tab {
-    flex-grow: .5;
+    flex-grow: 0.5;
 }
 
 .docCreatorMenu-section {
@@ -400,7 +404,7 @@
     display: grid;
     justify-content: space-evenly;
     row-gap: 2rem;
-    grid-template-columns: repeat(auto-fill, minmax(150px, 30%));
+    grid-template-columns: repeat(auto-fill, minmax(150px, 50%));
     margin: 5px;
     width: calc(100% - 10px);
     height: 100%;
@@ -413,7 +417,7 @@
     }
 }
 
-.divvv{
+.div {
     width: 200;
     height: 200;
     border: solid 1px white;
@@ -448,7 +452,7 @@
 .docCreatorMenu-GPT-generate {
     height: 30px;
     width: 30px;
-    background-color: rgb(176, 229, 149); 
+    background-color: rgb(176, 229, 149);
     border: 1px solid rgb(126, 219, 80);
     border-radius: 5px;
     padding: 0px;
@@ -459,7 +463,7 @@
 
     &:hover {
         background-color: rgb(129, 223, 83);
-        border: 2px solid rgb(80, 185, 28); 
+        border: 2px solid rgb(80, 185, 28);
     }
 }
 
@@ -477,7 +481,7 @@
 // DocCreatorMenu options CSS
 //--------------------------------------------------------------------------------------------------------------------------------------------
 
-.docCreatorMenu-option-container{
+.docCreatorMenu-option-container {
     display: flex;
     width: 180px;
     height: 30px;
@@ -487,16 +491,16 @@
     margin-top: 10px;
     margin-bottom: 10px;
 
-    &.layout{
+    &.layout {
         z-index: 5;
     }
 }
 
-.docCreatorMenu-option-title{
+.docCreatorMenu-option-title {
     display: flex;
     width: 140px;
     height: 30px;
-    background: whitesmoke; 
+    background: whitesmoke;
     background-color: rgb(34, 34, 37);
     border-radius: 5px;
     border: 1px solid rgb(180, 180, 180);
@@ -513,7 +517,7 @@
         border-radius: 0px;
         width: auto;
         text-transform: none;
-         
+
         &.small {
             height: 20px;
             transform: translateY(-5px);
@@ -607,38 +611,38 @@
     height: calc(100% - 30px);
     border: 1px solid rgb(180, 180, 180);
     border-radius: 5px;
-    -ms-overflow-style: none; 
+    -ms-overflow-style: none;
     scrollbar-width: none;
 
-    .docCreatorMenu-option-container{
+    .docCreatorMenu-option-container {
         width: 180px;
         height: 30px;
 
         .docCreatorMenu-dropdown-hoverable {
             width: 140px;
             height: 30px;
-    
+
             &:hover .docCreatorMenu-dropdown-content {
                 display: block;
             }
-    
+
             &:hover .docCreatorMenu-option-title {
                 border-bottom-left-radius: 0px;
                 border-bottom-right-radius: 0px;
             }
-        
+
             .docCreatorMenu-dropdown-content {
                 display: none;
                 min-width: 100px;
                 height: 75px;
                 overflow-y: scroll;
-                -ms-overflow-style: none; 
+                -ms-overflow-style: none;
                 scrollbar-width: none;
                 border-bottom: 1px solid rgb(180, 180, 180);
                 border-bottom-left-radius: 5px;
                 border-bottom-right-radius: 5px;
-        
-                .docCreatorMenu-dropdown-option{
+
+                .docCreatorMenu-dropdown-option {
                     display: flex;
                     background-color: rgb(42, 42, 46);
                     border-left: 1px solid rgb(180, 180, 180);
@@ -649,13 +653,13 @@
                     justify-content: center;
                     justify-items: center;
                     padding-top: 3px;
-    
+
                     &:hover {
                         background-color: rgb(68, 68, 74);
                         cursor: pointer;
                     }
                 }
-            }    
+            }
         }
     }
 }
@@ -710,7 +714,7 @@
         border: 1px solid rgb(180, 180, 180);
         border-radius: 5px;
         background-color: rgb(34, 34, 37);
-        -ms-overflow-style: none; 
+        -ms-overflow-style: none;
         scrollbar-width: none;
 
         &.small {
@@ -742,10 +746,10 @@
         z-index: 999;
     }
 
-    .docCreatorMenu-zoom-button{ 
+    .docCreatorMenu-zoom-button {
         width: 15px;
         height: 15px;
-        background: whitesmoke; 
+        background: whitesmoke;
         background-color: rgb(34, 34, 37);
         border-radius: 3px;
         border: 1px solid rgb(180, 180, 180);
@@ -759,8 +763,6 @@
     }
 }
 
-
-
 //------------------------------------------------------------------------------------------------------------------------------------------
 // DocCreatorMenu dashboard CSS
 //--------------------------------------------------------------------------------------------------------------------------------------------
@@ -778,7 +780,7 @@
     height: calc(100% - 30px);
     border: 1px solid rgb(180, 180, 180);
     border-radius: 5px;
-    -ms-overflow-style: none; 
+    -ms-overflow-style: none;
     scrollbar-width: none;
 
     .panels-container {
@@ -836,8 +838,8 @@
                 background-color: rgb(72, 72, 72);
                 cursor: pointer;
             }
-        }  
-        
+        }
+
         .opts-bar {
             display: flex;
             flex-direction: row;
@@ -880,11 +882,11 @@
                     flex-direction: row;
                     align-items: flex-start;
                 }
-        
+
                 &:hover .type-display {
                     display: none;
                 }
-        
+
                 .bubble {
                     margin: 3px;
                 }
@@ -919,7 +921,7 @@
                     flex-direction: row;
                     align-items: center;
                 }
-        
+
                 .bubble {
                     margin: 3px;
                     margin-right: 4px;
@@ -942,10 +944,8 @@
                 border-bottom-right-radius: 5px;
                 border-bottom-left-radius: 5px;
                 resize: none;
-
             }
         }
-
     }
 
     .conditionals-section {
@@ -972,7 +972,7 @@
         flex-direction: row;
         justify-content: flex-start;
         align-items: flex-start;
-        color: whitesmoke; 
+        color: whitesmoke;
         width: 100%;
         height: fit-content;
         margin-bottom: 15px;
@@ -1041,7 +1041,6 @@
             overflow-y: scroll;
             white-space: nowrap;
         }
-
     }
 
     .form {
@@ -1057,10 +1056,8 @@
             align-items: center;
             margin: 3px;
             cursor: pointer;
-
         }
     }
-
 }
 
 //------------------------------------------------------------------------------------------------------------------------------------------
@@ -1113,38 +1110,38 @@
     display: flex;
     align-items: center;
     justify-content: center;
-    gap: 2rem;                 
+    gap: 2rem;
     padding: 0.5rem 1rem;
     background: rgb(50, 50, 50);
     color: whitesmoke;
     font-family: system-ui, sans-serif;
     font-size: 0.9rem;
-    flex-wrap: wrap;         
-  }
-  
-  .menu‑item {
+    flex-wrap: wrap;
+}
+
+.menu‑item {
     display: flex;
     align-items: center;
     gap: 0.5rem;
     white-space: nowrap;
-  }
-  
-  .menu‑item input[type="range"] {
+}
+
+.menu‑item input[type='range'] {
     width: 7rem;
-    accent-color: whitesmoke;      
-  }
-  
-  .value {
+    accent-color: whitesmoke;
+}
+
+.value {
     min-width: 2ch;
     text-align: right;
-  }
-  
-  .switch {
+}
+
+.switch {
     gap: 0.75rem;
     margin-bottom: 0px;
-  }
-  
-  .switch .slider {
+}
+
+.switch .slider {
     position: relative;
     width: 2.2rem;
     height: 1.1rem;
@@ -1152,9 +1149,9 @@
     border-radius: 1rem;
     cursor: pointer;
     transition: background 0.2s;
-  }
-  
-  .switch .slider::before {
+}
+
+.switch .slider::before {
     content: '';
     position: absolute;
     top: 0.1rem;
@@ -1164,27 +1161,25 @@
     background: rgb(50, 50, 50);
     border-radius: 50%;
     transition: transform 0.2s;
-  }
-  
-  .switch input {
+}
+
+.switch input {
     display: none;
-  }
-  
-  .switch input:checked + .slider {
+}
+
+.switch input:checked + .slider {
     background: #78c2f1;
-  }
-  
-  .switch input:checked + .slider::before {
+}
+
+.switch input:checked + .slider::before {
     transform: translateX(1.1rem);
-  }
+}
 
 .firefly-option-label {
-    padding: .2em .6em .3em;
+    padding: 0.2em 0.6em 0.3em;
     font-size: 100%;
     color: whitesmoke;
     text-align: center;
     margin-bottom: 0px;
     font-weight: 500;
 }
-  
-
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index ebfa3fc65..fb083ea75 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -1,4 +1,3 @@
-
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, makeObservable, observable, runInAction } from 'mobx';
@@ -22,7 +21,7 @@ import { ViewType } from './TemplateFieldTypes/TemplateField';
 import { Template } from './Template';
 import { TemplateFieldSize, TemplateFieldType, TemplateLayouts } from './TemplateBackend';
 import { TemplateManager } from './Backend/TemplateManager';
-import { TemplateMenuAIUtils } from './Backend/TemplateMenuAIUtils'
+import { TemplateMenuAIUtils } from './Backend/TemplateMenuAIUtils';
 import { TemplatePreviewGrid } from './Menu/TemplatePreviewGrid';
 import { FireflyStructureOptions, TemplateEditingWindow } from './Menu/TemplateEditingWindow';
 import { DocCreatorMenuButton } from './Menu/DocCreatorMenuButton';
@@ -158,18 +157,12 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
         return bounds;
     }
 
-    setUpButtonClick = (e: React.PointerEvent, func: (...args: any) => void) => {
-        setupMoveUpEvents(
-            this,
-            e,
-            returnFalse,
-            emptyFunction,
-            undoable(clickEv => {
-                clickEv.stopPropagation();
-                clickEv.preventDefault();
-                func();
-            }, 'create docs')
-        );
+    setUpButtonClick = (e: React.PointerEvent, func: () => void) => {
+        setupMoveUpEvents(this, e, returnFalse, emptyFunction, clickEv => {
+            clickEv.stopPropagation();
+            clickEv.preventDefault();
+            undoable(func, 'create docs')();
+        });
     };
 
     @action
@@ -301,16 +294,13 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
         this._pageX = x + translation.x;
         this._pageY = y + translation.y;
     };
-    
-    async createDocsForPreview(): Promise<Doc[]> { return this._dataViz && this._selectedTemplate ? ((await this.templateManager.createDocsFromTemplate(this._dataViz, this._selectedTemplate, this.fieldsInfos, this.DEBUG_MODE)).filter(doc => doc).map(doc => doc!) ?? []) as unknown as Doc[] : []; }
 
-    @action updateSelectedTemplate = async (template: Template) => {
-        if (this._selectedTemplate === template) {
-            this._selectedTemplate = undefined;
-            return;
-        } else {
-            this._selectedTemplate = template;
-        }
+    async createDocsForPreview() {
+        return this._dataViz && this._selectedTemplate ? ((await this.templateManager.createDocsFromTemplate(this._dataViz, this._selectedTemplate, this.fieldsInfos, this.DEBUG_MODE)).filter(doc => doc).map(doc => doc!) ?? []) : [];
+    }
+
+    @action updateSelectedTemplate = (template: Template) => {
+        this._selectedTemplate = this._selectedTemplate === template ? undefined : template; // toggle selection
     };
 
     // testTemplate = async () => {
@@ -318,27 +308,16 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
     // };
 
     @action addField = () => {
-        const newFields: Col[] = this._userCreatedFields.concat([{ title: '', type: TemplateFieldType.UNSET, desc: '', sizes: [], AIGenerated: true }]);
-        this._userCreatedFields = newFields;
+        this._userCreatedFields = this._userCreatedFields.concat([{ title: '', type: TemplateFieldType.UNSET, desc: '', sizes: [], AIGenerated: true }]);
     };
 
     @action removeField = (field: { title: string; type: string; desc: string }) => {
         if (this._dataViz?.axes.includes(field.title)) {
             this._dataViz.selectAxes(this._dataViz.axes.filter(col => col !== field.title));
         } else {
-            const toRemove = this._userCreatedFields.filter(f => f === field);
-            if (!toRemove) return;
-
-            if (toRemove.length > 1) {
-                while (toRemove.length > 1) {
-                    toRemove.pop();
-                }
-            }
-
-            if (this._userCreatedFields.length === 1) {
-                this._userCreatedFields = [];
-            } else {
-                this._userCreatedFields.splice(this._userCreatedFields.indexOf(toRemove[0]), 1);
+            const toRemove = this._userCreatedFields.findIndex(f => f === field);
+            if (toRemove !== -1) {
+                this._userCreatedFields.splice(toRemove, 1);
             }
         }
     };
@@ -390,35 +369,22 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
         this.forceUpdate();
     };
 
-    compileFieldDescriptions = (templates: Template[]): string => {
-        let descriptions: string = '';
-        templates.forEach(template => {
-            descriptions += `----------  NEW TEMPLATE TO INCLUDE: The title is: ${template.title}. Its fields are: `;
-            descriptions += template.descriptionSummary;
-        });
-
-        return descriptions;
-    };
-
-    compileColDescriptions = (cols: Col[]): string => {
-        let descriptions: string = ' ------------- COL DESCRIPTIONS START HERE:';
-        cols.forEach(col => (descriptions += `{title: ${col.title}, sizes: ${String(col.sizes)}, type: ${col.type}, descreiption: ${col.desc}} `));
+    compileFieldDescriptions = (templates: Template[]) => 
+        templates.map(template => `----------  NEW TEMPLATE TO INCLUDE: The title is: ${template.title}. Its fields are: ` + template.descriptionSummary).join(''); // prettier-ignore
 
-        return descriptions;
-    };
+    compileColDescriptions = (cols: Col[]) => 
+        ' ------------- COL DESCRIPTIONS START HERE:' + cols.map(col => `{title: ${col.title}, sizes: ${String(col.sizes)}, type: ${col.type}, descreiption: ${col.desc}} `).join(''); // prettier-ignore
 
-    getColByTitle = (title: string) => {
-        return this.fieldsInfos.filter(col => col.title === title)[0];
-    };
+    getColByTitle = (title: string): Col | undefined => this.fieldsInfos.filter(col => col.title === title)[0];
 
     @action
     assignColsToFields = async (templates: Template[], cols: Col[]): Promise<[Template, { [field: number]: Col }][]> => {
-        const fieldDescriptions: string = this.compileFieldDescriptions(templates);
-        const colDescriptions: string = this.compileColDescriptions(cols);
+        const fieldDescriptions = this.compileFieldDescriptions(templates);
+        const colDescriptions = this.compileColDescriptions(cols);
 
         const inputText = fieldDescriptions.concat(colDescriptions);
 
-        const prompt: string = `(${Math.random() * 100000}) ${inputText}`;
+        const prompt = `(${Math.random() * 100000}) ${inputText}`;
 
         this._GPTLoading = true;
 
@@ -431,23 +397,25 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
 
                 Object.entries(assignments).forEach(([tempTitle, assignment]) => {
                     const template = templates.filter(temp => temp.title === tempTitle)[0];
-                    if (!template) return;
-                    const toObj = Object.entries(assignment).reduce(
-                        (a, [fieldID, colTitle]) => {
-                            const col = this.getColByTitle(colTitle);
-                            if (!col.AIGenerated) {
-                                var field = template.getFieldByID(Number(fieldID));
-                                field.setContent(col.defaultContent ?? '', col.type === TemplateFieldType.VISUAL ? ViewType.IMG : ViewType.TEXT);
-                                field = template.getFieldByID(Number(fieldID));
-                                field.setTitle(col.title);
-                            } else {
-                                a[Number(fieldID)] = this.getColByTitle(colTitle);
-                            }
-                            return a;
-                        },
-                        {} as { [field: number]: Col }
-                    );
-                    brokenDownAssignments.push([template, toObj]);
+                    if (template) {
+                        const toObj = Object.entries(assignment).reduce(
+                            (a, [fieldID, colTitle]) => {
+                                const col = this.getColByTitle(colTitle);
+                                if (col) {
+                                    if (!col.AIGenerated) {
+                                        const field = template.getFieldByID(Number(fieldID));
+                                        field?.setContent(col.defaultContent ?? '', col.type === TemplateFieldType.VISUAL ? ViewType.IMG : ViewType.TEXT);
+                                        field?.setTitle(col.title);
+                                    } else {
+                                        a[Number(fieldID)] = col;
+                                    }
+                                }
+                                return a;
+                            },
+                            {} as { [field: number]: Col }
+                        );
+                        brokenDownAssignments.push([template, toObj]);
+                    }
                 });
 
                 return brokenDownAssignments;
@@ -459,39 +427,32 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
         return [];
     };
 
-    generatePresetTemplates = async () => {
-        const templates: Template[] = [];
-
+    generatePresetTemplates = action(() => {
         if (this.DEBUG_MODE) {
-            templates.push(...this.templateManager.templates);
+            this.setSuggestedTemplates(this.templateManager._templates);
+            this._GPTLoading = false;
         } else {
             this._dataViz?.updateColDefaults();
-
             const contentFields = this.fieldsInfos.filter(field => field.type !== TemplateFieldType.DATA);
-
-            templates.push(...this.templateManager.getValidTemplates(contentFields));
-
-            const assignments = await this.assignColsToFields(templates, contentFields);
-
-            const renderedTemplatePromises = assignments.map(([template, assgns]) => TemplateMenuAIUtils.applyGPTContentToTemplate(template, assgns));
-
-            await Promise.all(renderedTemplatePromises);
+            const templates = this.templateManager.getValidTemplates(contentFields);
+
+            return this.assignColsToFields(templates, contentFields)
+                .then(pairs => 
+                    Promise.all(pairs.map(([templ, assgns]) => TemplateMenuAIUtils.applyGPTContentToTemplate(templ, assgns))))
+                .then(action(() => {
+                    this.setSuggestedTemplates(templates);
+                    this._GPTLoading = false;
+                })); // prettier-ignore
         }
+    });
 
-        setTimeout(
-            action(() => {
-                this.setSuggestedTemplates(templates);
-                this._GPTLoading = false;
-            })
-        );
-    };
-
-    generateVariations = async (onDoc: Doc, prompt: string, options: FireflyStructureOptions): Promise<string[]> => {
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
+    generateVariations = async (onDoc: Doc, prompt: string, options: FireflyStructureOptions) => {
         // const { numVariations, temperature, useStyleRef } = options;
         this.variations = [];
         const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
 
-        const clone: Doc = (await Doc.MakeClone(onDoc)).clone;
+        const clone = Doc.MakeClone(onDoc).clone;
         mainCollection.addDocument(clone);
         clone.x = 10000;
         clone.y = 10000;
@@ -499,13 +460,13 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
         // await DrawingFillHandler.drawingToImage(clone, 100 - temperature, prompt, useStyleRef ? clone : undefined, this, numVariations)
 
         return this.variations;
-    }
+    };
 
-    variations: string[] = []
+    variations: string[] = [];
 
     @action addVariation = (url: string) => {
         this.variations.push(url);
-    }
+    };
 
     addRenderedCollectionToMainview = (collection: Doc) => {
         if (collection) {
@@ -517,10 +478,11 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
         }
     };
 
-    @action editLastTemplate = () => { if (this._editedTemplateTrail.length) this._currEditingTemplate = this._editedTemplateTrail.pop()}
+    @action editLastTemplate = () => {
+        if (this._editedTemplateTrail.length) this._currEditingTemplate = this._editedTemplateTrail.pop();
+    };
 
     @action setExpandedView = (template: Template | undefined) => {
-
         if (template) {
             this._menuContent = 'templateEditing';
             this._currEditingTemplate && this._editedTemplateTrail.push(this._currEditingTemplate);
@@ -533,27 +495,23 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
         //Docs.Create.FreeformDocument([doc], { _height: NumListCast(doc._height)[0], _width: NumListCast(doc._width)[0], title: ''});
     };
 
-    @computed 
-    get templatesView() { return (
-        <div className='docCreatorMenu-templates-view'>
-            <div className="docCreatorMenu-templates-displays">
-                <TemplatePreviewGrid 
-                    title={'Suggested Templates'} 
-                    menu={this} 
-                    loading={this._GPTLoading}
-                    optionsButtonOpts={this.optionsButtonOpts}
-                    templates={this._suggestedTemplates}
-                />
-                <div className="docCreatorMenu-GPT-options">
-                    <div className="docCreatorMenu-GPT-options-container">
-                        <DocCreatorMenuButton icon={'arrows-rotate'} styles={'border'} function={this.generatePresetTemplates}/>
+    @computed
+    get templatesView() {
+        return (
+            <div className="docCreatorMenu-templates-view">
+                <div className="docCreatorMenu-templates-displays">
+                    <TemplatePreviewGrid title={'Suggested Templates'} menu={this} loading={this._GPTLoading} optionsButtonOpts={this.optionsButtonOpts} templates={this._suggestedTemplates} />
+                    <div className="docCreatorMenu-GPT-options">
+                        <div className="docCreatorMenu-GPT-options-container">
+                            <DocCreatorMenuButton icon={'arrows-rotate'} styles={'border'} function={this.generatePresetTemplates} />
+                        </div>
                     </div>
                 </div>
             </div>
-        </div>
-    )};
-    
-    private optionsButtonOpts: [IconProp, () => any] = ['gear', () => (this._menuContent = 'dashboard')];
+        );
+    }
+
+    private optionsButtonOpts: [IconProp, () => void] = ['gear', () => (this._menuContent = 'dashboard')];
 
     get renderSelectedViewType() {
         switch (this._menuContent) {
@@ -634,7 +592,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
                                 {topButton('magnifying-glass', 'options', onOptionsSelected, 'middle')}
                                 {topButton('bars', 'saved', onSavedSelected, 'right')}
                             </div>
-                            <DocCreatorMenuButton icon={'minus'} styles={'float-right'} function={this.closeMenu}/>
+                            <DocCreatorMenuButton icon={'minus'} styles={'float-right'} function={this.closeMenu} />
                         </div>
                         {this.renderSelectedViewType}
                     </div>
@@ -642,4 +600,4 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
             </div>
         );
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx
index b50fff9e0..c35099e82 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx
@@ -1,25 +1,25 @@
-import { action, makeObservable, observable, reaction, runInAction } from "mobx";
-import React from "react";
-import { returnFalse, returnEmptyFilter } from "../../../../../../ClientUtils";
-import { emptyFunction } from "../../../../../../Utils";
-import { Doc, returnEmptyDoclist } from "../../../../../../fields/Doc";
-import { DefaultStyleProvider } from "../../../../StyleProvider";
-import { DocumentView, DocumentViewInternal } from "../../../DocumentView";
-import { DocCreatorMenu } from "../DocCreatorMenu";
-import { TemplatePreviewGrid } from "./TemplatePreviewGrid";
-import { observer } from "mobx-react";
-import { Transform } from "../../../../../util/Transform";
-import { Template } from "../Template";
-import { ObservableReactComponent } from "../../../../ObservableReactComponent";
-import { IDisposer } from "mobx-utils";
-import { DocCreatorMenuButton } from "./DocCreatorMenuButton";
-import { IconProp } from "@fortawesome/fontawesome-svg-core";
+import { action, makeObservable, observable, reaction } from 'mobx';
+import React from 'react';
+import { returnFalse, returnEmptyFilter } from '../../../../../../ClientUtils';
+import { emptyFunction } from '../../../../../../Utils';
+import { returnEmptyDoclist } from '../../../../../../fields/Doc';
+import { DefaultStyleProvider } from '../../../../StyleProvider';
+import { DocumentView, DocumentViewInternal } from '../../../DocumentView';
+import { DocCreatorMenu } from '../DocCreatorMenu';
+import { TemplatePreviewGrid } from './TemplatePreviewGrid';
+import { observer } from 'mobx-react';
+import { Transform } from '../../../../../util/Transform';
+import { Template } from '../Template';
+import { ObservableReactComponent } from '../../../../ObservableReactComponent';
+import { IDisposer } from 'mobx-utils';
+import { DocCreatorMenuButton } from './DocCreatorMenuButton';
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
 
 export type FireflyStructureOptions = {
     numVariations: number;
     temperature: number;
     useStyleRef: boolean;
-}
+};
 
 interface FireflyVariationsTabProps {
     menu: DocCreatorMenu;
@@ -28,112 +28,93 @@ interface FireflyVariationsTabProps {
 
 @observer
 export class FireflyVariationsTab extends ObservableReactComponent<FireflyVariationsTabProps> {
+    private _prompt: string = 'Use this template to generate an empty baseball card template.';
+    private _optionsButtonOpts: [IconProp, () => void] = ['gear', emptyFunction];
+    private _previewBoxRightButtonOpts: [IconProp, () => void] = ['gear', () => this.forceUpdate()];
 
-    private prompt: string = 'Use this template to generate an empty baseball card template.';
-
-    @observable private promptInput: HTMLTextAreaElement | null = null;
-
+    @observable _fireflyOptions: FireflyStructureOptions = { numVariations: 3, temperature: 0, useStyleRef: false };
+    @observable _promptInput: HTMLTextAreaElement | null = null;
     @observable _loading: boolean = false;
     @observable _variationsTabOpen: boolean = false;
     @observable _variationURLs: string[] = [];
 
-    @observable private fireflyOptions: FireflyStructureOptions = {numVariations: 3, temperature: 0, useStyleRef: false};
-
     constructor(props: FireflyVariationsTabProps) {
         super(props);
         makeObservable(this);
     }
 
-    generateVariations = async () => {
+    generateVariations = action(async () => {
         this._props.menu._variations = [];
         this._loading = true;
         const cloneTemplate = this._props.template.clone(false);
         cloneTemplate.setMatteBackground();
-        const doc: Doc = cloneTemplate.getRenderedDoc()!;
-        this._variationURLs = await this._props.menu.generateVariations(doc, this.prompt, this.fireflyOptions);
-        this._variationURLs.forEach(() => {
-            const newTemplate: Template = this._props.template.clone(true);
-            this._props.menu._variations.push(newTemplate);
-        });
-        setTimeout(() => {
-            this._variationURLs.forEach((url, i) => {
-                this._props.menu._variations[i].setImageAsBackground(url, true);
-            });
-            this._loading = false;
-        });
-    }
-
-    setPromptInputRef: React.LegacyRef<HTMLTextAreaElement> = (node) => {
-        this.promptInput = node;
-    }
-
-    // eslint-disable-next-line
-    private optionsButtonOpts: [IconProp, () => any] = ['gear', () => {}];
-    // eslint-disable-next-line
-    private previewBoxRightButtonOpts: [IconProp, () => any] = ['gear', () => this.forceUpdate()];
+        const doc = cloneTemplate.getRenderedDoc()!;
+        this._props.menu.generateVariations(doc, this._prompt, this._fireflyOptions).then(
+            action((urls: string[]) => {
+                (this._variationURLs = urls).forEach(url => {
+                    const template = this._props.template.clone(true);
+                    template.setImageAsBackground(url, true);
+                    this._props.menu._variations.push(template);
+                });
+                this._loading = false;
+            })
+        );
+    });
 
     render() {
         return (
-            <div className='docCreatorMenu-editing-firefly-section'>
-                <div className="docCreatorMenu-option-divider full no-margin-bottom"/>
+            <div className="docCreatorMenu-editing-firefly-section">
+                <div className="docCreatorMenu-option-divider full no-margin-bottom" />
                 <TemplatePreviewGrid
                     menu={this._props.menu}
-                    title={'Generate Variations'}
+                    title="Generate Variations"
                     loading={this._loading}
-                    styles={'scrolling'}
+                    styles="scrolling"
                     templates={this._props.menu._variations}
-                    optionsButtonOpts={this.optionsButtonOpts}
-                    previewBoxRightButtonOpts={this.previewBoxRightButtonOpts}
+                    optionsButtonOpts={this._optionsButtonOpts}
+                    previewBoxRightButtonOpts={this._previewBoxRightButtonOpts}
                 />
                 <div className="docCreatorMenu-firefly-options">
                     <div className="docCreatorMenu-variation-prompt-row">
                         <textarea
                             className="docCreatorMenu-variation-prompt-input-textbox"
-                            ref={this.setPromptInputRef}
-                            onChange={e => { this.prompt = e.target.value }}
+                            ref={action((node: HTMLTextAreaElement | null) => (this._promptInput = node))}
+                            onChange={e => (this._prompt = e.target.value)}
                             onInput={() => {
-                                if (this.promptInput !== null) {
-                                    this.promptInput.style.height = 'auto';
-                                    this.promptInput.style.height = this.promptInput.scrollHeight + 'px';
+                                if (this._promptInput !== null) {
+                                    this._promptInput.style.height = 'auto';
+                                    this._promptInput.style.height = this._promptInput.scrollHeight + 'px';
                                 }
                             }}
-                            defaultValue={''}
-                            placeholder={'Enter a custom prompt here (optional)'}
+                            defaultValue=""
+                            placeholder="Enter a custom prompt here (optional)"
                         />
-                        <DocCreatorMenuButton icon={'arrows-rotate'} styles={'border'} function={this.generateVariations}/>
+                        <DocCreatorMenuButton icon={'arrows-rotate'} styles={'border'} function={this.generateVariations} />
                     </div>
-                        <nav className="options‑menu">
-                            <label className="menu‑item switch">
-                                <input type="checkbox" checked={this.fireflyOptions.useStyleRef} 
-                                    onChange={(e) => runInAction(() => { this.fireflyOptions.useStyleRef = e.target.checked })}
-                                />
-                                <span className="slider round"></span>
-                                <span className="firefly-option-label">Use template as style guide</span>
-                            </label>
-                            <div className="menu‑item">
-                                <span className="firefly-option-label">Variations</span>
-                                <input type="range" id="variations" 
-                                    min="1" 
-                                    max="5" 
-                                    value={this.fireflyOptions.numVariations} 
-                                    onChange={(e) => runInAction(() => { this.fireflyOptions.numVariations = Number(e.target.value) })}
-                                />
-                                <span className="value" id="varVal">{this.fireflyOptions.numVariations}</span>
-                            </div>
-                            <div className="menu‑item">
-                                <span className="firefly-option-label">Temperature</span>
-                                <input type="range" id="temperature" 
-                                    min="1" 
-                                    max="100" 
-                                    value={this.fireflyOptions.temperature} 
-                                    onChange={(e) => runInAction(() => { this.fireflyOptions.temperature = Number(e.target.value) })}
-                                />
-                                <span className="value" id="tempVal">{this.fireflyOptions.temperature}</span>
-                            </div>
-                        </nav>
+                    <nav className="options‑menu">
+                        <label className="menu‑item switch">
+                            <input type="checkbox" checked={this._fireflyOptions.useStyleRef} onChange={action(e => (this._fireflyOptions.useStyleRef = e.target.checked))} />
+                            <span className="slider round"></span>
+                            <span className="firefly-option-label">Use template as style guide</span>
+                        </label>
+                        <div className="menu‑item">
+                            <span className="firefly-option-label">Variations</span>
+                            <input type="range" id="variations" min="1" max="5" value={this._fireflyOptions.numVariations} onChange={action(e => (this._fireflyOptions.numVariations = Number(e.target.value)))} />
+                            <span className="value" id="varVal">
+                                {this._fireflyOptions.numVariations}
+                            </span>
+                        </div>
+                        <div className="menu‑item">
+                            <span className="firefly-option-label">Temperature</span>
+                            <input type="range" id="temperature" min="1" max="100" value={this._fireflyOptions.temperature} onChange={action(e => (this._fireflyOptions.temperature = Number(e.target.value)))} />
+                            <span className="value" id="tempVal">
+                                {this._fireflyOptions.temperature}
+                            </span>
+                        </div>
+                    </nav>
                 </div>
             </div>
-        )
+        );
     }
 }
 
@@ -144,11 +125,9 @@ interface TemplateEditingWindowProps {
 
 @observer
 export class TemplateEditingWindow extends ObservableReactComponent<TemplateEditingWindowProps> {
-
     private disposers: { [name: string]: IDisposer } = {};
 
-    @observable private previewWindow: HTMLDivElement | null = null;
-
+    @observable private _previewWindow: HTMLDivElement | null = null;
     @observable _variationsTabOpen: boolean = false;
 
     constructor(props: TemplateEditingWindowProps) {
@@ -157,83 +136,85 @@ export class TemplateEditingWindow extends ObservableReactComponent<TemplateEdit
     }
 
     componentDidMount(): void {
-        this.disposers.windowDimensions = reaction(() => 
-            this._props.menu._resizing, 
-            () => { this.forceUpdate() }, 
+        this.disposers.windowDimensions = reaction(
+            () => this._props.menu._resizing,
+            () => this.forceUpdate(),
             { fireImmediately: true }
-            );
+        );
     }
 
     componentWillUnmount() {
         Object.values(this.disposers).forEach(disposer => disposer?.());
     }
 
-    setContainerRef: React.LegacyRef<HTMLDivElement> = (node) => {
-        this.previewWindow = node;
-    }
-
     @action setVariationTab = (open: boolean) => {
         this._variationsTabOpen = open;
-        if (this.previewWindow && open) {
-            this.previewWindow.style.height = String(Number(this.previewWindow.clientHeight) * .6);
-        } else if (this.previewWindow && !open) {
-            this.previewWindow.style.height = String(Number(this.previewWindow.clientHeight) * 5/3);
+        if (this._previewWindow && open) {
+            this._previewWindow.style.height = String(Number(this._previewWindow.clientHeight) * 0.6);
+        } else if (this._previewWindow && !open) {
+            this._previewWindow.style.height = String((Number(this._previewWindow.clientHeight) * 5) / 3);
         }
-    }
-   
-    get renderedDocPreview(){
-        const doc: Doc = this._props.template.getRenderedDoc() as unknown as Doc;
+    };
 
+    previewPanelWidth = () => this._previewWindow?.clientWidth ?? 500;
+    previewPanelHeight = () => this._previewWindow?.clientHeight ?? 500;
+    previewScreenToLocalXf = () => new Transform(-this._props.menu._pageX - 5, -this._props.menu._pageY - 35, 1);
+    get renderedDocPreview() {
+        const doc = this._props.template.getRenderedDoc();
         return (
-            <div className="docCreatorMenu-expanded-template-preview" ref={this.setContainerRef}>
-                {this.previewWindow ? <DocumentView
-                    Document={doc}
-                    isContentActive={emptyFunction}
-                    addDocument={returnFalse}
-                    moveDocument={returnFalse}
-                    removeDocument={returnFalse}
-                    PanelWidth={() => this.previewWindow?.clientWidth ?? 500}
-                    PanelHeight={() => this.previewWindow?.clientHeight ?? 500}
-                    ScreenToLocalTransform={() => new Transform(-this._props.menu._pageX - 5, -this._props.menu._pageY - 35, 1)}
-                    renderDepth={5}
-                    whenChildContentsActiveChanged={emptyFunction}
-                    focus={emptyFunction}
-                    styleProvider={DefaultStyleProvider}
-                    addDocTab={DocumentViewInternal.addDocTabFunc}
-                    pinToPres={() => undefined}
-                    childFilters={returnEmptyFilter}
-                    childFiltersByRanges={returnEmptyFilter}
-                    searchFilterDocs={returnEmptyDoclist}
-                    fitContentsToBox={returnFalse}
-                    fitWidth={returnFalse}
-                /> : null}
+            <div className="docCreatorMenu-expanded-template-preview" ref={action((node: HTMLDivElement | null) => (this._previewWindow = node))}>
+                {this._previewWindow && doc ? (
+                    <DocumentView
+                        Document={doc}
+                        isContentActive={emptyFunction}
+                        addDocument={returnFalse}
+                        moveDocument={returnFalse}
+                        removeDocument={returnFalse}
+                        PanelWidth={this.previewPanelWidth}
+                        PanelHeight={this.previewPanelHeight}
+                        ScreenToLocalTransform={this.previewScreenToLocalXf}
+                        renderDepth={5}
+                        whenChildContentsActiveChanged={emptyFunction}
+                        focus={emptyFunction}
+                        styleProvider={DefaultStyleProvider}
+                        addDocTab={DocumentViewInternal.addDocTabFunc}
+                        pinToPres={emptyFunction}
+                        childFilters={returnEmptyFilter}
+                        childFiltersByRanges={returnEmptyFilter}
+                        searchFilterDocs={returnEmptyDoclist}
+                        // fitContentsToBox={returnFalse}
+                        // fitWidth={returnFalse}
+                    />
+                ) : null}
             </div>
-        )
+        );
     }
 
+    expandFunc = () => {
+        // if (this._props.template === this._props.menu._selectedTemplate) {
+        //     this._props.menu.updateRenderedPreviewCollection(this._props.template);
+        // }
+        this._props.menu.setExpandedView(undefined);
+    };
+    lastFunc = () => {
+        this._props.menu.editLastTemplate();
+        this.forceUpdate();
+    };
+    variationFunc = () => this.setVariationTab(!this._variationsTabOpen);
     render() {
         return (
-            <div className='docCreatorMenu-templates-view'>
+            <div className="docCreatorMenu-templates-view">
                 <div className="docCreatorMenu-expanded-template-preview">
-                    <div className="top-panel"/>
+                    <div className="top-panel" />
                     {this.renderedDocPreview}
-                    {this._variationsTabOpen ? <FireflyVariationsTab
-                        menu={this._props.menu}
-                        template={this._props.template}
-                    />
-                     : null}
+                    {this._variationsTabOpen ? <FireflyVariationsTab menu={this._props.menu} template={this._props.template} /> : null}
                     <div className="right-buttons-panel">
-                        <DocCreatorMenuButton icon={'minimize'} function={() => {
-                                // if (this._props.template === this._props.menu._selectedTemplate) {
-                                //     this._props.menu.updateRenderedPreviewCollection(this._props.template);
-                                // }
-                                this._props.menu.setExpandedView(undefined);
-                            }}/>
-                        <DocCreatorMenuButton icon={'lightbulb'} function={() => this.setVariationTab(!this._variationsTabOpen)}/>
-                        <DocCreatorMenuButton icon={'arrow-rotate-backward'} function={() => { this._props.menu.editLastTemplate(); this.forceUpdate(); }}/>
+                        <DocCreatorMenuButton icon="minimize" function={this.expandFunc} />
+                        <DocCreatorMenuButton icon="lightbulb" function={this.variationFunc} />
+                        <DocCreatorMenuButton icon="arrow-rotate-backward" function={this.lastFunc} />
                     </div>
                 </div>
             </div>
         );
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateMenuFieldOptions.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateMenuFieldOptions.tsx
index a4da54392..f0e20837c 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateMenuFieldOptions.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateMenuFieldOptions.tsx
@@ -1,11 +1,11 @@
-import { makeObservable, observable, runInAction } from "mobx";
-import { observer } from "mobx-react";
-import { ObservableReactComponent } from "../../../../ObservableReactComponent";
-import { Col, DocCreatorMenu } from "../DocCreatorMenu";
-import React from "react";
-import { Conditional, TemplateManager } from "../Backend/TemplateManager";
-import { TemplateFieldType, TemplateFieldSize } from "../TemplateBackend";
-import { DocCreatorMenuButton } from "./DocCreatorMenuButton";
+import { action, makeObservable, observable } from 'mobx';
+import { observer } from 'mobx-react';
+import { ObservableReactComponent } from '../../../../ObservableReactComponent';
+import { Col, DocCreatorMenu } from '../DocCreatorMenu';
+import React from 'react';
+import { Conditional, TemplateManager } from '../Backend/TemplateManager';
+import { TemplateFieldType, TemplateFieldSize } from '../TemplateBackend';
+import { DocCreatorMenuButton } from './DocCreatorMenuButton';
 
 interface TemplateMenuFieldOptionsProps {
     menu: DocCreatorMenu;
@@ -14,7 +14,6 @@ interface TemplateMenuFieldOptionsProps {
 
 @observer
 export class TemplateMenuFieldOptions extends ObservableReactComponent<TemplateMenuFieldOptionsProps> {
-
     @observable _collapsedCols: string[] = []; //any columns whose options panels are hidden
 
     constructor(props: TemplateMenuFieldOptionsProps) {
@@ -34,160 +33,153 @@ export class TemplateMenuFieldOptions extends ObservableReactComponent<TemplateM
                 condition: '',
                 target: 'Own',
                 attribute: '',
-                value: ''
+                value: '',
             });
         }
         return this._newCondCache[title];
     };
 
     conditionForm = (title: string, parameters?: Conditional, empty: boolean = false) => {
-
-        const contentFieldTitles = this._props.menu.fieldsInfos.filter(field => field.type !== TemplateFieldType.DATA).map(field => field.title).concat('Template');
+        const contentFieldTitles = this._props.menu.fieldsInfos
+            .filter(field => field.type !== TemplateFieldType.DATA)
+            .map(field => field.title)
+            .concat('Template');
         const params: Conditional = this.getParams(title, parameters);
 
         return (
-        <div className='form'>
-            <div className='form-row'>
-                <div className='form-row-plain-text'>If</div>
-                <div className='form-row-plain-text'>{title}</div>
-                <div className="operator-options-dropdown">
-                    <span className="operator-dropdown-current">{params.operator ?? '='}</span>
-                    <div className='operator-dropdown-option' onPointerDown={() => {params.operator = '='}}>{'='}</div>
-                </div>
-                <input
-                    className="form-row-textarea"
-                    onChange={e => runInAction(() => { params.condition = e.target.value })}
-                    placeholder='value'
-                    value={params.condition}
-                />
-                <div className='form-row-plain-text'>then</div>
-                <div className="operator-options-dropdown">
-                    <span className="operator-dropdown-current">{params.target ?? 'Own'}</span>
-                    {contentFieldTitles.map((fieldTitle, i) => 
-                        <div className='operator-dropdown-option' key={i} onPointerDown={() => {params.target = fieldTitle}}>{fieldTitle === title ? 'Own' : fieldTitle}</div>
-                    )}
+            <div className="form">
+                <div className="form-row">
+                    <div className="form-row-plain-text">If</div>
+                    <div className="form-row-plain-text">{title}</div>
+                    <div className="operator-options-dropdown">
+                        <span className="operator-dropdown-current">{params.operator ?? '='}</span>
+                        <div className="operator-dropdown-option" onPointerDown={() => (params.operator = '=')}>
+                            {'='}
+                        </div>
+                    </div>
+                    <input className="form-row-textarea" onChange={action(e => (params.condition = e.target.value))} placeholder="value" value={params.condition} />
+                    <div className="form-row-plain-text">then</div>
+                    <div className="operator-options-dropdown">
+                        <span className="operator-dropdown-current">{params.target ?? 'Own'}</span>
+                        {contentFieldTitles.map((fieldTitle, i) => (
+                            <div className="operator-dropdown-option" key={i} onPointerDown={() => (params.target = fieldTitle)}>
+                                {fieldTitle === title ? 'Own' : fieldTitle}
+                            </div>
+                        ))}
+                    </div>
+                    <input className="form-row-textarea" onChange={action(e => (params.attribute = e.target.value))} placeholder="attribute" value={params.attribute} />
+                    <div className="form-row-plain-text">{'becomes'}</div>
+                    <input className="form-row-textarea" onChange={action(e => (params.value = e.target.value))} placeholder="value" value={params.value} />
                 </div>
-                <input
-                    className="form-row-textarea"
-                    onChange={e => runInAction(() => { params.attribute = e.target.value })}
-                    placeholder='attribute'
-                    value={params.attribute}
-                />
-                <div className='form-row-plain-text'>{'becomes'}</div>
-                <input
-                    className="form-row-textarea"
-                    onChange={e => runInAction(() => { params.value = e.target.value })}
-                    placeholder='value'
-                    value={params.value}
-                />
+                {empty ? (
+                    <DocCreatorMenuButton
+                        icon={'plus'}
+                        styles={'float-right border'}
+                        function={() => {
+                            this._newCondCache[title] = observable<Conditional>({
+                                field: title,
+                                operator: '=',
+                                condition: '',
+                                target: 'Own',
+                                attribute: '',
+                                value: '',
+                            });
+                            this._props.templateManager.addFieldCondition(title, params);
+                        }}
+                    />
+                ) : (
+                    <DocCreatorMenuButton icon={'minus'} styles={'float-right border'} function={() => this._props.templateManager.removeFieldCondition(title, params)} />
+                )}
             </div>
-            {empty ? 
-            <DocCreatorMenuButton icon={'plus'} styles={'float-right border'} function={() => {
-                this._newCondCache[title] = observable<Conditional>({
-                    field: title,
-                    operator: '=',
-                    condition: '',
-                    target: 'Own',
-                    attribute: '',
-                    value: ''
-                });
-                this._props.templateManager.addFieldCondition(title, params);
-            }}/>
-            :
-            <DocCreatorMenuButton icon={'minus'} styles={'float-right border'} function={() => this._props.templateManager.removeFieldCondition(title, params)}/>
-            }
-        </div>
-        )
-    }
+        );
+    };
 
     fieldPanel = (field: Col, id: number) => (
         <div className="field-panel" key={id}>
-            <div className="top-bar" onPointerDown={e => this._props.menu.setUpButtonClick(e, runInAction(() => () => {
-                if (this._collapsedCols.includes(field.title)) {
-                    this._collapsedCols = this._collapsedCols.filter(col => col !== field.title);
-                } else {
-                    this._collapsedCols.push(field.title);
-                }
-            }))}>
+            <div
+                className="top-bar"
+                onPointerDown={e =>
+                    this._props.menu.setUpButtonClick(
+                        e,
+                        action(() => {
+                            if (this._collapsedCols.includes(field.title)) {
+                                this._collapsedCols = this._collapsedCols.filter(col => col !== field.title);
+                            } else {
+                                this._collapsedCols.push(field.title);
+                            }
+                        })
+                    )
+                }>
                 <span className="field-title">{`${field.title} Field`}</span>
-                <DocCreatorMenuButton icon={'minus'} styles={'no-margin absolute-right'} function={() => this._props.menu.removeField(field)}/>
+                <DocCreatorMenuButton icon={'minus'} styles={'no-margin absolute-right'} function={() => this._props.menu.removeField(field)} />
             </div>
-            { this._collapsedCols.includes(field.title) ? null :
+            {this._collapsedCols.includes(field.title) ? null : (
                 <>
-                <div className="opts-bar">
-                    <div className="opt-box">
-                        <div className="top-bar"> Title </div>
-                        <textarea className="content" style={{ width: '100%', height: 'calc(100% - 20px)' }} value={field.title} placeholder={'Enter title'} onChange={e => this._props.menu.setColTitle(field, e.target.value)} />
-                    </div>
-                    <div className="opt-box">
-                        <div className="top-bar"> Type </div>
-                        <div className="content">
-                            <span className="type-display">{
-                                field.type === TemplateFieldType.TEXT ? 'Text Field' 
-                                : field.type === TemplateFieldType.VISUAL ? 'File Field' 
-                                : field.type === TemplateFieldType.DATA ? 'Data Field' 
-                                : ''
-                            }</span>
-                            <div className="bubbles">
-                                <input className="bubble" type="radio" name="type" onClick={() => this._props.menu.setColType(field, TemplateFieldType.TEXT)} />
-                                <div className="text">Text</div>
-                                <input className="bubble" type="radio" name="type" onClick={() => this._props.menu.setColType(field, TemplateFieldType.VISUAL)} />
-                                <div className="text">File</div>
-                                <input className="bubble" type="radio" name="type" onClick={() => this._props.menu.setColType(field, TemplateFieldType.DATA)} />
-                                <div className="text">Data</div>
-                            </div>
+                    <div className="opts-bar">
+                        <div className="opt-box">
+                            <div className="top-bar"> Title </div>
+                            <textarea className="content" style={{ width: '100%', height: 'calc(100% - 20px)' }} value={field.title} placeholder={'Enter title'} onChange={e => this._props.menu.setColTitle(field, e.target.value)} />
                         </div>
-                    </div>
-                </div>
-                { field.type === TemplateFieldType.DATA ? null :
-                    (<> 
-                        <div className="sizes-box">
-                            <div className="top-bar"> Valid Sizes </div>
+                        <div className="opt-box">
+                            <div className="top-bar"> Type </div>
                             <div className="content">
+                                <span className="type-display">{field.type === TemplateFieldType.TEXT ? 'Text Field' : field.type === TemplateFieldType.VISUAL ? 'File Field' : field.type === TemplateFieldType.DATA ? 'Data Field' : ''}</span>
                                 <div className="bubbles">
-                                    {Object.values(TemplateFieldSize).map(size => (
-                                        <div key={field + size}>
-                                            <input className="bubble" type="checkbox" name="type" checked={field.sizes.includes(size)} onChange={e => this._props.menu.modifyColSizes(field, size, e.target.checked)} />
-                                            <div className="text">{size}</div>
-                                        </div>
-                                    ))}
+                                    <input className="bubble" type="radio" name="type" onClick={() => this._props.menu.setColType(field, TemplateFieldType.TEXT)} />
+                                    <div className="text">Text</div>
+                                    <input className="bubble" type="radio" name="type" onClick={() => this._props.menu.setColType(field, TemplateFieldType.VISUAL)} />
+                                    <div className="text">File</div>
+                                    <input className="bubble" type="radio" name="type" onClick={() => this._props.menu.setColType(field, TemplateFieldType.DATA)} />
+                                    <div className="text">Data</div>
                                 </div>
                             </div>
                         </div>
-                        <div className="desc-box">
-                            <div className="top-bar"> Prompt </div>
-                            <textarea
-                                className="content"
-                                onChange={e => this._props.menu.setColDesc(field, e.target.value)}
-                                defaultValue={field.desc === this._props.menu._dataViz?.GPTSummary?.get(field.title)?.desc ? '' : field.desc}
-                                placeholder={this._props.menu._dataViz?.GPTSummary?.get(field.title)?.desc ?? 'Add a description/prompt to help with template generation.'}
-                            />
-                        </div> 
-                    </>)
-                }
-                <div className="conditionals-section">
-                    <span className="conditionals-title">Conditional Logic</span>
-                    {this.conditionForm(field.title, undefined, true)}
-                    {this._props.templateManager.conditionalFieldLogic[field.title]?.map(condition => this.conditionForm(condition.field, condition))}
-                </div>
+                    </div>
+                    {field.type === TemplateFieldType.DATA ? null : (
+                        <>
+                            <div className="sizes-box">
+                                <div className="top-bar"> Valid Sizes </div>
+                                <div className="content">
+                                    <div className="bubbles">
+                                        {Object.values(TemplateFieldSize).map(size => (
+                                            <div key={field + size}>
+                                                <input className="bubble" type="checkbox" name="type" checked={field.sizes.includes(size)} onChange={e => this._props.menu.modifyColSizes(field, size, e.target.checked)} />
+                                                <div className="text">{size}</div>
+                                            </div>
+                                        ))}
+                                    </div>
+                                </div>
+                            </div>
+                            <div className="desc-box">
+                                <div className="top-bar"> Prompt </div>
+                                <textarea
+                                    className="content"
+                                    onChange={e => this._props.menu.setColDesc(field, e.target.value)}
+                                    defaultValue={field.desc === this._props.menu._dataViz?.GPTSummary?.get(field.title)?.desc ? '' : field.desc}
+                                    placeholder={this._props.menu._dataViz?.GPTSummary?.get(field.title)?.desc ?? 'Add a description/prompt to help with template generation.'}
+                                />
+                            </div>
+                        </>
+                    )}
+                    <div className="conditionals-section">
+                        <span className="conditionals-title">Conditional Logic</span>
+                        {this.conditionForm(field.title, undefined, true)}
+                        {this._props.templateManager._conditionalFieldLogic[field.title]?.map(condition => this.conditionForm(condition.field, condition))}
+                    </div>
                 </>
-            }
+            )}
         </div>
     );
 
-
-
     render() {
         return (
             <div className="docCreatorMenu-dashboard-view">
                 <div className="topbar">
-                    <DocCreatorMenuButton icon={'plus'} function={this._props.menu.addField}/>
-                    <DocCreatorMenuButton icon={'arrow-left'} styles={'float-right'} function={() => runInAction(() => (this._props.menu._menuContent = 'templates'))}/>
+                    <DocCreatorMenuButton icon="plus" function={this._props.menu.addField} />
+                    <DocCreatorMenuButton icon="arrow-left" styles="float-right" function={action(() => (this._props.menu._menuContent = 'templates'))} />
                 </div>
                 <div className="panels-container">{this._props.menu.fieldsInfos.map((field, i) => this.fieldPanel(field, i))}</div>
             </div>
         );
     }
-
-
-}
\ No newline at end of file
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewBox.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewBox.tsx
index dc4c35789..7d02fff12 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplatePreviewBox.tsx
@@ -1,35 +1,30 @@
-import { Colors } from "@dash/components/src";
-import { FontAwesomeIcon} from "@fortawesome/react-fontawesome";
-import { Template } from "../Template";
-import { makeObservable, observable } from "mobx";
-import React from "react";
-import { ObservableReactComponent } from "../../../../ObservableReactComponent";
-import { DocCreatorMenu } from "../DocCreatorMenu";
-import { IconProp } from "@fortawesome/fontawesome-svg-core";
-import { DocumentView } from "../../../DocumentView";
-import { emptyFunction } from "../../../../../../Utils";
-import { returnEmptyFilter, returnFalse } from "../../../../../../ClientUtils";
-import { Transform } from "../../../../../util/Transform";
-import { DefaultStyleProvider } from "../../../../StyleProvider";
-import { Doc, returnEmptyDoclist } from "../../../../../../fields/Doc";
-import { observer } from "mobx-react";
+import { Colors } from '@dash/components/src';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Template } from '../Template';
+import { action, makeObservable, observable } from 'mobx';
+import React from 'react';
+import { ObservableReactComponent } from '../../../../ObservableReactComponent';
+import { DocCreatorMenu } from '../DocCreatorMenu';
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
+import { DocumentView } from '../../../DocumentView';
+import { emptyFunction } from '../../../../../../Utils';
+import { returnEmptyFilter, returnFalse } from '../../../../../../ClientUtils';
+import { Transform } from '../../../../../util/Transform';
+import { DefaultStyleProvider } from '../../../../StyleProvider';
+import { Doc, returnEmptyDoclist } from '../../../../../../fields/Doc';
+import { observer } from 'mobx-react';
 
 export interface TemplatePreviewBoxProps {
     template: Template;
     menu: DocCreatorMenu; // eslint-disable-next-line
-    leftButtonOpts?: [icon: IconProp, func: (...args: any) => void] // eslint-disable-next-line
-    rightButtonOpts?: [icon: IconProp, func: (...args: any) => void]
+    leftButtonOpts?: [icon: IconProp, func: (...args: any) => void]; // eslint-disable-next-line
+    rightButtonOpts?: [icon: IconProp, func: (...args: any) => void];
 }
 
 @observer
 export class TemplatePreviewBox extends ObservableReactComponent<TemplatePreviewBoxProps> {
-
     @observable private previewWindow: HTMLDivElement | null = null;
 
-    setContainerRef: React.LegacyRef<HTMLDivElement> = (node) => {
-        this.previewWindow = node;
-    }
-
     constructor(props: TemplatePreviewBoxProps) {
         super(props);
         makeObservable(this);
@@ -39,6 +34,10 @@ export class TemplatePreviewBox extends ObservableReactComponent<TemplatePreview
         return this._props.template.getRenderedDoc() as Doc;
     }
 
+    docPanelWidth = () => this.previewWindow?.clientWidth ?? this._props.menu._menuDimensions.height * 0.3;
+    docPanelHeight = () => this.previewWindow?.clientHeight ?? this._props.menu._menuDimensions.height * 0.3;
+    docScreenToLocalXf = () => new Transform(-this._props.menu._pageX - 5, -this._props.menu._pageY - 35, 1);
+
     render() {
         const template = this._props.template;
 
@@ -46,49 +45,45 @@ export class TemplatePreviewBox extends ObservableReactComponent<TemplatePreview
             <div
                 key={template.title}
                 className="docCreatorMenu-preview-window"
-                ref={this.setContainerRef}
+                ref={action((node: HTMLDivElement | null) => (this.previewWindow = node))}
                 style={{
                     border: this._props.menu._selectedTemplate === template ? `solid 3px ${Colors.MEDIUM_BLUE}` : '',
                     boxShadow: this._props.menu._selectedTemplate === template ? `0 0 15px rgba(68, 118, 247, .8)` : '',
                 }}
-                onPointerDown={e => this._props.menu.setUpButtonClick(e, () => this._props.menu.updateSelectedTemplate(template))}
-                >
-                    { this._props.leftButtonOpts ? 
-                    <button
-                        className="option-button left"
-                        onPointerDown={e =>
-                            this._props.menu.setUpButtonClick(e, () => this._props.leftButtonOpts![1](template))
-                        }>
+                onPointerDown={e => this._props.menu.setUpButtonClick(e, () => this._props.menu.updateSelectedTemplate(template))}>
+                {this._props.leftButtonOpts ? (
+                    <button className="option-button left" onPointerDown={e => this._props.menu.setUpButtonClick(e, () => this._props.leftButtonOpts![1](template))}>
                         <FontAwesomeIcon icon={this._props.leftButtonOpts![0]} color="white" />
-                    </button> : null
-                    }
-                    { this._props.rightButtonOpts ? 
+                    </button>
+                ) : null}
+                {this._props.rightButtonOpts ? (
                     <button className="option-button right" onPointerDown={e => this._props.menu.setUpButtonClick(e, () => this._props.rightButtonOpts![1](template))}>
                         <FontAwesomeIcon icon={this._props.rightButtonOpts![0]} color="white" />
-                    </button> : null }
-                    <DocumentView
-                        Document={this.doc}
-                        isContentActive={emptyFunction} // !!! should be return false
-                        addDocument={returnFalse}
-                        moveDocument={returnFalse}
-                        removeDocument={returnFalse}
-                        PanelWidth={() => this.previewWindow?.clientWidth ?? this._props.menu._menuDimensions.height * .3}
-                        PanelHeight={() => this.previewWindow?.clientHeight ?? this._props.menu._menuDimensions.height * .3}
-                        ScreenToLocalTransform={() => new Transform(-this._props.menu._pageX - 5, -this._props.menu._pageY - 35, 1)}
-                        renderDepth={1}
-                        whenChildContentsActiveChanged={emptyFunction}
-                        focus={emptyFunction}
-                        styleProvider={DefaultStyleProvider}
-                        addDocTab={this._props.menu._props.addDocTab}
-                        pinToPres={() => undefined}
-                        childFilters={returnEmptyFilter}
-                        childFiltersByRanges={returnEmptyFilter}
-                        searchFilterDocs={returnEmptyDoclist}
-                        fitContentsToBox={returnFalse}
-                        fitWidth={returnFalse}
-                        hideDecorations={true}
-                    />
+                    </button>
+                ) : null}
+                <DocumentView
+                    Document={this.doc}
+                    isContentActive={emptyFunction} // !!! should be return false
+                    addDocument={returnFalse}
+                    moveDocument={returnFalse}
+                    removeDocument={returnFalse}
+                    PanelWidth={this.docPanelWidth}
+                    PanelHeight={this.docPanelHeight}
+                    ScreenToLocalTransform={this.docScreenToLocalXf}
+                    renderDepth={1}
+                    whenChildContentsActiveChanged={emptyFunction}
+                    focus={emptyFunction}
+                    styleProvider={DefaultStyleProvider}
+                    addDocTab={this._props.menu._props.addDocTab}
+                    pinToPres={emptyFunction}
+                    childFilters={returnEmptyFilter}
+                    childFiltersByRanges={returnEmptyFilter}
+                    searchFilterDocs={returnEmptyDoclist}
+                    // fitContentsToBox={returnFalse}
+                    // fitWidth={returnFalse}
+                    hideDecorations={true}
+                />
             </div>
-        )
+        );
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateRenderPreviewWindow.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateRenderPreviewWindow.tsx
index f281f770e..9222d7349 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateRenderPreviewWindow.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateRenderPreviewWindow.tsx
@@ -1,20 +1,20 @@
-import { action, computed, makeObservable, observable, runInAction } from "mobx";
-import { observer } from "mobx-react";
-import { ObservableReactComponent } from "../../../../ObservableReactComponent";
-import { DocCreatorMenu, LayoutType } from "../DocCreatorMenu";
-import React from "react";
-import { IconProp } from "@fortawesome/fontawesome-svg-core";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { setupMoveUpEvents, returnFalse, returnEmptyFilter } from "../../../../../../ClientUtils";
-import { emptyFunction } from "../../../../../../Utils";
-import { undoable } from "../../../../../util/UndoManager";
-import ReactLoading from "react-loading";
-import { Doc, NumListCast, returnEmptyDoclist } from "../../../../../../fields/Doc";
-import { StrCast } from "../../../../../../fields/Types";
-import { DefaultStyleProvider } from "../../../../StyleProvider";
-import { DocumentView } from "../../../DocumentView";
-import { Transform } from "../../../../../util/Transform";
-import { Docs, DocumentOptions } from "../../../../../documents/Documents";
+import { action, computed, makeObservable, observable, runInAction } from 'mobx';
+import { observer } from 'mobx-react';
+import { ObservableReactComponent } from '../../../../ObservableReactComponent';
+import { DocCreatorMenu, LayoutType } from '../DocCreatorMenu';
+import React from 'react';
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { setupMoveUpEvents, returnFalse, returnEmptyFilter } from '../../../../../../ClientUtils';
+import { emptyFunction } from '../../../../../../Utils';
+import { undoable } from '../../../../../util/UndoManager';
+import ReactLoading from 'react-loading';
+import { Doc, NumListCast, returnEmptyDoclist } from '../../../../../../fields/Doc';
+import { NumCast, StrCast } from '../../../../../../fields/Types';
+import { DefaultStyleProvider } from '../../../../StyleProvider';
+import { DocumentView } from '../../../DocumentView';
+import { Transform } from '../../../../../util/Transform';
+import { Docs, DocumentOptions } from '../../../../../documents/Documents';
 
 interface TemplatesRenderPreviewWindowProps {
     menu: DocCreatorMenu;
@@ -22,8 +22,7 @@ interface TemplatesRenderPreviewWindowProps {
 
 @observer
 export class TemplatesRenderPreviewWindow extends ObservableReactComponent<TemplatesRenderPreviewWindowProps> {
-
-    @observable private _layout: { type: LayoutType; yMargin: number; xMargin: number; columns?: number; repeat: number } = { type: LayoutType.FREEFORM, yMargin: 10, xMargin: 10, columns: 0, repeat: 0 };
+    @observable private _layout: { type: LayoutType; yMargin: number; xMargin: number; columns?: number; repeat: number } = { type: LayoutType.FREEFORM, yMargin: 10, xMargin: 10, columns: 1, repeat: 0 };
 
     @observable private renderedDocs: Doc[] = [];
     @observable private renderedDocCollection: Doc | undefined = undefined;
@@ -62,7 +61,7 @@ export class TemplatesRenderPreviewWindow extends ObservableReactComponent<Templ
     @computed get columnsCount() {
         switch (this._layout.type) {
             case LayoutType.FREEFORM:
-                return this._layout.columns ?? 0;
+                return this._layout.columns ?? 1;
             case LayoutType.CAROUSEL3D:
                 return 3;
             default:
@@ -130,28 +129,27 @@ export class TemplatesRenderPreviewWindow extends ObservableReactComponent<Templ
         const { horizontalSpan, verticalSpan } = this.previewInfo;
         collection._height = verticalSpan;
         collection._width = horizontalSpan;
-
-        const columns: number = this._layout.columns ?? this.columnsCount;
-        const xGap: number = this._layout.xMargin;
-        const yGap: number = this._layout.yMargin;
-        const startX: number = -Number(collection._width) / 2;
-        const startY: number = -Number(collection._height) / 2;
-        const docHeight: number = Number(docs[0]._height);
-        const docWidth: number = Number(docs[0]._width);
-
-        if (columns === 0 || docs.length === 0) {
-            return;
-        }
-
-        let i: number = 0;
-        let docsChanged: number = 0;
-        let curX: number = startX;
-        let curY: number = startY;
+        collection.layout_fitWidth = true;
+        collection.freeform_fitContentsToBox = true;
+
+        const columns = (this._layout.columns ?? this.columnsCount) || 1;
+        const xGap = this._layout.xMargin;
+        const yGap = this._layout.yMargin;
+        const startX = -collection._width / 2;
+        const startY = -collection._height / 2;
+        const docHeight = NumCast(docs[0]?._height);
+        const docWidth = NumCast(docs[0]?._width);
+
+        let i = 0;
+        let docsChanged = 0;
+        let curX = startX;
+        let curY = startY;
 
         while (docsChanged < docs.length) {
             while (i < columns && docsChanged < docs.length) {
                 docs[docsChanged].x = curX;
                 docs[docsChanged].y = curY;
+                docs[docsChanged].layout_fitWidth = false;
                 curX += docWidth + xGap;
                 ++docsChanged;
                 ++i;
@@ -164,8 +162,8 @@ export class TemplatesRenderPreviewWindow extends ObservableReactComponent<Templ
 
     @computed
     get previewInfo() {
-        const docHeight: number = Number(this.renderedDocs[0]._height);
-        const docWidth: number = Number(this.renderedDocs[0]._width);
+        const docHeight = NumCast(this.renderedDocs[0]?._height);
+        const docWidth = NumCast(this.renderedDocs[0]?._width);
         const layout = this._layout;
         return {
             docHeight: docHeight,
@@ -201,6 +199,10 @@ export class TemplatesRenderPreviewWindow extends ObservableReactComponent<Templ
         }
     }
 
+    layoutPanelWidth = () => this._props.menu._menuDimensions.width - 80;
+    layoutPanelHeight = () => this._props.menu._menuDimensions.height - 105;
+    layoutScreenToLocalXf = () => new Transform(-this._props.menu._pageX - 5, -this._props.menu._pageY - 35, 1);
+
     layoutPreviewContents = action(() => {
         return this.loading ? (
             <div className="docCreatorMenu-layout-preview-window-wrapper loading">
@@ -216,20 +218,18 @@ export class TemplatesRenderPreviewWindow extends ObservableReactComponent<Templ
                     addDocument={returnFalse}
                     moveDocument={returnFalse}
                     removeDocument={returnFalse}
-                    PanelWidth={() => this._props.menu._menuDimensions.width - 80}
-                    PanelHeight={() => this._props.menu._menuDimensions.height - 105}
-                    ScreenToLocalTransform={() => new Transform(-this._props.menu._pageX - 5, -this._props.menu._pageY - 35, 1)}
+                    PanelWidth={this.layoutPanelWidth}
+                    PanelHeight={this.layoutPanelHeight}
+                    ScreenToLocalTransform={this.layoutScreenToLocalXf}
                     renderDepth={5}
                     whenChildContentsActiveChanged={emptyFunction}
                     focus={emptyFunction}
                     styleProvider={DefaultStyleProvider}
                     addDocTab={this._props.menu._props.addDocTab}
-                    pinToPres={() => undefined}
+                    pinToPres={emptyFunction}
                     childFilters={returnEmptyFilter}
                     childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    fitContentsToBox={returnFalse}
-                    fitWidth={returnFalse}
                     hideDecorations={true}
                 />
             </div>
@@ -273,7 +273,6 @@ export class TemplatesRenderPreviewWindow extends ObservableReactComponent<Templ
     };
 
     get optionsMenuContents() {
-
         const repeatOptions = [0, 1, 2, 3, 4, 5];
 
         return (
@@ -341,5 +340,7 @@ export class TemplatesRenderPreviewWindow extends ObservableReactComponent<Templ
         );
     }
 
-    render() { return this.optionsMenuContents }
-}
\ No newline at end of file
+    render() {
+        return this.optionsMenuContents;
+    }
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
index 7591740e0..e2a2a3c1c 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
@@ -9,7 +9,7 @@ import { TemplateDataField } from './TemplateFieldTypes/DataField';
 export class Template {
     _mainField: DynamicField;
 
-    private dataFields: TemplateDataField[] = [];
+    private _dataFields: TemplateDataField[] = [];
 
     /**
      * A Template can be created from a description of its fields (FieldSettings) or from a DynamicField
@@ -20,37 +20,13 @@ export class Template {
         this._mainField = definition instanceof DynamicField ? definition : this.setupMainField(definition);
     }
 
-    get childFields(): TemplateField[] {
-        return this._mainField?.getSubfields ?? [];
-    }
-    get allFields(): TemplateField[] {
-        return this._mainField?.getAllSubfields ?? [];
-    }
-    get contentFields(): TemplateField[] {
-        return this.allFields.filter(field => field.isContentField);
-    }
-    get doc() {
-        return this._mainField?.renderedDoc;
-    }
-    get title() {
-        return this._mainField?.getTitle();
-    }
-
-    get descriptionSummary(): string {
-        let summary: string = '';
-        this.contentFields.forEach(field => {
-            summary += `--- Field #${field.getID} (title: ${field.getTitle()}): ${field.getDescription ?? ''} ---`;
-        });
-        return summary;
-    }
-
-    get compiledContent(): string {
-        let summary: string = '';
-        this.contentFields.forEach(field => {
-            summary += `--- Field #${field.getID} (title: ${field.getTitle()}): ${field.getContent() ?? ''} ---`;
-        });
-        return summary;
-    }
+    get childFields()        { return this._mainField?.getSubfields ?? []; } // prettier-ignore
+    get allFields()          { return this._mainField?.getAllSubfields ?? []; } // prettier-ignore
+    get contentFields()      { return this.allFields.filter(field => field.isContentField); } // prettier-ignore
+    get doc()                { return this._mainField?.renderedDoc; } // prettier-ignore
+    get title()              { return this._mainField?.getTitle(); } // prettier-ignore
+    get descriptionSummary() { return this.contentFields.map(f => `--- Field #${f.getID} (title: ${f.getTitle()}): ${f.getDescription ?? ''} ---`).join(); } // prettier-ignore
+    get compiledContent()    { return this.contentFields.map(f => `--- Field #${f.getID} (title: ${f.getTitle()}): ${f.getContent() ?? ''} ---`).join(); } // prettier-ignore
 
     cleanup = () => {
         //dispose each subfields disposers, etc.
@@ -58,61 +34,56 @@ export class Template {
 
     clone = (withContent: boolean = false) => {
         const clone = new Template(this._mainField?.makeClone(undefined, withContent) ?? TemplateLayouts.BasicSettings);
-        this.dataFields.forEach(field => clone.addDataField(field.title));
+        this._dataFields.forEach(field => clone.addDataField(field.title));
         return clone;
     };
 
     getRenderedDoc = () => this.doc;
 
-    getFieldByID = (id: number): TemplateField => this.allFields.filter(field => field.getID === id)[0];
+    getFieldByID = (id: number): TemplateField | undefined => this.allFields.filter(field => field.getID === id)[0];
 
-    getFieldByTitle = (title: string) => [...this.allFields, ...this.dataFields].filter(field => field.getTitle() === title)[0];
+    getFieldByTitle = (title: string) => [...this.allFields, ...this._dataFields].filter(field => field.getTitle() === title)[0];
 
     setupMainField = (templateInfo: FieldSettings) => TemplateField.CreateField(templateInfo, 1, undefined) as DynamicField;
 
     assignColToField = (fieldID: number, col: Col) => {
         const field = this.getFieldByID(fieldID);
-        field.setContent(col.defaultContent ?? '', col.type === TemplateFieldType.VISUAL ? ViewType.IMG : ViewType.TEXT);
-        field.setTitle(col.title);
-    }
+        field?.setContent(col.defaultContent ?? '', col.type === TemplateFieldType.VISUAL ? ViewType.IMG : ViewType.TEXT);
+        field?.setTitle(col.title);
+    };
 
-    addDataField = (title: string, content?: string) => {
-        this.dataFields.push(new TemplateDataField(title, content));
-    }
+    addDataField = (title: string, content?: string) => this._dataFields.push(new TemplateDataField(title, content));
 
-    removeDataField = (title: string) => {
-        this.dataFields = this.dataFields.filter(field => !(field.title === title));
-    }
+    removeDataField = (title: string) => (this._dataFields = this._dataFields.filter(field => field.title !== title));
 
-    isValidTemplate = (cols: Col[]) => {
-        const maxMatches = this.maxMatches(this.getMatches(cols));
-        return maxMatches === this.contentFields.length && this.title !== 'template_framework';
-    };
+    isValidTemplate = (cols: Col[]) => this.title !== 'template_framework' && this.maxMatches(this.getMatches(cols)) === this.contentFields.length;
 
     applyConditionalLogicToField = (field: TemplateField | TemplateDataField, logic: Record<string, Conditional[]>) => {
         if (field instanceof DynamicField) return;
-        const fieldStatements: Conditional[] = logic[field.getTitle()];
-        const content = field.getContent()
-        fieldStatements && fieldStatements.forEach(statement => {
+        const fieldStatements = logic[field.getTitle()];
+        const content = field.getContent();
+        fieldStatements?.forEach(statement => {
             if (content === statement.condition) {
                 if (statement.target === 'Template') {
-                    this._mainField.renderedDoc![statement.attribute] = statement.value;
-                    Object.assign(this._mainField.settings.opts, {[statement.attribute]: statement.value});
+                    if (this._mainField.renderedDoc) {
+                        this._mainField.renderedDoc[statement.attribute] = statement.value;
+                        Object.assign(this._mainField.settings.opts, { [statement.attribute]: statement.value });
+                    }
                 } else {
-                    const targetField: TemplateField = this.getFieldByTitle(statement.target) as TemplateField;
-                    if (targetField) {
-                        targetField.renderedDoc![statement.attribute] = statement.value;
-                        Object.assign(targetField.settings.opts, {[statement.attribute]: statement.value});
-                    } 
+                    const targetField = this.getFieldByTitle(statement.target);
+                    if (targetField instanceof TemplateField && targetField.renderedDoc) {
+                        targetField.renderedDoc[statement.attribute] = statement.value;
+                        Object.assign(targetField.settings.opts, { [statement.attribute]: statement.value });
+                    }
                 }
             }
-        })
-    }
+        });
+    };
 
     applyConditionalLogic = (logic: Record<string, Conditional[]>) => {
-        const fields: (TemplateField | TemplateDataField)[] = [...this.allFields, ...this.dataFields];
-        fields.forEach(field => this.applyConditionalLogicToField(field, logic));
-    }
+        [...this.allFields, ...this._dataFields].forEach(field => this.applyConditionalLogicToField(field, logic));
+        return this.getRenderedDoc();
+    };
 
     setImageAsBackground(url: string, makeTransparent: boolean = false) {
         const fieldSettings: FieldSettings = {
@@ -120,15 +91,15 @@ export class Template {
             br: [1, 1],
             opts: {},
             viewType: ViewType.IMG,
-        }
+        };
 
-        const field: TemplateField = TemplateField.CreateField(fieldSettings, Math.random() * 100 + 100, this._mainField);
+        const field = TemplateField.CreateField(fieldSettings, Math.random() * 100 + 100, this._mainField);
         field.setContent(url);
 
         if (makeTransparent) {
-            this.allFields.forEach(field => {
-                field.updateDocSetting('backgroundColor', 'transparent');
-                field.updateDocSetting('borderWidth', '0');
+            this.allFields.forEach(aField => {
+                aField.updateDocSetting('backgroundColor', 'transparent');
+                aField.updateDocSetting('borderWidth', '0');
             });
         }
 
@@ -138,7 +109,7 @@ export class Template {
     /**
      * This function is just a hack for now to get around weird document icon stuff (specifically it misses the background)
      */
-     setMatteBackground(makeTransparent: boolean = false) {
+    setMatteBackground(makeTransparent: boolean = false) {
         if (this._mainField.hasBackground) {
             return;
         }
@@ -146,18 +117,17 @@ export class Template {
         const fieldSettings: FieldSettings = {
             tl: [-1, -1],
             br: [1, 1],
-            opts: {backgroundColor: String(this._mainField.renderedDoc!.backgroundColor)},
+            opts: { backgroundColor: String(this._mainField.renderedDoc!.backgroundColor) },
             viewType: ViewType.TEXT,
-        }
+        };
 
-        const field: TemplateField = TemplateField.CreateField(fieldSettings, Math.random() * 100 + 100, this._mainField);
+        const field = TemplateField.CreateField(fieldSettings, Math.random() * 100 + 100, this._mainField);
 
-        if (makeTransparent) {
-            this.allFields.forEach(field => {
-                field.updateDocSetting('backgroundColor', 'transparent');
-                field.updateDocSetting('borderWidth', '0');
+        makeTransparent &&
+            this.allFields.forEach(aField => {
+                aField.updateDocSetting('backgroundColor', 'transparent');
+                aField.updateDocSetting('borderWidth', '0');
             });
-        }
 
         this._mainField.makeBackgroundField(field);
     }
@@ -167,9 +137,7 @@ export class Template {
 
         if (cols.length !== numFields) return [];
 
-        const matches: number[][] = Array(numFields)
-            .fill([])
-            .map(() => []);
+        const matches = Array<number[]>(numFields);
 
         this.contentFields.forEach((field, i) => (matches[i] = field.matches(cols)));
 
@@ -180,8 +148,8 @@ export class Template {
         if (matches.length === 0) return 0;
 
         const fieldsCt = this.contentFields.length;
-        const used: boolean[] = Array(fieldsCt).fill(false);
-        const mt: number[] = Array(fieldsCt).fill(-1);
+        const used = Array<boolean>(fieldsCt).fill(false);
+        const mt = Array<number>(fieldsCt).fill(-1);
 
         const augmentingPath = (v: number): boolean => {
             if (!used[v]) {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts
index c100d1cce..091ef834a 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts
@@ -67,13 +67,13 @@ export abstract class TemplateField {
     setTitle = (title: string) => {
         this._title = title;
         this.settings.title = title;
-        if (this._renderDoc) this._renderDoc.title = title
+        if (this._renderDoc) this._renderDoc.title = title;
     };
     getTitle = () => this._title;
 
     updateDocSetting(setting: string, newVal: string) {
         if (this._renderDoc) this._renderDoc[setting] = newVal;
-        const settings: {[s: string]: string } = {[setting]: newVal}
+        const settings: { [s: string]: string } = { [setting]: newVal };
         Object.assign(this.settings.opts, settings);
     }
 
@@ -162,7 +162,7 @@ export enum ViewType {
     DEC = 'decoration',
     IMG = 'image',
     TEXT = 'text',
-    NONE = 'none'
+    NONE = 'none',
 }
 
 export type FieldDimensions = {
@@ -170,4 +170,3 @@ export type FieldDimensions = {
     height: number;
     coord: { x: number; y: number };
 };
-
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 30fc44f62..8ed59c6e1 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -175,6 +175,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             () => ({ nativeSize: this.nativeSize, width: NumCast(this.layoutDoc._width), height: this.layoutDoc._height }),
             ({ nativeSize, width, height }) => {
                 if (!this.layoutDoc._layout_nativeDimEditable || !height || this.layoutDoc.layout_resetNativeDim) {
+                    if (!this._props.TemplateDataDocument) this.layoutDoc._nativeWidth = this.layoutDoc._nativeHeight = undefined;
                     this.layoutDoc.layout_resetNativeDim = undefined; // reset dimensions of templates rendered with content or if image changes.  afterwards, remove this flag.
                     this.layoutDoc._height = (width * nativeSize.nativeHeight) / nativeSize.nativeWidth;
                 }
-- 
cgit v1.2.3-70-g09d2

