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

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

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

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
new file mode 100644
index 000000000..a25eab74f
--- /dev/null
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
@@ -0,0 +1,491 @@
+import { FieldOpts, FieldSettings } from "./FieldTypes";
+
+export enum TemplateFieldType {
+    TEXT = 'text',
+    VISUAL = 'visual',
+    UNSET = 'unset',
+}
+
+export enum TemplateFieldSize {
+    TINY = 'tiny',
+    SMALL = 'small',
+    MEDIUM = 'medium',
+    LARGE = 'large',
+    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 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,
+        opts: {
+            backgroundColor: '#C0B887',
+            cornerRounding: 20,
+            borderColor: '#6B461F',
+            borderWidth: '12',
+        },
+        fields: [
+            {
+                tl: [-0.95, -1],
+                br: [0.95, -0.85],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY],
+                description: 'A title field for very short text that contextualizes the content.',
+                opts: {
+                    backgroundColor: 'transparent',
+                    color: '#F1F0E9',
+                    contentXCentering: 'h-center',
+                    fontBold: true,
+                },
+            },
+            {
+                tl: [-0.87, -0.83],
+                br: [0.87, 0.2],
+                types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                description: 'The main focus of the template; could be an image, long text, etc.',
+                opts: {
+                    cornerRounding: 20,
+                    borderColor: '#8F5B25',
+                    borderWidth: '6',
+                    backgroundColor: '#CECAB9',
+                },
+            },
+            {
+                tl: [-0.8, 0.2],
+                br: [0.8, 0.3],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
+                description: 'A caption for field #2, very short to short text that contextualizes the content of field #2',
+                opts: {
+                    backgroundColor: 'transparent',
+                    contentXCentering: 'h-center',
+                    color: '#F1F0E9',
+                },
+            },
+            {
+                tl: [-0.87, 0.37],
+                br: [0.87, 0.96],
+                types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                description: 'A medium-sized field for medium/long text.',
+                opts: {
+                    cornerRounding: 15,
+                    borderColor: '#8F5B25',
+                    borderWidth: '6',
+                    backgroundColor: '#CECAB9',
+                },
+            },
+        ],
+        decorations: [],
+    };
+
+    public static FourField002: TemplateDocInfos = {
+        title: 'fourfield2',
+        width: 425,
+        height: 778,
+        opts: {
+            backgroundColor: '#242425',
+        },
+        fields: [
+            {
+                tl: [-0.83, -0.95],
+                br: [0.83, -0.2],
+                types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
+                description: 'A medium to large-sized field suitable for an image or longer text that should be the main focus.',
+                opts: {
+                    borderWidth: '8',
+                    borderColor: '#F8E71C',
+                },
+            },
+            {
+                tl: [-0.65, -0.2],
+                br: [0.65, -0.02],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY],
+                description: 'A tiny field for just a word or two of plain text.',
+                opts: {
+                    backgroundColor: 'transparent',
+                    color: 'white',
+                    contentXCentering: 'h-center',
+                    fontTransform: 'uppercase',
+                },
+            },
+            {
+                tl: [-0.65, 0],
+                br: [0.65, 0.18],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY],
+                description: 'A tiny field for just a word or two of plain text.',
+                opts: {
+                    backgroundColor: 'transparent',
+                    color: 'white',
+                    contentXCentering: 'h-center',
+                    fontTransform: 'uppercase',
+                },
+            },
+            {
+                tl: [-0.83, 0.2],
+                br: [0.83, 0.95],
+                types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
+                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.',
+                opts: {
+                    borderWidth: '8',
+                    borderColor: '#F8E71C',
+                    color: 'white',
+                    backgroundColor: '#242425',
+                },
+            },
+        ],
+        decorations: [
+            {
+                tl: [-0.8, -0.075],
+                br: [-0.525, 0.075],
+                opts: {
+                    backgroundColor: '#F8E71C',
+                    //rotation: 45,
+                },
+            },
+            {
+                tl: [-0.3075, -0.0245],
+                br: [-0.2175, 0.0245],
+                opts: {
+                    backgroundColor: '#F8E71C',
+                    //rotation: 45,
+                },
+            },
+            {
+                tl: [-0.045, -0.0245],
+                br: [0.045, 0.0245],
+                opts: {
+                    backgroundColor: '#F8E71C',
+                    //rotation: 45,
+                },
+            },
+            {
+                tl: [0.2175, -0.0245],
+                br: [0.3075, 0.0245],
+                opts: {
+                    backgroundColor: '#F8E71C',
+                    //rotation: 45,
+                },
+            },
+            {
+                tl: [0.525, -0.075],
+                br: [0.8, 0.075],
+                opts: {
+                    backgroundColor: '#F8E71C',
+                    //rotation: 45,
+                },
+            },
+        ],
+    };
+
+    // public static FourField003: TemplateDocInfos = {
+    //     title: 'fourfield3',
+    //     width: 477,
+    //     height: 662,
+    //     opts: {
+    //         backgroundColor: '#9E9C95'
+    //     },
+    //     fields: [{
+    //         tl: [-.875, -.9],
+    //         br: [.875, .7],
+    //         types: [TemplateFieldType.VISUAL],
+    //         sizes: [TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+    //         description: '',
+    //         opts: {
+    //             borderWidth: '15',
+    //             borderColor: '#E0E0DA',
+    //         }
+    //     }, {
+    //         tl: [-.95, .8],
+    //         br: [-.1, .95],
+    //         types: [TemplateFieldType.TEXT],
+    //         sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
+    //         description: '',
+    //         opts: {
+    //             backgroundColor: 'transparent',
+    //             color: 'white',
+    //             contentXCentering: 'h-right',
+    //         }
+    //     }, {
+    //         tl: [.1, .8],
+    //         br: [.95, .95],
+    //         types: [TemplateFieldType.TEXT],
+    //         sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
+    //         description: '',
+    //         opts: {
+    //             backgroundColor: 'transparent',
+    //             color: 'red',
+    //             fontTransform: 'uppercase',
+    //             contentXCentering: 'h-left'
+    //         }
+    //     }, {
+    //         tl: [0, -.9],
+    //         br: [.85, -.66],
+    //         types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
+    //         sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+    //         description: '',
+    //         opts: {
+    //             backgroundColor: 'transparent',
+    //             contentXCentering: 'h-right'
+    //         }
+    //     }],
+    //     decorations: [{
+    //         tl: [-.025, .8],
+    //         br: [.025, .95],
+    //         opts: {
+    //             backgroundColor: '#E0E0DA',
+    //         }
+    //     }]
+    // };
+
+    public static FourField004: TemplateDocInfos = {
+        title: 'fourfield4',
+        width: 414,
+        height: 583,
+        opts: {
+            backgroundColor: '#6CCAF0',
+            borderColor: '#1088C3',
+            borderWidth: '10',
+        },
+        fields: [
+            {
+                tl: [-0.86, -0.92],
+                br: [-0.075, -0.77],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY],
+                description: 'A tiny field for just a word or two of plain text.',
+                opts: {
+                    backgroundColor: '#E2B4F5',
+                    borderWidth: '9',
+                    borderColor: '#9222F1',
+                    contentXCentering: 'h-center',
+                },
+            },
+            {
+                tl: [0.075, -0.92],
+                br: [0.86, -0.77],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY],
+                description: 'A tiny field for just a word or two of plain text.',
+                opts: {
+                    backgroundColor: '#F5B4DD',
+                    borderWidth: '9',
+                    borderColor: '#E260F3',
+                    contentXCentering: 'h-center',
+                },
+            },
+            {
+                tl: [-0.81, -0.64],
+                br: [0.81, 0.48],
+                types: [TemplateFieldType.VISUAL],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                description: 'A large to huge field for visual content that is the main content of the template.',
+                opts: {
+                    borderWidth: '16',
+                    borderColor: '#A2BD77',
+                },
+            },
+            {
+                tl: [-0.86, 0.6],
+                br: [0.86, 0.92],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
+                description: 'A medium to large field for text that describes the visual content above',
+                opts: {
+                    borderWidth: '9',
+                    borderColor: '#F0D601',
+                    backgroundColor: '#F3F57D',
+                },
+            },
+        ],
+        decorations: [
+            {
+                tl: [-0.852, -0.67],
+                br: [0.852, 0.51],
+                opts: {
+                    backgroundColor: 'transparent',
+                    borderColor: '#007C0C',
+                    borderWidth: '10',
+                },
+            },
+        ],
+    };
+
+    public static ThreeField001: TemplateDocInfos = {
+        title: 'threefield1',
+        width: 575,
+        height: 770,
+        opts: {
+            backgroundColor: '#DDD3A9',
+        },
+        fields: [
+            {
+                tl: [-0.66, -0.747],
+                br: [0.66, 0.247],
+                types: [TemplateFieldType.VISUAL],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                description: 'A medium to large field for visual content that is the central focus.',
+                opts: {
+                    borderColor: 'yellow',
+                    borderWidth: '8',
+                    rotation: 45,
+                },
+            },
+            {
+                tl: [-0.7, 0.2],
+                br: [0.7, 0.46],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
+                description: 'A very small text field for one to a few words. A good caption for the image.',
+                opts: {
+                    backgroundColor: 'transparent',
+                    contentXCentering: 'h-center',
+                },
+            },
+            {
+                tl: [-0.95, 0.5],
+                br: [0.95, 0.95],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
+                description: 'A medium to large text field for a thorough description of the image. ',
+                opts: {
+                    backgroundColor: 'transparent',
+                    color: 'white',
+                },
+            },
+        ],
+        decorations: [
+            {
+                tl: [0.2, -1.32],
+                br: [1.8, -0.66],
+                opts: {
+                    backgroundColor: '#CEB155',
+                    rotation: 45,
+                },
+            },
+            {
+                tl: [-1.8, -1.32],
+                br: [-0.2, -0.66],
+                opts: {
+                    backgroundColor: '#CEB155',
+                    rotation: 135,
+                },
+            },
+            {
+                tl: [0.33, 0.75],
+                br: [1.66, 1.25],
+                opts: {
+                    backgroundColor: '#CEB155',
+                    rotation: 135,
+                },
+            },
+            {
+                tl: [-1.66, 0.75],
+                br: [-0.33, 1.25],
+                opts: {
+                    backgroundColor: '#CEB155',
+                    rotation: 45,
+                },
+            },
+        ],
+    };
+
+    public static ThreeField002: TemplateDocInfos = {
+        title: 'threefield2',
+        width: 477,
+        height: 662,
+        opts: {
+            backgroundColor: '#9E9C95',
+        },
+        fields: [
+            {
+                tl: [-0.875, -0.9],
+                br: [0.875, 0.7],
+                types: [TemplateFieldType.VISUAL],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                description: 'A medium to large visual field for the main content of the template',
+                opts: {
+                    borderWidth: '15',
+                    borderColor: '#E0E0DA',
+                },
+            },
+            {
+                tl: [0.1, 0.775],
+                br: [0.95, 0.975],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
+                description: 'A very small text field for one to a few words. The content should represent a general categorization of the image.',
+                opts: {
+                    backgroundColor: 'transparent',
+                    color: '#AF0D0D',
+                    fontTransform: 'uppercase',
+                    fontBold: true,
+                    contentXCentering: 'h-left',
+                },
+            },
+            {
+                tl: [-0.95, 0.775],
+                br: [-0.1, 0.975],
+                types: [TemplateFieldType.TEXT],
+                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
+                description: 'A very small text field for one to a few words. The content should contextualize field 2.',
+                opts: {
+                    backgroundColor: 'transparent',
+                    color: 'black',
+                    contentXCentering: 'h-right',
+                },
+            },
+        ],
+        decorations: [
+            {
+                tl: [-0.025, 0.8],
+                br: [0.025, 0.95],
+                opts: {
+                    backgroundColor: '#E0E0DA',
+                },
+            },
+        ],
+    };
+}
+
+
-- 
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/TemplateBackend.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/TemplateBackend.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/TemplateBackend.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/TemplateBackend.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/TemplateBackend.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 ab4bba8fac883fcc8e839b88f2b597d9147dcb9b Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Wed, 30 Oct 2024 04:15:38 -0400
Subject: carousel doc working well enough for demo

