From a2802df5096cfea2d77371ed9025ce26c8eda222 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Thu, 24 Oct 2024 04:31:42 -0400
Subject: work on field refactor

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

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

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
new file mode 100644
index 000000000..f9bf22047
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -0,0 +1,48 @@
+
+import { Doc } from "../../../../../fields/Doc";
+import { Docs } from "../../../../documents/Documents";
+import { Field } from "./FieldTypes";
+import { TemplateDocInfos } from "./TemplateBackend";
+
+export class Template {
+
+    width: number = 0;
+    height: number = 0;
+    fields: Field[] = [];
+    mainDoc: Doc;
+
+    constructor(templateInfo: TemplateDocInfos) {
+        this.width = templateInfo.width;
+        this.height = templateInfo.height;
+        this.fields = templateInfo.fields.map(settings => new Field(settings, this));
+        this.mainDoc = this.setupMainDoc();
+    }
+
+    setupMainDoc = (): Doc => {
+        Docs.Create.FreeformDocument(, ){
+
+        }
+        return new Doc;
+    }
+
+    get childFields(): Field[] {
+        return this.fields;
+    }
+
+    get allFields(): Field[] {
+        const fields = this.fields;
+        this.fields.forEach(field => fields.concat(field.subfields));
+        return fields;
+    }
+
+    getChildDimensions = (coords: { tl: [number, number]; br: [number, number] }): { width: number; height: number; coord: { x: number; y: number } } => {
+        const l = (coords.tl[0] * this.height) / 2;
+        const t = coords.tl[1] * this.width / 2; //prettier-ignore
+        const r = (coords.br[0] * this.height) / 2;
+        const b = coords.br[1] * this.width / 2; //prettier-ignore
+        const width = r - l;
+        const height = b - t;
+        const coord = { x: l, y: t };
+        return { width, height, coord };
+    };
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From cfc160d7a777b5504b92ac14ac16052979418ce7 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Sun, 27 Oct 2024 04:29:50 -0400
Subject: work on template refactor

---
 src/client/views/nodes/DataVizBox/DataVizBox.tsx   |   3 +-
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   |  11 +-
 .../nodes/DataVizBox/DocCreatorMenu/FieldTypes.tsx | 274 ++++++++++++++++-----
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   |  10 +-
 4 files changed, 218 insertions(+), 80 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 14e0a8e66..311a0ad65 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -32,11 +32,12 @@ import { DocumentView } from '../DocumentView';
 import { FieldView, FieldViewProps } from '../FieldView';
 import { FocusViewOptions } from '../FocusViewOptions';
 import './DataVizBox.scss';
-import { Col, DataVizTemplateInfo, DocCreatorMenu, LayoutType, TemplateFieldSize, TemplateFieldType } from './DocCreatorMenu/DocCreatorMenu';
+import { Col, DataVizTemplateInfo, DocCreatorMenu, LayoutType} from './DocCreatorMenu/DocCreatorMenu';
 import { Histogram } from './components/Histogram';
 import { LineChart } from './components/LineChart';
 import { PieChart } from './components/PieChart';
 import { TableBox } from './components/TableBox';
+import { TemplateFieldSize, TemplateFieldType } from './DocCreatorMenu/TemplateBackend';
 
 export enum DataVizView {
     TABLE = 'table',
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index c34403e79..c86264716 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -379,8 +379,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             this._selectedTemplate = template;
             MakeTemplate(template);
             const templateInfo: DataVizTemplateInfo = { doc: template, layout: this._layout, referencePos: { x: this._pageX + 450, y: this._pageY }, columns: this.columnsCount };
-            // this._fullyRenderedDocs = this._dataViz?.createDocsFromTemplate(templateInfo, true) ?? [];
-            // this.updateRenderedDocCollection();
+            this._fullyRenderedDocs = this._dataViz?.createDocsFromTemplate(templateInfo, true) ?? [];
+            this.updateRenderedDocCollection();
         }
     };
 
@@ -724,7 +724,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                 col.desc;
 
                             const prompt = await gptAPICall(sysPrompt, GPTCallType.COMPLETEPROMPT);
-                            console.log(sysPrompt, prompt);
+                            //console.log(sysPrompt, prompt);
 
                             return createGeneratedImage(fieldNum, col, prompt);
                         })
