diff options
Diffstat (limited to 'src')
8 files changed, 113 insertions, 58 deletions
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts index 030c6db95..760940127 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts @@ -1,6 +1,6 @@ import { action, makeAutoObservable } from 'mobx'; import { Col } from '../DocCreatorMenu'; -import { FieldSettings } from '../TemplateFieldTypes/TemplateField'; +import { FieldSettings, TemplateField } from '../TemplateFieldTypes/TemplateField'; import { Template } from '../Template'; import { Doc, NumListCast } from '../../../../../../fields/Doc'; import { DataVizBox } from '../../DataVizBox'; @@ -11,7 +11,7 @@ export type Conditional = { field: string; operator: '=' | '>' | '<'; condition: string; - target: 'self' | 'template'; + target: string; attribute: string; value: string; } @@ -53,13 +53,21 @@ export class TemplateManager { } } + addDataField = (title: string) => { + this.templates.forEach(template => template.addDataField(title)); + } + + removeDataField = (title: string) => { + this.templates.forEach(template => template.removeDataField(title)); + } + createDocsFromTemplate = action((dv: DataVizBox, template: Template, cols: Col[], debug: boolean = false) => { - const fields = Array.from(Object.keys(dv.records[0])); + const csvFields = Array.from(Object.keys(dv.records[0])); const processContent = async (content: { [title: string]: string }) => { const templateCopy = template.clone(); - fields + csvFields .filter(title => title) .forEach(title => { const field = templateCopy.getFieldByTitle(title); @@ -71,7 +79,7 @@ export class TemplateManager { const promises = cols .filter(field => field.AIGenerated) .map(field => { - const templateField = templateCopy.getFieldByTitle(field.title); + const templateField: TemplateField = templateCopy.getFieldByTitle(field.title) as TemplateField; if (templateField !== undefined) { return gptFunc(field.type)(templateCopy, field, templateField.getID); } @@ -92,7 +100,7 @@ export class TemplateManager { const rowContents = debug ? [{}, {}, {}, {}] : NumListCast(dv.layoutDoc.dataViz_selectedRows).map(row => - fields.reduce( + csvFields.reduce( (values, col) => { values[col] = dv.records[row][col]; return values; diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss index 8ac718fb7..2f7b68c4d 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss @@ -1141,6 +1141,7 @@ .switch { gap: 0.75rem; + margin-bottom: 0px; } .switch .slider { @@ -1170,7 +1171,7 @@ } .switch input:checked + .slider { - background: #9fe29d; + background: #78c2f1; } .switch input:checked + .slider::before { @@ -1182,6 +1183,8 @@ font-size: 100%; color: whitesmoke; text-align: center; + margin-bottom: 0px; + font-weight: 500; } diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx index 2565a9332..873bfa734 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx @@ -30,7 +30,7 @@ import './DocCreatorMenu.scss'; import { TemplateField, ViewType } from './TemplateFieldTypes/TemplateField'; import { Template } from './Template'; import { TemplateFieldSize, TemplateFieldType, TemplateLayouts } from './TemplateBackend'; -import { TemplateManager } from './Backend/TemplateManager'; +import { Conditional, TemplateManager } from './Backend/TemplateManager'; import { DrawingFillHandler } from '../../../smartdraw/DrawingFillHandler'; import { CgPathIntersect } from 'react-icons/cg'; import { StaticContentField } from './TemplateFieldTypes/StaticContentField'; @@ -71,15 +71,6 @@ export type Col = { AIGenerated?: boolean; }; -export type Conditional = { - field: string; - operator: '=' | '>' | '<'; - condition: string; - target: 'self' | 'template'; - attribute: string; - value: string; -} - interface DocCreateMenuProps { addDocTab: (doc: Doc | Doc[], where: OpenWhere) => boolean; } @@ -364,15 +355,6 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> this._pageY = y + translation.y; }; - async getIcon(doc: Doc) { - const docView = DocumentView.getDocumentView(doc); - if (docView) { - docView.ComponentView?.updateIcon?.(); - return new Promise<ImageField | undefined>(res => setTimeout(() => res(ImageCast(docView.Document.icon)), 500)); - } - return undefined; - } - @action updateRenderedPreviewCollection = async (template: Template) => { this._docsRendering = true; this._fullyRenderedDocs = this._dataViz ? ((await this.templateManager.createDocsFromTemplate(this._dataViz, template, this.fieldsInfos, this.DEBUG_MODE)).filter(doc => doc).map(doc => doc!) ?? []) as unknown as Doc[] : []; @@ -469,11 +451,18 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> }; @action setColType = (column: Col, type: TemplateFieldType) => { + if (type === TemplateFieldType.DATA) { + this.templateManager.addDataField(column.title); + } else if (column.type === TemplateFieldType.DATA) { + this.templateManager.removeDataField(column.title); + } + if (this.selectedFields.includes(column.title)) { this._dataViz?.setColumnType(column.title, type); } else { column.type = type; } + this.forceUpdate(); }; @@ -576,9 +565,11 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> } else { this._dataViz?.updateColDefaults(); - templates.push(...this.templateManager.getValidTemplates(this.fieldsInfos)); + const contentFields = this.fieldsInfos.filter(field => field.type !== TemplateFieldType.DATA); + + templates.push(...this.templateManager.getValidTemplates(contentFields)); - const assignments = await this.assignColsToFields(templates, this.fieldsInfos); + const assignments = await this.assignColsToFields(templates, contentFields); const renderedTemplatePromises = assignments.map(([template, assgns]) => TemplateMenuAIUtils.applyGPTContentToTemplate(template, assgns)); @@ -918,6 +909,8 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> } get dashboardContents() { + const contentFieldTitles = this.fieldsInfos.filter(field => field.type !== TemplateFieldType.DATA).map(field => field.title).concat('template'); + const conditionForm = (title: string, parameters?: Conditional, empty: boolean = false) => { const params: Conditional = parameters ?? this._currEditingConditional; @@ -942,8 +935,9 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> <div className='form-row-plain-text'>then</div> <div className="operator-options-dropdown"> <span className="operator-dropdown-current">{params.target ?? 'self'}</span> - <div className='operator-dropdown-option' onPointerDown={() => {params.target = 'self'}}>{'own'}</div> - <div className='operator-dropdown-option' onPointerDown={() => {params.target = 'template'}}>{`template's`}</div> + {contentFieldTitles.map(fieldTitle => + <div className='operator-dropdown-option' onPointerDown={() => {params.target = fieldTitle}}>{fieldTitle === title ? 'own' : fieldTitle}</div> + )} </div> <textarea className="form-row-textarea" @@ -990,38 +984,49 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> <div className="opt-box"> <div className="top-bar"> Type </div> <div className="content"> - <span className="type-display">{field.type === TemplateFieldType.TEXT ? 'Text Field' : field.type === TemplateFieldType.VISUAL ? 'File Field' : ''}</span> + <span className="type-display">{ + field.type === TemplateFieldType.TEXT ? 'Text Field' + : field.type === TemplateFieldType.VISUAL ? 'File Field' + : field.type === TemplateFieldType.DATA ? 'Data Field' + : '' + }</span> <div className="bubbles"> <input className="bubble" type="radio" name="type" onClick={() => this.setColType(field, TemplateFieldType.TEXT)} /> <div className="text">Text</div> <input className="bubble" type="radio" name="type" onClick={() => this.setColType(field, TemplateFieldType.VISUAL)} /> <div className="text">File</div> + <input className="bubble" type="radio" name="type" onClick={() => this.setColType(field, TemplateFieldType.DATA)} /> + <div className="text">Data</div> </div> </div> </div> </div> - <div className="sizes-box"> - <div className="top-bar"> Valid Sizes </div> - <div className="content"> - <div className="bubbles"> - {Object.values(TemplateFieldSize).map(size => ( - <div key={field + size}> - <input className="bubble" type="checkbox" name="type" checked={field.sizes.includes(size)} onChange={e => this.modifyColSizes(field, size, e.target.checked)} /> - <div className="text">{size}</div> + { field.type === TemplateFieldType.DATA ? null : + (<> + <div className="sizes-box"> + <div className="top-bar"> Valid Sizes </div> + <div className="content"> + <div className="bubbles"> + {Object.values(TemplateFieldSize).map(size => ( + <div key={field + size}> + <input className="bubble" type="checkbox" name="type" checked={field.sizes.includes(size)} onChange={e => this.modifyColSizes(field, size, e.target.checked)} /> + <div className="text">{size}</div> + </div> + ))} </div> - ))} + </div> </div> - </div> - </div> - <div className="desc-box"> - <div className="top-bar"> Prompt </div> - <textarea - className="content" - onChange={e => this.setColDesc(field, e.target.value)} - defaultValue={field.desc === this._dataViz?.GPTSummary?.get(field.title)?.desc ? '' : field.desc} - placeholder={this._dataViz?.GPTSummary?.get(field.title)?.desc ?? 'Add a description/prompt to help with template generation.'} - /> - </div> + <div className="desc-box"> + <div className="top-bar"> Prompt </div> + <textarea + className="content" + onChange={e => this.setColDesc(field, e.target.value)} + defaultValue={field.desc === this._dataViz?.GPTSummary?.get(field.title)?.desc ? '' : field.desc} + placeholder={this._dataViz?.GPTSummary?.get(field.title)?.desc ?? 'Add a description/prompt to help with template generation.'} + /> + </div> + </>) + } <div className="conditionals-section"> <span className="conditionals-title">Conditional Logic</span> {conditionForm(field.title, this._currEditingConditional, true)} diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx index 4ff509d73..e1d8ea8a5 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx @@ -99,13 +99,13 @@ export class FireflyVariationsTab extends ObservableReactComponent<FireflyVariat <DocCreatorMenuButton icon={'arrows-rotate'} styles={'border'} function={this.generateVariations}/> </div> <nav className="options‑menu"> - <div className="menu‑item switch"> + <label className="menu‑item switch"> <input type="checkbox" checked={this.fireflyOptions.useStyleRef} onChange={(e) => runInAction(() => this.fireflyOptions.useStyleRef = e.target.checked)} /> <span className="slider round"></span> <span className="firefly-option-label">Use template as style guide</span> - </div> + </label> <div className="menu‑item"> <span className="firefly-option-label">Variations</span> <input type="range" id="variations" diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts index fae0d06e4..1889e4984 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts @@ -6,10 +6,13 @@ import { FieldSettings, TemplateField, ViewType } from './TemplateFieldTypes/Tem import { Conditional } from './Backend/TemplateManager'; import { ImageField } from '../../../../../fields/URLField'; import { Doc } from '../../../../../fields/Doc'; +import { TemplateDataField } from './TemplateFieldTypes/DataField'; export class Template { _mainField: DynamicField; + private dataFields: TemplateDataField[] = []; + /** * A Template can be created from a description of its fields (FieldSettings) or from a DynamicField * @param definition definition of template as settings or DynamicField @@ -55,13 +58,17 @@ export class Template { //dispose each subfields disposers, etc. }; - clone = (withContent: boolean = false) => new Template(this._mainField?.makeClone(undefined, withContent) ?? TemplateLayouts.BasicSettings); + clone = (withContent: boolean = false) => { + const clone = new Template(this._mainField?.makeClone(undefined, withContent) ?? TemplateLayouts.BasicSettings); + this.dataFields.forEach(field => clone.addDataField(field.title)); + return clone; + }; getRenderedDoc = () => this.doc; getFieldByID = (id: number): TemplateField => this.allFields.filter(field => field.getID === id)[0]; - getFieldByTitle = (title: string) => this.allFields.filter(field => field.getTitle() === title)[0]; + getFieldByTitle = (title: string) => [...this.allFields, ...this.dataFields].filter(field => field.getTitle() === title)[0]; setupMainField = (templateInfo: FieldSettings) => TemplateField.CreateField(templateInfo, 1, undefined) as DynamicField; @@ -77,12 +84,20 @@ export class Template { field.setTitle(col.title); } + addDataField = (title: string, content?: string) => { + this.dataFields.push(new TemplateDataField(title, content)); + } + + removeDataField = (title: string) => { + this.dataFields = this.dataFields.filter(field => !(field.title === title)); + } + isValidTemplate = (cols: Col[]) => { const maxMatches = this.maxMatches(this.getMatches(cols)); return maxMatches === this.contentFields.length && this.title !== 'template_framework'; }; - applyConditionalLogicToField = (field: TemplateField, logic: Record<string, Conditional[]>) => { + applyConditionalLogicToField = (field: TemplateField | TemplateDataField, logic: Record<string, Conditional[]>) => { if (field instanceof DynamicField) return; const fieldStatements: Conditional[] = logic[field.getTitle()]; const content = field.getContent() @@ -91,7 +106,8 @@ export class Template { if (statement.target === 'template') { this._mainField.renderedDoc![statement.attribute] = statement.value; } else { - field.renderedDoc![statement.attribute] = statement.value; + const targetField: TemplateField = this.getFieldByTitle(statement.target) as TemplateField; + targetField && (targetField.renderedDoc![statement.attribute] = statement.value); } } }) @@ -99,7 +115,7 @@ export class Template { applyConditionalLogic = (logic: Record<string, Conditional[]>) => { console.log('applying logic: ', logic) - const fields: TemplateField[] = [...this.allFields]; + const fields: (TemplateField | TemplateDataField)[] = [...this.allFields, ...this.dataFields]; fields.forEach(field => this.applyConditionalLogicToField(field, logic)); } diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.ts index 06eab63f0..26fd3a8fc 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.ts +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.ts @@ -4,6 +4,7 @@ export enum TemplateFieldType { TEXT = 'text', VISUAL = 'visual', UNSET = 'unset', + DATA = 'data', } export enum TemplateFieldSize { diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DataField.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DataField.ts new file mode 100644 index 000000000..aaa475bed --- /dev/null +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DataField.ts @@ -0,0 +1,21 @@ + +import { Template } from "../Template"; +import { TemplateField, ViewType } from "./TemplateField"; + +export class TemplateDataField { + + viewType: ViewType = ViewType.NONE; + + title: string = ''; + content: string | undefined; + + constructor(title: string, content?: string) { + this.title = title; + this.content = content; + } + + setContent(content: string, viewType?: ViewType) { this.content = content } + getContent() { return this.content } + + getTitle() { return this.title } +}
\ No newline at end of file diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts index bc6b13c76..2c304247d 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts @@ -157,6 +157,7 @@ export enum ViewType { DEC = 'decoration', IMG = 'image', TEXT = 'text', + NONE = 'none' } export type FieldDimensions = { |