---
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   |  8 ++----
 .../DataVizBox/DocCreatorMenu/TemplateBackend.tsx  | 31 ++++++++++++----------
 2 files changed, 19 insertions(+), 20 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index 54f109f84..e7d6bb98e 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -411,11 +411,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
     testTemplate = async () => {
 
-        console.log(this.templateManager.templates.map(template => {
-            template.mainField.getAllSubfields;
-        })
-            
-            )
+        console.log(this.templateManager.templates)
 
         this.forceUpdate();
 
@@ -611,7 +607,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         templates.forEach(template => {
             console.log('title: ', template.mainField.getTitle());
             descriptions += `----------  NEW TEMPLATE TO INCLUDE: The title is: ${template.mainField.getTitle()}. Its fields are: `;
-            template.allFields.forEach(field => {
+            template.contentFields.forEach(field => {
                 descriptions += `{Field #${field.getID}: ${field.getDescription}} `;
             });
         });
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
index 53b3e7fb6..dbb332734 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
@@ -357,6 +357,8 @@ export class TemplateLayouts {
                 opts: {
                     borderColor: 'yellow',
                     borderWidth: '8',
+                    contentXCentering: "h-center",
+                    backgroundColor: 'transparent',
                 },
             },
             {
@@ -366,27 +368,28 @@ export class TemplateLayouts {
                 opts: {
                     borderColor: 'yellow',
                     borderWidth: '8',
+                    backgroundColor: 'transparent',
                 },
                 subfields: [
                     {
                         viewType: ViewType.STATIC,
-                        tl: [0, 0],
-                        br: [0, 0],
-                        types: [TemplateFieldType.VISUAL],
+                        tl: [-.3, -.6],
+                        br: [.3, .6],
+                        types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
                         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.',
+                        description: 'A medium to large field for content that will share central focus with other content in the carousel.',
                         opts: {
-                            borderColor: 'black',
+                            borderColor: 'yellow',
                             borderWidth: '8',
                         },
                     },
                     {
                         viewType: ViewType.STATIC,
-                        tl: [0, 0],
-                        br: [0, 0],
-                        types: [TemplateFieldType.VISUAL],
+                        tl: [-.3, -.6],
+                        br: [.3, .6],
+                        types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
                         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.',
+                        description: 'A medium to large field for content that will share central focus with other content in the carousel.',
                         opts: {
                             borderColor: 'black',
                             borderWidth: '8',
@@ -394,13 +397,13 @@ export class TemplateLayouts {
                     },
                     {
                         viewType: ViewType.STATIC,
-                        tl: [0, 0],
-                        br: [0, 0],
-                        types: [TemplateFieldType.VISUAL],
+                        tl: [-.3, -.6],
+                        br: [.3, .6],
+                        types: [TemplateFieldType.VISUAL, TemplateFieldType.TEXT],
                         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.',
+                        description: 'A medium to large field for content that will share central focus with other content in the carousel.',
                         opts: {
-                            borderColor: 'black',
+                            borderColor: 'yellow',
                             borderWidth: '8',
                         },
                     },
-- 
cgit v1.2.3-70-g09d2


From 963898540707546280a624bcea3c659c5fd242ae Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Wed, 6 Nov 2024 19:14:01 -0500
Subject: UI work

---
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.scss  |  10 +-
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   |  88 +++++--------
 .../DocCreatorMenu/FieldTypes/FieldUtils.tsx       |   6 +-
 .../DataVizBox/DocCreatorMenu/TemplateBackend.tsx  | 136 +++++++++++++++++++--
 4 files changed, 169 insertions(+), 71 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss
index d4cde7aa3..b849c044d 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss
@@ -292,6 +292,7 @@
     display: flex;
     flex-direction: column;
     justify-content: flex-start;
+    color: black;
     position: relative;
     width: 100%;
     height: 100%;
@@ -324,6 +325,7 @@
     height: 113px;
     margin-top: 10px;
     margin-left: 10px;
+    color: none;
     border: 1px solid rgb(163, 163, 163);
     border-radius: 5px;
     box-shadow: 5px 5px rgb(29, 29, 31);
@@ -423,6 +425,7 @@
     align-items: center;
     overflow-y: scroll;
     position: relative;
+    color: black;
     height: 125px;
     width: calc(100% - 10px);
     -ms-overflow-style: none; 
@@ -691,10 +694,11 @@
     display: flex;
     justify-content: center;
     align-items: center;
-    width: 100%;
-    height: 100%;
+    width: calc(100% - 50px);
+    height: calc(100% - 50px);
     position: relative;
-    padding: 0px;
+    border: 1px solid rgb(180, 180, 180);
+    padding: 10px;
     margin-left: 20px;
     margin-right: 20px;
 
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index d214a7954..f0f6cafcc 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -33,6 +33,7 @@ import { TemplateFieldSize, TemplateFieldType, TemplateLayouts } from './Templat
 import { TemplateManager } from './TemplateManager';
 import { Template } from './Template';
 import { Field, FieldContentType } from './FieldTypes/Field';
+import { TabDocView } from '../../../collections/TabDocView';
 
 export enum LayoutType {
     FREEFORM = 'Freeform',
@@ -115,8 +116,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         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};
+            //const wrapper: Doc = Docs.Create.FreeformDocument([doc], { _height: NumListCast(doc._height)[0], _width: NumListCast(doc._width)[0], title: ''});
+            return {doc: doc, template: template};
         });
     };
     @action setSuggestedTemplates = (templates: Template[]) => {
@@ -133,7 +134,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             case LayoutType.FREEFORM:
                 return Math.ceil(this.docsToRender.length / (this._layout.columns ?? 1)) ?? 0;
             case LayoutType.CAROUSEL3D:
-                return 1.6;
+                return 1.67;
             default:
                 return 1;
         }
@@ -144,7 +145,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
             case LayoutType.FREEFORM:
                 return this._layout.columns ?? 0;
             case LayoutType.CAROUSEL3D:
-                return 2.7;
+                return 3;
             default:
                 return 1;
         }
@@ -719,25 +720,18 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
     @action setExpandedView = (doc: Doc | undefined) => {
         if (doc) {
-            this._expandedPreview = Docs.Create.FreeformDocument([doc], { _height: NumListCast(doc._height)[0], _width: NumListCast(doc._width)[0], title: ''});
+            this._expandedPreview = doc; //Docs.Create.FreeformDocument([doc], { _height: NumListCast(doc._height)[0], _width: NumListCast(doc._width)[0], title: ''});
         } else {
             this._expandedPreview = undefined;
         }
     };
 
     get editingWindow(){
-        const doc = this._expandedPreview ?? new Doc();
-        const rendered = 
+        const rendered = !this._expandedPreview ? null :
             <div className="docCreatorMenu-expanded-template-preview">
-                <CollectionFreeFormView
-                    Document={this._expandedPreview ?? new Doc()}
-                    docViewPath={returnEmptyDocViewList}
-                    childLayoutTemplate={() => Cast(doc.childLayoutTemplate, Doc, null)}
+                <DocumentView
+                    Document={this._expandedPreview}
                     isContentActive={emptyFunction}
-                    isAnyChildContentActive={() => true}
-                    select={emptyFunction}
-                    isSelected={returnFalse}
-                    fieldKey={Doc.LayoutFieldKey(doc)}
                     addDocument={returnFalse}
                     moveDocument={returnFalse}
                     removeDocument={returnFalse}
@@ -748,15 +742,14 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                     whenChildContentsActiveChanged={emptyFunction}
                     focus={emptyFunction}
                     styleProvider={DefaultStyleProvider}
-                    addDocTab={this._props.addDocTab}
+                    addDocTab={DocumentViewInternal.addDocTabFunc}
                     // eslint-disable-next-line no-use-before-define
                     pinToPres={() => undefined}
                     childFilters={returnEmptyFilter}
                     childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    fitContentsToBox={returnTrue}
-                    xPadding={0}
-                    yPadding={0}
+                    fitContentsToBox={returnFalse}
+                    fitWidth={returnFalse}
                 />
             </div>
 
@@ -825,20 +818,14 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                                 <button className="option-button right" onPointerDown={e => this.setUpButtonClick(e, () => this._templateDocs.push(template.mainField.renderedDoc()))}>
                                                     <FontAwesomeIcon icon="plus" color="white" />
                                                 </button>
-                                                <CollectionFreeFormView
+                                                <DocumentView
                                                     Document={doc}
-                                                    docViewPath={returnEmptyDocViewList}
-                                                    childLayoutTemplate={() => Cast(doc.childLayoutTemplate, Doc, null)}
-                                                    isContentActive={returnFalse}
-                                                    isAnyChildContentActive={() => true}
-                                                    select={emptyFunction}
-                                                    isSelected={returnFalse}
-                                                    fieldKey={Doc.LayoutFieldKey(doc)}
+                                                    isContentActive={emptyFunction}
                                                     addDocument={returnFalse}
                                                     moveDocument={returnFalse}
                                                     removeDocument={returnFalse}
-                                                    PanelWidth={() => 100}
-                                                    PanelHeight={() => 100}
+                                                    PanelWidth={() => 111}
+                                                    PanelHeight={() => 111}
                                                     ScreenToLocalTransform={() => new Transform(-this._pageX - 5,-this._pageY - 35, 1)}
                                                     renderDepth={1}
                                                     whenChildContentsActiveChanged={emptyFunction}
@@ -850,9 +837,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                                     childFilters={returnEmptyFilter}
                                                     childFiltersByRanges={returnEmptyFilter}
                                                     searchFilterDocs={returnEmptyDoclist}
-                                                    fitContentsToBox={returnTrue}
-                                                    xPadding={0}
-                                                    yPadding={0}
+                                                    fitContentsToBox={returnFalse}
+                                                    fitWidth={returnFalse}
+                                                    hideDecorations={true}
                                                     />
                                             </div>
                                         ))
@@ -946,7 +933,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         setTimeout(() => {
             if (!this._renderedDocCollection || !this._fullyRenderedDocs) return;
             this.applyLayout(this._renderedDocCollection, this._fullyRenderedDocs);
-            this.updatePreview(this._renderedDocCollection);
         });
     };
     @action updateYMargin = (input: string) => {
@@ -954,7 +940,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         setTimeout(() => {
             if (!this._renderedDocCollection || !this._fullyRenderedDocs) return;
             this.applyLayout(this._renderedDocCollection, this._fullyRenderedDocs);
-            this.updatePreview(this._renderedDocCollection);
         });
     };
     @action updateColumns = (input: string) => {
@@ -1052,11 +1037,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         }
     }
 
-    updatePreview = (collection: Doc) => {
-        const wrapper: Doc = Docs.Create.FreeformDocument([collection], { _height: NumListCast(collection._height)[0], _width: NumListCast(collection._width)[0], title: ''});
-        this._renderedDocCollectionPreview = wrapper;
-    }
-
     /**
      * Updates the preview that shows how all docs will be rendered in the chosen collection type.
     @type the type of collection the docs should render to (ie. freeform, carousel, card)
@@ -1096,12 +1076,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
         this.applyLayout(collection, this._fullyRenderedDocs);
 
-        const wrapper: Doc = Docs.Create.FreeformDocument([collection], { _height: 200, _width: 200, title: ''});
-
-        const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
-        mainCollection.addDocument(collection);
-
-        this._renderedDocCollectionPreview = wrapper;
         this._renderedDocCollection = collection;
     }
 
@@ -1109,22 +1083,16 @@ 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 (
+        return !this._renderedDocCollection? null : (
             <div className="docCreatorMenu-layout-preview-window-wrapper" id={String(id) ?? undefined}>
-                <CollectionFreeFormView
-                    Document={this._renderedDocCollectionPreview ?? new Doc()}
-                    docViewPath={returnEmptyDocViewList}
-                    childLayoutTemplate={() => Cast(doc.childLayoutTemplate, Doc, null)}
-                    isContentActive={returnFalse}
-                    isAnyChildContentActive={() => true}
-                    select={emptyFunction}
-                    isSelected={returnFalse}
-                    fieldKey={Doc.LayoutFieldKey(doc)}
+                <DocumentView
+                    Document={this._renderedDocCollection}
+                    isContentActive={emptyFunction}
                     addDocument={returnFalse}
                     moveDocument={returnFalse}
                     removeDocument={returnFalse}
-                    PanelWidth={() => this._menuDimensions.width - 10}
-                    PanelHeight={() => this._menuDimensions.height - 60}
+                    PanelWidth={() => this._menuDimensions.width - 75}
+                    PanelHeight={() => this._menuDimensions.height - 105}
                     ScreenToLocalTransform={() => new Transform(-this._pageX - 5,-this._pageY - 35, 1)}
                     renderDepth={5}
                     whenChildContentsActiveChanged={emptyFunction}
@@ -1136,9 +1104,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                     childFilters={returnEmptyFilter}
                     childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    fitContentsToBox={returnTrue}
-                    xPadding={0}
-                    yPadding={0}
+                    fitContentsToBox={returnFalse}
+                    fitWidth={returnFalse}
+                    hideDecorations={true}
                 />
             </div>
         );
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
index 70596632a..cfe4d2632 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
@@ -1,4 +1,5 @@
 import { Doc } from "../../../../../../fields/Doc";
+import { ScriptField } from "../../../../../../fields/ScriptField";
 import { Col } from "../DocCreatorMenu";
 import { TemplateFieldSize, TemplateFieldType, TemplateLayouts } from "../TemplateBackend";
 import { FieldDimensions, FieldSettings } from "./Field";
@@ -24,12 +25,15 @@ 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 = oldDoc ? oldDoc.layout_borderRounding : `${opts.cornerRounding ?? 0}px`;
+        doc._layout_borderRounding = ScriptField.MakeFunction(`${(opts.cornerRounding ?? 0) * parentDimensions.width}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;
+        doc.nativeWidth = parentDimensions.width;
+        doc.nativeHeight = parentDimensions.height;
+        doc._layout_nativeDimEditable = true;
     };
 
     public static calculateFontSize = (contWidth: number, contHeight: number, text: string, uppercase: boolean): number => {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
index dbb332734..20080e7b1 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
@@ -338,6 +338,76 @@ export class TemplateLayouts {
         ],
     };
 
+    public static FourField005: FieldSettings = {
+        title: 'fourfield04',
+        viewType: ViewType.FREEFORM,
+        tl: [0,0],
+        br: [400,700],
+        opts: {
+            backgroundColor: '#6CCAF0',
+            borderColor: '#1088C3',
+            borderWidth: '10',
+        },
+        subfields: [
+            {
+                viewType: ViewType.STATIC,
+                tl: [-0.8, -.9],
+                br: [-.05, .15],
+                types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
+                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',
+                    contentXCentering: "h-center",
+                    backgroundColor: 'transparent',
+                },
+            },
+            {
+                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',
+                    contentXCentering: "h-center",
+                    backgroundColor: 'transparent',
+                },
+            },
+            {
+                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',
+                    contentXCentering: "h-center",
+                    backgroundColor: 'transparent',
+                },
+            },
+            {
+                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',
+                    contentXCentering: "h-center",
+                    backgroundColor: 'transparent',
+                },
+            },
+        ]
+    }
+
     public static FourFieldCarousel: FieldSettings = {
         title: 'title_fourfieldcarousel',
         viewType: ViewType.FREEFORM,
@@ -422,17 +492,29 @@ export class TemplateLayouts {
         },
         subfields: [
             {
-                viewType: ViewType.STATIC,
+                viewType: ViewType.FREEFORM,
                 tl: [-0.66, -0.747],
                 br: [0.66, 0.247],
-                types: [TemplateFieldType.VISUAL],
-                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
                 description: 'A medium to large field for visual content that is the central focus.',
                 opts: {
                     borderColor: 'yellow',
                     borderWidth: '8',
+                    backgroundColor: '#DDD3A9',
                     rotation: 45,
                 },
+                subfields: [
+                    {
+                    viewType: ViewType.STATIC,
+                    tl: [-1.25, -1.25],
+                    br: [1.25, 1.25],
+                    types: [TemplateFieldType.VISUAL],
+                    sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
+                    description: 'A medium to large field for visual content that is the central focus.',
+                    opts: {
+                        rotation: -45,
+                    },
+                },
+            ]
             },
             {
                 viewType: ViewType.STATIC,
@@ -459,40 +541,80 @@ export class TemplateLayouts {
                 },
             },
             {
-                viewType: ViewType.DEC,
+                viewType: ViewType.FREEFORM,
                 tl: [0.2, -1.32],
                 br: [1.8, -0.66],
                 opts: {
                     backgroundColor: '#CEB155',
                     rotation: 45,
                 },
+                subfields: [
+                    {
+                        viewType: ViewType.DEC,
+                        tl: [-1, -.7],
+                        br: [1, -.625],
+                        opts: {
+                            backgroundColor: 'yellow',
+                        },
+                    },
+                ]
             },
             {
-                viewType: ViewType.DEC,
+                viewType: ViewType.FREEFORM,
                 tl: [-1.8, -1.32],
                 br: [-0.2, -0.66],
                 opts: {
                     backgroundColor: '#CEB155',
                     rotation: 135,
                 },
+                subfields: [
+                    {
+                        viewType: ViewType.DEC,
+                        tl: [-1, -.7],
+                        br: [1, -.625],
+                        opts: {
+                            backgroundColor: 'yellow',
+                        },
+                    },
+                ]
             },
             {
-                viewType: ViewType.DEC,
+                viewType: ViewType.FREEFORM,
                 tl: [0.33, 0.75],
                 br: [1.66, 1.25],
                 opts: {
                     backgroundColor: '#CEB155',
                     rotation: 135,
                 },
+                subfields: [
+                    {
+                        viewType: ViewType.DEC,
+                        tl: [-1, -.7],
+                        br: [1, -.625],
+                        opts: {
+                            backgroundColor: 'yellow',
+                        },
+                    },
+                ]
             },
             {
-                viewType: ViewType.DEC,
+                viewType: ViewType.FREEFORM,
                 tl: [-1.66, 0.75],
                 br: [-0.33, 1.25],
                 opts: {
                     backgroundColor: '#CEB155',
                     rotation: 45,
                 },
+                subfields: [
+                    {
+                        viewType: ViewType.DEC,
+                        tl: [-1, -.7],
+                        br: [1, -.625],
+                        opts: {
+                            backgroundColor: 'yellow',
+                        },
+                    },
+                ]
             },
         ],
     };
-- 
cgit v1.2.3-70-g09d2


From 9f0ae26a91e51b4ba927d9db8d717b8435ecde1a Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Thu, 7 Nov 2024 00:44:37 -0500
Subject: c

---
 .../views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx      | 4 ++--
 .../nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx     | 2 +-
 .../views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx     | 8 ++++----
 3 files changed, 7 insertions(+), 7 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index 2e96465fc..a08686a36 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -112,7 +112,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         this._userTemplates.push({template: template, doc: template.mainField.renderedDoc()});
     };
     @action removeUserTemplate = (template: Template) => {
-        this._userTemplates = this._userTemplates.filter(info => info.template === template);
+        this._userTemplates = this._userTemplates.filter(info => info.template !== template);
     }
     @action updateTemplatePreview = (template: Template) => {
         template.renderUpdates();
@@ -897,7 +897,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                                                 removeDocument={returnFalse}
                                                 PanelWidth={() => this._selectedTemplate === template ? 104 : 111}
                                                 PanelHeight={() => this._selectedTemplate === template ? 104 : 111}
-                                                ScreenToLocalTransform={() => new Transform(-this._pageX - 5,-this._pageY - 35, 1)}
+                                                ScreenToLocalTransform={() => new Transform(-this._pageX - 5, -this._pageY - 35, 1)}
                                                 renderDepth={1}
                                                 whenChildContentsActiveChanged={emptyFunction}
                                                 focus={emptyFunction}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
index cfe4d2632..de542b40b 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 = ScriptField.MakeFunction(`${(opts.cornerRounding ?? 0) * parentDimensions.width}px`);
+        doc._layout_borderRounding = !opts.cornerRounding ? '0px' : ScriptField.MakeScript(`${opts.cornerRounding * parentDimensions.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/TemplateBackend.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
index 20080e7b1..d434e98b1 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
@@ -28,8 +28,8 @@ export class TemplateLayouts {
         opts: {
             backgroundColor: '#C0B887',
             cornerRounding: 20,
-            borderColor: '#6B461F',
-            borderWidth: '12',
+            //borderColor: '#6B461F',
+            //borderWidth: '12',
         },
         subfields: [
             {
@@ -268,8 +268,8 @@ export class TemplateLayouts {
         br: [414,583],
         opts: {
             backgroundColor: '#6CCAF0',
-            borderColor: '#1088C3',
-            borderWidth: '10',
+            //borderColor: '#1088C3',
+            //borderWidth: '10',
         },
         subfields: [
             {
-- 
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/TemplateBackend.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/TemplateBackend.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 1f3fa3b79753ae6ca72af5fc23dfe5dfa3fc09bb Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Fri, 8 Nov 2024 03:12:49 -0500
Subject: new template added

---
 src/client/apis/gpt/GPT.ts                         |   8 +-
 .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx   |  18 ++-
 .../DocCreatorMenu/FieldTypes/FieldUtils.tsx       |   2 +-
 .../DataVizBox/DocCreatorMenu/TemplateBackend.tsx  | 127 ++++++++++++++++-----
 4 files changed, 116 insertions(+), 39 deletions(-)

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

diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts
index 80cbc86b3..d64b38655 100644
--- a/src/client/apis/gpt/GPT.ts
+++ b/src/client/apis/gpt/GPT.ts
@@ -72,24 +72,24 @@ const callTypeMap: { [type: string]: GPTCallOpts } = {
         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',
+        model: 'gpt-4-turbo',
         maxTokens: 512,
         temp: 0.5,
         prompt: 'Your job is to provide brief descriptions for columns in a dataset based on example rows. Your descriptions should be geared towards how each column’s data might fit together into a visual template. Would they make good titles, main focuses, captions, descriptions, etc. Pay special attention to connections between columns, i.e. is there one column that specifically seems to describe/be related to another more than the rest? You should provide your analysis in JSON format like so: {“col1”:”description”, “col2”:”description”, …}. DO NOT INCLUDE ANY OTHER TEXT, ONLY THE JSON.',
     },
     vizsum2: {
-        model: 'gpt-4o-mini',
+        model: 'gpt-4-turbo',
         maxTokens: 512,
         temp: 0.5,
         prompt: 'Your job is to provide structured information on columns in a dataset based on example rows. You will categorize each column in two ways: by type and size. The size categories are as follows: tiny (one or two words), small (a sentence/multiple words), medium (a few sentences), large (a longer paragraph), and huge (a very long or multiple paragraphs). The type categories are as follows: visual (links/file paths to images, pdfs, maps, or any other visual media type), and text (plain text that isn’t a link/file path). Visual media should be assumed to have size “medium” “large” or “huge”. You will give your responses in JSON format, like so: {“title (of column)”:{“type”:”text”, “size”:”small”}, “title (of column)”:{“type”:”visual”, “size”:”medium”}, …}. DO NOT INCLUDE ANY OTHER TEXT, ONLY THE JSON.',
     },
     fill: {
-        model: 'gpt-4-turbo',
+        model: 'gpt-4o',
         maxTokens: 512,
         temp: 0.5,
         prompt: 'Your job is to generate content for fields based on a user prompt and background context given to you. You will be given the content of the other fields present in the format: ---- Field # (field title): content ---- Field # (field title): content ----- (etc.) You will be given info on the columns to generate for in the format ---- title: , prompt: , word limit: , assigned field: ----. For each column, based on the prompt, word limit, and the context of existing fields, you should generate a short response in the following JSON format: {“___”(where ___ is the title from the column description with no additions): {“number”:”#” (where # is the assigned field of the column), “content”:”response” (where response is your response to the prompt in the column info)}}. Here’s another example of the format with only one column: {“position”: {“number”:”2”, “content”:”*your response goes here*”}}. ONLY INCLUDE THE JSON TEXT WITH NO OTHER ADDED TEXT. YOUR RESPONSE MUST BE VALID JSON. The word limit for each column applies only to that column’s response. Do not include speculation or information that you can’t glean from your factual knowledge or the content of the other fields (no description of images you can’t see, for example). You should include one object per column you are provided info on.',
     },
-    completeprompt: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'Your prompt is as follows:' },
+    completeprompt: { model: 'gpt-4o', maxTokens: 512, temp: 0.5, prompt: 'Your prompt is as follows:' },
     draw: {
         model: 'gpt-4o',
         maxTokens: 1024,
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index 257c7fc00..1889344fd 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -108,9 +108,13 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
     @action setDataViz = (dataViz: DataVizBox) => {
         this._dataViz = dataViz;
+        this._selectedTemplate = undefined;
+        this._renderedDocCollection = undefined;
+        this._renderedDocCollectionPreview = undefined;
+        this._fullyRenderedDocs = [];
     };
     @action addUserTemplate = (template: Template) => {
-        this._userTemplates.push({template: template, doc: template.getRenderedDoc()});
+        this._userTemplates.push({template: template.cloneBase(), doc: template.getRenderedDoc()});
     };
     @action removeUserTemplate = (template: Template) => {
         this._userTemplates = this._userTemplates.filter(info => info.template !== template);
@@ -394,6 +398,13 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
 
         //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 {
@@ -691,6 +702,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;
@@ -798,7 +810,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                 />
             </div>
 
-
         return (
             <div className="docCreatorMenu-expanded-template-preview">
                 <div className="top-panel"/>
@@ -811,11 +822,10 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
                         <FontAwesomeIcon icon="minimize" />
                     </button>
                     <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" />
+                        <FontAwesomeIcon icon="arrows-rotate" color="white" />
                     </button>
                 </div>
             </div>
-
         );
     }
 
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
index bb8489c21..4a8bfa03f 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
@@ -51,7 +51,7 @@ export class FieldUtils {
 
             while (wordIndex < words.length) {
                 const word = words[wordIndex];
-                const wordWidth = word.length * currFontSize * 0.5;
+                const wordWidth = word.length * currFontSize * 0.7;
 
                 if (currentRowWidth + wordWidth <= contWidth) {
                     currentRowWidth += wordWidth;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
index ee7f19907..648f9e034 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
@@ -66,7 +66,7 @@ export class TemplateLayouts {
                 br: [0.8, 0.3],
                 types: [TemplateFieldType.TEXT],
                 sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
-                description: 'A caption for field #2, very short to short text that contextualizes the content of field #2',
+                description: 'A caption for field #2, very short text.',
                 opts: {
                     backgroundColor: 'transparent',
                     contentXCentering: 'h-center',
@@ -341,70 +341,137 @@ export class TemplateLayouts {
     };
 
     public static FourField005: FieldSettings = {
-        title: 'fourfield04',
+        title: 'fourfield05',
         viewType: ViewType.FREEFORM,
         tl: [0,0],
-        br: [400,700],
+        br: [400,550],
         opts: {
-            backgroundColor: '#6CCAF0',
-            borderColor: '#1088C3',
-            borderWidth: '10',
+            backgroundColor: '#95A575',
         },
         subfields: [
             {
                 viewType: ViewType.STATIC,
-                tl: [-0.8, -.9],
-                br: [-.05, .15],
-                types: [TemplateFieldType.TEXT, TemplateFieldType.VISUAL],
+                tl: [-0.9, -.925],
+                br: [-.075, -.775],
+                types: [TemplateFieldType.TEXT],
                 sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
-                description: 'A small text field for a title that categorizes the rest of the content.',
+                description: 'A small text field for a title or word(s) that categorize the rest of the content.',
                 opts: {
-                    borderColor: 'yellow',
+                    borderColor: '#3B4A2C',
                     borderWidth: '8',
                     contentXCentering: "h-center",
-                    backgroundColor: 'transparent',
+                    backgroundColor: '#B8DC90',
                 },
             },
             {
                 viewType: ViewType.STATIC,
-                tl: [-0.8, -.9],
-                br: [0.8, -.5],
+                tl: [.075, -.925],
+                br: [.9, -.775],
                 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',
+                    borderColor: '#3B4A2C',
                     borderWidth: '8',
                     contentXCentering: "h-center",
-                    backgroundColor: 'transparent',
+                    backgroundColor: '#B8DC90',
+                },
+            },
+            {
+                viewType: ViewType.DEC,
+                tl: [-.82, -.4],
+                br: [-.5, -.2],
+                opts: {
+                    backgroundColor: '#94B058',
+                    borderColor: '#3B4A2C',
+                    borderWidth: '8',
                 },
             },
             {
                 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.',
+                tl: [-0.66, -.65],
+                br: [0.66, .25],
+                types: [TemplateFieldType.VISUAL],
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
+                description: 'A medium to large field in the center of the template, for the main visual content.',
                 opts: {
-                    borderColor: 'yellow',
+                    borderColor: '#3B4A2C',
                     borderWidth: '8',
-                    contentXCentering: "h-center",
-                    backgroundColor: 'transparent',
+                    backgroundColor: '#B8DC90',
                 },
             },
             {
                 viewType: ViewType.STATIC,
-                tl: [-0.8, -.9],
-                br: [0.8, -.5],
+                tl: [-.875, .425],
+                br: [0.875, .925],
                 types: [TemplateFieldType.TEXT],
-                sizes: [TemplateFieldSize.TINY, TemplateFieldSize.SMALL],
-                description: 'A small text field for a title that categorizes the rest of the content.',
+                sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE],
+                description: 'A medium to large field at the bottom of the template, for the main text content.',
                 opts: {
-                    borderColor: 'yellow',
+                    borderColor: '#3B4A2C',
                     borderWidth: '8',
                     contentXCentering: "h-center",
-                    backgroundColor: 'transparent',
+                    backgroundColor: '#B8DC90',
+                },
+            },
+            {
+                viewType: ViewType.DEC,
+                tl: [-1.1, -.62],
+                br: [-.9, -.5],
+                opts: {
+                    backgroundColor: '#7A9D31',
+                    borderColor: '#3B4A2C',
+                    borderWidth: '8',
+                },
+            },
+            {
+                viewType: ViewType.DEC,
+                tl: [-1.1, 0],
+                br: [-.9, .15],
+                opts: {
+                    backgroundColor: '#94B058',
+                    borderColor: '#3B4A2C',
+                    borderWidth: '8',
+                },
+            },
+            {
+                viewType: ViewType.DEC,
+                tl: [-.93, -.265],
+                br: [-.715, -.125],
+                opts: {
+                    backgroundColor: '#728745',
+                    borderColor: '#3B4A2C',
+                    borderWidth: '8',
+                },
+            },
+            {
+                viewType: ViewType.DEC,
+                tl: [.7, -.45],
+                br: [.85, -.3],
+                opts: {
+                    backgroundColor: '#7A9D31',
+                    borderColor: '#3B4A2C',
+                    borderWidth: '8',
+                },
+            },
+            {
+                viewType: ViewType.DEC,
+                tl: [.8, .03],
+                br: [1.2, .33],
+                opts: {
+                    backgroundColor: '#728745',
+                    borderColor: '#3B4A2C',
+                    borderWidth: '8',
+                },
+            },
+            {
+                viewType: ViewType.DEC,
+                tl: [.875, -.13],
+                br: [1.2, .12],
+                opts: {
+                    backgroundColor: '#94B058',
+                    borderColor: '#3B4A2C',
+                    borderWidth: '8',
                 },
             },
         ]
-- 
cgit v1.2.3-70-g09d2


From d2eef0d1341c475a8cb753efeb31b270714e76ec Mon Sep 17 00:00:00 2001
From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com>
Date: Fri, 8 Nov 2024 19:32:54 -0500
Subject: c

---
 src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx | 3 +++
 .../views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx | 2 +-
 .../views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx       | 6 +++---
 3 files changed, 7 insertions(+), 4 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index 1889344fd..2324006f7 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -112,6 +112,9 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
         this._renderedDocCollection = undefined;
         this._renderedDocCollectionPreview = undefined;
         this._fullyRenderedDocs = [];
+        this._suggestedTemplatePreviews = [];
+        this._suggestedTemplates = [];
+        this._userCreatedFields = [];
     };
     @action addUserTemplate = (template: Template) => {
         this._userTemplates.push({template: template.cloneBase(), doc: template.getRenderedDoc()});
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
index 4a8bfa03f..3886774d2 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes/FieldUtils.tsx
@@ -1,5 +1,5 @@
 import { Doc } from "../../../../../../fields/Doc";
-import { ScriptField } from "../../../../../../fields/ScriptField";
+import { ComputedField, ScriptField } from "../../../../../../fields/ScriptField";
 import { Col } from "../DocCreatorMenu";
 import { TemplateFieldSize, TemplateFieldType, TemplateLayouts } from "../TemplateBackend";
 import { FieldDimensions, FieldSettings } from "./Field";
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
index 648f9e034..99edce34e 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.tsx
@@ -27,7 +27,7 @@ export class TemplateLayouts {
         viewType: ViewType.FREEFORM,
         opts: {
             backgroundColor: '#C0B887',
-            cornerRounding: 20,
+            cornerRounding: .05,
             //borderColor: '#6B461F',
             //borderWidth: '12',
         },
@@ -54,7 +54,7 @@ export class TemplateLayouts {
                 sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
                 description: 'The main focus of the template; could be an image, long text, etc.',
                 opts: {
-                    cornerRounding: 20,
+                    cornerRounding: .05,
                     borderColor: '#8F5B25',
                     borderWidth: '6',
                     backgroundColor: '#CECAB9',
@@ -81,7 +81,7 @@ export class TemplateLayouts {
                 sizes: [TemplateFieldSize.MEDIUM, TemplateFieldSize.LARGE, TemplateFieldSize.HUGE],
                 description: 'A medium-sized field for medium/long text.',
                 opts: {
-                    cornerRounding: 15,
+                    cornerRounding: .05,
                     borderColor: '#8F5B25',
                     borderWidth: '6',
                     backgroundColor: '#CECAB9',
-- 
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/TemplateBackend.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