@@ -781,7 +781,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         });
 
         template.decorations.forEach(dec => {
-            const doc = FieldUtils.FreeformField(
+            console.log(dec);
+            const doc = FieldUtils.TextField(
                 {
                     tl: dec.tl,
                     br: dec.br,
@@ -1814,4 +1815,4 @@ export class FieldUtils {
 
         return doc;
     };
-}
\ No newline at end of file
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes.tsx
index 119de88d0..f30183ed3 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes.tsx
@@ -1,8 +1,9 @@
 import { Doc } from "../../../../../fields/Doc";
 import { FieldType } from "../../../../../fields/ObjectField";
 import { Docs, DocumentOptions } from "../../../../documents/Documents";
+import { Col } from "./DocCreatorMenu";
 import { Template } from "./Template";
-import { TemplateFieldSize, TemplateFieldType } from "./TemplateBackend";
+import { TemplateDocInfos, TemplateFieldSize, TemplateFieldType } from "./TemplateBackend";
 
 export enum FieldContentType {
     STRING = 'string',
@@ -14,6 +15,12 @@ export enum ViewType {
     FREEFORM = 'freeform',
 }
 
+export type FieldDimensions = {
+    width: number;
+    height: number;
+    coord: {x: number, y: number};
+}
+
 export interface FieldOpts {
     backgroundColor?: string;
     color?: string;
@@ -41,25 +48,37 @@ export type FieldSettings = {
     description?: string;
 };
 
-export class Field {
+export interface Field {
+    getContent: () => string;
+    setContent: (content: string) => void;
+    getDimensions: FieldDimensions;
+    getSubfields: Field[];
+    getAllSubfields: Field[];
+    setupSubfields: () => Field[];
+    renderedDoc: (content: string) => Doc;
+    matches: () => number[][];
+}
+
+export class StaticField {
     private content: string;
     private contentType: FieldContentType | undefined;
-    private subfields: Field[] | undefined;
+    private subfields: Field[] = [];
 
     private settings: FieldSettings;
 
-    private parent: Field | Template;
-    private dimensions: { width: number; height: number; coord: { x: number; y: number }};
+    private parent: Field;
+    private dimensions: FieldDimensions;
 
-    constructor(settings: FieldSettings, parent: Field | Template) {
+    constructor(settings: FieldSettings, parent: Field, autoSetupFields: boolean = true) {
         this.settings = settings;
         this.parent = parent;
-        this.dimensions = this.parent.getChildDimensions({tl: settings.tl, br: settings.br});
+        this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
         this.content = '';
-        this.setupSubfields();
-    }
+        if (autoSetupFields) { this.subfields = this.setupSubfields(); }
+    };
 
     get getSubfields(): Field[] { return this.subfields ?? []; };
+
     get getAllSubfields(): Field[] {
         const fields: Field[] = [];
         this.subfields?.forEach(field => {
@@ -67,22 +86,33 @@ export class Field {
             fields.concat(field.getAllSubfields)
         });
         return fields;
-    }
+    };
+
+    get getDimensions() { return this.dimensions };
 
     setContent = (newContent: string) => { this.content = newContent };
     getContent() { return this.content };
 
-    setupSubfields = () => {
+    setupSubfields = (): Field[] => {
+        const fields: Field[] = [];
         this.settings.subfields?.forEach(fieldSettings => {
             let field: Field;
             const dynamicType = fieldSettings.dynamicType;
 
-            if (dynamicType) { field = new DynamicField(fieldSettings, this, dynamicType); }
+            if (dynamicType) { 
+                field = new DynamicField(fieldSettings, this, dynamicType); 
+            } else {
+                field = new StaticField(fieldSettings, this);
+            }
 
-            field = new Field(fieldSettings, this);
-            this.subfields?.push(field);
+            fields.push(field);
         });
-    }
+        return fields;
+    };
+
+    matches = (): number[][] => {
+        return [];
+    };
 
     renderedDoc = (content: string): Doc => {
         const opts = this.settings.opts;
@@ -97,21 +127,72 @@ export class Field {
                     contentBold: opts.fontBold,
                     textTransform: opts.fontTransform,
                     color: opts.color,
-                    _text_fontSize: `${this.calculateFontSize(this.dimensions.width, this.dimensions.height, text, true)}`
+                    _text_fontSize: `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, text, true)}`
                 });
-                this.applyBasicOpts(textDoc);
+                FieldUtils.applyBasicOpts(textDoc, this.dimensions, this.settings);
                 return textDoc;
             case FieldContentType.IMAGE:
                 const url = String(content);
                 const imgDoc = Docs.Create.ImageDocument(url, {
                     _layout_fitWidth: false,
                 });
-                this.applyBasicOpts(imgDoc);
+                FieldUtils.applyBasicOpts(imgDoc, this.dimensions, this.settings);
                 return imgDoc;
         }   
+    };
+
+}
+
+class DynamicField implements Field {
+    private type: ViewType;
+    private subfields: Field[] = [];
+
+    private settings: FieldSettings;
+
+    private parent: Field;
+    private dimensions: FieldDimensions;
+
+    constructor(settings: FieldSettings, parent: Field, type: ViewType) {
+        this.type = type;
+        this.settings = settings;
+        this.parent = parent;
+        this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
+        this.subfields = this.setupSubfields();
+    }
+
+    setContent = (content: string) => { return };
+    getContent = () => { return '' };
+
+    get getSubfields() { return this.subfields };
+    get getAllSubfields() {
+        const fields: Field[] = [];
+        this.subfields?.forEach(field => {
+            fields.push(field);
+            fields.concat(field.getAllSubfields)
+        });
+        return fields;
+    };
+
+    get getDimensions() { return this.dimensions };
+
+    matches = () => {
+        return [];
     }
 
-    getChildDimensions = (coords: { tl: [number, number]; br: [number, number] }): { width: number; height: number; coord: { x: number; y: number } } => {
+    setupSubfields = (): Field[] => {
+        this.settings.subfields?.forEach(fieldSettings => {
+            let field: Field;
+            const dynamicType = fieldSettings.dynamicType;
+
+            if (dynamicType) { field = new DynamicField(fieldSettings, this, dynamicType); }
+
+            field = new StaticField(fieldSettings, this);
+            this.subfields?.push(field);
+        });
+        return [];
+    }
+
+    getChildDimensions = (coords: { tl: [number, number]; br: [number, number] }): FieldDimensions => {
         const l = (coords.tl[0] * this.dimensions.height) / 2;
         const t = coords.tl[1] * this.dimensions.width / 2; //prettier-ignore
         const r = (coords.br[0] * this.dimensions.height) / 2;
@@ -122,13 +203,113 @@ export class Field {
         return { width, height, coord };
     };
 
-    applyBasicOpts = (doc: Doc) => {
-        const opts = this.settings.opts;
+    renderedDoc = (): Doc => {
+        switch (this.type) {
+            case ViewType.CAROUSEL3D:
+                const carouselDoc = Docs.Create.Carousel3DDocument([], {
+                });
+                FieldUtils.applyBasicOpts(carouselDoc, this.dimensions, this.settings);
+            case ViewType.FREEFORM:
+                const freeformDoc = Docs.Create.FreeformDocument([], {
+                });
+                FieldUtils.applyBasicOpts(freeformDoc, this.dimensions, this.settings);
+            default:
+                return new Doc();
+        }
+    }
+
+}
+
+export class TemplateMatcher {
+
+    static matchesForTemplate = (field: FieldSettings, cols: Col[]): number[][] => {
+        const colMatchesField = (col: Col, field: FieldSettings) => {
+            return field.sizes?.some(size => col.sizes?.includes(size)) && field.types?.includes(col.type);
+        };
+
+        const matches: number[][] = Array(field.subfields?.length)
+            .fill([])
+            .map(() => []);
+
+        field.subfields?.forEach((field, i) => {
+            cols.forEach((col, v) => {
+                if (colMatchesField(col, field)) {
+                    matches[i].push(v);
+                }
+            });
+        });
+
+        return matches;
+    };
+
+    static maxMatches = (fieldsCt: number, matches: number[][]) => {
+        const used: boolean[] = Array(fieldsCt).fill(false);
+        const mt: number[] = Array(fieldsCt).fill(-1);
+
+        const augmentingPath = (v: number): boolean => {
+            if (used[v]) return false;
+            used[v] = true;
+            for (const to of matches[v]) {
+                if (mt[to] === -1 || augmentingPath(mt[to])) {
+                    mt[to] = v;
+                    return true;
+                }
+            }
+            return false;
+        };
+
+        for (let v = 0; v < fieldsCt; ++v) {
+            used.fill(false);
+            augmentingPath(v);
+        }
+
+        let count: number = 0;
+
+        for (let i = 0; i < fieldsCt; ++i) {
+            if (mt[i] !== -1) ++count;
+        }
+
+        return count;
+    };
+
+    findValidTemplates = (cols: Col[], templates: TemplateDocInfos[]) => {
+        let validTemplates: any[] = [];
+        templates.forEach(template => {
+            const numFields = template.fields.length;
+            if (!(numFields === cols.length)) return;
+            const matches = this.matchesForTemplate(template, cols);
+            if (this.maxMatches(numFields, matches) === numFields) {
+                validTemplates.push(template.title);
+            }
+        });
+
+        validTemplates = validTemplates.map(title => TemplateLayouts.getTemplateByTitle(title));
+
+        return validTemplates;
+    };
+
+}
+
+
+export class FieldUtils {
+    public static getLocalDimensions = (coords: { tl: [number, number]; br: [number, number] }, parentDimensions: FieldDimensions): FieldDimensions => {
+        const l = (coords.tl[0] * parentDimensions.height) / 2;
+        const t = coords.tl[1] * parentDimensions.width / 2; //prettier-ignore
+        const r = (coords.br[0] * parentDimensions.height) / 2;
+        const b = coords.br[1] * parentDimensions.width / 2; //prettier-ignore
+        const width = r - l;
+        const height = b - t;
+        const coord = { x: l, y: t };
+        return { width, height, coord };
+    };
+
+    public static applyBasicOpts = (doc: Doc, parentDimensions: FieldDimensions, settings: FieldSettings) => {
+        const opts = settings.opts;
         doc.isDefaultTemplateDoc = true,
-        doc.x = this.dimensions.coord.x;
-        doc.y = this.dimensions.coord.y;
-        doc._height = this.dimensions.height;
-        doc._width = this.dimensions.width;
+        doc.x = parentDimensions.coord.x;
+        doc.y = parentDimensions.coord.y;
+        doc._height = parentDimensions.height;
+        doc._width = parentDimensions.width;
         doc.backgroundColor = opts.backgroundColor ?? '';
         doc._layout_borderRounding = `${opts.cornerRounding ?? 0}px`;
         doc.borderColor = opts.borderColor;
@@ -136,9 +317,9 @@ export class Field {
         doc.opacity = opts.opacity;
         doc._rotation = opts.rotation;
         doc.hCentering = opts.contentXCentering;
-    }
+    };
 
-    calculateFontSize = (contWidth: number, contHeight: number, text: string, uppercase: boolean): number => {
+    public static calculateFontSize = (contWidth: number, contHeight: number, text: string, uppercase: boolean): number => {
         const words: string[] = text.split(/\s+/).filter(Boolean);
 
         let currFontSize = 1;
@@ -178,41 +359,4 @@ export class Field {
 
         return currFontSize - 1;
     };
-
-}
-
-class DynamicField extends Field {
-    type: ViewType;
-
-    constructor(settings: FieldSettings, parent: Field | Template, type: ViewType) {
-        super(settings, parent);
-        this.type = type;
-    }
-
-    renderedDoc = (): Doc => {
-        switch (this.type) {
-            case ViewType.CAROUSEL3D:
-                const carouselDoc = Docs.Create.Carousel3DDocument([], {
-                });
-                this.applyBasicOpts(carouselDoc);
-            case ViewType.FREEFORM:
-                const freeformDoc = Docs.Create.FreeformDocument([], {
-                });
-                this.applyBasicOpts(freeformDoc);
-            default:
-                return new Doc();
-        }
-    }
-
-
-
-}
-
-
-type DecorationField = FieldSettings;
-
-type InkDecoration = {};
-
-type TemplateDecorations = FieldSettings | InkDecoration;
-
-interface TemplateOpts extends FieldOpts {}
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index f9bf22047..57565906b 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -6,23 +6,15 @@ import { TemplateDocInfos } from "./TemplateBackend";
 
 export class Template {
 
+    mainField: Field;
     width: number = 0;
     height: number = 0;
     fields: Field[] = [];
-    mainDoc: Doc;
 
     constructor(templateInfo: TemplateDocInfos) {
         this.width = templateInfo.width;
         this.height = templateInfo.height;
         this.fields = templateInfo.fields.map(settings => new Field(settings, this));
-        this.mainDoc = this.setupMainDoc();
-    }
-
-    setupMainDoc = (): Doc => {
-        Docs.Create.FreeformDocument(, ){
-
-        }
-        return new Doc;
     }
 
     get childFields(): Field[] {
-- 
cgit v1.2.3-70-g09d2


From 857797d1d47f22b641d1bddb4177028c26677f19 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Sun, 27 Oct 2024 06:19:21 -0400
Subject: breaking up files

---
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   |   2 +-
 .../nodes/DataVizBox/DocCreatorMenu/FieldTypes.tsx | 362 ---------------------
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx     |  92 ++++++
 .../DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx |  57 ++++
 .../DocCreatorMenu/FieldTypes/FieldUtils.tsx       | 144 ++++++++
 .../DocCreatorMenu/FieldTypes/StaticField.tsx      |  98 ++++++
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   |  37 +--
 .../DataVizBox/DocCreatorMenu/TemplateBackend.tsx  |   3 +-
 8 files changed, 405 insertions(+), 390 deletions(-)
 delete mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes.tsx
 create mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
 create mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
 create mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
 create mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx

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

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index c86264716..02fd7f869 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -30,7 +30,7 @@ import { DefaultStyleProvider, returnEmptyDocViewList } from '../../../StyleProv
 import { Transform } from '../../../../util/Transform';
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { TemplateDocInfos, TemplateFieldSize, TemplateFieldType, TemplateLayouts } from './TemplateBackend';
-import { FieldOpts, FieldSettings } from './FieldTypes';
+import { FieldOpts, FieldSettings } from './FieldTypes/StaticField';
 
 export enum LayoutType {
     STACKED = 'stacked',
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes.tsx
deleted file mode 100644
index f30183ed3..000000000
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes.tsx
+++ /dev/null
@@ -1,362 +0,0 @@
-import { Doc } from "../../../../../fields/Doc";
-import { FieldType } from "../../../../../fields/ObjectField";
-import { Docs, DocumentOptions } from "../../../../documents/Documents";
-import { Col } from "./DocCreatorMenu";
-import { Template } from "./Template";
-import { TemplateDocInfos, TemplateFieldSize, TemplateFieldType } from "./TemplateBackend";
-
-export enum FieldContentType {
-    STRING = 'string',
-    IMAGE = 'image',
-}
-
-export enum ViewType {
-    CAROUSEL3D = 'carousel3d',
-    FREEFORM = 'freeform',
-}
-
-export type FieldDimensions = {
-    width: number;
-    height: number;
-    coord: {x: number, y: number};
-}
-
-export interface FieldOpts {
-    backgroundColor?: string;
-    color?: string;
-    cornerRounding?: number;
-    borderWidth?: string;
-    borderColor?: string;
-    contentXCentering?: 'h-left' | 'h-center' | 'h-right';
-    contentYCentering?: 'top' | 'center' | 'bottom';
-    opacity?: number;
-    rotation?: number;
-    //animation?: boolean;
-    fontBold?: boolean;
-    fontTransform?: 'uppercase' | 'lowercase';
-    fieldViewType?: 'freeform' | 'stacked';
-}
-
-export type FieldSettings = {
-    tl: [number, number];
-    br: [number, number];
-    opts: FieldOpts;
-    dynamicType?: ViewType;
-    subfields?: FieldSettings[];
-    types?: TemplateFieldType[];
-    sizes?: TemplateFieldSize[];
-    description?: string;
-};
-
-export interface Field {
-    getContent: () => string;
-    setContent: (content: string) => void;
-    getDimensions: FieldDimensions;
-    getSubfields: Field[];
-    getAllSubfields: Field[];
-    setupSubfields: () => Field[];
-    renderedDoc: (content: string) => Doc;
-    matches: () => number[][];
-}
-
-export class StaticField {
-    private content: string;
-    private contentType: FieldContentType | undefined;
-    private subfields: Field[] = [];
-
-    private settings: FieldSettings;
-
-    private parent: Field;
-    private dimensions: FieldDimensions;
-
-    constructor(settings: FieldSettings, parent: Field, autoSetupFields: boolean = true) {
-        this.settings = settings;
-        this.parent = parent;
-        this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
-        this.content = '';
-        if (autoSetupFields) { this.subfields = this.setupSubfields(); }
-    };
-
-    get getSubfields(): Field[] { return this.subfields ?? []; };
-
-    get getAllSubfields(): Field[] {
-        const fields: Field[] = [];
-        this.subfields?.forEach(field => {
-            fields.push(field);
-            fields.concat(field.getAllSubfields)
-        });
-        return fields;
-    };
-
-    get getDimensions() { return this.dimensions };
-
-    setContent = (newContent: string) => { this.content = newContent };
-    getContent() { return this.content };
-
-    setupSubfields = (): Field[] => {
-        const fields: Field[] = [];
-        this.settings.subfields?.forEach(fieldSettings => {
-            let field: Field;
-            const dynamicType = fieldSettings.dynamicType;
-
-            if (dynamicType) { 
-                field = new DynamicField(fieldSettings, this, dynamicType); 
-            } else {
-                field = new StaticField(fieldSettings, this);
-            }
-
-            fields.push(field);
-        });
-        return fields;
-    };
-
-    matches = (): number[][] => {
-        return [];
-    };
-
-    renderedDoc = (content: string): Doc => {
-        const opts = this.settings.opts;
-
-        if (!this.contentType) { this.contentType = FieldContentType.STRING };
-
-        switch (this.contentType) {
-            case FieldContentType.STRING:
-                const text = String(content);
-                const textDoc = Docs.Create.TextDocument(text, {
-                    text_fontColor: opts.color,
-                    contentBold: opts.fontBold,
-                    textTransform: opts.fontTransform,
-                    color: opts.color,
-                    _text_fontSize: `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, text, true)}`
-                });
-                FieldUtils.applyBasicOpts(textDoc, this.dimensions, this.settings);
-                return textDoc;
-            case FieldContentType.IMAGE:
-                const url = String(content);
-                const imgDoc = Docs.Create.ImageDocument(url, {
-                    _layout_fitWidth: false,
-                });
-                FieldUtils.applyBasicOpts(imgDoc, this.dimensions, this.settings);
-                return imgDoc;
-        }   
-    };
-
-}
-
-class DynamicField implements Field {
-    private type: ViewType;
-    private subfields: Field[] = [];
-
-    private settings: FieldSettings;
-
-    private parent: Field;
-    private dimensions: FieldDimensions;
-
-    constructor(settings: FieldSettings, parent: Field, type: ViewType) {
-        this.type = type;
-        this.settings = settings;
-        this.parent = parent;
-        this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
-        this.subfields = this.setupSubfields();
-    }
-
-    setContent = (content: string) => { return };
-    getContent = () => { return '' };
-
-    get getSubfields() { return this.subfields };
-    get getAllSubfields() {
-        const fields: Field[] = [];
-        this.subfields?.forEach(field => {
-            fields.push(field);
-            fields.concat(field.getAllSubfields)
-        });
-        return fields;
-    };
-
-    get getDimensions() { return this.dimensions };
-
-    matches = () => {
-        return [];
-    }
-
-    setupSubfields = (): Field[] => {
-        this.settings.subfields?.forEach(fieldSettings => {
-            let field: Field;
-            const dynamicType = fieldSettings.dynamicType;
-
-            if (dynamicType) { field = new DynamicField(fieldSettings, this, dynamicType); }
-
-            field = new StaticField(fieldSettings, this);
-            this.subfields?.push(field);
-        });
-        return [];
-    }
-
-    getChildDimensions = (coords: { tl: [number, number]; br: [number, number] }): FieldDimensions => {
-        const l = (coords.tl[0] * this.dimensions.height) / 2;
-        const t = coords.tl[1] * this.dimensions.width / 2; //prettier-ignore
-        const r = (coords.br[0] * this.dimensions.height) / 2;
-        const b = coords.br[1] * this.dimensions.width / 2; //prettier-ignore
-        const width = r - l;
-        const height = b - t;
-        const coord = { x: l, y: t };
-        return { width, height, coord };
-    };
-
-    renderedDoc = (): Doc => {
-        switch (this.type) {
-            case ViewType.CAROUSEL3D:
-                const carouselDoc = Docs.Create.Carousel3DDocument([], {
-                });
-                FieldUtils.applyBasicOpts(carouselDoc, this.dimensions, this.settings);
-            case ViewType.FREEFORM:
-                const freeformDoc = Docs.Create.FreeformDocument([], {
-                });
-                FieldUtils.applyBasicOpts(freeformDoc, this.dimensions, this.settings);
-            default:
-                return new Doc();
-        }
-    }
-
-}
-
-export class TemplateMatcher {
-
-    static matchesForTemplate = (field: FieldSettings, cols: Col[]): number[][] => {
-        const colMatchesField = (col: Col, field: FieldSettings) => {
-            return field.sizes?.some(size => col.sizes?.includes(size)) && field.types?.includes(col.type);
-        };
-
-        const matches: number[][] = Array(field.subfields?.length)
-            .fill([])
-            .map(() => []);
-
-        field.subfields?.forEach((field, i) => {
-            cols.forEach((col, v) => {
-                if (colMatchesField(col, field)) {
-                    matches[i].push(v);
-                }
-            });
-        });
-
-        return matches;
-    };
-
-    static maxMatches = (fieldsCt: number, matches: number[][]) => {
-        const used: boolean[] = Array(fieldsCt).fill(false);
-        const mt: number[] = Array(fieldsCt).fill(-1);
-
-        const augmentingPath = (v: number): boolean => {
-            if (used[v]) return false;
-            used[v] = true;
-            for (const to of matches[v]) {
-                if (mt[to] === -1 || augmentingPath(mt[to])) {
-                    mt[to] = v;
-                    return true;
-                }
-            }
-            return false;
-        };
-
-        for (let v = 0; v < fieldsCt; ++v) {
-            used.fill(false);
-            augmentingPath(v);
-        }
-
-        let count: number = 0;
-
-        for (let i = 0; i < fieldsCt; ++i) {
-            if (mt[i] !== -1) ++count;
-        }
-
-        return count;
-    };
-
-    findValidTemplates = (cols: Col[], templates: TemplateDocInfos[]) => {
-        let validTemplates: any[] = [];
-        templates.forEach(template => {
-            const numFields = template.fields.length;
-            if (!(numFields === cols.length)) return;
-            const matches = this.matchesForTemplate(template, cols);
-            if (this.maxMatches(numFields, matches) === numFields) {
-                validTemplates.push(template.title);
-            }
-        });
-
-        validTemplates = validTemplates.map(title => TemplateLayouts.getTemplateByTitle(title));
-
-        return validTemplates;
-    };
-
-}
-
-
-export class FieldUtils {
-    public static getLocalDimensions = (coords: { tl: [number, number]; br: [number, number] }, parentDimensions: FieldDimensions): FieldDimensions => {
-        const l = (coords.tl[0] * parentDimensions.height) / 2;
-        const t = coords.tl[1] * parentDimensions.width / 2; //prettier-ignore
-        const r = (coords.br[0] * parentDimensions.height) / 2;
-        const b = coords.br[1] * parentDimensions.width / 2; //prettier-ignore
-        const width = r - l;
-        const height = b - t;
-        const coord = { x: l, y: t };
-        return { width, height, coord };
-    };
-
-    public static applyBasicOpts = (doc: Doc, parentDimensions: FieldDimensions, settings: FieldSettings) => {
-        const opts = settings.opts;
-        doc.isDefaultTemplateDoc = true,
-        doc.x = parentDimensions.coord.x;
-        doc.y = parentDimensions.coord.y;
-        doc._height = parentDimensions.height;
-        doc._width = parentDimensions.width;
-        doc.backgroundColor = opts.backgroundColor ?? '';
-        doc._layout_borderRounding = `${opts.cornerRounding ?? 0}px`;
-        doc.borderColor = opts.borderColor;
-        doc.borderWidth = opts.borderWidth;
-        doc.opacity = opts.opacity;
-        doc._rotation = opts.rotation;
-        doc.hCentering = opts.contentXCentering;
-    };
-
-    public static calculateFontSize = (contWidth: number, contHeight: number, text: string, uppercase: boolean): number => {
-        const words: string[] = text.split(/\s+/).filter(Boolean);
-
-        let currFontSize = 1;
-        let rowsCount = 1;
-        let currTextHeight = currFontSize * rowsCount * 2;
-
-        while (currTextHeight <= contHeight) {
-            let wordIndex = 0;
-            let currentRowWidth = 0;
-            let wordsInCurrRow = 0;
-            rowsCount = 1;
-
-            while (wordIndex < words.length) {
-                const word = words[wordIndex];
-                const wordWidth = word.length * currFontSize * 0.5;
-
-                if (currentRowWidth + wordWidth <= contWidth) {
-                    currentRowWidth += wordWidth;
-                    ++wordsInCurrRow;
-                } else {
-                    if (words.length !== 1 && words.length > wordsInCurrRow) {
-                        rowsCount++;
-                        currentRowWidth = wordWidth;
-                        wordsInCurrRow = 1;
-                    } else {
-                        break;
-                    }
-                }
-
-                wordIndex++;
-            }
-
-            currTextHeight = rowsCount * currFontSize * 2;
-
-            currFontSize += 1;
-        }
-
-        return currFontSize - 1;
-    };
-}
\ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
new file mode 100644
index 000000000..361476446
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
@@ -0,0 +1,92 @@
+import { Doc } from "../../../../../../fields/Doc";
+import { Docs } from "../../../../../documents/Documents";
+import { Col } from "../DocCreatorMenu";
+import { TemplateLayouts } from "../TemplateBackend";
+import { Field, FieldDimensions, FieldSettings, ViewType } from "./Field";
+import { FieldUtils } from "./FieldUtils";
+import { StaticField } from "./StaticField";
+
+export class DynamicField implements Field {
+    private type: ViewType;
+    private subfields: Field[] = [];
+
+    private id: number;
+    private settings: FieldSettings;
+
+    private parent: Field;
+    private dimensions: FieldDimensions;
+
+    constructor(settings: FieldSettings, type: ViewType, id: number, parent?: Field) {
+        this.type = type;
+        this.id = id;
+        this.settings = settings;
+        if (!parent) {
+            this.parent = this;
+            this.dimensions = {width: this.settings.br[0] - this.settings.tl[0], height: this.settings.br[1] - this.settings.tl[1], coord: {x: this.settings.tl[0], y: this.settings.tl[1]}};
+        } else {
+            this.parent = parent;
+            this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
+        }
+        this.subfields = this.setupSubfields();
+    }
+
+    setContent = (content: string) => { return };
+    getContent = () => { return '' };
+
+    get getSubfields() { return this.subfields };
+    get getAllSubfields() {
+        const fields: Field[] = [];
+        this.subfields?.forEach(field => {
+            fields.push(field);
+            fields.concat(field.getAllSubfields)
+        });
+        return fields;
+    };
+
+    get getDimensions() { return this.dimensions };
+    get getID() { return this.id };
+
+    matches = () => {
+        return [];
+    }
+
+    setupSubfields = (): Field[] => {
+        this.settings.subfields?.forEach(fieldSettings => {
+            let field: Field;
+            const dynamicType = fieldSettings.dynamicType;
+
+            if (dynamicType) { field = new DynamicField(fieldSettings, dynamicType, 0, this); }
+
+            field = new StaticField(fieldSettings, this, 0);
+            this.subfields?.push(field);
+        });
+        return [];
+    }
+
+    getChildDimensions = (coords: { tl: [number, number]; br: [number, number] }): FieldDimensions => {
+        const l = (coords.tl[0] * this.dimensions.height) / 2;
+        const t = coords.tl[1] * this.dimensions.width / 2; //prettier-ignore
+        const r = (coords.br[0] * this.dimensions.height) / 2;
+        const b = coords.br[1] * this.dimensions.width / 2; //prettier-ignore
+        const width = r - l;
+        const height = b - t;
+        const coord = { x: l, y: t };
+        return { width, height, coord };
+    };
+
+    renderedDoc = (): Doc => {
+        switch (this.type) {
+            case ViewType.CAROUSEL3D:
+                const carouselDoc = Docs.Create.Carousel3DDocument([], {
+                });
+                FieldUtils.applyBasicOpts(carouselDoc, this.dimensions, this.settings);
+            case ViewType.FREEFORM:
+                const freeformDoc = Docs.Create.FreeformDocument([], {
+                });
+                FieldUtils.applyBasicOpts(freeformDoc, this.dimensions, this.settings);
+            default:
+                return new Doc();
+        }
+    }
+
+}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
new file mode 100644
index 000000000..0c1b6e5fc
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
@@ -0,0 +1,57 @@
+import { Doc } from "../../../../../../fields/Doc";
+import { TemplateFieldSize, TemplateFieldType } from "../TemplateBackend";
+
+export interface Field {
+    getContent: () => string;
+    setContent: (content: string) => void;
+    getDimensions: FieldDimensions;
+    getSubfields: Field[];
+    getAllSubfields: Field[];
+    getID: number;
+    setupSubfields: () => Field[];
+    renderedDoc: (content: string) => Doc;
+    matches: () => number[][];
+}
+
+export type FieldSettings = {
+    tl: [number, number];
+    br: [number, number];
+    opts: FieldOpts;
+    dynamicType?: ViewType;
+    subfields?: FieldSettings[];
+    types?: TemplateFieldType[];
+    sizes?: TemplateFieldSize[];
+    description?: string;
+};
+
+export enum FieldContentType {
+    STRING = 'string',
+    IMAGE = 'image',
+}
+
+export enum ViewType {
+    CAROUSEL3D = 'carousel3d',
+    FREEFORM = 'freeform',
+}
+
+export type FieldDimensions = {
+    width: number;
+    height: number;
+    coord: {x: number, y: number};
+}
+
+export interface FieldOpts {
+    backgroundColor?: string;
+    color?: string;
+    cornerRounding?: number;
+    borderWidth?: string;
+    borderColor?: string;
+    contentXCentering?: 'h-left' | 'h-center' | 'h-right';
+    contentYCentering?: 'top' | 'center' | 'bottom';
+    opacity?: number;
+    rotation?: number;
+    //animation?: boolean;
+    fontBold?: boolean;
+    fontTransform?: 'uppercase' | 'lowercase';
+    fieldViewType?: 'freeform' | 'stacked';
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
new file mode 100644
index 000000000..ead46d721
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
@@ -0,0 +1,144 @@
+import { Doc } from "../../../../../../fields/Doc";
+import { Col } from "../DocCreatorMenu";
+import { TemplateFieldSize, TemplateFieldType, TemplateLayouts } from "../TemplateBackend";
+import { FieldDimensions, FieldSettings } from "./Field";
+
+export class FieldUtils {
+    public static getLocalDimensions = (coords: { tl: [number, number]; br: [number, number] }, parentDimensions: FieldDimensions): FieldDimensions => {
+        const l = (coords.tl[0] * parentDimensions.height) / 2;
+        const t = coords.tl[1] * parentDimensions.width / 2; //prettier-ignore
+        const r = (coords.br[0] * parentDimensions.height) / 2;
+        const b = coords.br[1] * parentDimensions.width / 2; //prettier-ignore
+        const width = r - l;
+        const height = b - t;
+        const coord = { x: l, y: t };
+        return { width, height, coord };
+    };
+
+    public static applyBasicOpts = (doc: Doc, parentDimensions: FieldDimensions, settings: FieldSettings) => {
+        const opts = settings.opts;
+        doc.isDefaultTemplateDoc = true,
+        doc.x = parentDimensions.coord.x;
+        doc.y = parentDimensions.coord.y;
+        doc._height = parentDimensions.height;
+        doc._width = parentDimensions.width;
+        doc.backgroundColor = opts.backgroundColor ?? '';
+        doc._layout_borderRounding = `${opts.cornerRounding ?? 0}px`;
+        doc.borderColor = opts.borderColor;
+        doc.borderWidth = opts.borderWidth;
+        doc.opacity = opts.opacity;
+        doc._rotation = opts.rotation;
+        doc.hCentering = opts.contentXCentering;
+    };
+
+    public static calculateFontSize = (contWidth: number, contHeight: number, text: string, uppercase: boolean): number => {
+        const words: string[] = text.split(/\s+/).filter(Boolean);
+
+        let currFontSize = 1;
+        let rowsCount = 1;
+        let currTextHeight = currFontSize * rowsCount * 2;
+
+        while (currTextHeight <= contHeight) {
+            let wordIndex = 0;
+            let currentRowWidth = 0;
+            let wordsInCurrRow = 0;
+            rowsCount = 1;
+
+            while (wordIndex < words.length) {
+                const word = words[wordIndex];
+                const wordWidth = word.length * currFontSize * 0.5;
+
+                if (currentRowWidth + wordWidth <= contWidth) {
+                    currentRowWidth += wordWidth;
+                    ++wordsInCurrRow;
+                } else {
+                    if (words.length !== 1 && words.length > wordsInCurrRow) {
+                        rowsCount++;
+                        currentRowWidth = wordWidth;
+                        wordsInCurrRow = 1;
+                    } else {
+                        break;
+                    }
+                }
+
+                wordIndex++;
+            }
+
+            currTextHeight = rowsCount * currFontSize * 2;
+
+            currFontSize += 1;
+        }
+
+        return currFontSize - 1;
+    };
+}
+
+export class TemplateMatcher {
+
+    static matchesForTemplate = (field: FieldSettings, cols: Col[]): number[][] => {
+        const colMatchesField = (col: Col, field: FieldSettings) => {
+            return field.sizes?.some(size => col.sizes?.includes(size)) && field.types?.includes(col.type);
+        };
+
+        const matches: number[][] = Array(field.subfields?.length)
+            .fill([])
+            .map(() => []);
+
+        field.subfields?.forEach((field, i) => {
+            cols.forEach((col, v) => {
+                if (colMatchesField(col, field)) {
+                    matches[i].push(v);
+                }
+            });
+        });
+
+        return matches;
+    };
+
+    static maxMatches = (fieldsCt: number, matches: number[][]) => {
+        const used: boolean[] = Array(fieldsCt).fill(false);
+        const mt: number[] = Array(fieldsCt).fill(-1);
+
+        const augmentingPath = (v: number): boolean => {
+            if (used[v]) return false;
+            used[v] = true;
+            for (const to of matches[v]) {
+                if (mt[to] === -1 || augmentingPath(mt[to])) {
+                    mt[to] = v;
+                    return true;
+                }
+            }
+            return false;
+        };
+
+        for (let v = 0; v < fieldsCt; ++v) {
+            used.fill(false);
+            augmentingPath(v);
+        }
+
+        let count: number = 0;
+
+        for (let i = 0; i < fieldsCt; ++i) {
+            if (mt[i] !== -1) ++count;
+        }
+
+        return count;
+    };
+
+    findValidTemplates = (cols: Col[], templates: FieldSettings[]) => {
+        let validTemplates: any[] = [];
+        templates.forEach(template => {
+            const numFields = template.subfields?.length;
+            if (!(numFields === cols.length)) return;
+            const matches = TemplateMatcher.matchesForTemplate(template, cols);
+            if (TemplateMatcher.maxMatches(numFields, matches) === numFields) {
+                validTemplates.push('');
+            }
+        });
+
+        validTemplates = validTemplates.map(title => TemplateLayouts.getTemplateByTitle(title));
+
+        return validTemplates;
+    };
+
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
new file mode 100644
index 000000000..efceae65a
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
@@ -0,0 +1,98 @@
+import { TbHospital } from "react-icons/tb";
+import { Doc } from "../../../../../../fields/Doc";
+import { FieldType } from "../../../../../../fields/ObjectField";
+import { Docs, DocumentOptions } from "../../../../../documents/Documents";
+import { Col } from "../DocCreatorMenu";
+import { Template } from "../Template";
+import { TemplateDocInfos, TemplateFieldSize, TemplateFieldType, TemplateLayouts } from "../TemplateBackend";
+import { DynamicField } from "./DynamicField";
+import { FieldUtils } from "./FieldUtils";
+import { Field, FieldContentType, FieldDimensions, FieldSettings } from "./Field";
+
+export class StaticField {
+    private content: string;
+    private contentType: FieldContentType | undefined;
+    private subfields: Field[] = [];
+
+    private id: number;
+
+    private settings: FieldSettings;
+
+    private parent: Field;
+    private dimensions: FieldDimensions;
+
+    constructor(settings: FieldSettings, parent: Field, id: number) {
+        this.settings = settings;
+        this.id = id;
+        this.parent = parent;
+        this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
+        this.content = '';
+        this.subfields = this.setupSubfields();
+    };
+
+    get getSubfields(): Field[] { return this.subfields ?? []; };
+
+    get getAllSubfields(): Field[] {
+        const fields: Field[] = [];
+        this.subfields?.forEach(field => {
+            fields.push(field);
+            fields.concat(field.getAllSubfields)
+        });
+        return fields;
+    };
+
+    get getDimensions() { return this.dimensions };
+    get getID() { return this.id };
+
+    setContent = (newContent: string) => { this.content = newContent };
+    getContent() { return this.content };
+
+    setupSubfields = (): Field[] => {
+        const fields: Field[] = [];
+        this.settings.subfields?.forEach(fieldSettings => {
+            let field: Field;
+            const dynamicType = fieldSettings.dynamicType;
+
+            if (dynamicType) { 
+                field = new DynamicField(fieldSettings, dynamicType, 0, this); 
+            } else {
+                field = new StaticField(fieldSettings, this, 0);
+            }
+
+            fields.push(field);
+        });
+        return fields;
+    };
+
+    matches = (): number[][] => {
+        return [];
+    };
+
+    renderedDoc = (content: string): Doc => {
+        const opts = this.settings.opts;
+
+        if (!this.contentType) { this.contentType = FieldContentType.STRING };
+
+        switch (this.contentType) {
+            case FieldContentType.STRING:
+                const text = String(content);
+                const textDoc = Docs.Create.TextDocument(text, {
+                    text_fontColor: opts.color,
+                    contentBold: opts.fontBold,
+                    textTransform: opts.fontTransform,
+                    color: opts.color,
+                    _text_fontSize: `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, text, true)}`
+                });
+                FieldUtils.applyBasicOpts(textDoc, this.dimensions, this.settings);
+                return textDoc;
+            case FieldContentType.IMAGE:
+                const url = String(content);
+                const imgDoc = Docs.Create.ImageDocument(url, {
+                    _layout_fitWidth: false,
+                });
+                FieldUtils.applyBasicOpts(imgDoc, this.dimensions, this.settings);
+                return imgDoc;
+        }   
+    };
+
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index 57565906b..f05f61b61 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -1,40 +1,25 @@
 
 import { Doc } from "../../../../../fields/Doc";
 import { Docs } from "../../../../documents/Documents";
-import { Field } from "./FieldTypes";
+import { DynamicField } from "./FieldTypes/DynamicField";
+import { Field, FieldSettings, ViewType } from "./FieldTypes/Field";
+import {  } from "./FieldTypes/FieldUtils";
+import { } from "./FieldTypes/StaticField";
 import { TemplateDocInfos } from "./TemplateBackend";
 
 export class Template {
 
-    mainField: Field;
-    width: number = 0;
-    height: number = 0;
-    fields: Field[] = [];
+    mainField: DynamicField;
 
-    constructor(templateInfo: TemplateDocInfos) {
-        this.width = templateInfo.width;
-        this.height = templateInfo.height;
-        this.fields = templateInfo.fields.map(settings => new Field(settings, this));
+    constructor(templateInfo: FieldSettings) {
+        this.mainField = this.setupMainField(templateInfo);
     }
 
-    get childFields(): Field[] {
-        return this.fields;
-    }
+    get childFields(): Field[] { return this.mainField.getSubfields };
+    get allFields(): Field[] { return this.mainField.getAllSubfields };
 
-    get allFields(): Field[] {
-        const fields = this.fields;
-        this.fields.forEach(field => fields.concat(field.subfields));
-        return fields;
+    setupMainField = (templateInfo: FieldSettings) => {
+        return new DynamicField(templateInfo, ViewType.FREEFORM, 0);
     }
 
-    getChildDimensions = (coords: { tl: [number, number]; br: [number, number] }): { width: number; height: number; coord: { x: number; y: number } } => {
-        const l = (coords.tl[0] * this.height) / 2;
-        const t = coords.tl[1] * this.width / 2; //prettier-ignore
-        const r = (coords.br[0] * this.height) / 2;
-        const b = coords.br[1] * this.width / 2; //prettier-ignore
-        const width = r - l;
-        const height = b - t;
-        const coord = { x: l, y: t };
-        return { width, height, coord };
-    };
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
index a25eab74f..43b0b1572 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
@@ -1,4 +1,5 @@
-import { FieldOpts, FieldSettings } from "./FieldTypes";
+import { FieldOpts, FieldSettings } from "./FieldTypes/Field";
+import { } from "./FieldTypes/StaticField";
 
 export enum TemplateFieldType {
     TEXT = 'text',
-- 
cgit v1.2.3-70-g09d2


From 691fc130de706c691a42f7e87688c14102016ccc Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Tue, 29 Oct 2024 04:02:29 -0400
Subject: starting to integrate refactor with docreatormenu functionality

---
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   | 290 ++-------------------
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx     |  15 +-
 .../DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx |  12 +-
 .../DocCreatorMenu/FieldTypes/FieldUtils.tsx       |  70 -----
 .../DocCreatorMenu/FieldTypes/StaticField.tsx      |  37 ++-
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   |  54 +++-
 .../DataVizBox/DocCreatorMenu/TemplateBackend.tsx  | 134 +++++-----
 .../DataVizBox/DocCreatorMenu/TemplateManager.tsx  |  23 ++
 8 files changed, 215 insertions(+), 420 deletions(-)
 create mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx

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

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index 02fd7f869..36264f886 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -29,8 +29,10 @@ import './DocCreatorMenu.scss';
 import { DefaultStyleProvider, returnEmptyDocViewList } from '../../../StyleProvider';
 import { Transform } from '../../../../util/Transform';
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
-import { TemplateDocInfos, TemplateFieldSize, TemplateFieldType, TemplateLayouts } from './TemplateBackend';
-import { FieldOpts, FieldSettings } from './FieldTypes/StaticField';
+import { TemplateFieldSize, TemplateFieldType, TemplateLayouts } from './TemplateBackend';
+import { TemplateManager } from './TemplateManager';
+import { Template } from './Template';
+import { Field, FieldContentType } from './FieldTypes/Field';
 
 export enum LayoutType {
     STACKED = 'stacked',
@@ -49,6 +51,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
     private _ref: HTMLDivElement | null = null;
 
+    private templateManager: TemplateManager; 
+
     @observable _fullyRenderedDocs: Doc[] = [];
     @observable _renderedDocCollectionPreview: Doc | undefined = undefined;
     @observable _renderedDocCollection: Doc | undefined = undefined;
@@ -99,6 +103,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         super(props);
         makeObservable(this);
         DocCreatorMenu.Instance = this;
+        this.templateManager = new TemplateManager(TemplateLayouts.allTemplates);
         //setTimeout(() => this.generateTemplates(''));
     }
 
@@ -562,79 +567,13 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         }
     };
 
-    matchesForTemplate = (template: TemplateDocInfos, cols: Col[]): number[][] => {
-        const colMatchesField = (col: Col, field: FieldSettings) => {
-            return field.sizes?.some(size => col.sizes?.includes(size)) && field.types?.includes(col.type);
-        };
-
-        const matches: number[][] = Array(template.fields.length)
-            .fill([])
-            .map(() => []);
-
-        template.fields.forEach((field, i) => {
-            cols.forEach((col, v) => {
-                if (colMatchesField(col, field)) {
-                    matches[i].push(v);
-                }
-            });
-        });
-
-        return matches;
-    };
-
-    maxMatches = (fieldsCt: number, matches: number[][]) => {
-        const used: boolean[] = Array(fieldsCt).fill(false);
-        const mt: number[] = Array(fieldsCt).fill(-1);
-
-        const augmentingPath = (v: number): boolean => {
-            if (used[v]) return false;
-            used[v] = true;
-            for (const to of matches[v]) {
-                if (mt[to] === -1 || augmentingPath(mt[to])) {
-                    mt[to] = v;
-                    return true;
-                }
-            }
-            return false;
-        };
-
-        for (let v = 0; v < fieldsCt; ++v) {
-            used.fill(false);
-            augmentingPath(v);
-        }
-
-        let count: number = 0;
-
-        for (let i = 0; i < fieldsCt; ++i) {
-            if (mt[i] !== -1) ++count;
-        }
-
-        return count;
-    };
-
-    findValidTemplates = (cols: Col[], templates: TemplateDocInfos[]) => {
-        let validTemplates: any[] = [];
-        templates.forEach(template => {
-            const numFields = template.fields.length;
-            if (!(numFields === cols.length)) return;
-            const matches = this.matchesForTemplate(template, cols);
-            if (this.maxMatches(numFields, matches) === numFields) {
-                validTemplates.push(template.title);
-            }
-        });
-
-        validTemplates = validTemplates.map(title => TemplateLayouts.getTemplateByTitle(title));
-
-        return validTemplates;
-    };
-
     /**
      * Populates a preset template framework with content from a datavizbox or any AI-generated content.
      * @param template the preloaded template framework being filled in
      * @param assignments a list of template field numbers (from top to bottom) and their assigned columns from the linked dataviz
      * @returns a doc containing the fully rendered template
      */
-    fillPresetTemplate = async (template: TemplateDocInfos, assignments: { [field: string]: Col }): Promise<Doc> => {
+    fillPresetTemplate = async (template: Template, assignments: { [field: string]: Col }): Promise<Doc> => {
         const wordLimit = (size: TemplateFieldSize) => {
             switch (size) {
                 case TemplateFieldSize.TINY:
@@ -665,22 +604,11 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                         const assignments: { [title: string]: { number: string; content: string } } = JSON.parse(res);
                         //console.log('assignments', GPTAssignments, 'assignment string', GPTAssignmentString, 'field content', fieldContent, 'response', res, 'assignments', assignments);
                         Object.entries(assignments).forEach(([title, info]) => {
-                            const field: FieldSettings = template.fields[Number(info.number)];
+                            const field: Field = template.getFieldByID(Number(info.number));
                             const col = this.getColByTitle(title);
 
-                            const doc = FieldUtils.TextField(
-                                {
-                                    tl: field.tl,
-                                    br: field.br,
-                                },
-                                template.height,
-                                template.width,
-                                col.title,
-                                info.content ?? '',
-                                field.opts
-                            );
-
-                            rendered.push(doc);
+                            field.setContent(info.content ?? '', FieldContentType.STRING);
+                            field.setTitle(col.title);
                         });
                     }
                 } catch (err) {
@@ -691,22 +619,12 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             return rendered;
         };
 
-        const createGeneratedImage = async (fieldNum: string, col: Col, prompt: string) => {
+        const generateAndLoadImage = async (fieldNum: string, col: Col, prompt: string) => {
             const url = await this.generateGPTImage(prompt);
-            const field: FieldSettings = template.fields[Number(fieldNum)];
-            const doc = FieldUtils.ImageField(
-                {
-                    tl: field.tl,
-                    br: field.br,
-                },
-                template.height,
-                template.width,
-                col.title,
-                url ?? '',
-                field.opts
-            );
+            const field: Field = template.getFieldByID(Number(fieldNum));
 
-            return doc;
+            field.setContent(url ?? '', FieldContentType.IMAGE);
+            field.setTitle(col.title);
         };
 
         const renderImageCalls = async (): Promise<Doc[]> => {
@@ -715,7 +633,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
             if (calls.length) {
                 try {
-                    const renderedImages: Doc[] = await Promise.all(
+                    await Promise.all(
                         calls.map(async ([fieldNum, col]) => {
                             const sysPrompt =
                                 'Your job is to create a prompt for an AI image generator to help it generate an image based on existing content in a template and a user prompt. Your prompt should focus heavily on visual elements to help the image generator; avoid unecessary info that might distract it. ONLY INCLUDE THE PROMPT, NO OTHER TEXT OR EXPLANATION. The existing content is as follows: ' +
@@ -724,14 +642,10 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                 col.desc;
 
                             const prompt = await gptAPICall(sysPrompt, GPTCallType.COMPLETEPROMPT);
-                            //console.log(sysPrompt, prompt);
 
-                            return createGeneratedImage(fieldNum, col, prompt);
+                            generateAndLoadImage(fieldNum, col, prompt);
                         })
                     );
-
-                    const renderedTemplates: Doc[] = await Promise.all(renderedImages);
-                    renderedTemplates.forEach(doc => rendered.push(doc));
                 } catch (e) {
                     console.log(e);
                 }
@@ -740,12 +654,12 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             return rendered;
         };
 
-        const fields: Doc[] = [];
+        const fields: Field[] = [];
 
-        const GPTAssignments = Object.entries(assignments).filter(([f, col]) => this._columns.includes(col));
-        const nonGPTAssignments: [string, Col][] = Object.entries(assignments).filter(a => !GPTAssignments.includes(a));
-        const GPTTextCalls = GPTAssignments.filter(([str, col]) => col.type === TemplateFieldType.TEXT);
-        const GPTIMGCalls = GPTAssignments.filter(([str, col]) => col.type === TemplateFieldType.VISUAL);
+        const autoLoadedFields = Object.entries(assignments).filter(([f, col]) => this._columns.includes(col));
+        const userCreatedFields: [string, Col][] = Object.entries(assignments).filter(a => !autoLoadedFields.includes(a));
+        const GPTTextCalls = autoLoadedFields.filter(([str, col]) => col.type === TemplateFieldType.TEXT);
+        const GPTIMGCalls = autoLoadedFields.filter(([str, col]) => col.type === TemplateFieldType.VISUAL);
 
         const stringifyGPTInfo = (calls: [string, Col][]): string => {
             let string: string = '*** COLUMN INFO:';
@@ -759,9 +673,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
         let fieldContent: string = '';
 
-        Object.entries(nonGPTAssignments).forEach(([f, strCol]) => {
-            const field: FieldSettings = template.fields[Number(f)];
-            const col = strCol[1];
+        Object.entries(userCreatedFields).forEach(([fieldID, strAndCol]) => {
+            const field: Field = template.getFieldByID(Number(fieldID));
+            const col = strAndCol[1];
 
             const doc = (col.type === TemplateFieldType.VISUAL ? FieldUtils.ImageField : FieldUtils.TextField)(
                 {
@@ -775,7 +689,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                 field.opts
             );
 
-            fieldContent += `--- Field #${f} (title: ${col.title}): ${col.defaultContent ?? ''} ---`;
+            fieldContent += `--- Field #${fieldID} (title: ${col.title}): ${col.defaultContent ?? ''} ---`;
 
             fields.push(doc);
         });
@@ -829,7 +743,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         return createMainDoc();
     };
 
-    compileFieldDescriptions = (templates: TemplateDocInfos[]): string => {
+    compileFieldDescriptions = (templates: Template[]): string => {
         let descriptions: string = '';
         templates.forEach(template => {
             descriptions += `----------  NEW TEMPLATE TO INCLUDE: Description of template ${template.title}'s fields: `;
@@ -898,7 +812,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         this._dataViz?.updateColDefaults();
 
         const cols = this.fieldsInfos;
-        const templates = this.findValidTemplates(cols, TemplateLayouts.allTemplates);
+        const templates = this.templateManager.getValidTemplates(cols);
 
         const assignments: [TemplateDocInfos, { [field: number]: Col }][] = await this.assignColsToFields(templates, cols);
 
@@ -1668,151 +1582,3 @@ export type Col = {
     type: TemplateFieldType;
     defaultContent?: string;
 };
-
-type DecorationField = FieldSettings;
-
-type InkDecoration = {};
-
-type TemplateDecorations = FieldSettings | InkDecoration;
-
-interface TemplateOpts extends FieldOpts {}
-
-export class FieldUtils {
-    public static calculateFontSize = (contWidth: number, contHeight: number, text: string, uppercase: boolean): number => {
-        const words: string[] = text.split(/\s+/).filter(Boolean);
-
-        let currFontSize = 1;
-        let rowsCount = 1;
-        let currTextHeight = currFontSize * rowsCount * 2;
-
-        while (currTextHeight <= contHeight) {
-            let wordIndex = 0;
-            let currentRowWidth = 0;
-            let wordsInCurrRow = 0;
-            rowsCount = 1;
-
-            while (wordIndex < words.length) {
-                const word = words[wordIndex];
-                const wordWidth = word.length * currFontSize * 0.5;
-                //console.log(wordWidth)
-
-                if (currentRowWidth + wordWidth <= contWidth) {
-                    currentRowWidth += wordWidth;
-                    ++wordsInCurrRow;
-                } else {
-                    if (words.length !== 1 && words.length > wordsInCurrRow) {
-                        rowsCount++;
-                        currentRowWidth = wordWidth;
-                        wordsInCurrRow = 1;
-                    } else {
-                        break;
-                    }
-                }
-
-                wordIndex++;
-            }
-
-            currTextHeight = rowsCount * currFontSize * 2;
-            //console.log(rowsCount, currFontSize, currTextHeight)
-
-            currFontSize += 1;
-        }
-
-        return currFontSize - 1;
-    };
-
-    private static getDimensions = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number): { width: number; height: number; coord: { x: number; y: number } } => {
-        const l = (coords.tl[0] * parentHeight) / 2;
-        const t = coords.tl[1] * parentWidth / 2; //prettier-ignore
-        const r = (coords.br[0] * parentHeight) / 2;
-        const b = coords.br[1] * parentWidth / 2; //prettier-ignore
-        const width = r - l;
-        const height = b - t;
-        const coord = { x: l, y: t };
-        //console.log(coords, parentWidth, parentHeight, height);
-        return { width, height, coord };
-    };
-
-    public static FreeformField = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
-        const { width, height, coord } = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
-
-        const docWithBasicOpts = Docs.Create.FreeformDocument([], {
-            isDefaultTemplateDoc: true,
-            _height: height,
-            _width: width,
-            title: title,
-            x: coord.x,
-            y: coord.y,
-            backgroundColor: opts.backgroundColor ?? '',
-            _layout_borderRounding: `${opts.cornerRounding ?? 0}px`,
-            borderColor: opts.borderColor,
-            borderWidth: opts.borderWidth,
-            opacity: opts.opacity,
-            hCentering: opts.contentXCentering,
-            _rotation: opts.rotation,
-        });
-
-        return docWithBasicOpts;
-    };
-
-    public static TextField = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
-        const { width, height, coord } = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
-
-        const docWithBasicOpts = Docs.Create.TextDocument(content, {
-            isDefaultTemplateDoc: true,
-            _height: height,
-            _width: width,
-            title: title,
-            x: coord.x,
-            y: coord.y,
-            _text_fontSize: `${FieldUtils.calculateFontSize(width, height, content, true)}`,
-            backgroundColor: opts.backgroundColor ?? '',
-            text_fontColor: opts.color,
-            contentBold: opts.fontBold,
-            textTransform: opts.fontTransform,
-            color: opts.color,
-            _layout_borderRounding: `${opts.cornerRounding ?? 0}px`,
-            borderColor: opts.borderColor,
-            borderWidth: opts.borderWidth,
-            opacity: opts.opacity,
-            hCentering: opts.contentXCentering,
-            _rotation: opts.rotation,
-        });
-
-        docWithBasicOpts._layout_hideScroll = true;
-
-        return docWithBasicOpts;
-    };
-
-    public static ImageField = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number, title: string, content: string, opts: FieldOpts) => {
-        const { width, height, coord } = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
-
-        const doc = Docs.Create.ImageDocument(content, {
-            isDefaultTemplateDoc: true,
-            _height: height,
-            _width: width,
-            title: title,
-            x: coord.x,
-            y: coord.y,
-            _layout_fitWidth: false,
-            backgroundColor: opts.backgroundColor ?? '',
-            _layout_borderRounding: `${opts.cornerRounding ?? 0}px`,
-            borderColor: opts.borderColor,
-            borderWidth: opts.borderWidth,
-            opacity: opts.opacity,
-            _rotation: opts.rotation,
-        });
-
-        //setTimeout(() => {doc._height = height; doc._width = width}, 10);
-
-        return doc;
-    };
-
-    public static CarouselField = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number, title: string, fields: Doc[]) => {
-        const { width, height, coord } = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
-
-        const doc = Docs.Create.Carousel3DDocument(fields, { _height: height, _width: width, title: title, x: coord.x, y: coord.y, _text_fontSize: `${height / 2}` });
-
-        return doc;
-    };
-}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
index 361476446..a55f44589 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
@@ -2,7 +2,7 @@ import { Doc } from "../../../../../../fields/Doc";
 import { Docs } from "../../../../../documents/Documents";
 import { Col } from "../DocCreatorMenu";
 import { TemplateLayouts } from "../TemplateBackend";
-import { Field, FieldDimensions, FieldSettings, ViewType } from "./Field";
+import { Field, FieldContentType, FieldDimensions, FieldSettings, ViewType } from "./Field";
 import { FieldUtils } from "./FieldUtils";
 import { StaticField } from "./StaticField";
 
@@ -12,6 +12,7 @@ export class DynamicField implements Field {
 
     private id: number;
     private settings: FieldSettings;
+    private title: string = '';
 
     private parent: Field;
     private dimensions: FieldDimensions;
@@ -30,9 +31,12 @@ export class DynamicField implements Field {
         this.subfields = this.setupSubfields();
     }
 
-    setContent = (content: string) => { return };
+    setContent = (content: string, type: FieldContentType) => { return };
     getContent = () => { return '' };
 
+    setTitle = (title: string) => { this.title = title };
+    getTitle = () => { return this.title };
+
     get getSubfields() { return this.subfields };
     get getAllSubfields() {
         const fields: Field[] = [];
@@ -45,15 +49,16 @@ export class DynamicField implements Field {
 
     get getDimensions() { return this.dimensions };
     get getID() { return this.id };
+    get getViewType() { return this.type };
 
-    matches = () => {
+    matches = (cols: Col[]): Array<number> => {
         return [];
     }
 
     setupSubfields = (): Field[] => {
         this.settings.subfields?.forEach(fieldSettings => {
             let field: Field;
-            const dynamicType = fieldSettings.dynamicType;
+            const dynamicType = fieldSettings.viewType;
 
             if (dynamicType) { field = new DynamicField(fieldSettings, dynamicType, 0, this); }
 
@@ -78,10 +83,12 @@ export class DynamicField implements Field {
         switch (this.type) {
             case ViewType.CAROUSEL3D:
                 const carouselDoc = Docs.Create.Carousel3DDocument([], {
+                    title: this.title,
                 });
                 FieldUtils.applyBasicOpts(carouselDoc, this.dimensions, this.settings);
             case ViewType.FREEFORM:
                 const freeformDoc = Docs.Create.FreeformDocument([], {
+                    title: this.title,
                 });
                 FieldUtils.applyBasicOpts(freeformDoc, this.dimensions, this.settings);
             default:
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
index 0c1b6e5fc..aa1d1de33 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
@@ -1,23 +1,27 @@
 import { Doc } from "../../../../../../fields/Doc";
+import { Col } from "../DocCreatorMenu";
 import { TemplateFieldSize, TemplateFieldType } from "../TemplateBackend";
 
 export interface Field {
     getContent: () => string;
-    setContent: (content: string) => void;
+    setContent: (content: string, type: FieldContentType) => void;
     getDimensions: FieldDimensions;
     getSubfields: Field[];
     getAllSubfields: Field[];
     getID: number;
+    getViewType: ViewType;
+    getTitle: () => string;
+    setTitle: (title: string) => void;
     setupSubfields: () => Field[];
     renderedDoc: (content: string) => Doc;
-    matches: () => number[][];
+    matches: (cols: Col[]) => number[];
 }
 
 export type FieldSettings = {
     tl: [number, number];
     br: [number, number];
     opts: FieldOpts;
-    dynamicType?: ViewType;
+    viewType: ViewType;
     subfields?: FieldSettings[];
     types?: TemplateFieldType[];
     sizes?: TemplateFieldSize[];
@@ -32,6 +36,8 @@ export enum FieldContentType {
 export enum ViewType {
     CAROUSEL3D = 'carousel3d',
     FREEFORM = 'freeform',
+    STATIC = 'static',
+    DEC = 'decoration'
 }
 
 export type FieldDimensions = {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
index ead46d721..c389704cf 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
@@ -71,74 +71,4 @@ export class FieldUtils {
 
         return currFontSize - 1;
     };
-}
-
-export class TemplateMatcher {
-
-    static matchesForTemplate = (field: FieldSettings, cols: Col[]): number[][] => {
-        const colMatchesField = (col: Col, field: FieldSettings) => {
-            return field.sizes?.some(size => col.sizes?.includes(size)) && field.types?.includes(col.type);
-        };
-
-        const matches: number[][] = Array(field.subfields?.length)
-            .fill([])
-            .map(() => []);
-
-        field.subfields?.forEach((field, i) => {
-            cols.forEach((col, v) => {
-                if (colMatchesField(col, field)) {
-                    matches[i].push(v);
-                }
-            });
-        });
-
-        return matches;
-    };
-
-    static maxMatches = (fieldsCt: number, matches: number[][]) => {
-        const used: boolean[] = Array(fieldsCt).fill(false);
-        const mt: number[] = Array(fieldsCt).fill(-1);
-
-        const augmentingPath = (v: number): boolean => {
-            if (used[v]) return false;
-            used[v] = true;
-            for (const to of matches[v]) {
-                if (mt[to] === -1 || augmentingPath(mt[to])) {
-                    mt[to] = v;
-                    return true;
-                }
-            }
-            return false;
-        };
-
-        for (let v = 0; v < fieldsCt; ++v) {
-            used.fill(false);
-            augmentingPath(v);
-        }
-
-        let count: number = 0;
-
-        for (let i = 0; i < fieldsCt; ++i) {
-            if (mt[i] !== -1) ++count;
-        }
-
-        return count;
-    };
-
-    findValidTemplates = (cols: Col[], templates: FieldSettings[]) => {
-        let validTemplates: any[] = [];
-        templates.forEach(template => {
-            const numFields = template.subfields?.length;
-            if (!(numFields === cols.length)) return;
-            const matches = TemplateMatcher.matchesForTemplate(template, cols);
-            if (TemplateMatcher.maxMatches(numFields, matches) === numFields) {
-                validTemplates.push('');
-            }
-        });
-
-        validTemplates = validTemplates.map(title => TemplateLayouts.getTemplateByTitle(title));
-
-        return validTemplates;
-    };
-
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
index efceae65a..cd1008429 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
@@ -4,10 +4,9 @@ import { FieldType } from "../../../../../../fields/ObjectField";
 import { Docs, DocumentOptions } from "../../../../../documents/Documents";
 import { Col } from "../DocCreatorMenu";
 import { Template } from "../Template";
-import { TemplateDocInfos, TemplateFieldSize, TemplateFieldType, TemplateLayouts } from "../TemplateBackend";
 import { DynamicField } from "./DynamicField";
 import { FieldUtils } from "./FieldUtils";
-import { Field, FieldContentType, FieldDimensions, FieldSettings } from "./Field";
+import { Field, FieldContentType, FieldDimensions, FieldSettings, ViewType } from "./Field";
 
 export class StaticField {
     private content: string;
@@ -15,6 +14,7 @@ export class StaticField {
     private subfields: Field[] = [];
 
     private id: number;
+    private title: string = '';
 
     private settings: FieldSettings;
 
@@ -36,36 +36,55 @@ export class StaticField {
         const fields: Field[] = [];
         this.subfields?.forEach(field => {
             fields.push(field);
-            fields.concat(field.getAllSubfields)
+            fields.concat(field.getAllSubfields);
         });
         return fields;
     };
 
     get getDimensions() { return this.dimensions };
     get getID() { return this.id };
+    get getViewType() { return ViewType.STATIC };
 
-    setContent = (newContent: string) => { this.content = newContent };
+    setContent = (newContent: string, type: FieldContentType) => { 
+        this.content = newContent;
+        this.contentType = type;
+    };
     getContent() { return this.content };
 
+    setTitle = (title: string) => { this.title = title };
+    getTitle = () => { return this.title };
+
     setupSubfields = (): Field[] => {
         const fields: Field[] = [];
         this.settings.subfields?.forEach(fieldSettings => {
             let field: Field;
-            const dynamicType = fieldSettings.dynamicType;
+            const dynamicType = fieldSettings.viewType;
 
             if (dynamicType) { 
                 field = new DynamicField(fieldSettings, dynamicType, 0, this); 
             } else {
                 field = new StaticField(fieldSettings, this, 0);
-            }
+            };
 
             fields.push(field);
         });
         return fields;
     };
 
-    matches = (): number[][] => {
-        return [];
+    matches = (cols: Col[]): number[] => {
+        const colMatchesField = (col: Col) => {
+            return this.settings.sizes?.some(size => col.sizes?.includes(size)) && this.settings.types?.includes(col.type);
+        };
+
+        const matches: Array<number> = [];
+
+        cols.forEach((col, v) => {
+            if (colMatchesField(col)) {
+                matches.push(v);
+            }
+        });
+
+        return matches;
     };
 
     renderedDoc = (content: string): Doc => {
@@ -77,6 +96,7 @@ export class StaticField {
             case FieldContentType.STRING:
                 const text = String(content);
                 const textDoc = Docs.Create.TextDocument(text, {
+                    title: this.title,
                     text_fontColor: opts.color,
                     contentBold: opts.fontBold,
                     textTransform: opts.fontTransform,
@@ -88,6 +108,7 @@ export class StaticField {
             case FieldContentType.IMAGE:
                 const url = String(content);
                 const imgDoc = Docs.Create.ImageDocument(url, {
+                    title: this.title,
                     _layout_fitWidth: false,
                 });
                 FieldUtils.applyBasicOpts(imgDoc, this.dimensions, this.settings);
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index f05f61b61..486fe7f7e 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -1,11 +1,11 @@
 
 import { Doc } from "../../../../../fields/Doc";
 import { Docs } from "../../../../documents/Documents";
+import { Col } from "./DocCreatorMenu";
 import { DynamicField } from "./FieldTypes/DynamicField";
 import { Field, FieldSettings, ViewType } from "./FieldTypes/Field";
 import {  } from "./FieldTypes/FieldUtils";
 import { } from "./FieldTypes/StaticField";
-import { TemplateDocInfos } from "./TemplateBackend";
 
 export class Template {
 
@@ -17,9 +17,61 @@ export class Template {
 
     get childFields(): Field[] { return this.mainField.getSubfields };
     get allFields(): Field[] { return this.mainField.getAllSubfields };
+    get contentFields(): Field[] { return this.allFields.filter(field => field.getViewType === ViewType.STATIC) };
+
+    getFieldByID = (id: number): Field => {
+        return this.allFields.filter(field => field.getID === id)[0];
+    }
 
     setupMainField = (templateInfo: FieldSettings) => {
         return new DynamicField(templateInfo, ViewType.FREEFORM, 0);
     }
 
+    isValidTemplate = (cols: Col[]) => {
+        return this.maxMatches(this.getMatches(cols)) === this.contentFields.length;
+    }
+
+    getMatches = (cols: Col[]) => {
+        const matches: number[][] = Array(this.contentFields.length)
+            .fill([])
+            .map(() => []);
+
+        this.contentFields.forEach((field, i) => {
+            matches[i].concat(field.matches(cols));
+        });
+
+        return matches;
+    }
+
+    maxMatches = (matches: number[][]) => {
+        const fieldsCt = this.contentFields.length;
+        const used: boolean[] = Array(fieldsCt).fill(false);
+        const mt: number[] = Array(fieldsCt).fill(-1);
+
+        const augmentingPath = (v: number): boolean => {
+            if (used[v]) return false;
+            used[v] = true;
+            for (const to of matches[v]) {
+                if (mt[to] === -1 || augmentingPath(mt[to])) {
+                    mt[to] = v;
+                    return true;
+                }
+            }
+            return false;
+        };
+
+        for (let v = 0; v < fieldsCt; ++v) {
+            used.fill(false);
+            augmentingPath(v);
+        }
+
+        let count: number = 0;
+
+        for (let i = 0; i < fieldsCt; ++i) {
+            if (mt[i] !== -1) ++count;
+        }
+
+        return count;
+    };
+
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
index 43b0b1572..00eb8fab4 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
@@ -1,4 +1,4 @@
-import { FieldOpts, FieldSettings } from "./FieldTypes/Field";
+import { FieldOpts, FieldSettings, ViewType } from "./FieldTypes/Field";
 import { } from "./FieldTypes/StaticField";
 
 export enum TemplateFieldType {
@@ -15,53 +15,24 @@ export enum TemplateFieldSize {
     HUGE = 'huge',
 }
 
-export interface TemplateDocInfos {
-    title: string;
-    height: number;
-    width: number;
-    opts: FieldOpts;
-    fields: FieldSettings[];
-    decorations: FieldSettings[];
-}
-
 export class TemplateLayouts {
-    public static get allTemplates(): TemplateDocInfos[] {
-        return Object.values(TemplateLayouts).filter(value => typeof value === 'object' && value !== null && 'title' in value) as TemplateDocInfos[];
+    public static get allTemplates(): FieldSettings[] {
+        return Object.values(TemplateLayouts).filter(value => typeof value === 'object' && value !== null && 'title' in value) as FieldSettings[];
     }
 
-    public static getTemplateByTitle = (title: string): TemplateDocInfos | undefined => {
-        switch (title) {
-            case 'fourfield1':
-                return TemplateLayouts.FourField001;
-            case 'fourfield2':
-                return TemplateLayouts.FourField002;
-            // case 'fourfield3':
-            //     return TemplateLayouts.FourField003;
-            case 'fourfield4':
-                return TemplateLayouts.FourField004;
-            case 'threefield1':
-                return TemplateLayouts.ThreeField001;
-            case 'threefield2':
-                return TemplateLayouts.ThreeField002;
-            default:
-                break;
-        }
-
-        return undefined;
-    };
-
-    public static FourField001: TemplateDocInfos = {
-        title: 'fourfield1',
-        width: 416,
-        height: 700,
+    public static FourField001: FieldSettings = {
+        tl: [0, 0],
+        br: [416, 700],
+        viewType: ViewType.FREEFORM,
         opts: {
             backgroundColor: '#C0B887',
             cornerRounding: 20,
             borderColor: '#6B461F',
             borderWidth: '12',
         },
-        fields: [
+        subfields: [
             {
+                viewType: ViewType.STATIC,
                 tl: [-0.95, -1],
                 br: [0.95, -0.85],
                 types: [TemplateFieldType.TEXT],
@@ -75,6 +46,7 @@ export class TemplateLayouts {
                 },
             },
             {
+                viewType: ViewType.STATIC,
                 tl: [-0.87, -0.83],
                 br: [0.87, 0.2],
                 types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
@@ -88,6 +60,7 @@ export class TemplateLayouts {
                 },
             },
             {
+                viewType: ViewType.STATIC,
                 tl: [-0.8, 0.2],
                 br: [0.8, 0.3],
                 types: [TemplateFieldType.TEXT],
@@ -100,6 +73,7 @@ export class TemplateLayouts {
                 },
             },
             {
+                viewType: ViewType.STATIC,
                 tl: [-0.87, 0.37],
                 br: [0.87, 0.96],
                 types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
@@ -113,18 +87,18 @@ export class TemplateLayouts {
                 },
             },
         ],
-        decorations: [],
     };
 
-    public static FourField002: TemplateDocInfos = {
-        title: 'fourfield2',
-        width: 425,
-        height: 778,
+    public static FourField002: FieldSettings = {
+        viewType: ViewType.FREEFORM,
+        tl: [0,0],
+        br: [425, 778],
         opts: {
             backgroundColor: '#242425',
         },
-        fields: [
+        subfields: [
             {
+                viewType: ViewType.STATIC,
                 tl: [-0.83, -0.95],
                 br: [0.83, -0.2],
                 types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
@@ -136,6 +110,7 @@ export class TemplateLayouts {
                 },
             },
             {
+                viewType: ViewType.STATIC,
                 tl: [-0.65, -0.2],
                 br: [0.65, -0.02],
                 types: [TemplateFieldType.TEXT],
@@ -149,6 +124,7 @@ export class TemplateLayouts {
                 },
             },
             {
+                viewType: ViewType.STATIC,
                 tl: [-0.65, 0],
                 br: [0.65, 0.18],
                 types: [TemplateFieldType.TEXT],
@@ -162,6 +138,7 @@ export class TemplateLayouts {
                 },
             },
             {
+                viewType: ViewType.STATIC,
                 tl: [-0.83, 0.2],
                 br: [0.83, 0.95],
                 types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
@@ -174,46 +151,49 @@ export class TemplateLayouts {
                     backgroundColor: '#242425',
                 },
             },
-        ],
-        decorations: [
             {
+                viewType: ViewType.DEC,
                 tl: [-0.8, -0.075],
                 br: [-0.525, 0.075],
                 opts: {
                     backgroundColor: '#F8E71C',
-                    //rotation: 45,
+                    rotation: 45,
                 },
             },
             {
+                viewType: ViewType.DEC,
                 tl: [-0.3075, -0.0245],
                 br: [-0.2175, 0.0245],
                 opts: {
                     backgroundColor: '#F8E71C',
-                    //rotation: 45,
+                    rotation: 45,
                 },
             },
             {
+                viewType: ViewType.DEC,
                 tl: [-0.045, -0.0245],
                 br: [0.045, 0.0245],
                 opts: {
                     backgroundColor: '#F8E71C',
-                    //rotation: 45,
+                    rotation: 45,
                 },
             },
             {
+                viewType: ViewType.DEC,
                 tl: [0.2175, -0.0245],
                 br: [0.3075, 0.0245],
                 opts: {
                     backgroundColor: '#F8E71C',
-                    //rotation: 45,
+                    rotation: 45,
                 },
             },
             {
+                viewType: ViewType.DEC,
                 tl: [0.525, -0.075],
                 br: [0.8, 0.075],
                 opts: {
                     backgroundColor: '#F8E71C',
-                    //rotation: 45,
+                    rotation: 45,
                 },
             },
         ],
@@ -279,17 +259,18 @@ export class TemplateLayouts {
     //     }]
     // };
 
-    public static FourField004: TemplateDocInfos = {
-        title: 'fourfield4',
-        width: 414,
-        height: 583,
+    public static FourField004: FieldSettings = {
+        viewType: ViewType.FREEFORM,
+        tl: [0,0],
+        br: [414,583],
         opts: {
             backgroundColor: '#6CCAF0',
             borderColor: '#1088C3',
             borderWidth: '10',
         },
-        fields: [
+        subfields: [
             {
+                viewType: ViewType.STATIC,
                 tl: [-0.86, -0.92],
                 br: [-0.075, -0.77],
                 types: [TemplateFieldType.TEXT],
@@ -303,6 +284,7 @@ export class TemplateLayouts {
                 },
             },
             {
+                viewType: ViewType.STATIC,
                 tl: [0.075, -0.92],
                 br: [0.86, -0.77],
                 types: [TemplateFieldType.TEXT],
@@ -316,6 +298,7 @@ export class TemplateLayouts {
                 },
             },
             {
+                viewType: ViewType.STATIC,
                 tl: [-0.81, -0.64],
                 br: [0.81, 0.48],
                 types: [TemplateFieldType.VISUAL],
@@ -327,6 +310,7 @@ export class TemplateLayouts {
                 },
             },
             {
+                viewType: ViewType.STATIC,
                 tl: [-0.86, 0.6],
                 br: [0.86, 0.92],
                 types: [TemplateFieldType.TEXT],
@@ -338,9 +322,8 @@ export class TemplateLayouts {
                     backgroundColor: '#F3F57D',
                 },
             },
-        ],
-        decorations: [
             {
+                viewType: ViewType.DEC,
                 tl: [-0.852, -0.67],
                 br: [0.852, 0.51],
                 opts: {
@@ -352,15 +335,16 @@ export class TemplateLayouts {
         ],
     };
 
-    public static ThreeField001: TemplateDocInfos = {
-        title: 'threefield1',
-        width: 575,
-        height: 770,
+    public static ThreeField001: FieldSettings = {
+        viewType: ViewType.FREEFORM,
+        tl: [0,0],
+        br: [575, 770],
         opts: {
             backgroundColor: '#DDD3A9',
         },
-        fields: [
+        subfields: [
             {
+                viewType: ViewType.STATIC,
                 tl: [-0.66, -0.747],
                 br: [0.66, 0.247],
                 types: [TemplateFieldType.VISUAL],
@@ -373,6 +357,7 @@ export class TemplateLayouts {
                 },
             },
             {
+                viewType: ViewType.STATIC,
                 tl: [-0.7, 0.2],
                 br: [0.7, 0.46],
                 types: [TemplateFieldType.TEXT],
@@ -384,6 +369,7 @@ export class TemplateLayouts {
                 },
             },
             {
+                viewType: ViewType.STATIC,
                 tl: [-0.95, 0.5],
                 br: [0.95, 0.95],
                 types: [TemplateFieldType.TEXT],
@@ -394,9 +380,8 @@ export class TemplateLayouts {
                     color: 'white',
                 },
             },
-        ],
-        decorations: [
             {
+                viewType: ViewType.DEC,
                 tl: [0.2, -1.32],
                 br: [1.8, -0.66],
                 opts: {
@@ -405,6 +390,7 @@ export class TemplateLayouts {
                 },
             },
             {
+                viewType: ViewType.DEC,
                 tl: [-1.8, -1.32],
                 br: [-0.2, -0.66],
                 opts: {
@@ -413,6 +399,7 @@ export class TemplateLayouts {
                 },
             },
             {
+                viewType: ViewType.DEC,
                 tl: [0.33, 0.75],
                 br: [1.66, 1.25],
                 opts: {
@@ -421,6 +408,7 @@ export class TemplateLayouts {
                 },
             },
             {
+                viewType: ViewType.DEC,
                 tl: [-1.66, 0.75],
                 br: [-0.33, 1.25],
                 opts: {
@@ -431,15 +419,16 @@ export class TemplateLayouts {
         ],
     };
 
-    public static ThreeField002: TemplateDocInfos = {
-        title: 'threefield2',
-        width: 477,
-        height: 662,
+    public static ThreeField002: FieldSettings = {
+        viewType: ViewType.FREEFORM,
+        tl: [0,0],
+        br: [477, 662],
         opts: {
             backgroundColor: '#9E9C95',
         },
-        fields: [
+        subfields: [
             {
+                viewType: ViewType.STATIC,
                 tl: [-0.875, -0.9],
                 br: [0.875, 0.7],
                 types: [TemplateFieldType.VISUAL],
@@ -451,6 +440,7 @@ export class TemplateLayouts {
                 },
             },
             {
+                viewType: ViewType.STATIC,
                 tl: [0.1, 0.775],
                 br: [0.95, 0.975],
                 types: [TemplateFieldType.TEXT],
@@ -465,6 +455,7 @@ export class TemplateLayouts {
                 },
             },
             {
+                viewType: ViewType.STATIC,
                 tl: [-0.95, 0.775],
                 br: [-0.1, 0.975],
                 types: [TemplateFieldType.TEXT],
@@ -476,9 +467,8 @@ export class TemplateLayouts {
                     contentXCentering: 'h-right',
                 },
             },
-        ],
-        decorations: [
             {
+                viewType: ViewType.DEC,
                 tl: [-0.025, 0.8],
                 br: [0.025, 0.95],
                 opts: {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
new file mode 100644
index 000000000..890bc6f73
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
@@ -0,0 +1,23 @@
+import { Col } from "./DocCreatorMenu";
+import { FieldSettings } from "./FieldTypes/Field";
+import { Template } from "./Template";
+import { TemplateLayouts } from "./TemplateBackend";
+
+export class TemplateManager {
+
+    templates: Template[] = [];
+
+    constructor(templateSettings: FieldSettings[]) {
+        this.templates = this.initializeTemplates(templateSettings);
+    }
+
+    initializeTemplates = (templateSettings: FieldSettings[]): Template[] => {
+        const initializedTemplates: Template[] = [];
+        templateSettings.forEach(settings => initializedTemplates.push(new Template(settings)));
+        return initializedTemplates;
+    }
+
+    getValidTemplates = (cols: Col[]): Template[] => {
+        return this.templates.filter(template => template.isValidTemplate(cols));
+    }
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 66fcb190ad52aa7e5fc7e0055fed392a569c1972 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Tue, 29 Oct 2024 18:48:25 -0400
Subject: matching algorithm working

---
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx    |  4 +++-
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx      | 15 +++++++--------
 .../DocCreatorMenu/FieldTypes/StaticField.tsx       | 16 ++++++++++------
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx    | 21 ++++++++++++++++-----
 .../DataVizBox/DocCreatorMenu/TemplateBackend.tsx   |  2 +-
 .../DataVizBox/DocCreatorMenu/TemplateManager.tsx   |  1 +
 6 files changed, 38 insertions(+), 21 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index 46266883f..a1de81fa3 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -469,7 +469,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     };
 
     testTemplate = async () => {
-        this.updateIcons(this._suggestedTemplates.slice());
+        
+        console.log(this.templateManager.templates);
+
         this.forceUpdate();
 
         // try {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
index 220d938ff..f235d3218 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
@@ -7,7 +7,6 @@ import { FieldUtils } from "./FieldUtils";
 import { StaticField } from "./StaticField";
 
 export class DynamicField implements Field {
-    private type: ViewType;
     private subfields: Field[] = [];
 
     private id: number;
@@ -17,8 +16,7 @@ export class DynamicField implements Field {
     private parent: Field;
     private dimensions: FieldDimensions;
 
-    constructor(settings: FieldSettings, type: ViewType, id: number, parent?: Field) {
-        this.type = type;
+    constructor(settings: FieldSettings, id: number, parent?: Field) {
         this.id = id;
         this.settings = settings;
         if (settings.title) { this.title = settings.title };
@@ -50,7 +48,7 @@ export class DynamicField implements Field {
 
     get getDimensions() { return this.dimensions };
     get getID() { return this.id };
-    get getViewType() { return this.type };
+    get getViewType() { return this.settings.viewType };
 
     get getDescription(): string {
         return this.settings.description ?? '';
@@ -61,16 +59,17 @@ export class DynamicField implements Field {
     }
 
     setupSubfields = (): Field[] => {
+        const fields: Field[] = [];
         this.settings.subfields?.forEach(fieldSettings => {
             let field: Field;
             const dynamicType = fieldSettings.viewType;
 
-            if (dynamicType) { field = new DynamicField(fieldSettings, dynamicType, 0, this); }
+            if (dynamicType) { field = new DynamicField(fieldSettings, 0, this); }
 
             field = new StaticField(fieldSettings, this, 0);
-            this.subfields?.push(field);
+            fields.push(field);
         });
-        return [];
+        return fields;
     }
 
     getChildDimensions = (coords: { tl: [number, number]; br: [number, number] }): FieldDimensions => {
@@ -85,7 +84,7 @@ export class DynamicField implements Field {
     };
 
     renderedDoc = (): Doc => {
-        switch (this.type) {
+        switch (this.settings.viewType) {
             case ViewType.CAROUSEL3D:
                 const carouselDoc = Docs.Create.Carousel3DDocument([], {
                     title: this.title,
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
index 809b40520..0f3631858 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
@@ -44,7 +44,7 @@ export class StaticField {
 
     get getDimensions() { return this.dimensions };
     get getID() { return this.id };
-    get getViewType() { return ViewType.STATIC };
+    get getViewType() { return this.settings.viewType };
 
     get getDescription(): string {
         return this.settings.description ?? '';
@@ -63,10 +63,10 @@ export class StaticField {
         const fields: Field[] = [];
         this.settings.subfields?.forEach(fieldSettings => {
             let field: Field;
-            const dynamicType = fieldSettings.viewType;
+            const type = fieldSettings.viewType;
 
-            if (dynamicType) { 
-                field = new DynamicField(fieldSettings, dynamicType, 0, this); 
+            if (type === ViewType.FREEFORM || type === ViewType.CAROUSEL3D) { 
+                field = new DynamicField(fieldSettings, 0, this); 
             } else {
                 field = new StaticField(fieldSettings, this, 0);
             };
@@ -78,8 +78,12 @@ export class StaticField {
 
     matches = (cols: Col[]): number[] => {
         const colMatchesField = (col: Col) => {
-            return this.settings.sizes?.some(size => col.sizes?.includes(size)) && this.settings.types?.includes(col.type);
-        };
+            const isMatch: boolean = (
+                this.settings.sizes?.some(size => col.sizes?.includes(size)) 
+                && this.settings.types?.includes(col.type)) 
+                ?? false;
+            return isMatch;
+        }
 
         const matches: Array<number> = [];
 
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index 486fe7f7e..708170359 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -24,33 +24,44 @@ export class Template {
     }
 
     setupMainField = (templateInfo: FieldSettings) => {
-        return new DynamicField(templateInfo, ViewType.FREEFORM, 0);
+        return new DynamicField(templateInfo, 0);
     }
 
     isValidTemplate = (cols: Col[]) => {
-        return this.maxMatches(this.getMatches(cols)) === this.contentFields.length;
+        const matches: number[][] = this.getMatches(cols);
+        const maxMatches: number = this.maxMatches(matches);
+        return maxMatches === this.contentFields.length;
     }
 
-    getMatches = (cols: Col[]) => {
-        const matches: number[][] = Array(this.contentFields.length)
+    getMatches = (cols: Col[]): number[][] => {
+        const numFields = this.contentFields.length;
+
+        if (cols.length !== numFields) return [];
+
+        const matches: number[][] = Array(numFields)
             .fill([])
             .map(() => []);
 
         this.contentFields.forEach((field, i) => {
-            matches[i].concat(field.matches(cols));
+            matches[i] = (field.matches(cols));
         });
 
         return matches;
     }
 
     maxMatches = (matches: number[][]) => {
+        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);
 
+        console.log(matches, fieldsCt);
+
         const augmentingPath = (v: number): boolean => {
             if (used[v]) return false;
             used[v] = true;
+
             for (const to of matches[v]) {
                 if (mt[to] === -1 || augmentingPath(mt[to])) {
                     mt[to] = v;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
index 00eb8fab4..a23c3ba3d 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
@@ -17,7 +17,7 @@ export enum TemplateFieldSize {
 
 export class TemplateLayouts {
     public static get allTemplates(): FieldSettings[] {
-        return Object.values(TemplateLayouts).filter(value => typeof value === 'object' && value !== null && 'title' in value) as FieldSettings[];
+        return Object.values(TemplateLayouts);
     }
 
     public static FourField001: FieldSettings = {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
index d47ae802c..535bd423f 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
@@ -30,6 +30,7 @@ export class TemplateManager {
     }
 
     getValidTemplates = (cols: Col[]): Template[] => {
+        console.log(this.templates.filter(template => template.isValidTemplate(cols)));
         return this.templates.filter(template => template.isValidTemplate(cols));
     }
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From de18eecdbd0ac99cdc78aef2dd477e341c28df76 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Tue, 29 Oct 2024 21:45:37 -0400
Subject: content is being filled into fields properly

---
 src/client/apis/gpt/GPT.ts                         |   2 +-
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   | 108 +++++++++------------
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx     |   8 +-
 .../DocCreatorMenu/FieldTypes/StaticField.tsx      |   9 +-
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   |   4 +-
 .../DataVizBox/DocCreatorMenu/TemplateBackend.tsx  |   5 +
 .../DataVizBox/DocCreatorMenu/TemplateManager.tsx  |   1 -
 7 files changed, 62 insertions(+), 75 deletions(-)

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

diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts
index d38e512bd..19f124bf7 100644
--- a/src/client/apis/gpt/GPT.ts
+++ b/src/client/apis/gpt/GPT.ts
@@ -66,7 +66,7 @@ const callTypeMap: { [type: string]: GPTCallOpts } = {
         prompt: 'List unique differences between the content of the UserAnswer and Rubric. Before each difference, label it and provide any additional information the UserAnswer missed and explain it in second person without separating it into UserAnswer and Rubric content and additional information. If there are no differences, say correct',
     },
     template: {
-        model: 'gpt-4o-mini',
+        model: 'gpt-4-turbo',
         maxTokens: 512,
         temp: 0.5,
         prompt: 'You will be given a list of field descriptions for multiple templates in the format {field #0: “description”}{field #1: “description”}{...}, and a list of column descriptions in the format {“title”: “description”}{...}. Your job is to match columns with fields based on their descriptions. Your output should be in the following JSON format: {“Template title”:{“#”: “title”, “#”: “title”, “#”: “title” …}, “Template title”:{“#”: “title”, “#”: “title”, “#”: “title” …}} where “Template title” represents the template,  # represents the field # and “title” the title of the column assigned to it. A filled out example might look like {“fivefield2”:{“0”:”Name”, “1”:”Image”, “2”:”Caption”, “3”:”Position”, “4”:”Stats”}, “fivefield3”:{0:”Image”, 1:”Name”, 2:”Caption”, 3:”Stats”, 4:”Position”}. Include one object for each template. IT IS VERY IMPORTANT THAT YOU ONLY INCLUDE TEXT IN THE FORMAT ABOVE, WITH NO ADDITIONS WHATSOEVER. Do not include extraneous ‘#’ characters, ‘column’ for columns, or ‘template’ for templates: ONLY THE TITLES AND NUMBERS. There should never be one column assigned to more than one field (ie. if the “name” column is assigned to field 1, it can’t be assigned to any other fields) . Do this for each template whose fields are described. The descriptions are as follows:',
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index a1de81fa3..405b32e8a 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -104,7 +104,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         makeObservable(this);
         DocCreatorMenu.Instance = this;
         this.templateManager = new TemplateManager(TemplateLayouts.allTemplates);
-        //setTimeout(() => this.generateTemplates(''));
     }
 
     @action setDataViz = (dataViz: DataVizBox) => {
@@ -264,7 +263,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     }
 
     updateIcons = (docs: Doc[]) => {
-        console.log('called')
         docs.map(this.getIcon);
     };
 
@@ -593,34 +591,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             }
         };
 
-        const renderTextCalls = async (): Promise<Doc[]> => {
-            const rendered: Doc[] = [];
-
-            if (GPTTextCalls.length) {
-                try {
-                    const prompt = fieldContent + GPTTextAssignment;
-
-                    const res = await gptAPICall(prompt, GPTCallType.FILL);
-
-                    if (res) {
-                        const assignments: { [title: string]: { number: string; content: string } } = JSON.parse(res);
-                        //console.log('assignments', GPTAssignments, 'assignment string', GPTAssignmentString, 'field content', fieldContent, 'response', res, 'assignments', assignments);
-                        Object.entries(assignments).forEach(([title, info]) => {
-                            const field: Field = template.getFieldByID(Number(info.number));
-                            const col = this.getColByTitle(title);
-
-                            field.setContent(info.content ?? '', FieldContentType.STRING);
-                            field.setTitle(col.title);
-                        });
-                    }
-                } catch (err) {
-                    console.log(err);
-                }
-            }
-
-            return rendered;
-        };
-
         const generateAndLoadImage = async (fieldNum: string, col: Col, prompt: string) => {
             const url = await this.generateGPTImage(prompt);
             const field: Field = template.getFieldByID(Number(fieldNum));
@@ -629,33 +599,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             field.setTitle(col.title);
         };
 
-        const renderImageCalls = async (): Promise<Doc[]> => {
-            const rendered: Doc[] = [];
-            const calls = GPTIMGCalls;
-
-            if (calls.length) {
-                try {
-                    await Promise.all(
-                        calls.map(async ([fieldNum, col]) => {
-                            const sysPrompt =
-                                'Your job is to create a prompt for an AI image generator to help it generate an image based on existing content in a template and a user prompt. Your prompt should focus heavily on visual elements to help the image generator; avoid unecessary info that might distract it. ONLY INCLUDE THE PROMPT, NO OTHER TEXT OR EXPLANATION. The existing content is as follows: ' +
-                                fieldContent +
-                                ' **** The user prompt is: ' +
-                                col.desc;
-
-                            const prompt = await gptAPICall(sysPrompt, GPTCallType.COMPLETEPROMPT);
-
-                            generateAndLoadImage(fieldNum, col, prompt);
-                        })
-                    );
-                } catch (e) {
-                    console.log(e);
-                }
-            }
-
-            return rendered;
-        };
-
         const GPTTextCalls = Object.entries(assignments).filter(([str, col]) => col.type === TemplateFieldType.TEXT);
         const GPTIMGCalls = Object.entries(assignments).filter(([str, col]) => col.type === TemplateFieldType.VISUAL);
 
@@ -671,15 +614,50 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
         let fieldContent: string = this.templateManager.getContentSummary(template);
 
-        const textCalls = await renderTextCalls();
-        const imageCalls = await renderImageCalls();
+        if (GPTTextCalls.length) {
+            try {
+                const prompt = fieldContent + GPTTextAssignment;
 
-        return template;
-    };
+                const res = await gptAPICall(prompt, GPTCallType.FILL);
 
-    renderTemplates = (templates: Template[]) => {
+                if (res) {
+                    const assignments: { [title: string]: { number: string; content: string } } = JSON.parse(res);
+                    //console.log('assignments', GPTAssignments, 'assignment string', GPTAssignmentString, 'field content', fieldContent, 'response', res, 'assignments', assignments);
+                    Object.entries(assignments).forEach(([title, info]) => {
+                        const field: Field = template.getFieldByID(Number(info.number));
+                        const col = this.getColByTitle(title);
 
-    }
+                        field.setContent(info.content ?? '', FieldContentType.STRING);
+                        field.setTitle(col.title);
+                    });
+                }
+            } catch (err) {
+                console.log(err);
+            }
+        }
+
+        if (GPTIMGCalls.length) {
+            try {
+                await Promise.all(
+                    GPTIMGCalls.map(async ([fieldNum, col]) => {
+                        const sysPrompt =
+                            'Your job is to create a prompt for an AI image generator to help it generate an image based on existing content in a template and a user prompt. Your prompt should focus heavily on visual elements to help the image generator; avoid unecessary info that might distract it. ONLY INCLUDE THE PROMPT, NO OTHER TEXT OR EXPLANATION. The existing content is as follows: ' +
+                            fieldContent +
+                            ' **** The user prompt is: ' +
+                            col.desc;
+
+                        const prompt = await gptAPICall(sysPrompt, GPTCallType.COMPLETEPROMPT);
+
+                        generateAndLoadImage(fieldNum, col, prompt);
+                    })
+                );
+            } catch (e) {
+                console.log(e);
+            }
+        };
+
+        return template;
+    };
 
     compileFieldDescriptions = (templates: Template[]): string => {
         let descriptions: string = '';
@@ -723,6 +701,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
             if (res && this._callCount === origCount) {
                 const assignments: { [templateTitle: string]: { [fieldID: string]: string } } = JSON.parse(res);
+                console.log('assignments', assignments)
                 const brokenDownAssignments: [Template, { [fieldID: number]: Col }][] = [];
 
                 Object.entries(assignments).forEach(([tempTitle, assignment]) => {
@@ -733,6 +712,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                             const col = this.getColByTitle(colTitle);
                             if (!this._userCreatedColumns.includes(col)){ // do the following for any fields not added by the user; will change in the future, for now only GPT content works with user-added fields
                                 const field = template.getFieldByID(Number(fieldID));
+                                //console.log(field);
                                 field.setContent(col.defaultContent ?? '', col.type === TemplateFieldType.VISUAL ? FieldContentType.IMAGE : FieldContentType.STRING);
                                 field.setTitle(col.title);
                             } else {
@@ -766,7 +746,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         const renderedTemplates: Template[] = await Promise.all(renderedTemplatePromises);
 
         setTimeout(() => {
-            this.setGSuggestedTemplates(renderedTemplates.map(template => template.mainField.renderedDoc()));
+            this.setGSuggestedTemplates(templates.map(template => template.mainField.renderedDoc()));
             this._GPTLoading = false;
         });
     };
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
index f235d3218..c47db2007 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
@@ -60,13 +60,15 @@ export class DynamicField implements Field {
 
     setupSubfields = (): Field[] => {
         const fields: Field[] = [];
-        this.settings.subfields?.forEach(fieldSettings => {
+        this.settings.subfields?.forEach((fieldSettings, index) => {
             let field: Field;
             const dynamicType = fieldSettings.viewType;
 
-            if (dynamicType) { field = new DynamicField(fieldSettings, 0, this); }
+            const id = Number(String(this.id) + String(index));
 
-            field = new StaticField(fieldSettings, this, 0);
+            if (dynamicType) { field = new DynamicField(fieldSettings, id, this); }
+
+            field = new StaticField(fieldSettings, this, id);
             fields.push(field);
         });
         return fields;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
index 0f3631858..a0b25485a 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
@@ -53,6 +53,7 @@ export class StaticField {
     setContent = (newContent: string, type: FieldContentType) => { 
         this.content = newContent;
         this.contentType = type;
+        console.log('id: ', this.content)
     };
     getContent() { return this.content };
 
@@ -61,14 +62,16 @@ export class StaticField {
 
     setupSubfields = (): Field[] => {
         const fields: Field[] = [];
-        this.settings.subfields?.forEach(fieldSettings => {
+        this.settings.subfields?.forEach((fieldSettings, index) => {
             let field: Field;
             const type = fieldSettings.viewType;
 
+            const id = Number(String(this.id) + String(index));
+
             if (type === ViewType.FREEFORM || type === ViewType.CAROUSEL3D) { 
-                field = new DynamicField(fieldSettings, 0, this); 
+                field = new DynamicField(fieldSettings, id, this); 
             } else {
-                field = new StaticField(fieldSettings, this, 0);
+                field = new StaticField(fieldSettings, this, id);
             };
 
             fields.push(field);
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index 708170359..69f5cfb81 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -24,7 +24,7 @@ export class Template {
     }
 
     setupMainField = (templateInfo: FieldSettings) => {
-        return new DynamicField(templateInfo, 0);
+        return new DynamicField(templateInfo, 1);
     }
 
     isValidTemplate = (cols: Col[]) => {
@@ -56,8 +56,6 @@ export class Template {
         const used: boolean[] = Array(fieldsCt).fill(false);
         const mt: number[] = Array(fieldsCt).fill(-1);
 
-        console.log(matches, fieldsCt);
-
         const augmentingPath = (v: number): boolean => {
             if (used[v]) return false;
             used[v] = true;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
index a23c3ba3d..166d27228 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
@@ -21,6 +21,7 @@ export class TemplateLayouts {
     }
 
     public static FourField001: FieldSettings = {
+        title: 'fourfield001',
         tl: [0, 0],
         br: [416, 700],
         viewType: ViewType.FREEFORM,
@@ -90,6 +91,7 @@ export class TemplateLayouts {
     };
 
     public static FourField002: FieldSettings = {
+        title: 'fourfield002',
         viewType: ViewType.FREEFORM,
         tl: [0,0],
         br: [425, 778],
@@ -260,6 +262,7 @@ export class TemplateLayouts {
     // };
 
     public static FourField004: FieldSettings = {
+        title: 'fourfield04',
         viewType: ViewType.FREEFORM,
         tl: [0,0],
         br: [414,583],
@@ -336,6 +339,7 @@ export class TemplateLayouts {
     };
 
     public static ThreeField001: FieldSettings = {
+        title: 'threefield001',
         viewType: ViewType.FREEFORM,
         tl: [0,0],
         br: [575, 770],
@@ -420,6 +424,7 @@ export class TemplateLayouts {
     };
 
     public static ThreeField002: FieldSettings = {
+        title: 'threefield002',
         viewType: ViewType.FREEFORM,
         tl: [0,0],
         br: [477, 662],
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
index 535bd423f..d47ae802c 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
@@ -30,7 +30,6 @@ export class TemplateManager {
     }
 
     getValidTemplates = (cols: Col[]): Template[] => {
-        console.log(this.templates.filter(template => template.isValidTemplate(cols)));
         return this.templates.filter(template => template.isValidTemplate(cols));
     }
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 4b9536c0b4db5922ac33523dc3d4f33d37007982 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Wed, 30 Oct 2024 03:36:01 -0400
Subject: getAllsubfields works now

---
 src/client/apis/gpt/GPT.ts                         |  2 +-
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   | 13 ++--
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx     | 14 +++--
 .../DocCreatorMenu/FieldTypes/StaticField.tsx      |  4 +-
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   |  3 +
 .../DataVizBox/DocCreatorMenu/TemplateBackend.tsx  | 71 ++++++++++++++++++++++
 6 files changed, 94 insertions(+), 13 deletions(-)

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

diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts
index 19f124bf7..80cbc86b3 100644
--- a/src/client/apis/gpt/GPT.ts
+++ b/src/client/apis/gpt/GPT.ts
@@ -69,7 +69,7 @@ const callTypeMap: { [type: string]: GPTCallOpts } = {
         model: 'gpt-4-turbo',
         maxTokens: 512,
         temp: 0.5,
-        prompt: 'You will be given a list of field descriptions for multiple templates in the format {field #0: “description”}{field #1: “description”}{...}, and a list of column descriptions in the format {“title”: “description”}{...}. Your job is to match columns with fields based on their descriptions. Your output should be in the following JSON format: {“Template title”:{“#”: “title”, “#”: “title”, “#”: “title” …}, “Template title”:{“#”: “title”, “#”: “title”, “#”: “title” …}} where “Template title” represents the template,  # represents the field # and “title” the title of the column assigned to it. A filled out example might look like {“fivefield2”:{“0”:”Name”, “1”:”Image”, “2”:”Caption”, “3”:”Position”, “4”:”Stats”}, “fivefield3”:{0:”Image”, 1:”Name”, 2:”Caption”, 3:”Stats”, 4:”Position”}. Include one object for each template. IT IS VERY IMPORTANT THAT YOU ONLY INCLUDE TEXT IN THE FORMAT ABOVE, WITH NO ADDITIONS WHATSOEVER. Do not include extraneous ‘#’ characters, ‘column’ for columns, or ‘template’ for templates: ONLY THE TITLES AND NUMBERS. There should never be one column assigned to more than one field (ie. if the “name” column is assigned to field 1, it can’t be assigned to any other fields) . Do this for each template whose fields are described. The descriptions are as follows:',
+        prompt: 'You will be given a list of field descriptions for one or more templates in the format {field #0: “description”}{field #1: “description”}{...}, and a list of column descriptions in the format {“title”: “description”}{...}. Your job is to match columns with fields based on their descriptions. Your output should be in the following JSON format: {“template_title”:{“#”: “title”, “#”: “title”, “#”: “title” …}, “template_title”:{“#”: “title”, “#”: “title”, “#”: “title” …}} where “template_title” is the templates title as specified in the description provided,  # represents the field # and “title” the title of the column assigned to it. A filled out example might look like {“fivefield2”:{“0”:”Name”, “1”:”Image”, “2”:”Caption”, “3”:”Position”, “4”:”Stats”}, “fivefield3”:{0:”Image”, 1:”Name”, 2:”Caption”, 3:”Stats”, 4:”Position”}. Include one object for each template. IT IS VERY IMPORTANT THAT YOU ONLY INCLUDE TEXT IN THE FORMAT ABOVE, WITH NO ADDITIONS WHATSOEVER. Do not include extraneous ‘#’ characters, ‘column’ for columns, or ‘template’ for templates: ONLY THE TITLES AND NUMBERS. There should never be one column assigned to more than one field (ie. if the “name” column is assigned to field 1, it can’t be assigned to any other fields) . Do this for each template whose fields are described. The descriptions are as follows:',
     },
     vizsum: {
         model: 'gpt-4o-mini',
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index ad7aa7cb9..54f109f84 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -411,9 +411,11 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
     testTemplate = async () => {
 
-        console.log(this._suggestedTemplates
-            ?.map(doc => ({ icon: ImageCast(doc.icon), doc }))
-            .filter(info => info.icon && info.doc));
+        console.log(this.templateManager.templates.map(template => {
+            template.mainField.getAllSubfields;
+        })
+            
+            )
 
         this.forceUpdate();
 
@@ -607,7 +609,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     compileFieldDescriptions = (templates: Template[]): string => {
         let descriptions: string = '';
         templates.forEach(template => {
-            descriptions += `----------  NEW TEMPLATE TO INCLUDE: Description of template ${template.mainField.getTitle()}'s fields: `;
+            console.log('title: ', template.mainField.getTitle());
+            descriptions += `----------  NEW TEMPLATE TO INCLUDE: The title is: ${template.mainField.getTitle()}. Its fields are: `;
             template.allFields.forEach(field => {
                 descriptions += `{Field #${field.getID}: ${field.getDescription}} `;
             });
@@ -685,6 +688,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         const cols = this.fieldsInfos;
         const templates = this.templateManager.getValidTemplates(cols);
 
+        console.log('templates: ', templates)
+
         const assignments: [Template, { [field: number]: Col }][] = await this.assignColsToFields(templates, cols);
 
         const renderedTemplatePromises: Promise<Template>[] = assignments.map(([template, assignments]) => this.applyGPTContentToTemplate(template, assignments));
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
index 136392c07..cd83472d8 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
@@ -38,10 +38,10 @@ export class DynamicField implements Field {
 
     get getSubfields() { return this.subfields };
     get getAllSubfields() {
-        const fields: Field[] = [];
+        let fields: Field[] = [];
         this.subfields?.forEach(field => {
             fields.push(field);
-            fields.concat(field.getAllSubfields)
+            fields = fields.concat(field.getAllSubfields)
         });
         return fields;
     };
@@ -62,13 +62,15 @@ export class DynamicField implements Field {
         const fields: Field[] = [];
         this.settings.subfields?.forEach((fieldSettings, index) => {
             let field: Field;
-            const dynamicType = fieldSettings.viewType;
+            const type = fieldSettings.viewType;
 
             const id = Number(String(this.id) + String(index));
 
-            if (dynamicType) { field = new DynamicField(fieldSettings, id, this); }
-
-            field = new StaticField(fieldSettings, this, id);
+            if (type == ViewType.CAROUSEL3D || type === ViewType.FREEFORM) {
+                field = new DynamicField(fieldSettings, id, this); 
+            } else {  
+                field = new StaticField(fieldSettings, this, id);
+            }
             fields.push(field);
         });
         return fields;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
index a56fa4fd6..795581008 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
@@ -34,10 +34,10 @@ export class StaticField {
     get getSubfields(): Field[] { return this.subfields ?? []; };
 
     get getAllSubfields(): Field[] {
-        const fields: Field[] = [];
+        let fields: Field[] = [];
         this.subfields?.forEach(field => {
             fields.push(field);
-            fields.concat(field.getAllSubfields);
+            fields = fields.concat(field.getAllSubfields);
         });
         return fields;
     };
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index 69f5cfb81..09eb86d20 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -34,6 +34,7 @@ export class Template {
     }
 
     getMatches = (cols: Col[]): number[][] => {
+        console.log(this.mainField.getTitle(), this.allFields)
         const numFields = this.contentFields.length;
 
         if (cols.length !== numFields) return [];
@@ -80,6 +81,8 @@ export class Template {
             if (mt[i] !== -1) ++count;
         }
 
+        console.log(this.mainField.getTitle(), count)
+
         return count;
     };
 
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
index 166d27228..53b3e7fb6 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
@@ -338,6 +338,77 @@ export class TemplateLayouts {
         ],
     };
 
+    public static FourFieldCarousel: FieldSettings = {
+        title: 'title_fourfieldcarousel',
+        viewType: ViewType.FREEFORM,
+        tl:[0,0],
+        br:[500, 600],
+        opts: {
+            backgroundColor: '#DDD3A9',
+        },
+        subfields: [
+            {
+                viewType: ViewType.STATIC,
+                tl: [-0.8, -.9],
+                br: [0.8, -.5],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
+                description: 'A small text field for a title that categorizes the rest of the content.',
+                opts: {
+                    borderColor: 'yellow',
+                    borderWidth: '8',
+                },
+            },
+            {
+                viewType: ViewType.CAROUSEL3D,
+                tl: [-0.9, -.3],
+                br: [0.9, .9],
+                opts: {
+                    borderColor: 'yellow',
+                    borderWidth: '8',
+                },
+                subfields: [
+                    {
+                        viewType: ViewType.STATIC,
+                        tl: [0, 0],
+                        br: [0, 0],
+                        types: [TemplateFieldType.VISUAL],
+                        sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                        description: 'A medium to large field for visual content that will share central focus with other content in the carousel.',
+                        opts: {
+                            borderColor: 'black',
+                            borderWidth: '8',
+                        },
+                    },
+                    {
+                        viewType: ViewType.STATIC,
+                        tl: [0, 0],
+                        br: [0, 0],
+                        types: [TemplateFieldType.VISUAL],
+                        sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                        description: 'A medium to large field for visual content that will share central focus with other content in the carousel.',
+                        opts: {
+                            borderColor: 'black',
+                            borderWidth: '8',
+                        },
+                    },
+                    {
+                        viewType: ViewType.STATIC,
+                        tl: [0, 0],
+                        br: [0, 0],
+                        types: [TemplateFieldType.VISUAL],
+                        sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                        description: 'A medium to large field for visual content that will share central focus with other content in the carousel.',
+                        opts: {
+                            borderColor: 'black',
+                            borderWidth: '8',
+                        },
+                    },
+                ]
+            },
+        ]
+    }
+
     public static ThreeField001: FieldSettings = {
         title: 'threefield001',
         viewType: ViewType.FREEFORM,
-- 
cgit v1.2.3-70-g09d2


From 4ce711a5c497a7b198f4be05325cca217fb0844c Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Mon, 4 Nov 2024 04:48:32 -0500
Subject: reworking doc generation from template

---
 src/client/views/nodes/DataVizBox/DataVizBox.tsx   |  2 +
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   | 88 ++++++++++++++--------
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx     |  6 +-
 .../DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx |  3 +-
 .../DocCreatorMenu/FieldTypes/FieldUtils.tsx       | 28 +++----
 .../DocCreatorMenu/FieldTypes/StaticField.tsx      | 49 ++++++++----
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   | 10 +++
 7 files changed, 124 insertions(+), 62 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 311a0ad65..6621c610f 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -703,6 +703,8 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             const values: string[] = [];
             fields.forEach(col => values.push(this.records[row][col]));
 
+            
+
             const proto = new Doc();
             proto.author = ClientUtils.CurrentUserEmail();
             values.forEach((val, i) => {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index e7d6bb98e..7491642eb 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -58,7 +58,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     @observable _renderedDocCollection: Doc | undefined = undefined;
 
     @observable _templateDocs: Doc[] = [];
-    @observable _selectedTemplate: Doc | undefined = undefined;
+    @observable _selectedTemplateDoc: Doc | undefined = undefined;
     @observable _userCreatedColumns: Col[] = [];
     @observable _selectedCols: { title: string; type: string; desc: string }[] | undefined = [];
 
@@ -68,7 +68,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     @observable _savedLayouts: DataVizTemplateLayout[] = [];
     @observable _expandedPreview: { icon: ImageField; doc: Doc } | undefined = undefined;
 
-    @observable _suggestedTemplates: Doc[] = [];
+    @observable _suggestedTemplates: Template[] = [];
     @observable _GPTOpt: boolean = false;
     @observable _userPrompt: string = '';
     @observable _callCount: number = 0;
@@ -112,12 +112,12 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     @action setTemplateDocs = (docs: Doc[]) => {
         this._templateDocs = docs.map(doc => (doc.annotationOn ? DocCast(doc.annotationOn) : doc));
     };
-    @action setGSuggestedTemplates = (docs: Doc[]) => {
-        this._suggestedTemplates = docs;
+    @action setSuggestedTemplates = (templates: Template[]) => {
+        this._suggestedTemplates = templates;
     };
 
     @computed get docsToRender() {
-        return this._selectedTemplate ? NumListCast(this._dataViz?.layoutDoc.dataViz_selectedRows) : [];
+        return this._selectedTemplateDoc ? NumListCast(this._dataViz?.layoutDoc.dataViz_selectedRows) : [];
     }
 
     @computed get rowsCount() {
@@ -179,7 +179,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     }
 
     @computed get canMakeDocs() {
-        return this._selectedTemplate !== undefined && this._layout !== undefined;
+        return this._selectedTemplateDoc !== undefined && this._layout !== undefined;
     }
 
     get bounds(): { t: number; b: number; l: number; r: number } {
@@ -239,7 +239,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             docs => this.updateIcons(docs)
         );
         this._disposers.gpt = reaction(
-            () => this._suggestedTemplates.slice(),
+            () => this._suggestedTemplates.map(template => template.mainField.renderedDoc()).slice(),
             docs => this.updateIcons(docs)
         );
         //this._disposers.columns = reaction(() => this._dataViz?.layoutDoc._dataViz_axes, () => {this.generateTemplates('')})
@@ -289,7 +289,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
     @action
     openMenu = () => {
-        const allTemplates = this._templateDocs.concat(this._suggestedTemplates);
+        const allTemplates = this._templateDocs.concat(this._suggestedTemplates.map(temp => temp.mainField.renderedDoc()));
         this._shouldDisplay = true;
         this.updateIcons(allTemplates);
     };
@@ -374,15 +374,14 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         return undefined;
     }
 
-    @action updateSelectedTemplate = (template: Doc) => {
-        if (this._selectedTemplate === template) {
-            this._selectedTemplate = undefined;
+    @action updateSelectedTemplate = (template: Template) => {
+        if (this._selectedTemplateDoc === template.mainField.renderedDoc()) {
+            this._selectedTemplateDoc = undefined;
             return;
         } else {
-            this._selectedTemplate = template;
-            MakeTemplate(template);
-            const templateInfo: DataVizTemplateInfo = { doc: template, layout: this._layout, referencePos: { x: this._pageX + 450, y: this._pageY }, columns: this.columnsCount };
-            this._fullyRenderedDocs = this._dataViz?.createDocsFromTemplate(templateInfo, true) ?? [];
+            this._selectedTemplateDoc = template.mainField.renderedDoc();
+            template.renderUpdates();
+            this._fullyRenderedDocs = this.createDocsFromTemplate(template) ?? [];
             this.updateRenderedDocCollection();
         }
     };
@@ -701,11 +700,40 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         });
 
         setTimeout(() => {
-            this.setGSuggestedTemplates(renderedTemplates);
+            this.setSuggestedTemplates(templates);
             this._GPTLoading = false;
         });
     };
 
+    createDocsFromTemplate = (template: Template) => {
+        const dv = this._dataViz;
+        if (!dv) return;
+        const fields: string[] = Array.from(Object.keys(dv.records[0]));
+        const selectedRows = NumListCast(dv.layoutDoc.dataViz_selectedRows);
+
+        const fieldContents: {[title: string]: string}[] = selectedRows.map(row => {
+            let values: {[title: string]: string} = {};
+            fields.forEach(col => {
+                values[col] = dv.records[row][col];
+            });
+
+            return values;
+        });
+
+        const renderedDocs: Doc[] = [];
+
+        fieldContents.forEach(content => {
+            fields.forEach(title => {
+                const field = template.getFieldByTitle(title);
+                field.setContent(content[title]);
+            });
+
+            renderedDocs.push(template.mainField.renderedDoc());
+        });
+
+        return renderedDocs;
+    }
+
     @action setExpandedView = (info: { icon: ImageField; doc: Doc } | undefined) => {
         if (info) {
             const doc = info.doc;
@@ -758,7 +786,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                 <div className="top-panel"/>
                 {rendered}
                 <div className="right-buttons-panel">
-                    <button className="docCreatorMenu-menu-button section-reveal-options top-right" onPointerDown={e => this.setUpButtonClick(e, () => {this._expandedPreview && this.updateIcons(this._suggestedTemplates.slice()); this.setExpandedView(undefined)})}>
+                    <button className="docCreatorMenu-menu-button section-reveal-options top-right" onPointerDown={e => this.setUpButtonClick(e, () => {this._expandedPreview && this.updateIcons(this._suggestedTemplates.map(template => template.mainField.renderedDoc()).slice()); this.setExpandedView(undefined)})}>
                         <FontAwesomeIcon icon="minimize" />
                     </button>
                     <button className="docCreatorMenu-menu-button section-reveal-options top-right-lower" onPointerDown={e => this.setUpButtonClick(e, () => this._expandedPreview && this._templateDocs.push(this._expandedPreview.doc))}>
@@ -797,16 +825,16 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                     </div>
                                 ) : (
                                     this._suggestedTemplates
-                                        ?.map(doc => ({ icon: ImageCast(doc.icon), doc }))
+                                        ?.map(template => ({ icon: ImageCast(template.mainField.renderedDoc().icon), doc: template.mainField.renderedDoc(), template: template }))
                                         .filter(info => info.icon && info.doc)
                                         .map(info => (
                                             <div
                                                 className="docCreatorMenu-preview-window"
                                                 style={{
-                                                    border: this._selectedTemplate === info.doc ? `solid 3px ${Colors.MEDIUM_BLUE}` : '',
-                                                    boxShadow: this._selectedTemplate === info.doc ? `0 0 15px rgba(68, 118, 247, .8)` : '',
+                                                    border: this._selectedTemplateDoc === info.doc ? `solid 3px ${Colors.MEDIUM_BLUE}` : '',
+                                                    boxShadow: this._selectedTemplateDoc === info.doc ? `0 0 15px rgba(68, 118, 247, .8)` : '',
                                                 }}
-                                                onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedTemplate(info.doc)))}>
+                                                onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedTemplate(info.template)))}>
                                                 <button
                                                     className="option-button left"
                                                     onPointerDown={e =>
@@ -845,7 +873,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                 <div className="docCreatorMenu-preview-window empty" onPointerDown={e => this.testTemplate()}>
                                     <FontAwesomeIcon icon="plus" color="rgb(160, 160, 160)" />
                                 </div>
-                                {this._templateDocs
+                                {/* {this._templateDocs
                                     .map(doc => ({ icon: ImageCast(doc.icon), doc }))
                                     .filter(info => info.icon && info.doc)
                                     .map(info => {
@@ -855,8 +883,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                             <div
                                                 className="docCreatorMenu-preview-window"
                                                 style={{
-                                                    border: this._selectedTemplate === info.doc ? `solid 3px ${Colors.MEDIUM_BLUE}` : '',
-                                                    boxShadow: this._selectedTemplate === info.doc ? `0 0 15px rgba(68, 118, 247, .8)` : '',
+                                                    border: this._selectedTemplateDoc === info.doc ? `solid 3px ${Colors.MEDIUM_BLUE}` : '',
+                                                    boxShadow: this._selectedTemplateDoc === info.doc ? `0 0 15px rgba(68, 118, 247, .8)` : '',
                                                 }}
                                                 onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedTemplate(info.doc)))}>
                                                 <button
@@ -880,7 +908,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                                 <img className="docCreatorMenu-preview-image" src={info.icon!.url.href.replace('.png', '_o.png')} />
                                             </div>
                                         );
-                                    })}
+                                    })} */}
                             </div>
                         </div>
                     </div>
@@ -1072,7 +1100,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     }
 
     layoutPreviewContents = (outerSpan: number, altLayout?: DataVizTemplateLayout, small: boolean = false, id?: number) => {
-        const doc: Doc | undefined = altLayout ? altLayout.template : this._selectedTemplate;
+        const doc: Doc | undefined = altLayout ? altLayout.template : this._selectedTemplateDoc;
         if (!doc) return;
 
         return (
@@ -1192,9 +1220,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                 emptyFunction,
                                 undoable(clickEv => {
                                     clickEv.stopPropagation();
-                                    if (!this._selectedTemplate) return;
+                                    if (!this._selectedTemplateDoc) return;
                                     const layout: DataVizTemplateLayout = {
-                                        template: this._selectedTemplate,
+                                        template: this._selectedTemplateDoc,
                                         layout: { type: this._layout.type, xMargin: this._layout.xMargin, yMargin: this._layout.yMargin, repeat: 0 },
                                         columns: this.columnsCount,
                                         rows: this.rowsCount,
@@ -1219,8 +1247,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                 emptyFunction,
                                 undoable(clickEv => {
                                     clickEv.stopPropagation();
-                                    if (!this._selectedTemplate) return;
-                                    const templateInfo: DataVizTemplateInfo = { doc: this._selectedTemplate, layout: this._layout, referencePos: { x: this._pageX + 450, y: this._pageY }, columns: this.columnsCount };
+                                    if (!this._selectedTemplateDoc) return;
+                                    const templateInfo: DataVizTemplateInfo = { doc: this._selectedTemplateDoc, layout: this._layout, referencePos: { x: this._pageX + 450, y: this._pageY }, columns: this.columnsCount };
                                     this._dataViz?.createDocsFromTemplate(templateInfo);
                                 }, 'make docs')
                             )
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
index cd83472d8..c0f2f183a 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
@@ -30,7 +30,7 @@ export class DynamicField implements Field {
         this.subfields = this.setupSubfields();
     }
 
-    setContent = (content: string, type: FieldContentType) => { return };
+    setContent = (content: string, type?: FieldContentType) => { return };
     getContent = () => { return '' };
 
     setTitle = (title: string) => { this.title = title };
@@ -58,6 +58,10 @@ export class DynamicField implements Field {
         return [];
     }
 
+    updateRenderedDoc = () => {
+        return new Doc();
+    }
+
     setupSubfields = (): Field[] => {
         const fields: Field[] = [];
         this.settings.subfields?.forEach((fieldSettings, index) => {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
index aeeaa58dd..8a571dae3 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
@@ -4,7 +4,7 @@ import { TemplateFieldSize, TemplateFieldType } from "../TemplateBackend";
 
 export interface Field {
     getContent: () => string;
-    setContent: (content: string, type: FieldContentType) => void;
+    setContent: (content: string, type?: FieldContentType) => void;
     getDimensions: FieldDimensions;
     getSubfields: Field[];
     getAllSubfields: Field[];
@@ -16,6 +16,7 @@ export interface Field {
     setupSubfields: () => Field[];
     renderedDoc: () => Doc;
     matches: (cols: Col[]) => number[];
+    updateRenderedDoc: () => Doc;
 }
 
 export type FieldSettings = {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
index 91adebe81..70596632a 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
@@ -15,21 +15,21 @@ export class FieldUtils {
         return { width, height, coord };
     };
 
-    public static applyBasicOpts = (doc: Doc, parentDimensions: FieldDimensions, settings: FieldSettings) => {
+    public static applyBasicOpts = (doc: Doc, parentDimensions: FieldDimensions, settings: FieldSettings, oldDoc?: Doc) => {
         const opts = settings.opts;
-        doc.isDefaultTemplateDoc = true;
-        doc._layout_hideScroll = true;
-        doc.x = parentDimensions.coord.x;
-        doc.y = parentDimensions.coord.y;
-        doc._height = parentDimensions.height;
-        doc._width = parentDimensions.width;
-        doc.backgroundColor = opts.backgroundColor ?? '';
-        doc._layout_borderRounding = `${opts.cornerRounding ?? 0}px`;
-        doc.borderColor = opts.borderColor;
-        doc.borderWidth = opts.borderWidth;
-        doc.opacity = opts.opacity;
-        doc._rotation = opts.rotation;
-        doc.hCentering = opts.contentXCentering;
+        doc.isDefaultTemplateDoc = oldDoc ? oldDoc.isDefaultTemplateDoc : true;
+        doc._layout_hideScroll = oldDoc ? oldDoc._layout_hideScroll : true;
+        doc.x = oldDoc ? oldDoc.x : parentDimensions.coord.x;
+        doc.y = oldDoc ? oldDoc.y : parentDimensions.coord.y;
+        doc._height = oldDoc ? oldDoc.height : parentDimensions.height;
+        doc._width = oldDoc ? oldDoc.width : parentDimensions.width;
+        doc.backgroundColor = oldDoc ? oldDoc.backgroundColor : opts.backgroundColor ?? '';
+        doc._layout_borderRounding = oldDoc ? oldDoc.layout_borderRounding : `${opts.cornerRounding ?? 0}px`;
+        doc.borderColor = oldDoc ? oldDoc.borderColor : opts.borderColor;
+        doc.borderWidth = oldDoc ? oldDoc.borderWidth : opts.borderWidth;
+        doc.opacity = oldDoc ? oldDoc.opacity : opts.opacity;
+        doc._rotation = oldDoc ? oldDoc._rotation : opts.rotation;
+        doc.hCentering = oldDoc ? oldDoc.hCentering : opts.contentXCentering;
     };
 
     public static calculateFontSize = (contWidth: number, contHeight: number, text: string, uppercase: boolean): number => {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
index 795581008..3e0c8abcf 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
@@ -12,6 +12,7 @@ export class StaticField {
     private content: string;
     private contentType: FieldContentType | undefined;
     private subfields: Field[] = [];
+    private renderedDocument: Doc;
 
     private id: number;
     private title: string = '';
@@ -29,6 +30,7 @@ export class StaticField {
         this.dimensions = FieldUtils.getLocalDimensions({tl: settings.tl, br: settings.br}, this.parent.getDimensions);
         this.content = '';
         this.subfields = this.setupSubfields();
+        this.renderedDocument = this.updateRenderedDoc();
     };
 
     get getSubfields(): Field[] { return this.subfields ?? []; };
@@ -50,14 +52,22 @@ export class StaticField {
         return this.settings.description ?? '';
     }
 
-    setContent = (newContent: string, type: FieldContentType) => { 
+    renderedDoc = () => {
+        return this.renderedDocument;
+    }
+
+    setContent = (newContent: string, type?: FieldContentType) => { 
         this.content = newContent;
-        this.contentType = type;
-        console.log('id: ', this.content)
+        if (type) this.contentType = type;
+        this.updateRenderedDoc(this.renderedDocument);
     };
     getContent() { return this.content };
 
-    setTitle = (title: string) => { this.title = title };
+    setTitle = (title: string) => { 
+        this.title = title;
+        this.renderedDocument.title = title;
+        this.updateRenderedDoc(this.renderedDocument);
+    };
     getTitle = () => { return this.title };
 
     setupSubfields = (): Field[] => {
@@ -99,33 +109,40 @@ export class StaticField {
         return matches;
     };
 
-    renderedDoc = (): Doc => {
+    updateRenderedDoc = (oldDoc?: Doc): Doc => {
         const opts = this.settings.opts;
 
         if (!this.contentType) { this.contentType = FieldContentType.STRING };
 
+        let doc: Doc;
+
         switch (this.contentType) {
             case FieldContentType.STRING:
                 const text = String(this.content);
-                const textDoc = Docs.Create.TextDocument(text, {
+                console.log('made text')
+                doc = Docs.Create.TextDocument(text, {
                     title: this.title,
-                    text_fontColor: opts.color,
-                    contentBold: opts.fontBold,
-                    textTransform: opts.fontTransform,
-                    color: opts.color,
+                    text_fontColor: oldDoc ? String(oldDoc.color) : opts.color,
+                    contentBold: oldDoc ? Boolean(oldDoc.fontBold) : opts.fontBold,
+                    textTransform: oldDoc ? String(oldDoc.fontTransform) : opts.fontTransform,
+                    color: oldDoc ? String(oldDoc.color) : opts.color,
                     _text_fontSize: `${FieldUtils.calculateFontSize(this.dimensions.width, this.dimensions.height, text, true)}`
                 });
-                FieldUtils.applyBasicOpts(textDoc, this.dimensions, this.settings);
-                return textDoc;
+                FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings, oldDoc);
+                break;
             case FieldContentType.IMAGE:
+                console.log('made image')
                 const url = String(this.content);
-                const imgDoc = Docs.Create.ImageDocument(url, {
+                doc = Docs.Create.ImageDocument(url, {
                     title: this.title,
                     _layout_fitWidth: false,
                 });
-                FieldUtils.applyBasicOpts(imgDoc, this.dimensions, this.settings);
-                return imgDoc;
+                FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings, oldDoc);
+                break;
         }   
-    };
 
+        this.renderedDocument = doc;
+
+        return doc;
+    };
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index 09eb86d20..6b981d77f 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -23,10 +23,20 @@ export class Template {
         return this.allFields.filter(field => field.getID === id)[0];
     }
 
+    getFieldByTitle = (title: string) => {
+        return this.allFields.filter(field => field.getTitle() === title)[0];
+    }
+
     setupMainField = (templateInfo: FieldSettings) => {
         return new DynamicField(templateInfo, 1);
     }
 
+    renderUpdates = () => {
+        this.allFields.forEach(field => {
+            field.updateRenderedDoc();
+        });
+    };
+
     isValidTemplate = (cols: Col[]) => {
         const matches: number[][] = this.getMatches(cols);
         const maxMatches: number = this.maxMatches(matches);
-- 
cgit v1.2.3-70-g09d2


From 6548836831a0c4bef2664ea4690b4ce1d1614aef Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Tue, 5 Nov 2024 04:30:11 -0500
Subject: reworking preview rendering to make it just docs rather than images
 of docs

---
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   | 110 +++++++++++++--------
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx     |   1 +
 .../DocCreatorMenu/FieldTypes/StaticField.tsx      |   1 +
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   |   1 +
 4 files changed, 73 insertions(+), 40 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index 7491642eb..fcf237e02 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -57,8 +57,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     @observable _renderedDocCollectionPreview: Doc | undefined = undefined;
     @observable _renderedDocCollection: Doc | undefined = undefined;
 
-    @observable _templateDocs: Doc[] = [];
-    @observable _selectedTemplateDoc: Doc | undefined = undefined;
+    @observable _templateDocs: Doc[] = []; //!!! used to keep track of all templates, should be refactored to work with actual templates and not docs
+    @observable _selectedTemplate: Template | undefined = undefined;
     @observable _userCreatedColumns: Col[] = [];
     @observable _selectedCols: { title: string; type: string; desc: string }[] | undefined = [];
 
@@ -69,6 +69,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     @observable _expandedPreview: { icon: ImageField; doc: Doc } | undefined = undefined;
 
     @observable _suggestedTemplates: Template[] = [];
+    @observable _suggestedTemplateDocs
     @observable _GPTOpt: boolean = false;
     @observable _userPrompt: string = '';
     @observable _callCount: number = 0;
@@ -117,7 +118,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     };
 
     @computed get docsToRender() {
-        return this._selectedTemplateDoc ? NumListCast(this._dataViz?.layoutDoc.dataViz_selectedRows) : [];
+        return this._selectedTemplate ? NumListCast(this._dataViz?.layoutDoc.dataViz_selectedRows) : [];
     }
 
     @computed get rowsCount() {
@@ -156,6 +157,45 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         return StrListCast(this._dataViz?.layoutDoc._dataViz_axes);
     }
 
+    @computed get selectedTemplateDocs(): {doc: React.JSX.Element, template: Template}[] {
+        const docs: {doc: Doc, template: Template}[] = this._suggestedTemplates?.map(template => { return {doc: template.mainField.renderedDoc(), template: template}});
+        const docPreviews: {doc: Doc, template: Template}[] = docs.map(info => 
+            {return {doc: Docs.Create.FreeformDocument([info.doc], { _height: NumListCast(info.doc._height)[0], _width: NumListCast(info.doc._width)[0], title: ''}), template: info.template}
+        });
+        const renderedComponents = docPreviews.map(info => 
+            {return {doc: <CollectionFreeFormView
+            Document={info.doc}
+            docViewPath={returnEmptyDocViewList}
+            childLayoutTemplate={() => Cast(info.doc.childLayoutTemplate, Doc, null)}
+            isContentActive={emptyFunction}
+            isAnyChildContentActive={() => true}
+            select={emptyFunction}
+            isSelected={returnFalse}
+            fieldKey={Doc.LayoutFieldKey(info.doc)}
+            addDocument={returnFalse}
+            moveDocument={returnFalse}
+            removeDocument={returnFalse}
+            PanelWidth={() => 100}
+            PanelHeight={() => 100}
+            ScreenToLocalTransform={() => new Transform(-this._pageX - 5,-this._pageY - 35, 1)}
+            renderDepth={5}
+            whenChildContentsActiveChanged={emptyFunction}
+            focus={emptyFunction}
+            styleProvider={DefaultStyleProvider}
+            addDocTab={this._props.addDocTab}
+            // eslint-disable-next-line no-use-before-define
+            pinToPres={() => undefined}
+            childFilters={returnEmptyFilter}
+            childFiltersByRanges={returnEmptyFilter}
+            searchFilterDocs={returnEmptyDoclist}
+            fitContentsToBox={returnTrue}
+            xPadding={0}
+            yPadding={0}
+            />, template: info.template}
+        });
+        return renderedComponents;
+    }
+
     @computed get fieldsInfos(): Col[] {
         const colInfo = this._dataViz?.colsInfo;
         return this.selectedFields
@@ -179,7 +219,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     }
 
     @computed get canMakeDocs() {
-        return this._selectedTemplateDoc !== undefined && this._layout !== undefined;
+        return this._selectedTemplate !== undefined && this._layout !== undefined;
     }
 
     get bounds(): { t: number; b: number; l: number; r: number } {
@@ -239,8 +279,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             docs => this.updateIcons(docs)
         );
         this._disposers.gpt = reaction(
-            () => this._suggestedTemplates.map(template => template.mainField.renderedDoc()).slice(),
-            docs => this.updateIcons(docs)
+            () => this._suggestedTemplates.slice(),
+            templates => this.updateIcons(templates.map(t => t.doc))
         );
         //this._disposers.columns = reaction(() => this._dataViz?.layoutDoc._dataViz_axes, () => {this.generateTemplates('')})
         this._disposers.lightbox = reaction(
@@ -263,6 +303,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     }
 
     updateIcons = (docs: Doc[]) => {
+        console.log('called')
         docs.map(this.getIcon);
     };
 
@@ -289,9 +330,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
     @action
     openMenu = () => {
-        const allTemplates = this._templateDocs.concat(this._suggestedTemplates.map(temp => temp.mainField.renderedDoc()));
+        const allTemplates = this._templateDocs.concat(this._suggestedTemplates.map(temp => temp.doc));
         this._shouldDisplay = true;
-        this.updateIcons(allTemplates);
     };
 
     @action
@@ -375,11 +415,11 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     }
 
     @action updateSelectedTemplate = (template: Template) => {
-        if (this._selectedTemplateDoc === template.mainField.renderedDoc()) {
-            this._selectedTemplateDoc = undefined;
+        if (this._selectedTemplate === template) {
+            this._selectedTemplate = undefined;
             return;
         } else {
-            this._selectedTemplateDoc = template.mainField.renderedDoc();
+            this._selectedTemplate = template;
             template.renderUpdates();
             this._fullyRenderedDocs = this.createDocsFromTemplate(template) ?? [];
             this.updateRenderedDocCollection();
@@ -691,14 +731,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
         //const renderedTemplates: Template[] = await Promise.all(renderedTemplatePromises);
 
-        const renderedTemplates: Doc[] = templates.map(template => template.mainField.renderedDoc());
-
-        const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
-        
-        renderedTemplates.forEach(doc => {
-            mainCollection.addDocument(doc);
-        });
-
         setTimeout(() => {
             this.setSuggestedTemplates(templates);
             this._GPTLoading = false;
@@ -734,14 +766,13 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         return renderedDocs;
     }
 
-    @action setExpandedView = (info: { icon: ImageField; doc: Doc } | undefined) => {
-        if (info) {
-            const doc = info.doc;
-            const wrapper: Doc = Docs.Create.FreeformDocument([info.doc], { _height: NumListCast(doc._height)[0], _width: NumListCast(doc._width)[0], title: ''});
+    @action setExpandedView = (doc: Doc | undefined) => {
+        if (doc) {
+            const wrapper: Doc = Docs.Create.FreeformDocument([doc], { _height: NumListCast(doc._height)[0], _width: NumListCast(doc._width)[0], title: ''});
             const newInfo = {icon: new ImageField(''), doc: wrapper}
             this._expandedPreview = newInfo;
         } else {
-            this._expandedPreview = info;
+            this._expandedPreview = {icon: new ImageField(''), doc: doc ?? new Doc()}; //!!! get rid of image stuff
         }
     };
 
@@ -786,7 +817,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                 <div className="top-panel"/>
                 {rendered}
                 <div className="right-buttons-panel">
-                    <button className="docCreatorMenu-menu-button section-reveal-options top-right" onPointerDown={e => this.setUpButtonClick(e, () => {this._expandedPreview && this.updateIcons(this._suggestedTemplates.map(template => template.mainField.renderedDoc()).slice()); this.setExpandedView(undefined)})}>
+                    <button className="docCreatorMenu-menu-button section-reveal-options top-right" onPointerDown={e => this.setUpButtonClick(e, () => {this._expandedPreview && this.updateIcons(this._suggestedTemplates.map(template => template.doc).slice()); this.setExpandedView(undefined)})}>
                         <FontAwesomeIcon icon="minimize" />
                     </button>
                     <button className="docCreatorMenu-menu-button section-reveal-options top-right-lower" onPointerDown={e => this.setUpButtonClick(e, () => this._expandedPreview && this._templateDocs.push(this._expandedPreview.doc))}>
@@ -805,6 +836,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
         //<img className='docCreatorMenu-preview-image expanded' src={this._expandedPreview.icon!.url.href.replace(".png", "_o.png")} />
 
+        console.log('rendered')
         return (
             <div className={`docCreatorMenu-templates-view`}>
                 {this._expandedPreview ? (
@@ -824,30 +856,28 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                         <ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} />
                                     </div>
                                 ) : (
-                                    this._suggestedTemplates
-                                        ?.map(template => ({ icon: ImageCast(template.mainField.renderedDoc().icon), doc: template.mainField.renderedDoc(), template: template }))
-                                        .filter(info => info.icon && info.doc)
-                                        .map(info => (
+                                    this.selectedTemplateDocs
+                                        .map(({doc, template}) => (
                                             <div
                                                 className="docCreatorMenu-preview-window"
                                                 style={{
-                                                    border: this._selectedTemplateDoc === info.doc ? `solid 3px ${Colors.MEDIUM_BLUE}` : '',
-                                                    boxShadow: this._selectedTemplateDoc === info.doc ? `0 0 15px rgba(68, 118, 247, .8)` : '',
+                                                    border: this._selectedTemplate === template ? `solid 3px ${Colors.MEDIUM_BLUE}` : '',
+                                                    boxShadow: this._selectedTemplate === template ? `0 0 15px rgba(68, 118, 247, .8)` : '',
                                                 }}
-                                                onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedTemplate(info.template)))}>
+                                                onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedTemplate(template)))}>
                                                 <button
                                                     className="option-button left"
                                                     onPointerDown={e =>
                                                         this.setUpButtonClick(e, () => {
-                                                            this.setExpandedView(info);
+                                                            this.setExpandedView(template.mainField.renderedDoc());
                                                         })
                                                     }>
                                                     <FontAwesomeIcon icon="magnifying-glass" color="white" />
                                                 </button>
-                                                <button className="option-button right" onPointerDown={e => this.setUpButtonClick(e, () => this._templateDocs.push(info.doc))}>
+                                                <button className="option-button right" onPointerDown={e => this.setUpButtonClick(e, () => this._templateDocs.push(template.mainField.renderedDoc()))}>
                                                     <FontAwesomeIcon icon="plus" color="white" />
                                                 </button>
-                                                <img className="docCreatorMenu-preview-image" src={info.icon!.url.href.replace('.png', '_o.png')} />
+                                                {doc}
                                             </div>
                                         ))
                                 )}
@@ -1100,7 +1130,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     }
 
     layoutPreviewContents = (outerSpan: number, altLayout?: DataVizTemplateLayout, small: boolean = false, id?: number) => {
-        const doc: Doc | undefined = altLayout ? altLayout.template : this._selectedTemplateDoc;
+        const doc: Doc | undefined = altLayout ? altLayout.template : this._selectedTemplate?.mainField.renderedDoc(); //!!! might cause a slow down
         if (!doc) return;
 
         return (
@@ -1220,9 +1250,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                 emptyFunction,
                                 undoable(clickEv => {
                                     clickEv.stopPropagation();
-                                    if (!this._selectedTemplateDoc) return;
+                                    if (!this._selectedTemplate) return;
                                     const layout: DataVizTemplateLayout = {
-                                        template: this._selectedTemplateDoc,
+                                        template: this._selectedTemplate.mainField.renderedDoc(),
                                         layout: { type: this._layout.type, xMargin: this._layout.xMargin, yMargin: this._layout.yMargin, repeat: 0 },
                                         columns: this.columnsCount,
                                         rows: this.rowsCount,
@@ -1247,8 +1277,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                 emptyFunction,
                                 undoable(clickEv => {
                                     clickEv.stopPropagation();
-                                    if (!this._selectedTemplateDoc) return;
-                                    const templateInfo: DataVizTemplateInfo = { doc: this._selectedTemplateDoc, layout: this._layout, referencePos: { x: this._pageX + 450, y: this._pageY }, columns: this.columnsCount };
+                                    if (!this._selectedTemplate) return;
+                                    const templateInfo: DataVizTemplateInfo = { doc: this._selectedTemplate.mainField.renderedDoc(), layout: this._layout, referencePos: { x: this._pageX + 450, y: this._pageY }, columns: this.columnsCount };
                                     this._dataViz?.createDocsFromTemplate(templateInfo);
                                 }, 'make docs')
                             )
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
index c0f2f183a..953dbabf6 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
@@ -92,6 +92,7 @@ export class DynamicField implements Field {
     };
 
     renderedDoc = (): Doc => {
+        console.log('called')
         switch (this.settings.viewType) {
             case ViewType.CAROUSEL3D:
                 const carouselDoc = Docs.Create.Carousel3DDocument(this.subfields.map(field => field.renderedDoc()), {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
index 3e0c8abcf..1320e270d 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
@@ -53,6 +53,7 @@ export class StaticField {
     }
 
     renderedDoc = () => {
+        console.log('called')
         return this.renderedDocument;
     }
 
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index 6b981d77f..c96135b4d 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -18,6 +18,7 @@ export class Template {
     get childFields(): Field[] { return this.mainField.getSubfields };
     get allFields(): Field[] { return this.mainField.getAllSubfields };
     get contentFields(): Field[] { return this.allFields.filter(field => field.getViewType === ViewType.STATIC) };
+    get doc(){ return this.mainField.renderedDoc(); };
 
     getFieldByID = (id: number): Field => {
         return this.allFields.filter(field => field.getID === id)[0];
-- 
cgit v1.2.3-70-g09d2


From c86f18caf079d97f673935b7a83a16d6e97bb804 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Tue, 5 Nov 2024 17:12:29 -0500
Subject: edits are persisting!!

---
 src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx    | 3 ++-
 src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx  | 2 +-
 .../views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx   | 1 -
 src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx          | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index e21f0a70c..d214a7954 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -112,12 +112,13 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         this._templateDocs = docs.map(doc => (doc.annotationOn ? DocCast(doc.annotationOn) : doc));
     };
     @action updateTemplatePreviews = (templates: Template[]) => {
+        templates.forEach(template => template.renderUpdates());
         this._suggestedTemplatePreviews = templates.map(template => {
             const doc = template.mainField.renderedDoc();
             const wrapper: Doc = Docs.Create.FreeformDocument([doc], { _height: NumListCast(doc._height)[0], _width: NumListCast(doc._width)[0], title: ''});
             return {doc: wrapper, template: template};
         });
-    }
+    };
     @action setSuggestedTemplates = (templates: Template[]) => {
         this._suggestedTemplates = templates;
         this.updateTemplatePreviews(templates);
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
index 8a571dae3..a0eaffebf 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
@@ -16,7 +16,7 @@ export interface Field {
     setupSubfields: () => Field[];
     renderedDoc: () => Doc;
     matches: (cols: Col[]) => number[];
-    updateRenderedDoc: () => Doc;
+    updateRenderedDoc: (oldDoc?: Doc) => Doc;
 }
 
 export type FieldSettings = {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
index 1320e270d..3e0c8abcf 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
@@ -53,7 +53,6 @@ export class StaticField {
     }
 
     renderedDoc = () => {
-        console.log('called')
         return this.renderedDocument;
     }
 
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index c96135b4d..4c6425f23 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -34,7 +34,7 @@ export class Template {
 
     renderUpdates = () => {
         this.allFields.forEach(field => {
-            field.updateRenderedDoc();
+            field.updateRenderedDoc(field.renderedDoc());
         });
     };
 
-- 
cgit v1.2.3-70-g09d2


From 9b42bf8ab277979194e4ef73152b6b23c479786b Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Thu, 7 Nov 2024 03:36:50 -0500
Subject: gpt text gen working for previews

---
 src/client/views/nodes/DataVizBox/DataVizBox.tsx   | 107 ---------------------
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.scss  |   3 +-
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   |  40 +++-----
 .../DocCreatorMenu/FieldTypes/StaticField.tsx      |   2 -
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   |  17 +++-
 .../DataVizBox/DocCreatorMenu/TemplateBackend.tsx  |   5 +-
 .../DataVizBox/DocCreatorMenu/TemplateManager.tsx  |  12 ---
 7 files changed, 36 insertions(+), 150 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 6621c610f..dececd1dc 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -511,7 +511,6 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     openDocCreatorMenu = (x: number, y: number) => {
         DocCreatorMenu.Instance.toggleDisplay(x, y);
         DocCreatorMenu.Instance.setDataViz(this);
-        DocCreatorMenu.Instance.setTemplateDocs(this.getPossibleTemplates());
     };
 
     specificContextMenu = (e: React.MouseEvent) => {
@@ -623,112 +622,6 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         }
     };
 
-    getPossibleTemplates = (): Doc[] => {
-        const linkedDocs: Doc[] = LinkManager.Instance.getAllRelatedLinks(this.Document).map(d => DocCast(LinkManager.getOppositeAnchor(d, this.Document)));
-        const linkedCollections: Doc[] = linkedDocs.filter(doc => doc.type === 'config').map(doc => DocCast(doc.annotationOn));
-        const isColumnTitle = (title: string): boolean => {
-            const colTitles: string[] = Object.keys(this.records[0]);
-            for (let i = 0; i < colTitles.length; ++i) {
-                if (colTitles[i] === title) {
-                    return true;
-                }
-            }
-            return false;
-        };
-        const isValidTemplate = (collection: Doc) => {
-            const childDocs = DocListCast(collection[Doc.LayoutFieldKey(collection)]);
-            for (let i = 0; i < childDocs.length; ++i) {
-                if (isColumnTitle(String(childDocs[i].title))) return true;
-            }
-            return false;
-        };
-        return linkedCollections.filter(col => isValidTemplate(col));
-    };
-
-    ApplyTemplateTo = (templateDoc: Doc, target: Doc, targetKey: string, titleTarget: string | undefined) => {
-        if (!Doc.AreProtosEqual(target[targetKey] as Doc, templateDoc)) {
-            if (target.resolvedDataDoc) {
-                target[targetKey] = new PrefetchProxy(templateDoc);
-            } else {
-                titleTarget && (Doc.GetProto(target).title = titleTarget);
-                const setDoc = [AclAdmin, AclEdit, AclAugment].includes(GetEffectiveAcl(Doc.GetProto(target))) ? Doc.GetProto(target) : target;
-                setDoc[targetKey] = new PrefetchProxy(templateDoc);
-            }
-        }
-        return target;
-    };
-
-    applyLayout = (templateInfo: DataVizTemplateInfo, docs: Doc[]) => {
-        if (templateInfo.layout.type === LayoutType.STACKED) return;
-        const columns: number = templateInfo.columns;
-        const xGap: number = templateInfo.layout.xMargin;
-        const yGap: number = templateInfo.layout.yMargin;
-        // const repeat: number = templateInfo.layout.repeat;
-        const startX: number = templateInfo.referencePos.x;
-        const startY: number = templateInfo.referencePos.y;
-        const templWidth = Number(templateInfo.doc._width);
-        const templHeight = Number(templateInfo.doc._height);
-
-        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 += templWidth + xGap;
-                ++docsChanged;
-                ++i;
-            }
-
-            i = 0;
-            curX = startX;
-            curY += templHeight + yGap;
-        }
-    };
-
-    // @action addSavedLayout = (layout: DataVizTemplateLayout) => {
-    //     const saved = Cast(this.layoutDoc.dataViz_savedTemplates, listSpec('RefField'));
-
-    // }
-
-    @action
-    createDocsFromTemplate = (templateInfo: DataVizTemplateInfo, returnList?: boolean): Doc[] => {
-        if (!templateInfo.doc) {console.log('noinfo'); return []; }
-        const fields: string[] = Array.from(Object.keys(this.records[0]));
-        const selectedRows = NumListCast(this.layoutDoc.dataViz_selectedRows);
-        const docs: Doc[] = selectedRows.map(row => {
-            const values: string[] = [];
-            fields.forEach(col => values.push(this.records[row][col]));
-
-            
-
-            const proto = new Doc();
-            proto.author = ClientUtils.CurrentUserEmail();
-            values.forEach((val, i) => {
-                proto[fields[i]] = val as FieldType;
-            });
-
-            const target = Doc.MakeDelegate(proto);
-            const targetKey = StrCast(templateInfo.doc!.layout_fieldKey, 'layout');
-            const applied = this.ApplyTemplateTo(templateInfo.doc!, target, targetKey, templateInfo.doc!.title + `${row}`);
-            target.layout_fieldKey = targetKey;
-
-            //this.applyImagesTo(target, fields);
-            return applied;
-        });
-
-        if (returnList) return docs;
-
-        const mainCollection = this.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
-        docs.forEach(doc => mainCollection.addDocument(doc));
-
-        this.applyLayout(templateInfo, docs);
-        return [];
-    };
-
     /**
      * creates a new dataviz document filter from this one
      *      it appears to the right of this document, with the
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss
index b849c044d..98d630dae 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss
@@ -45,9 +45,10 @@
         font-size: 12px;
         width: 18px;
         height: 18px;
-        border-radius: 2px;
         font-size: 12px;
         margin-left: auto;
+        margin-right: 5px;
+        margin-bottom: 3px;
     }
 
     &.options {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index a08686a36..379a33a99 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -123,7 +123,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     };
     @action setSuggestedTemplates = (templates: Template[]) => {
         this._suggestedTemplates = templates;
-        templates.forEach(template => { this._suggestedTemplatePreviews.push({template: template, doc: template.mainField.renderedDoc()}) }); //prettier-ignore
+        this._suggestedTemplatePreviews = templates.map(template => {return {template: template, doc: template.mainField.renderedDoc()}}); //prettier-ignore
     };
 
     @computed get docsToRender() {
@@ -497,7 +497,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
      * @param assignments a list of template field numbers (from top to bottom) and their assigned columns from the linked dataviz
      * @returns a doc containing the fully rendered template
      */
-    applyGPTContentToTemplate = async (template: Template, assignments: { [field: string]: Col }): Promise<Template> => {
+    applyGPTContentToTemplate = async (template: Template, assignments: { [field: string]: Col }): Promise<Template | undefined> => {
         const wordLimit = (size: TemplateFieldSize) => {
             switch (size) {
                 case TemplateFieldSize.TINY:
@@ -526,6 +526,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         const GPTTextCalls = Object.entries(assignments).filter(([str, col]) => col.type === TemplateFieldType.TEXT);
         const GPTIMGCalls = Object.entries(assignments).filter(([str, col]) => col.type === TemplateFieldType.VISUAL);
 
+        if (!GPTTextCalls && !GPTIMGCalls) return;
+
         const stringifyGPTInfo = (calls: [string, Col][]): string => {
             let string: string = '*** COLUMN INFO:';
             calls.forEach(([fieldNum, col]) => {
@@ -536,13 +538,14 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
         const GPTTextAssignment = stringifyGPTInfo(GPTTextCalls);
 
-        let fieldContent: string = this.templateManager.getContentSummary(template);
+
+        let fieldContent: string = template.compiledContent;
 
         if (GPTTextCalls.length) {
             try {
                 const prompt = fieldContent + GPTTextAssignment;
 
-                const res = await gptAPICall(prompt, GPTCallType.FILL);
+                const res = await gptAPICall(`${++this._callCount}: ${prompt}`, GPTCallType.FILL);
 
                 if (res) {
                     const assignments: { [title: string]: { number: string; content: string } } = JSON.parse(res);
@@ -586,11 +589,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     compileFieldDescriptions = (templates: Template[]): string => {
         let descriptions: string = '';
         templates.forEach(template => {
-            console.log('title: ', template.mainField.getTitle());
             descriptions += `----------  NEW TEMPLATE TO INCLUDE: The title is: ${template.mainField.getTitle()}. Its fields are: `;
-            template.contentFields.forEach(field => {
-                descriptions += `{Field #${field.getID}: ${field.getDescription}} `;
-            });
+            descriptions += template.descriptionSummary;
         });
 
         return descriptions;
@@ -624,9 +624,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         try {
             const res = await gptAPICall(prompt, GPTCallType.TEMPLATE);
 
-            if (res && this._callCount === origCount) {
+            if (res) {
                 const assignments: { [templateTitle: string]: { [fieldID: string]: string } } = JSON.parse(res);
-                console.log('assignments', assignments)
                 const brokenDownAssignments: [Template, { [fieldID: number]: Col }][] = [];
 
                 Object.entries(assignments).forEach(([tempTitle, assignment]) => {
@@ -667,9 +666,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
         const assignments: [Template, { [field: number]: Col }][] = await this.assignColsToFields(templates, cols);
 
-        const renderedTemplatePromises: Promise<Template>[] = assignments.map(([template, assignments]) => this.applyGPTContentToTemplate(template, assignments));
+        const renderedTemplatePromises: Promise<Template | undefined>[] = assignments.map(([template, assignments]) => this.applyGPTContentToTemplate(template, assignments));
 
-        //const renderedTemplates: Template[] = await Promise.all(renderedTemplatePromises);
+        const renderedTemplates: (Template | undefined)[] = await Promise.all(renderedTemplatePromises);
 
         setTimeout(() => {
             this.setSuggestedTemplates(templates);
@@ -1029,13 +1028,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         }
     };
 
-    addDocAsResult = (doc: Doc) => {
-        doc.x = this._pageX;
-        doc.y = this._pageY;
-        this.closeMenu();
-        //!!! will need to add to main collection when I refactor 
-    }
-
     @computed
     get previewInfo(){
         const docHeight: number = Number(this._fullyRenderedDocs[0]._height);
@@ -1078,8 +1070,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
         const collection: Doc = collectionFactory()(this._fullyRenderedDocs, {
             isDefaultTemplateDoc: true,
-            x: 40000,
-            y: 40000,
             _height: verticalSpan,
             _width: horizontalSpan,
             title: 'title',
@@ -1243,9 +1233,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     get dashboardContents() {
         const sizes: string[] = ['tiny', 'small', 'medium', 'large', 'huge'];
 
-        const fieldPanel = (field: Col) => {
+        const fieldPanel = (field: Col, id: number) => {
             return (
-                <div className="field-panel" key={field.title}>
+                <div className="field-panel" key={id}>
                     <div className="top-bar">
                         <span className="field-title">{`${field.title} Field`}</span>
                         <button className="docCreatorMenu-menu-button section-reveal-options no-margin" onPointerDown={e => this.setUpButtonClick(e, () => this.removeField(field))} style={{ position: 'absolute', right: '0px' }}>
@@ -1328,7 +1318,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                         <FontAwesomeIcon icon="arrow-left" />
                     </button>
                 </div>
-                <div className="panels-container">{this.fieldsInfos.map(field => fieldPanel(field))}</div>
+                <div className="panels-container">{this.fieldsInfos.map((field, i) => fieldPanel(field, i))}</div>
             </div>
         );
     }
@@ -1434,7 +1424,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                             <div className="docCreatorMenu-top-buttons-container">
                                 {topButton('lightbulb', 'templates', onPreviewSelected, 'left')}
                                 {topButton('magnifying-glass', 'options', onOptionsSelected, 'middle')}
-                                {topButton('floppy-disk', 'saved', onSavedSelected, 'right')}
+                                {topButton('bars', 'saved', onSavedSelected, 'right')}
                             </div>
                             <button className="docCreatorMenu-menu-button close-menu" onPointerDown={e => this.setUpButtonClick(e, this.closeMenu)}>
                                 <FontAwesomeIcon icon={'minus'} />
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
index 3e0c8abcf..033900fe9 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
@@ -119,7 +119,6 @@ export class StaticField {
         switch (this.contentType) {
             case FieldContentType.STRING:
                 const text = String(this.content);
-                console.log('made text')
                 doc = Docs.Create.TextDocument(text, {
                     title: this.title,
                     text_fontColor: oldDoc ? String(oldDoc.color) : opts.color,
@@ -131,7 +130,6 @@ export class StaticField {
                 FieldUtils.applyBasicOpts(doc, this.dimensions, this.settings, oldDoc);
                 break;
             case FieldContentType.IMAGE:
-                console.log('made image')
                 const url = String(this.content);
                 doc = Docs.Create.ImageDocument(url, {
                     title: this.title,
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index 4c6425f23..7d32d26d1 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -32,6 +32,22 @@ export class Template {
         return new DynamicField(templateInfo, 1);
     }
 
+    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;
+    }
+
     renderUpdates = () => {
         this.allFields.forEach(field => {
             field.updateRenderedDoc(field.renderedDoc());
@@ -45,7 +61,6 @@ export class Template {
     }
 
     getMatches = (cols: Col[]): number[][] => {
-        console.log(this.mainField.getTitle(), this.allFields)
         const numFields = this.contentFields.length;
 
         if (cols.length !== numFields) return [];
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
index d434e98b1..9b8ec64c0 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
@@ -109,6 +109,7 @@ export class TemplateLayouts {
                 opts: {
                     borderWidth: '8',
                     borderColor: '#F8E71C',
+                    backgroundColor: '#242425',
                 },
             },
             {
@@ -143,9 +144,9 @@ export class TemplateLayouts {
                 viewType: ViewType.STATIC,
                 tl: [-0.83, 0.2],
                 br: [0.83, 0.95],
-                types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
+                types: [TemplateFieldType.TEXT],
                 sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
-                description: 'A medium to large-sized field suitable for an image or longer text that should be the main focus, or share focus with field 1.',
+                description: 'A medium to large-sized field suitable for longer text that should contextualize field 1.',
                 opts: {
                     borderWidth: '8',
                     borderColor: '#F8E71C',
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
index d47ae802c..890bc6f73 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateManager.tsx
@@ -17,18 +17,6 @@ export class TemplateManager {
         return initializedTemplates;
     }
 
-    /**
-     * Provides a text summary of content currently filled into a template, formatted for GPT analysis.
-     * @param template the template to be summarized
-     */
-    getContentSummary = (template: Template) => {
-        let summary: string = '';
-        template.contentFields.forEach(field => {
-            summary += `--- Field #${field.getID} (title: ${field.getTitle()}): ${field.getContent() ?? ''} ---`;
-        });
-        return summary;
-    }
-
     getValidTemplates = (cols: Col[]): Template[] => {
         return this.templates.filter(template => template.isValidTemplate(cols));
     }
-- 
cgit v1.2.3-70-g09d2


From 9a188952fc50cb82ebaebf3b0e3bf5183946f5c9 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Thu, 7 Nov 2024 05:20:00 -0500
Subject: GPT text generation working fully!!

---
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   | 172 ++++++++++++---------
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx     |   5 +-
 .../DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx |   1 +
 .../DocCreatorMenu/FieldTypes/StaticField.tsx      |   5 +
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   |  11 ++
 .../DataVizBox/DocCreatorMenu/TemplateBackend.tsx  |   1 +
 6 files changed, 118 insertions(+), 77 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index 379a33a99..ea38430ca 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -61,7 +61,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     @observable _selectedTemplate: Template | undefined = undefined;
     @observable _currEditingTemplate: Template | undefined = undefined;
 
-    @observable _userCreatedColumns: Col[] = [];
+    @observable _userCreatedFields: Col[] = [];
     @observable _selectedCols: { title: string; type: string; desc: string }[] | undefined = [];
 
     @observable _layout: { type: LayoutType; yMargin: number; xMargin: number; columns?: number; repeat: number } = { type: LayoutType.FREEFORM, yMargin: 10, xMargin: 10, columns: 3, repeat: 0 };
@@ -175,7 +175,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
                 return col;
             })
-            .concat(this._userCreatedColumns);
+            .concat(this._userCreatedFields);
     }
 
     @computed get canMakeDocs() {
@@ -360,14 +360,14 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         return undefined;
     }
 
-    @action updateSelectedTemplate = (template: Template) => {
+    @action updateSelectedTemplate = async (template: Template) => {
         if (this._selectedTemplate === template) {
             this._selectedTemplate = undefined;
             return;
         } else {
             this._selectedTemplate = template;
             template.renderUpdates();
-            this._fullyRenderedDocs = this.createDocsFromTemplate(template) ?? [];
+            this._fullyRenderedDocs = await this.createDocsFromTemplate(template) ?? [];
             this.updateRenderedDocCollection();
         }
     };
@@ -410,15 +410,15 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     };
 
     @action addField = () => {
-        const newFields: Col[] = this._userCreatedColumns.concat([{ title: '', type: TemplateFieldType.UNSET, desc: '', sizes: [] }]);
-        this._userCreatedColumns = newFields;
+        const newFields: Col[] = this._userCreatedFields.concat([{ title: '', type: TemplateFieldType.UNSET, desc: '', sizes: [] }]);
+        this._userCreatedFields = newFields;
     };
 
     @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._userCreatedColumns.filter(f => f === field);
+            const toRemove = this._userCreatedFields.filter(f => f === field);
             if (!toRemove) return;
 
             if (toRemove.length > 1) {
@@ -427,10 +427,10 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                 }
             }
 
-            if (this._userCreatedColumns.length === 1) {
-                this._userCreatedColumns = [];
+            if (this._userCreatedFields.length === 1) {
+                this._userCreatedFields = [];
             } else {
-                this._userCreatedColumns.splice(this._userCreatedColumns.indexOf(toRemove[0]), 1);
+                this._userCreatedFields.splice(this._userCreatedFields.indexOf(toRemove[0]), 1);
             }
         }
     };
@@ -498,22 +498,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
      * @returns a doc containing the fully rendered template
      */
     applyGPTContentToTemplate = async (template: Template, assignments: { [field: string]: Col }): Promise<Template | undefined> => {
-        const wordLimit = (size: TemplateFieldSize) => {
-            switch (size) {
-                case TemplateFieldSize.TINY:
-                    return 2;
-                case TemplateFieldSize.SMALL:
-                    return 5;
-                case TemplateFieldSize.MEDIUM:
-                    return 20;
-                case TemplateFieldSize.LARGE:
-                    return 50;
-                case TemplateFieldSize.HUGE:
-                    return 100;
-                default:
-                    return 10;
-            }
-        };
 
         const generateAndLoadImage = async (fieldNum: string, col: Col, prompt: string) => {
             const url = await this.generateGPTImage(prompt);
@@ -523,44 +507,17 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             field.setTitle(col.title);
         };
 
-        const GPTTextCalls = Object.entries(assignments).filter(([str, col]) => col.type === TemplateFieldType.TEXT);
-        const GPTIMGCalls = Object.entries(assignments).filter(([str, col]) => col.type === TemplateFieldType.VISUAL);
-
-        if (!GPTTextCalls && !GPTIMGCalls) return;
-
-        const stringifyGPTInfo = (calls: [string, Col][]): string => {
-            let string: string = '*** COLUMN INFO:';
-            calls.forEach(([fieldNum, col]) => {
-                string += `--- title: ${col.title}, prompt: ${col.desc}, word limit: ${wordLimit(col.sizes[0])} words, assigned field: ${fieldNum} ---`;
-            });
-            return (string += ' ***');
-        };
-
-        const GPTTextAssignment = stringifyGPTInfo(GPTTextCalls);
-
+        const GPTTextCalls = Object.entries(assignments).filter(([str, col]) => col.type === TemplateFieldType.TEXT && this._userCreatedFields.includes(col));
+        const GPTIMGCalls = Object.entries(assignments).filter(([str, col]) => col.type === TemplateFieldType.VISUAL && this._userCreatedFields.includes(col));
 
         let fieldContent: string = template.compiledContent;
 
         if (GPTTextCalls.length) {
-            try {
-                const prompt = fieldContent + GPTTextAssignment;
-
-                const res = await gptAPICall(`${++this._callCount}: ${prompt}`, GPTCallType.FILL);
-
-                if (res) {
-                    const assignments: { [title: string]: { number: string; content: string } } = JSON.parse(res);
-                    //console.log('assignments', GPTAssignments, 'assignment string', GPTAssignmentString, 'field content', fieldContent, 'response', res, 'assignments', assignments);
-                    Object.entries(assignments).forEach(([title, info]) => {
-                        const field: Field = template.getFieldByID(Number(info.number));
-                        const col = this.getColByTitle(title);
+            const promises = GPTTextCalls.map(([str, col]) => {
+                return this.renderGPTTextCall(template, col, Number(str));
+            });
 
-                        field.setContent(info.content ?? '', FieldContentType.STRING);
-                        field.setTitle(col.title);
-                    });
-                }
-            } catch (err) {
-                console.log(err);
-            }
+            await Promise.all(promises);
         }
 
         if (GPTIMGCalls.length) {
@@ -634,7 +591,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                     const toObj = Object.entries(assignment).reduce(
                         (a, [fieldID, colTitle]) => {
                             const col = this.getColByTitle(colTitle);
-                            if (!this._userCreatedColumns.includes(col)){ // do the following for any fields not added by the user; will change in the future, for now only GPT content works with user-added fields
+                            if (!this._userCreatedFields.includes(col)){ // do the following for any fields not added by the user; will change in the future, for now only GPT content works with user-added fields
                                 const field = template.getFieldByID(Number(fieldID));
                                 //console.log(field);
                                 field.setContent(col.defaultContent ?? '', col.type === TemplateFieldType.VISUAL ? FieldContentType.IMAGE : FieldContentType.STRING);
@@ -676,38 +633,101 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         });
     };
 
-    createDocsFromTemplate = (template: Template) => {
+    renderGPTTextCall = async (template: Template, col: Col, fieldNum: number): Promise<boolean> => {
+        const wordLimit = (size: TemplateFieldSize) => {
+            switch (size) {
+                case TemplateFieldSize.TINY:
+                    return 2;
+                case TemplateFieldSize.SMALL:
+                    return 5;
+                case TemplateFieldSize.MEDIUM:
+                    return 20;
+                case TemplateFieldSize.LARGE:
+                    return 50;
+                case TemplateFieldSize.HUGE:
+                    return 100;
+                default:
+                    return 10;
+            }
+        };
+
+        const textAssignment = `--- title: ${col.title}, prompt: ${col.desc}, word limit: ${wordLimit(col.sizes[0])} words, assigned field: ${fieldNum} ---`;
+
+        let fieldContent: string = template.compiledContent;
+
+        try {
+            const prompt = fieldContent + textAssignment;
+
+            const res = await gptAPICall(`${++this._callCount}: ${prompt}`, GPTCallType.FILL);
+
+            console.log('prompt: ', prompt, ' response: ', res);
+
+            if (res) {
+                const assignments: { [title: string]: { number: string; content: string } } = JSON.parse(res);
+                Object.entries(assignments).forEach(([title, info]) => {
+                    const field: Field = template.getFieldByID(Number(info.number));
+                    const col = this.getColByTitle(title);
+
+                    field.setContent(info.content ?? '', FieldContentType.STRING);
+                    field.setTitle(col.title);
+                });
+            }
+        } catch (err) {
+            console.log(err);
+        }
+
+        return true;
+    }
+
+    createDocsFromTemplate = async (template: Template) => {
         const dv = this._dataViz;
         if (!dv) return;
         const fields: string[] = Array.from(Object.keys(dv.records[0]));  
         const selectedRows = NumListCast(dv.layoutDoc.dataViz_selectedRows);
-
-        const fieldContents: {[title: string]: string}[] = selectedRows.map(row => {
-            let values: {[title: string]: string} = {};
+    
+        const rowContents: { [title: string]: string }[] = selectedRows.map(row => {
+            let values: { [title: string]: string } = {};
             fields.forEach(col => {
                 values[col] = dv.records[row][col];
             });
-
+    
             return values;
         });
+    
+        const processContent = async (content: {[title: string]: string}) => {
+            const templateCopy = template.cloneBase(); 
+    
+            console.log('rows: ', content, '---------------- fields: ', fields)
 
-
-        const renderedDocs: Doc[] = [];
-
-        fieldContents.forEach(content => {
             fields.filter(title => title).forEach(title => {
-                const field = template.getFieldByTitle(title);
-                if (field === undefined){
-                    return;
-                }
+                const field = templateCopy.getFieldByTitle(title);
+                console.log('field: ', field);
+                if (field === undefined) { return };
                 field.setContent(content[title]);
             });
-
-            renderedDocs.push(template.mainField.renderedDoc());
-        });
+    
+            const gptPromises = this._userCreatedFields.map(field => {
+                const title = field.title;
+                const templateField = templateCopy.getFieldByTitle(title);
+                if (templateField === undefined) { return };
+                const templatefieldID = templateField.getID;
+    
+                return this.renderGPTTextCall(templateCopy, field, templatefieldID);
+            });
+    
+            await Promise.all(gptPromises);
+    
+            console.log(templateCopy);
+            return templateCopy.mainField.renderedDoc();
+        };
+    
+        const promises = rowContents.map(content => processContent(content));
+    
+        const renderedDocs = await Promise.all(promises);
 
         return renderedDocs;
     }
+    
 
     addRenderedCollectionToMainview = () => {
         const collection = this._renderedDocCollection;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
index 953dbabf6..12c0bea9a 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
@@ -80,6 +80,10 @@ export class DynamicField implements Field {
         return fields;
     }
 
+    applyAttributes = (field: Field) => {
+        return;
+    }
+
     getChildDimensions = (coords: { tl: [number, number]; br: [number, number] }): FieldDimensions => {
         const l = (coords.tl[0] * this.dimensions.height) / 2;
         const t = coords.tl[1] * this.dimensions.width / 2; //prettier-ignore
@@ -92,7 +96,6 @@ export class DynamicField implements Field {
     };
 
     renderedDoc = (): Doc => {
-        console.log('called')
         switch (this.settings.viewType) {
             case ViewType.CAROUSEL3D:
                 const carouselDoc = Docs.Create.Carousel3DDocument(this.subfields.map(field => field.renderedDoc()), {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
index a0eaffebf..ebd8f0f6c 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx
@@ -14,6 +14,7 @@ export interface Field {
     getTitle: () => string;
     setTitle: (title: string) => void;
     setupSubfields: () => Field[];
+    applyAttributes: (field: Field) => void;
     renderedDoc: () => Doc;
     matches: (cols: Col[]) => number[];
     updateRenderedDoc: (oldDoc?: Doc) => Doc;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
index 033900fe9..133954d3c 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
@@ -70,6 +70,11 @@ export class StaticField {
     };
     getTitle = () => { return this.title };
 
+    applyAttributes = (field: Field) => { //!!! can be updated later for more robust clonign; this is all ythat's needed now
+        field.setTitle(this.title);
+        field.setContent('', this.contentType);
+    }
+
     setupSubfields = (): Field[] => {
         const fields: Field[] = [];
         this.settings.subfields?.forEach((fieldSettings, index) => {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index 7d32d26d1..21344dfeb 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -10,9 +10,11 @@ import { } from "./FieldTypes/StaticField";
 export class Template {
 
     mainField: DynamicField;
+    settings: FieldSettings;
 
     constructor(templateInfo: FieldSettings) {
         this.mainField = this.setupMainField(templateInfo);
+        this.settings = templateInfo;
     }
 
     get childFields(): Field[] { return this.mainField.getSubfields };
@@ -20,6 +22,15 @@ export class Template {
     get contentFields(): Field[] { return this.allFields.filter(field => field.getViewType === ViewType.STATIC) };
     get doc(){ return this.mainField.renderedDoc(); };
 
+    cloneBase = () => {
+        const clone: Template = new Template(this.settings);
+        clone.contentFields.forEach(field => {
+            const matchingField: Field = this.contentFields.filter(f => f.getID === field.getID)[0];
+            matchingField.applyAttributes(field);
+        })
+        return clone;
+    }
+
     getFieldByID = (id: number): Field => {
         return this.allFields.filter(field => field.getID === id)[0];
     }
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
index 9b8ec64c0..ee7f19907 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
@@ -110,6 +110,7 @@ export class TemplateLayouts {
                     borderWidth: '8',
                     borderColor: '#F8E71C',
                     backgroundColor: '#242425',
+                    color: 'white',
                 },
             },
             {
-- 
cgit v1.2.3-70-g09d2


From 8a64d6cac98a561cdce3da467d825ccea813b524 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Thu, 7 Nov 2024 22:01:13 -0500
Subject: fields set properly

---
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.scss  |  1 +
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   | 37 ++++++++++++----------
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx     |  3 +-
 .../DocCreatorMenu/FieldTypes/FieldUtils.tsx       |  2 +-
 .../DocCreatorMenu/FieldTypes/StaticField.tsx      |  1 +
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   | 24 ++++++++++++--
 6 files changed, 47 insertions(+), 21 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss
index 98d630dae..c2e59b4a4 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss
@@ -695,6 +695,7 @@
     display: flex;
     justify-content: center;
     align-items: center;
+    color: black;
     width: calc(100% - 50px);
     height: calc(100% - 50px);
     position: relative;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index ea38430ca..fe91254f8 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -56,6 +56,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     @observable _fullyRenderedDocs: Doc[] = [];
     @observable _renderedDocCollectionPreview: Doc | undefined = undefined;
     @observable _renderedDocCollection: Doc | undefined = undefined;
+    @observable _docsRendering: boolean = false;
 
     @observable _userTemplates: {template: Template, doc: Doc}[] = []; //!!! used to keep track of all templates, should be refactored to work with actual templates and not docs
     @observable _selectedTemplate: Template | undefined = undefined;
@@ -109,21 +110,20 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         this._dataViz = dataViz;
     };
     @action addUserTemplate = (template: Template) => {
-        this._userTemplates.push({template: template, doc: template.mainField.renderedDoc()});
+        this._userTemplates.push({template: template, doc: template.getRenderedDoc()});
     };
     @action removeUserTemplate = (template: Template) => {
         this._userTemplates = this._userTemplates.filter(info => info.template !== template);
     }
     @action updateTemplatePreview = (template: Template) => {
         template.renderUpdates();
-        const preview = {template: template, doc: template.mainField.renderedDoc()};
-        const doc = template.mainField.renderedDoc();
-        this._suggestedTemplatePreviews.map(t => { return t.template === preview.template ? {doc: doc, template: template} : t }); //prettier-ignore
-        this._userTemplates = this._userTemplates.map(t => { return t.template === preview.template ? {doc: doc, template: template} : t }); //prettier-ignore
+        const preview = {template: template, doc: template.getRenderedDoc()};
+        this._suggestedTemplatePreviews.map(t => { return t.template === preview.template ? preview : t }); //prettier-ignore
+        this._userTemplates = this._userTemplates.map(t => { return t.template === preview.template ? preview : t }); //prettier-ignore
     };
     @action setSuggestedTemplates = (templates: Template[]) => {
         this._suggestedTemplates = templates;
-        this._suggestedTemplatePreviews = templates.map(template => {return {template: template, doc: template.mainField.renderedDoc()}}); //prettier-ignore
+        this._suggestedTemplatePreviews = templates.map(template => {return {template: template, doc: template.getRenderedDoc()}}); //prettier-ignore
     };
 
     @computed get docsToRender() {
@@ -682,6 +682,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     createDocsFromTemplate = async (template: Template) => {
         const dv = this._dataViz;
         if (!dv) return;
+
+        this._docsRendering = true;
+
         const fields: string[] = Array.from(Object.keys(dv.records[0]));  
         const selectedRows = NumListCast(dv.layoutDoc.dataViz_selectedRows);
     
@@ -696,12 +699,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     
         const processContent = async (content: {[title: string]: string}) => {
             const templateCopy = template.cloneBase(); 
-    
-            console.log('rows: ', content, '---------------- fields: ', fields)
 
             fields.filter(title => title).forEach(title => {
                 const field = templateCopy.getFieldByTitle(title);
-                console.log('field: ', field);
                 if (field === undefined) { return };
                 field.setContent(content[title]);
             });
@@ -717,14 +717,15 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     
             await Promise.all(gptPromises);
     
-            console.log(templateCopy);
-            return templateCopy.mainField.renderedDoc();
+            return templateCopy.getRenderedDoc();
         };
     
         const promises = rowContents.map(content => processContent(content));
     
         const renderedDocs = await Promise.all(promises);
 
+        this._docsRendering = false;
+
         return renderedDocs;
     }
     
@@ -831,7 +832,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                                     className="option-button left"
                                                     onPointerDown={e =>
                                                         this.setUpButtonClick(e, () => {
-                                                            this.setExpandedView(template.mainField.renderedDoc());
+                                                            this.setExpandedView(template.getRenderedDoc());
                                                         })
                                                     }>
                                                     <FontAwesomeIcon icon="magnifying-glass" color="white" />
@@ -900,7 +901,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                                 className="option-button left"
                                                 onPointerDown={e =>
                                                     this.setUpButtonClick(e, () => {
-                                                        this.setExpandedView(template.mainField.renderedDoc());
+                                                        this.setExpandedView(template.getRenderedDoc());
                                                     })
                                                 }>
                                                 <FontAwesomeIcon icon="magnifying-glass" color="white" />
@@ -1105,7 +1106,11 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         const doc: Doc | undefined = altLayout ? altLayout.template : this._fullyRenderedDocs[0]; //!!! might cause a slow down
         if (!doc) return;
 
-        return !this._renderedDocCollection? null : (
+        return this._docsRendering ? (
+            <div className="loading-spinner">
+                <ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} />
+            </div> 
+            ) : !this._renderedDocCollection? null : (
             <div className="docCreatorMenu-layout-preview-window-wrapper" id={String(id) ?? undefined}>
                 <DocumentView
                     Document={this._renderedDocCollection}
@@ -1131,7 +1136,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                     hideDecorations={true}
                 />
             </div>
-        );
+        )
     };
 
     get optionsMenuContents() {
@@ -1213,7 +1218,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                     clickEv.stopPropagation();
                                     if (!this._selectedTemplate) return;
                                     const layout: DataVizTemplateLayout = {
-                                        template: this._selectedTemplate.mainField.renderedDoc(),
+                                        template: this._selectedTemplate.getRenderedDoc(),
                                         layout: { type: this._layout.type, xMargin: this._layout.xMargin, yMargin: this._layout.yMargin, repeat: 0 },
                                         columns: this.columnsCount,
                                         rows: this.rowsCount,
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
index 12c0bea9a..68cf027b0 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/DynamicField.tsx
@@ -81,7 +81,8 @@ export class DynamicField implements Field {
     }
 
     applyAttributes = (field: Field) => {
-        return;
+        field.setTitle(this.title);
+        field.updateRenderedDoc(this.renderedDoc());
     }
 
     getChildDimensions = (coords: { tl: [number, number]; br: [number, number] }): FieldDimensions => {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
index de542b40b..bb8489c21 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
@@ -25,7 +25,7 @@ export class FieldUtils {
         doc._height = oldDoc ? oldDoc.height : parentDimensions.height;
         doc._width = oldDoc ? oldDoc.width : parentDimensions.width;
         doc.backgroundColor = oldDoc ? oldDoc.backgroundColor : opts.backgroundColor ?? '';
-        doc._layout_borderRounding = !opts.cornerRounding ? '0px' : ScriptField.MakeScript(`${opts.cornerRounding * parentDimensions.width}px`);
+        doc._layout_borderRounding = !opts.cornerRounding ? '0px' : ScriptField.MakeFunction(`${opts.cornerRounding} * this.width + 'px'`);
         doc.borderColor = oldDoc ? oldDoc.borderColor : opts.borderColor;
         doc.borderWidth = oldDoc ? oldDoc.borderWidth : opts.borderWidth;
         doc.opacity = oldDoc ? oldDoc.opacity : opts.opacity;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
index 133954d3c..e55c127e7 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
@@ -73,6 +73,7 @@ export class StaticField {
     applyAttributes = (field: Field) => { //!!! can be updated later for more robust clonign; this is all ythat's needed now
         field.setTitle(this.title);
         field.setContent('', this.contentType);
+        field.updateRenderedDoc(this.renderedDoc());
     }
 
     setupSubfields = (): Field[] => {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index 21344dfeb..292c20a10 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -1,5 +1,5 @@
 
-import { Doc } from "../../../../../fields/Doc";
+import { Doc, FieldType } from "../../../../../fields/Doc";
 import { Docs } from "../../../../documents/Documents";
 import { Col } from "./DocCreatorMenu";
 import { DynamicField } from "./FieldTypes/DynamicField";
@@ -24,13 +24,31 @@ export class Template {
 
     cloneBase = () => {
         const clone: Template = new Template(this.settings);
-        clone.contentFields.forEach(field => {
-            const matchingField: Field = this.contentFields.filter(f => f.getID === field.getID)[0];
+        clone.allFields.forEach(field => {
+            const matchingField: Field = this.allFields.filter(f => f.getID === field.getID)[0];
             matchingField.applyAttributes(field);
         })
         return clone;
     }
 
+    applyFields = () => {
+        this.contentFields.forEach(field => {
+            this.mainField
+        });
+    }
+
+    getRenderedDoc = () => {
+        const doc: Doc = this.mainField.renderedDoc();
+        this.contentFields.forEach(field => {
+            const title: string = field.getTitle();
+            const val: FieldType = field.getContent() as FieldType;
+            doc[title] = val;
+            console.log(doc[title])
+            console.log(doc['title']);
+        });
+        return doc;
+    }
+
     getFieldByID = (id: number): Field => {
         return this.allFields.filter(field => field.getID === id)[0];
     }
-- 
cgit v1.2.3-70-g09d2


From b6ed6542f911694c673b9e324d7387ea16dc7d0b Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Thu, 7 Nov 2024 23:37:49 -0500
Subject: template reset option and fixed preview not rendering on edits after
 1st

---
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx    | 21 +++++++++++++--------
 .../DocCreatorMenu/FieldTypes/StaticField.tsx       |  2 ++
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx    | 12 ++++++------
 3 files changed, 21 insertions(+), 14 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index fe91254f8..48f87ebfe 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -118,7 +118,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     @action updateTemplatePreview = (template: Template) => {
         template.renderUpdates();
         const preview = {template: template, doc: template.getRenderedDoc()};
-        this._suggestedTemplatePreviews.map(t => { return t.template === preview.template ? preview : t }); //prettier-ignore
+        this._suggestedTemplatePreviews = this._suggestedTemplatePreviews.map(t => { return t.template === preview.template ? preview : t }); //prettier-ignore
         this._userTemplates = this._userTemplates.map(t => { return t.template === preview.template ? preview : t }); //prettier-ignore
     };
     @action setSuggestedTemplates = (templates: Template[]) => {
@@ -740,10 +740,12 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         this.closeMenu();
     }
 
-    @action setExpandedView = (doc: Doc | undefined) => {
-        if (doc) {
-            this._expandedPreview = doc; //Docs.Create.FreeformDocument([doc], { _height: NumListCast(doc._height)[0], _width: NumListCast(doc._width)[0], title: ''});
+    @action setExpandedView = (template: Template | undefined) => {
+        if (template) {
+            this._currEditingTemplate = template;
+            this._expandedPreview = template.mainField.renderedDoc(); //Docs.Create.FreeformDocument([doc], { _height: NumListCast(doc._height)[0], _width: NumListCast(doc._width)[0], title: ''});
         } else {
+            this._currEditingTemplate = undefined;
             this._expandedPreview = undefined;
         }
     };
@@ -781,10 +783,13 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                 <div className="top-panel"/>
                 {rendered}
                 <div className="right-buttons-panel">
-                    <button className="docCreatorMenu-menu-button section-reveal-options top-right" onPointerDown={e => this.setUpButtonClick(e, () => {this._currEditingTemplate && this.updateTemplatePreview(this._currEditingTemplate); this.setExpandedView(undefined)})}>
+                    <button className="docCreatorMenu-menu-button section-reveal-options top-right" onPointerDown={e => this.setUpButtonClick(e, () => {
+                        this._currEditingTemplate && this.updateTemplatePreview(this._currEditingTemplate); 
+                        this.setExpandedView(undefined)}
+                        )}>
                         <FontAwesomeIcon icon="minimize" />
                     </button>
-                    <button className="docCreatorMenu-menu-button section-reveal-options top-right-lower" onPointerDown={e => this.setUpButtonClick(e, () => this._expandedPreview && this._currEditingTemplate && this.addUserTemplate(this._currEditingTemplate))}>
+                    <button className="docCreatorMenu-menu-button section-reveal-options top-right-lower" onPointerDown={e => this.setUpButtonClick(e, () => {this._currEditingTemplate?.resetToBase(); this.setExpandedView(this._currEditingTemplate);})}>
                         <FontAwesomeIcon icon="plus" color="white" />
                     </button>
                 </div>
@@ -832,7 +837,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                                     className="option-button left"
                                                     onPointerDown={e =>
                                                         this.setUpButtonClick(e, () => {
-                                                            this.setExpandedView(template.getRenderedDoc());
+                                                            this.setExpandedView(template);
                                                         })
                                                     }>
                                                     <FontAwesomeIcon icon="magnifying-glass" color="white" />
@@ -901,7 +906,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                                 className="option-button left"
                                                 onPointerDown={e =>
                                                     this.setUpButtonClick(e, () => {
-                                                        this.setExpandedView(template.getRenderedDoc());
+                                                        this.setExpandedView(template);
                                                     })
                                                 }>
                                                 <FontAwesomeIcon icon="magnifying-glass" color="white" />
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
index e55c127e7..dfef77c0b 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
@@ -118,6 +118,8 @@ export class StaticField {
     updateRenderedDoc = (oldDoc?: Doc): Doc => {
         const opts = this.settings.opts;
 
+        console.log('called')
+
         if (!this.contentType) { this.contentType = FieldContentType.STRING };
 
         let doc: Doc;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index 292c20a10..11fad3bf1 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -31,12 +31,6 @@ export class Template {
         return clone;
     }
 
-    applyFields = () => {
-        this.contentFields.forEach(field => {
-            this.mainField
-        });
-    }
-
     getRenderedDoc = () => {
         const doc: Doc = this.mainField.renderedDoc();
         this.contentFields.forEach(field => {
@@ -83,6 +77,12 @@ export class Template {
         });
     };
 
+    resetToBase = () => {
+        this.allFields.forEach(field => {
+            field.updateRenderedDoc();
+        })
+    }
+
     isValidTemplate = (cols: Col[]) => {
         const matches: number[][] = this.getMatches(cols);
         const maxMatches: number = this.maxMatches(matches);
-- 
cgit v1.2.3-70-g09d2


From 74e0744cfd3be6d375ff47f0d32588996074f956 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Fri, 8 Nov 2024 00:07:59 -0500
Subject: image generation working

---
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   | 73 ++++++++++++++--------
 .../DocCreatorMenu/FieldTypes/StaticField.tsx      |  2 -
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   |  3 +-
 3 files changed, 48 insertions(+), 30 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index 48f87ebfe..3cdde90d5 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -499,14 +499,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
      */
     applyGPTContentToTemplate = async (template: Template, assignments: { [field: string]: Col }): Promise<Template | undefined> => {
 
-        const generateAndLoadImage = async (fieldNum: string, col: Col, prompt: string) => {
-            const url = await this.generateGPTImage(prompt);
-            const field: Field = template.getFieldByID(Number(fieldNum));
-
-            field.setContent(url ?? '', FieldContentType.IMAGE);
-            field.setTitle(col.title);
-        };
-
         const GPTTextCalls = Object.entries(assignments).filter(([str, col]) => col.type === TemplateFieldType.TEXT && this._userCreatedFields.includes(col));
         const GPTIMGCalls = Object.entries(assignments).filter(([str, col]) => col.type === TemplateFieldType.VISUAL && this._userCreatedFields.includes(col));
 
@@ -520,24 +512,14 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             await Promise.all(promises);
         }
 
+        console.log(GPTIMGCalls)
+
         if (GPTIMGCalls.length) {
-            try {
-                await Promise.all(
-                    GPTIMGCalls.map(async ([fieldNum, col]) => {
-                        const sysPrompt =
-                            'Your job is to create a prompt for an AI image generator to help it generate an image based on existing content in a template and a user prompt. Your prompt should focus heavily on visual elements to help the image generator; avoid unecessary info that might distract it. ONLY INCLUDE THE PROMPT, NO OTHER TEXT OR EXPLANATION. The existing content is as follows: ' +
-                            fieldContent +
-                            ' **** The user prompt is: ' +
-                            col.desc;
-
-                        const prompt = await gptAPICall(sysPrompt, GPTCallType.COMPLETEPROMPT);
-
-                        generateAndLoadImage(fieldNum, col, prompt);
-                    })
-                );
-            } catch (e) {
-                console.log(e);
-            }
+            const promises = GPTIMGCalls.map(async ([fieldNum, col]) => {
+                return this.renderGPTImageCall(template, col, Number(fieldNum));
+            });
+
+            await Promise.all(promises);
         };
 
         return template;
@@ -633,6 +615,34 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         });
     };
 
+    renderGPTImageCall = async (template: Template, col: Col, fieldNum: number): Promise<boolean> => {
+        const generateAndLoadImage = async (fieldNum: string, col: Col, prompt: string) => {
+            const url = await this.generateGPTImage(prompt);
+            console.log('url: ', url)
+            const field: Field = template.getFieldByID(Number(fieldNum));
+
+            field.setContent(url ?? '', FieldContentType.IMAGE);
+            field.setTitle(col.title);
+        };
+
+        let fieldContent: string = template.compiledContent;
+
+        try {
+            const sysPrompt =
+                'Your job is to create a prompt for an AI image generator to help it generate an image based on existing content in a template and a user prompt. Your prompt should focus heavily on visual elements to help the image generator; avoid unecessary info that might distract it. ONLY INCLUDE THE PROMPT, NO OTHER TEXT OR EXPLANATION. The existing content is as follows: ' +
+                fieldContent +
+                ' **** The user prompt is: ' +
+                col.desc;
+
+            const prompt = await gptAPICall(sysPrompt, GPTCallType.COMPLETEPROMPT);
+
+            await generateAndLoadImage(String(fieldNum), col, prompt);
+        } catch (e) {
+            console.log(e);
+        }
+        return true;
+    }
+
     renderGPTTextCall = async (template: Template, col: Col, fieldNum: number): Promise<boolean> => {
         const wordLimit = (size: TemplateFieldSize) => {
             switch (size) {
@@ -706,7 +716,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                 field.setContent(content[title]);
             });
     
-            const gptPromises = this._userCreatedFields.map(field => {
+            const gptPromises = this._userCreatedFields.filter(field => field.type === TemplateFieldType.TEXT).map(field => {
                 const title = field.title;
                 const templateField = templateCopy.getFieldByTitle(title);
                 if (templateField === undefined) { return };
@@ -714,8 +724,19 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     
                 return this.renderGPTTextCall(templateCopy, field, templatefieldID);
             });
+
+            const imagePromises = this._userCreatedFields.filter(field => field.type === TemplateFieldType.VISUAL).map(field => {
+                const title = field.title;
+                const templateField = templateCopy.getFieldByTitle(title);
+                if (templateField === undefined) { return };
+                const templatefieldID = templateField.getID;
+    
+                return this.renderGPTImageCall(templateCopy, field, templatefieldID);
+            });
     
             await Promise.all(gptPromises);
+
+            await Promise.all(imagePromises);
     
             return templateCopy.getRenderedDoc();
         };
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
index dfef77c0b..e55c127e7 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/StaticField.tsx
@@ -118,8 +118,6 @@ export class StaticField {
     updateRenderedDoc = (oldDoc?: Doc): Doc => {
         const opts = this.settings.opts;
 
-        console.log('called')
-
         if (!this.contentType) { this.contentType = FieldContentType.STRING };
 
         let doc: Doc;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index 11fad3bf1..31402eeeb 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -36,9 +36,8 @@ export class Template {
         this.contentFields.forEach(field => {
             const title: string = field.getTitle();
             const val: FieldType = field.getContent() as FieldType;
+            if (!title || !val) return;
             doc[title] = val;
-            console.log(doc[title])
-            console.log(doc['title']);
         });
         return doc;
     }
-- 
cgit v1.2.3-70-g09d2


From 41d56b090d00b76c44644c07fdd2017a96ac3aae Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Tue, 4 Mar 2025 03:27:14 -0500
Subject: removed logs

---
 src/client/views/nodes/DataVizBox/DataVizBox.tsx   |  1 -
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   | 60 +---------------------
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   |  2 -
 3 files changed, 2 insertions(+), 61 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index dececd1dc..50d72e2e4 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -172,7 +172,6 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         const colInfo = this.colsInfo.get(colTitle);
         if (colInfo) {
             colInfo.title = newTitle;
-            console.log(colInfo.title);
         } else {
             this.colsInfo.set(colTitle, { title: newTitle, desc: '', type: TemplateFieldType.UNSET, sizes: [] });
         }
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index 2324006f7..7b28a06a3 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -241,18 +241,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     componentDidMount() {
         document.addEventListener('pointerdown', this.onPointerDown, true);
         document.addEventListener('pointerup', this.onPointerUp);
-        //this._disposers.columns = reaction(() => this._dataViz?.layoutDoc._dataViz_axes, () => {this.generateTemplates('')})
-        this._disposers.lightbox = reaction(
-            () => LightboxView.LightboxDoc(),
-            doc => {
-                doc ? this._shouldDisplay && this.closeMenu() : !this._shouldDisplay && this.openMenu();
-            }
-        );
-        // this._disposers.layout = reaction(
-        //     () => this._layout,
-        //     layout => { this.updateRenderedDocCollection(); }
-        // );
-        //this._disposers.fields = reaction(() => this._dataViz?.axes, cols => this._selectedCols = cols?.map(col => { return {title: col, type: '', desc: ''}}))
     }
 
     componentWillUnmount() {
@@ -391,38 +379,11 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     };
 
     editTemplate = (doc: Doc) => {
-        //this.closeMenu();
         DocumentViewInternal.addDocTabFunc(doc, OpenWhere.addRight);
         DocumentView.DeselectAll();
         Doc.UnBrushDoc(doc);
     };
 
-    testTemplate = async () => {
-
-        //console.log(this.templateManager.templates)
-
-        const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
-        
-        this.templateManager.templates.forEach(template => {
-            const doc = template.mainField.renderedDoc();
-            mainCollection.addDocument(doc);
-        })
-
-        this.forceUpdate();
-
-        // try {
-        //     const res = await gptImageCall('Image of panda eating a cookie');
-
-        //     if (res) {
-        //         const result = await Networking.PostToServer('/uploadRemoteImage', { sources: res });
-
-        //         console.log(result);
-        //     }
-        // } catch (e) {
-        //     console.log(e);
-        // }
-    };
-
     @action addField = () => {
         const newFields: Col[] = this._userCreatedFields.concat([{ title: '', type: TemplateFieldType.UNSET, desc: '', sizes: [] }]);
         this._userCreatedFields = newFields;
@@ -490,8 +451,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     };
 
     generateGPTImage = async (prompt: string): Promise<string | undefined> => {
-        console.log(prompt);
-
         try {
             const res = await gptImageCall(prompt);
 
@@ -526,8 +485,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             await Promise.all(promises);
         }
 
-        console.log(GPTIMGCalls)
-
         if (GPTIMGCalls.length) {
             const promises = GPTIMGCalls.map(async ([fieldNum, col]) => {
                 return this.renderGPTImageCall(template, col, Number(fieldNum));
@@ -589,7 +546,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                             const col = this.getColByTitle(colTitle);
                             if (!this._userCreatedFields.includes(col)){ // do the following for any fields not added by the user; will change in the future, for now only GPT content works with user-added fields
                                 const field = template.getFieldByID(Number(fieldID));
-                                //console.log(field);
                                 field.setContent(col.defaultContent ?? '', col.type === TemplateFieldType.VISUAL ? FieldContentType.IMAGE : FieldContentType.STRING);
                                 field.setTitle(col.title);
                             } else {
@@ -632,7 +588,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     renderGPTImageCall = async (template: Template, col: Col, fieldNum: number): Promise<boolean> => {
         const generateAndLoadImage = async (fieldNum: string, col: Col, prompt: string) => {
             const url = await this.generateGPTImage(prompt);
-            console.log('url: ', url)
             const field: Field = template.getFieldByID(Number(fieldNum));
 
             field.setContent(url ?? '', FieldContentType.IMAGE);
@@ -684,8 +639,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
             const res = await gptAPICall(`${++this._callCount}: ${prompt}`, GPTCallType.FILL);
 
-            console.log('prompt: ', prompt, ' response: ', res);
-
             if (res) {
                 const assignments: { [title: string]: { number: string; content: string } } = JSON.parse(res);
                 Object.entries(assignments).forEach(([title, info]) => {
@@ -705,7 +658,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
     createDocsFromTemplate = async (template: Template) => {
         const dv = this._dataViz;
-        console.log('dataviz: ', dv);
+
         if (!dv) return;
 
         this._docsRendering = true;
@@ -837,8 +790,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
         const GPTOptions = <div></div>;
 
-        //<img className='docCreatorMenu-preview-image expanded' src={this._expandedPreview.icon!.url.href.replace(".png", "_o.png")} />
-
         return (
             <div className={`docCreatorMenu-templates-view`}>
                 {this._expandedPreview ? (
@@ -924,7 +875,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                 </button>
                             </div>
                             <div className="docCreatorMenu-templates-preview-window" style={{ justifyContent: this._menuDimensions.width > 400 ? 'center' : '' }}>
-                                <div className="docCreatorMenu-preview-window empty" onPointerDown={e => this.testTemplate()}>
+                                <div className="docCreatorMenu-preview-window empty">
                                     <FontAwesomeIcon icon="plus" color="rgb(160, 160, 160)" />
                                 </div>
                                 {this._userTemplates
@@ -1027,10 +978,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         }
     }
 
-    // doc = () => {
-    //     return Docs.Create.FreeformDocument([], { _height: 200, _width: 200, title: 'title'});
-    // }
-
     screenToLocalTransform = () => this._props.ScreenToLocalTransform();
 
     applyLayout = (collection: Doc, docs: Doc[]) => {
@@ -1092,7 +1039,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         if (!this._fullyRenderedDocs) return;
 
         const { horizontalSpan, verticalSpan } = this.previewInfo;
-        //const largerSpan: number = horizontalSpan > verticalSpan ? horizontalSpan : verticalSpan;
 
         const collectionFactory = (): (docs: Doc[], options: DocumentOptions) => Doc => {
             switch (this._layout.type) {
@@ -1162,8 +1108,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
     };
 
     get optionsMenuContents() {
-        const layoutEquals = (layout: DataVizTemplateLayout) => {}; //TODO: ADD LATER
-
         const layoutOption = (option: LayoutType, optStyle?: {}, specialFunc?: Function) => {
             return (
                 <div
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
index 31402eeeb..39215eb06 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.tsx
@@ -135,8 +135,6 @@ export class Template {
             if (mt[i] !== -1) ++count;
         }
 
-        console.log(this.mainField.getTitle(), count)
-
         return count;
     };
 
-- 
cgit v1.2.3-70-g09d2


From 0a8f3739cf5c30852f18751a4c05d81e0dabe928 Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Tue, 4 Mar 2025 04:19:01 -0500
Subject: linting

---
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   | 156 ++++++++++-----------
 .../DocCreatorMenu/FieldTypes/DynamicField.tsx     |  21 ++-
 .../DataVizBox/DocCreatorMenu/FieldTypes/Field.tsx |  61 ++++----
 .../DocCreatorMenu/FieldTypes/StaticField.tsx      |  13 +-
 .../nodes/DataVizBox/DocCreatorMenu/Template.tsx   |   2 -
 .../DataVizBox/DocCreatorMenu/TemplateBackend.tsx  |   2 +-
 .../DataVizBox/DocCreatorMenu/TemplateManager.tsx  |   1 -
 7 files changed, 116 insertions(+), 140 deletions(-)

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

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

