From ec1c58855b7209c49026e98185bd52906aa84a37 Mon Sep 17 00:00:00 2001
From: geireann <geireann.lindfield@gmail.com>
Date: Thu, 20 Feb 2025 14:50:56 -0500
Subject: enabled non-uniform image resize

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

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

diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index caefbf542..697577955 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -147,7 +147,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         this._disposers.path = reaction(
             () => ({ nativeSize: this.nativeSize, width: NumCast(this.layoutDoc._width) }),
             ({ nativeSize, width }) => {
-                if (layoutDoc === this.layoutDoc || !this.layoutDoc._height) {
+                if ((layoutDoc === this.layoutDoc || !this.layoutDoc._height) && !this.layoutDoc._layout_nativeDimEditable) {
                     this.layoutDoc._height = (width * nativeSize.nativeHeight) / nativeSize.nativeWidth;
                 }
             },
-- 
cgit v1.2.3-70-g09d2


From 76292349418bfadedb904a2bcb0c6d1466709326 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 21 Feb 2025 17:25:04 -0500
Subject: fixed dropping image onto image boxes.  re-enabled rag tool

---
 src/client/views/nodes/ImageBox.scss               |  7 ++-
 src/client/views/nodes/ImageBox.tsx                | 57 ++++++++++++++--------
 .../views/nodes/chatbot/agentsystem/Agent.ts       |  3 +-
 .../views/nodes/chatbot/vectorstore/Vectorstore.ts |  2 +-
 4 files changed, 45 insertions(+), 24 deletions(-)

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

diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss
index fe4f0b1a2..59e093683 100644
--- a/src/client/views/nodes/ImageBox.scss
+++ b/src/client/views/nodes/ImageBox.scss
@@ -40,7 +40,7 @@
     max-height: 100%;
     pointer-events: inherit;
     background: transparent;
-    z-index: -10000;
+    // z-index: -10000; // bcz: not sure why this was here.  it broke dropping images on the image box alternate bullseye icon.
 
     img {
         height: auto;
@@ -129,7 +129,12 @@
     right: 0;
     bottom: 0;
     z-index: 2;
+    transform-origin: bottom right;
     cursor: default;
+    > svg {
+        width: 100%;
+        height: 100%;
+    }
 }
 
 .imageBox-fader img {
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 697577955..ff6baf199 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -1,11 +1,12 @@
+import { Button, Colors, Size, Type } from '@dash/components';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { Slider, Tooltip } from '@mui/material';
 import axios from 'axios';
-import { Colors, Button, Type, Size } from '@dash/components';
 import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import { extname } from 'path';
 import * as React from 'react';
+import { AiOutlineSend } from 'react-icons/ai';
 import ReactLoading from 'react-loading';
 import { ClientUtils, DashColor, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents, UpdateIcon } from '../../../ClientUtils';
 import { Doc, DocListCast, Opt } from '../../../fields/Doc';
@@ -16,12 +17,14 @@ import { ObjectField } from '../../../fields/ObjectField';
 import { Cast, DocCast, ImageCast, NumCast, RTFCast, StrCast } from '../../../fields/Types';
 import { ImageField } from '../../../fields/URLField';
 import { TraceMobx } from '../../../fields/util';
+import { Upload } from '../../../server/SharedMediaTypes';
 import { emptyFunction } from '../../../Utils';
 import { Docs } from '../../documents/Documents';
 import { DocumentType } from '../../documents/DocumentTypes';
 import { DocUtils, FollowLinkScript } from '../../documents/DocUtils';
 import { Networking } from '../../Network';
 import { DragManager } from '../../util/DragManager';
+import { SettingsManager } from '../../util/SettingsManager';
 import { SnappingManager } from '../../util/SnappingManager';
 import { undoable, undoBatch } from '../../util/UndoManager';
 import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
@@ -32,6 +35,9 @@ import { MarqueeAnnotator } from '../MarqueeAnnotator';
 import { OverlayView } from '../OverlayView';
 import { AnchorMenu } from '../pdf/AnchorMenu';
 import { PinDocView, PinProps } from '../PinFuncs';
+import { DrawingFillHandler } from '../smartdraw/DrawingFillHandler';
+import { FireflyImageData } from '../smartdraw/FireflyConstants';
+import { SmartDrawHandler } from '../smartdraw/SmartDrawHandler';
 import { StickerPalette } from '../smartdraw/StickerPalette';
 import { StyleProp } from '../StyleProp';
 import { DocumentView } from './DocumentView';
@@ -39,12 +45,6 @@ import { FieldView, FieldViewProps } from './FieldView';
 import { FocusViewOptions } from './FocusViewOptions';
 import './ImageBox.scss';
 import { OpenWhere } from './OpenWhere';
-import { Upload } from '../../../server/SharedMediaTypes';
-import { SmartDrawHandler } from '../smartdraw/SmartDrawHandler';
-import { SettingsManager } from '../../util/SettingsManager';
-import { AiOutlineSend } from 'react-icons/ai';
-import { FireflyImageData } from '../smartdraw/FireflyConstants';
-import { DrawingFillHandler } from '../smartdraw/DrawingFillHandler';
 
 export class ImageEditorData {
     // eslint-disable-next-line no-use-before-define
@@ -83,7 +83,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     private _disposers: { [name: string]: IReactionDisposer } = {};
     private _getAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = () => undefined;
     private _overlayIconRef = React.createRef<HTMLDivElement>();
-    private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
+    private _mainCont: HTMLDivElement | null = null;
     private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
     imageRef: HTMLImageElement | null = null; // <video> ref
     marqueeref = React.createRef<MarqueeAnnotator>();
@@ -108,6 +108,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     }
 
     protected createDropTarget = (ele: HTMLDivElement) => {
+        this._mainCont = ele;
         this._dropDisposer?.();
         ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.Document));
     };
@@ -157,8 +158,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             () => this.layoutDoc.layout_scrollTop,
             sTop => {
                 this._forcedScroll = true;
-                !this._ignoreScroll && this._mainCont.current && (this._mainCont.current.scrollTop = NumCast(sTop));
-                this._mainCont.current?.scrollTo({ top: NumCast(sTop) });
+                !this._ignoreScroll && this._mainCont && (this._mainCont.scrollTop = NumCast(sTop));
+                this._mainCont?.scrollTo({ top: NumCast(sTop) });
                 this._forcedScroll = false;
             },
             { fireImmediately: true }
@@ -381,7 +382,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
 
     // updateIcon = () => new Promise<void>(res => res());
     updateIcon = (usePanelDimensions?: boolean) => {
-        const contentDiv = this._mainCont.current;
+        const contentDiv = this._mainCont;
         return !contentDiv
             ? new Promise<void>(res => res())
             : UpdateIcon(
@@ -423,6 +424,20 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         const nativeOrientation = NumCast(this.dataDoc[this.fieldKey + '_nativeOrientation'], 1);
         return { nativeWidth, nativeHeight, nativeOrientation };
     }
+    private _sideBtnWidth = 35;
+    /**
+     * How much the content of the view is being scaled based on its nesting and its fit-to-width settings
+     */
+    @computed get viewScaling() { return this.ScreenToLocalBoxXf().Scale * ( this._props.NativeDimScaling?.() || 1); } // prettier-ignore
+    /**
+     * The maximum size a UI widget can be scaled so that it won't be bigger in screen pixels than its normal 35 pixel size.
+     */
+    @computed get maxWidgetSize() { return Math.min(this._sideBtnWidth, 0.5 * Math.min(NumCast(this.Document.width)))* this.viewScaling; } // prettier-ignore
+    /**
+     * How much to reactively scale a UI element so that it is as big as it can be (up to its normal 35pixel size) without being too big for the Doc content
+     */
+    @computed get uiBtnScaling() { return Math.min(this.maxWidgetSize / this._sideBtnWidth, 1); } // prettier-ignore
+
     @computed get overlayImageIcon() {
         const usePath = this.layoutDoc[`_${this.fieldKey}_usePath`];
         return (
@@ -451,9 +466,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                         })
                     }
                     style={{
-                        display: (this._props.isContentActive() !== false && SnappingManager.CanEmbed) || this.dataDoc[this.fieldKey + '_alternates'] ? 'block' : 'none',
-                        width: 'min(10%, 25px)',
-                        height: 'min(10%, 25px)',
+                        display: this._props.isContentActive() && (SnappingManager.CanEmbed || this.dataDoc[this.fieldKey + '_alternates']) ? 'block' : 'none',
+                        transform: `scale(${this.uiBtnScaling})`,
+                        width: this._sideBtnWidth,
+                        height: this._sideBtnWidth,
                         background: usePath === undefined ? 'white' : usePath === 'alternate' ? 'black' : 'gray',
                         color: usePath === undefined ? 'black' : 'white',
                     }}>
@@ -510,7 +526,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                     this._isHovering = false;
                 })}
                 key={this.layoutDoc[Id]}
-                ref={this.createDropTarget}
                 onPointerDown={this.marqueeDown}>
                 <div className="imageBox-fader" style={{ opacity: backAlpha }}>
                     <img
@@ -531,7 +546,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                         </div>
                     )}
                 </div>
-                {this.overlayImageIcon}
             </div>
         );
     }
@@ -739,12 +753,12 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             <div
                 className="imageBox"
                 onContextMenu={this.specificContextMenu}
-                ref={this._mainCont}
+                ref={this.createDropTarget}
                 onScroll={action(() => {
                     if (!this._forcedScroll) {
-                        if (this.layoutDoc._layout_scrollTop || this._mainCont.current?.scrollTop) {
+                        if (this.layoutDoc._layout_scrollTop || this._mainCont?.scrollTop) {
                             this._ignoreScroll = true;
-                            this.layoutDoc._layout_scrollTop = this._mainCont.current?.scrollTop;
+                            this.layoutDoc._layout_scrollTop = this._mainCont?.scrollTop;
                             this._ignoreScroll = false;
                         }
                     }
@@ -786,8 +800,9 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                         <ReactLoading type="spin" height={50} width={50} color={'blue'} />
                     </div>
                 ) : null}
+                {this.overlayImageIcon}
                 {this.annotationLayer}
-                {!this._mainCont.current || !this.DocumentView || !this._annotationLayer.current ? null : (
+                {!this._mainCont || !this.DocumentView || !this._annotationLayer.current ? null : (
                     <MarqueeAnnotator
                         Document={this.Document}
                         ref={this.marqueeref}
@@ -802,7 +817,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                         savedAnnotations={this.savedAnnotations}
                         selectionText={returnEmptyString}
                         annotationLayer={this._annotationLayer.current}
-                        marqueeContainer={this._mainCont.current}
+                        marqueeContainer={this._mainCont}
                         highlightDragSrcColor=""
                         anchorMenuCrop={this.crop}
                         // anchorMenuFlashcard={() => this.getImageDesc()}
diff --git a/src/client/views/nodes/chatbot/agentsystem/Agent.ts b/src/client/views/nodes/chatbot/agentsystem/Agent.ts
index 2ed808622..e93fb87db 100644
--- a/src/client/views/nodes/chatbot/agentsystem/Agent.ts
+++ b/src/client/views/nodes/chatbot/agentsystem/Agent.ts
@@ -23,6 +23,7 @@ import { Doc } from '../../../../../fields/Doc';
 import { parsedDoc } from '../chatboxcomponents/ChatBox';
 import { WebsiteInfoScraperTool } from '../tools/WebsiteInfoScraperTool';
 import { Upload } from '../../../../../server/SharedMediaTypes';
+import { RAGTool } from '../tools/RAGTool';
 //import { CreateTextDocTool } from '../tools/CreateTextDocumentTool';
 
 dotenv.config();
@@ -77,7 +78,7 @@ export class Agent {
         // Define available tools for the assistant
         this.tools = {
             calculate: new CalculateTool(),
-            // rag: new RAGTool(this.vectorstore),
+            rag: new RAGTool(this.vectorstore),
             dataAnalysis: new DataAnalysisTool(csvData),
             websiteInfoScraper: new WebsiteInfoScraperTool(addLinkedUrlDoc),
             searchTool: new SearchTool(addLinkedUrlDoc),
diff --git a/src/client/views/nodes/chatbot/vectorstore/Vectorstore.ts b/src/client/views/nodes/chatbot/vectorstore/Vectorstore.ts
index ef24e59bc..7027aceb4 100644
--- a/src/client/views/nodes/chatbot/vectorstore/Vectorstore.ts
+++ b/src/client/views/nodes/chatbot/vectorstore/Vectorstore.ts
@@ -39,7 +39,7 @@ export class Vectorstore {
      * @param doc_ids A function that returns a list of document IDs.
      */
     constructor(id: string, doc_ids: () => string[]) {
-        const pineconeApiKey = '51738e9a-bea2-4c11-b6bf-48a825e774dc';
+        const pineconeApiKey = process.env.PINECONE_API_KEY || '51738e9a-bea2-4c11-b6bf-48a825e774dc';
         if (!pineconeApiKey) {
             throw new Error('PINECONE_API_KEY is not defined.');
         }
-- 
cgit v1.2.3-70-g09d2


From 30ec70722678eba318fb7521a8b2bd642328bf54 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 23 Feb 2025 16:34:40 -0500
Subject: added option+maximize to open in doc editor view (currently only for
 images).  fixed imageEditor to generate edits the first time through.

---
 src/client/views/DocumentDecorations.tsx           |  7 +-
 src/client/views/StyleProviderQuiz.tsx             |  2 +-
 src/client/views/ViewBoxInterface.ts               |  1 +
 src/client/views/nodes/ImageBox.tsx                | 21 +++---
 src/client/views/nodes/calendarBox/CalendarBox.tsx |  2 +-
 src/client/views/nodes/imageEditor/ImageEditor.tsx | 83 ++++++++++------------
 .../views/nodes/imageEditor/ImageEditorButtons.tsx |  4 +-
 .../imageEditor/imageEditorUtils/ImageHandler.ts   |  1 -
 .../imageEditorUtils/imageEditorInterfaces.ts      |  5 +-
 9 files changed, 58 insertions(+), 68 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 54ff3904d..d9b6bdf1a 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -36,6 +36,7 @@ import { ImageBox } from './nodes/ImageBox';
 import { OpenWhere, OpenWhereMod } from './nodes/OpenWhere';
 import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
 import { TagsView } from './TagsView';
+import { ImageField } from '../../fields/URLField';
 
 interface DocumentDecorationsProps {
     PanelWidth: number;
@@ -284,8 +285,8 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
                 embedding.y = -NumCast(embedding._height) / 2;
                 CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([embedding], { title: 'Tab for ' + embedding.title }), OpenWhereMod.right);
             } else if (e.altKey) {
-                // open same document in new tab
-                CollectionDockingView.ToggleSplit(selView.Document, OpenWhereMod.right);
+                // open same document in new tab or in custom editor
+                selView.ComponentView?.docEditorView?.() ?? CollectionDockingView.ToggleSplit(selView.Document, OpenWhereMod.right);
             } else {
                 let openDoc = selView.Document;
                 if (openDoc.layout_fieldKey === 'layout_icon') {
@@ -821,7 +822,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
                                 {hideDeleteButton ? null : topBtn('close', 'times', undefined, () => this.onCloseClick(true), 'Close')}
                                 {hideResizers || hideDeleteButton ? null : topBtn('minimize', 'window-maximize', undefined, () => this.onCloseClick(undefined), 'Minimize')}
                                 {titleArea}
-                                {hideOpenButton ? <div /> : topBtn('open', 'external-link-alt', this.onMaximizeDown, undefined, 'Open in Lightbox (ctrl: as alias, shift: in new collection)')}
+                                {hideOpenButton ? <div /> : topBtn('open', 'external-link-alt', this.onMaximizeDown, undefined, 'Open in Lightbox (ctrl: as alias, shift: in new collection, opption: in editor view)')}
                             </div>
                             {hideResizers ? null : (
                                 <>
diff --git a/src/client/views/StyleProviderQuiz.tsx b/src/client/views/StyleProviderQuiz.tsx
index d8eeb3490..db9ab831a 100644
--- a/src/client/views/StyleProviderQuiz.tsx
+++ b/src/client/views/StyleProviderQuiz.tsx
@@ -125,7 +125,7 @@ export namespace styleProviderQuiz {
         try {
             const hrefBase64 = await createCanvas(img);
             const response = await gptImageLabel(hrefBase64, 'Make flashcards out of this image with each question and answer labeled as "question" and "answer". Do not label each flashcard and do not include asterisks: ');
-            AnchorMenu.Instance.transferToFlashcard(response, NumCast(img.layoutDoc['x']), NumCast(img.layoutDoc['y']));
+            AnchorMenu.Instance.transferToFlashcard(response, NumCast(img.layoutDoc.x), NumCast(img.layoutDoc.y));
         } catch (error) {
             console.log('Error', error);
         }
diff --git a/src/client/views/ViewBoxInterface.ts b/src/client/views/ViewBoxInterface.ts
index 30da8c616..b943259ff 100644
--- a/src/client/views/ViewBoxInterface.ts
+++ b/src/client/views/ViewBoxInterface.ts
@@ -23,6 +23,7 @@ export abstract class ViewBoxInterface<P> extends ObservableReactComponent<React
     }
     promoteCollection?: () => void; // moves contents of collection to parent
     hasChildDocs?: () => Doc[];
+    docEditorView?: () => void;
     updateIcon?: (usePanelDimensions?: boolean) => Promise<void>; // updates the icon representation of the document
     getAnchor?: (addAsAnnotation: boolean, pinData?: PinProps) => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box)
     restoreView?: (viewSpec: Doc) => boolean; // DEPRECATED: do not use, it will go away.  see PresBox.restoreTargetDocView
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index ff6baf199..dd28832f9 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -316,6 +316,16 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         return cropping;
     };
 
+    docEditorView = action(() => {
+        const field = Cast(this.dataDoc[this.fieldKey], ImageField);
+        if (field) {
+            ImageEditorData.Open = true;
+            ImageEditorData.Source = this.choosePath(field.url);
+            ImageEditorData.AddDoc = this._props.addDocument;
+            ImageEditorData.RootDoc = this.Document;
+        }
+    });
+
     specificContextMenu = (): void => {
         const field = Cast(this.dataDoc[this.fieldKey], ImageField);
         if (field) {
@@ -353,16 +363,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                 icon: 'expand-arrows-alt',
             });
             funcs.push({ description: 'Copy path', event: () => ClientUtils.CopyText(this.choosePath(field.url)), icon: 'copy' });
-            funcs.push({
-                description: 'Open Image Editor',
-                event: action(() => {
-                    ImageEditorData.Open = true;
-                    ImageEditorData.Source = this.choosePath(field.url);
-                    ImageEditorData.AddDoc = this._props.addDocument;
-                    ImageEditorData.RootDoc = this.Document;
-                }),
-                icon: 'pencil-alt',
-            });
+            funcs.push({ description: 'Open Image Editor', event: this.docEditorView, icon: 'pencil-alt' });
             this.layoutDoc.ai &&
                 funcs.push({
                     description: 'Regenerate AI Image',
diff --git a/src/client/views/nodes/calendarBox/CalendarBox.tsx b/src/client/views/nodes/calendarBox/CalendarBox.tsx
index c1f6f5859..009eb82cd 100644
--- a/src/client/views/nodes/calendarBox/CalendarBox.tsx
+++ b/src/client/views/nodes/calendarBox/CalendarBox.tsx
@@ -6,7 +6,7 @@ import interactionPlugin from '@fullcalendar/interaction';
 import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { dateRangeStrToDates, simulateMouseClick } from '../../../../ClientUtils';
+import { dateRangeStrToDates } from '../../../../ClientUtils';
 import { Doc } from '../../../../fields/Doc';
 import { BoolCast, NumCast, StrCast } from '../../../../fields/Types';
 import { CollectionSubView, SubCollectionViewProps } from '../../collections/CollectionSubView';
diff --git a/src/client/views/nodes/imageEditor/ImageEditor.tsx b/src/client/views/nodes/imageEditor/ImageEditor.tsx
index 6b1d05031..3c0ab3da5 100644
--- a/src/client/views/nodes/imageEditor/ImageEditor.tsx
+++ b/src/client/views/nodes/imageEditor/ImageEditor.tsx
@@ -90,18 +90,8 @@ const ImageEditor = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addDoc
      * @param type The new tool type we are changing to
      */
     const changeTool = (type: ImageToolType) => {
-        switch (type) {
-            case ImageToolType.GenerativeFill:
-                setCurrTool(genFillTool);
-                setCursorData(prev => ({ ...prev, width: genFillTool.sliderDefault as number }));
-                break;
-            case ImageToolType.Cut:
-                setCurrTool(cutTool);
-                setCursorData(prev => ({ ...prev, width: cutTool.sliderDefault as number }));
-                break;
-            default:
-                break;
-        }
+        setCurrToolType(type);
+        setCursorData(prev => ({ ...prev, width: currTool().sliderDefault as number }));
     };
     // Undo and Redo
     const handleUndo = () => {
@@ -171,9 +161,8 @@ const ImageEditor = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addDoc
 
     // handles brushing on pointer movement
     useEffect(() => {
-        if (!isBrushing) return undefined;
         const canvas = canvasRef.current;
-        if (!canvas) return undefined;
+        if (!isBrushing || !canvas) return undefined;
         const ctx = ImageUtility.getCanvasContext(canvasRef);
         if (!ctx) return undefined;
 
@@ -188,33 +177,29 @@ const ImageEditor = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addDoc
         };
 
         drawingAreaRef.current?.addEventListener('pointermove', handlePointerMove);
-        return () => {
-            drawingAreaRef.current?.removeEventListener('pointermove', handlePointerMove);
-        };
+        return () => drawingAreaRef.current?.removeEventListener('pointermove', handlePointerMove);
     }, [isBrushing]);
 
     // first load
     useEffect(() => {
-        const loadInitial = async () => {
-            if (!imageEditorSource || imageEditorSource === '') return;
-            const img = new Image();
-            const res = await ImageUtility.urlToBase64(imageEditorSource);
-            if (!res) return;
-            img.src = `data:image/png;base64,${res}`;
-
-            img.onload = () => {
-                currImg.current = img;
-                originalImg.current = img;
-                const imgWidth = img.naturalWidth;
-                const imgHeight = img.naturalHeight;
-                const scale = Math.min(canvasSize / imgWidth, canvasSize / imgHeight);
-                const width = imgWidth * scale;
-                const height = imgHeight * scale;
-                setCanvasDims({ width, height });
-            };
-        };
-
-        loadInitial();
+        if (imageEditorSource && imageEditorSource) {
+            ImageUtility.urlToBase64(imageEditorSource).then(res => {
+                if (res) {
+                    const img = new Image();
+                    img.src = `data:image/png;base64,${res}`;
+                    img.onload = () => {
+                        currImg.current = img;
+                        originalImg.current = img;
+                        const imgWidth = img.naturalWidth;
+                        const imgHeight = img.naturalHeight;
+                        const scale = Math.min(canvasSize / imgWidth, canvasSize / imgHeight);
+                        const width = imgWidth * scale;
+                        const height = imgHeight * scale;
+                        setCanvasDims({ width, height });
+                    };
+                }
+            });
+        }
 
         // cleanup
         return () => {
@@ -300,7 +285,7 @@ const ImageEditor = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addDoc
             if (!canvasMask) return;
             const maskBlob = await ImageUtility.canvasToBlob(canvasMask);
             const imgBlob = await ImageUtility.canvasToBlob(canvasOriginalImg);
-            const res = await ImageUtility.getEdit(imgBlob, maskBlob, input !== '' ? input + ' in the same style' : 'Fill in the image in the same style', 2);
+            const res = await ImageUtility.getEdit(imgBlob, maskBlob, input || 'Fill in the image in the same style', 2);
 
             // create first image
             if (!newCollectionRef.current) {
@@ -569,11 +554,15 @@ const ImageEditor = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addDoc
         setIsFirstDoc(true);
     };
 
+    function currTool() {
+        return imageEditTools.find(tool => tool.type === currToolType) ?? genFillTool;
+    }
+
     // defines the tools and sets current tool
-    const genFillTool: ImageEditTool = { type: ImageToolType.GenerativeFill, name: 'Generative Fill', btnText: 'GET EDITS', icon: 'fill', applyFunc: getEdit, sliderMin: 25, sliderMax: 500, sliderDefault: 150 };
-    const cutTool: ImageEditTool = { type: ImageToolType.Cut, name: 'Cut', btnText: 'CUT IMAGE', icon: 'scissors', applyFunc: cutImage, sliderMin: 1, sliderMax: 50, sliderDefault: 5 };
+    const genFillTool: ImageEditTool = { type: ImageToolType.GenerativeFill, btnText: 'GET EDITS', icon: 'fill', applyFunc: getEdit, sliderMin: 25, sliderMax: 500, sliderDefault: 150 };
+    const cutTool: ImageEditTool = { type: ImageToolType.Cut, btnText: 'CUT IMAGE', icon: 'scissors', applyFunc: cutImage, sliderMin: 1, sliderMax: 50, sliderDefault: 5 };
     const imageEditTools: ImageEditTool[] = [genFillTool, cutTool];
-    const [currTool, setCurrTool] = useState<ImageEditTool>(genFillTool);
+    const [currToolType, setCurrToolType] = useState<ImageToolType>(ImageToolType.GenerativeFill);
 
     // the top controls for making a new collection, resetting, and applying edits,
     function renderControls() {
@@ -595,7 +584,7 @@ const ImageEditor = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addDoc
                         labelPlacement="end"
                         sx={{ whiteSpace: 'nowrap' }}
                     />
-                    <ApplyFuncButtons onClick={() => currTool.applyFunc(cutType, cursorData.width, edits, isFirstDoc)} loading={loading} onReset={handleReset} btnText={currTool.btnText} />
+                    <ApplyFuncButtons onClick={() => currTool().applyFunc(cutType, cursorData.width, edits, isFirstDoc)} loading={loading} onReset={handleReset} btnText={currTool().btnText} />
                     <IconButton color={activeColor} tooltip="close" icon={<CgClose size="16px" />} onClick={handleViewClose} />
                 </div>
             </div>
@@ -607,8 +596,8 @@ const ImageEditor = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addDoc
         return (
             <div className="sideControlsContainer" style={{ backgroundColor: bgColor }}>
                 <div className="sideControls">
-                    <div className="imageToolsContainer">{imageEditTools.map(tool => ImageToolButton(tool, tool.type === currTool.type, changeTool))}</div>
-                    {currTool.type == ImageToolType.Cut && (
+                    <div className="imageToolsContainer">{imageEditTools.map(tool => ImageToolButton(tool, tool.type === currTool().type, changeTool))}</div>
+                    {currTool().type == ImageToolType.Cut && (
                         <div className="cutToolsContainer">
                             <Button style={{ width: '100%' }} text="Keep in" type={Type.TERT} color={cutType == CutMode.IN ? SettingsManager.userColor : bgColor} onClick={() => setCutType(CutMode.IN)} />
                             <Button style={{ width: '100%' }} text="Keep out" type={Type.TERT} color={cutType == CutMode.OUT ? SettingsManager.userColor : bgColor} onClick={() => setCutType(CutMode.OUT)} />
@@ -617,7 +606,7 @@ const ImageEditor = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addDoc
                         </div>
                     )}
                     <div className="sliderContainer" onPointerDown={e => e.stopPropagation()}>
-                        {currTool.type === ImageToolType.GenerativeFill && (
+                        {currTool().type === ImageToolType.GenerativeFill && (
                             <Slider
                                 sx={{
                                     '& input[type="range"]': {
@@ -633,7 +622,7 @@ const ImageEditor = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addDoc
                                 onChange={(e, val) => setCursorData(prev => ({ ...prev, width: val as number }))}
                             />
                         )}
-                        {currTool.type === ImageToolType.Cut && (
+                        {currTool().type === ImageToolType.Cut && (
                             <Slider
                                 sx={{
                                     '& input[type="range"]': {
@@ -780,7 +769,7 @@ const ImageEditor = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addDoc
                 {renderSideIcons()}
                 {renderEditThumbnails()}
             </div>
-            {currTool.type === ImageToolType.GenerativeFill && renderPromptBox()}
+            {currTool().type === ImageToolType.GenerativeFill && renderPromptBox()}
         </div>
     );
 };
diff --git a/src/client/views/nodes/imageEditor/ImageEditorButtons.tsx b/src/client/views/nodes/imageEditor/ImageEditorButtons.tsx
index 985dc914f..3eaa251f2 100644
--- a/src/client/views/nodes/imageEditor/ImageEditorButtons.tsx
+++ b/src/client/views/nodes/imageEditor/ImageEditorButtons.tsx
@@ -53,10 +53,10 @@ export function ApplyFuncButtons({ loading, onClick: getEdit, onReset, btnText }
 
 export function ImageToolButton(tool: ImageEditTool, isActive: boolean, selectTool: (type: ImageToolType) => void) {
     return (
-        <div key={tool.name} className="imageEditorButtonContainer">
+        <div key={tool.type} className="imageEditorButtonContainer">
             <Button
                 style={{ width: '100%' }}
-                text={tool.name}
+                text={tool.type}
                 type={Type.TERT}
                 color={isActive ? SettingsManager.userVariantColor : bgColor}
                 icon={<FontAwesomeIcon icon={tool.icon} />}
diff --git a/src/client/views/nodes/imageEditor/imageEditorUtils/ImageHandler.ts b/src/client/views/nodes/imageEditor/imageEditorUtils/ImageHandler.ts
index ece0f4d7f..1c6a38a24 100644
--- a/src/client/views/nodes/imageEditor/imageEditorUtils/ImageHandler.ts
+++ b/src/client/views/nodes/imageEditor/imageEditorUtils/ImageHandler.ts
@@ -87,7 +87,6 @@ export class ImageUtility {
                 body: fd,
             });
             const data = await res.json();
-            console.log(data.data);
             return {
                 status: 'success',
                 urls: (data.data as { b64_json: string }[]).map(urlData => `data:image/png;base64,${urlData.b64_json}`),
diff --git a/src/client/views/nodes/imageEditor/imageEditorUtils/imageEditorInterfaces.ts b/src/client/views/nodes/imageEditor/imageEditorUtils/imageEditorInterfaces.ts
index a14b55439..02dbc0312 100644
--- a/src/client/views/nodes/imageEditor/imageEditorUtils/imageEditorInterfaces.ts
+++ b/src/client/views/nodes/imageEditor/imageEditorUtils/imageEditorInterfaces.ts
@@ -13,8 +13,8 @@ export interface Point {
 }
 
 export enum ImageToolType {
-    GenerativeFill = 'genFill',
-    Cut = 'cut',
+    GenerativeFill = 'Generative Fill',
+    Cut = 'Cut',
 }
 
 export enum CutMode {
@@ -26,7 +26,6 @@ export enum CutMode {
 
 export interface ImageEditTool {
     type: ImageToolType;
-    name: string;
     btnText: string;
     icon: IconProp;
     // this is the function that the image tool applies, so it can be defined depending on the tool
-- 
cgit v1.2.3-70-g09d2


From c1159c2587d69e42496c493b508ecb3e8ba0f65c Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 24 Feb 2025 10:59:15 -0500
Subject: made images able to non-unifrom resize.  changed popup to generate
 descriptions only after it's opened.

---
 src/client/views/nodes/ImageBox.tsx        | 2 +-
 src/client/views/pdf/GPTPopup/GPTPopup.tsx | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

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

diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index dd28832f9..1cc298b11 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -855,5 +855,5 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
 
 Docs.Prototypes.TemplateMap.set(DocumentType.IMG, {
     layout: { view: ImageBox, dataField: 'data' },
-    options: { acl: '', freeform: '', systemIcon: 'BsFileEarmarkImageFill' },
+    options: { acl: '', freeform: '', _layout_nativeDimEditable: true, systemIcon: 'BsFileEarmarkImageFill' },
 });
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
index b7eaf2674..2cf39bec4 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
@@ -75,9 +75,9 @@ export class GPTPopup extends ObservableReactComponent<object> {
     }
     componentDidMount(): void {
         reaction(
-            () => DocumentView.Selected().lastElement(),
-            selDoc => {
-                const hasChildDocs = selDoc?.ComponentView?.hasChildDocs;
+            () => ({ selDoc: DocumentView.Selected().lastElement(), visible: SnappingManager.ChatVisible }),
+            ({ selDoc, visible }) => {
+                const hasChildDocs = visible && selDoc?.ComponentView?.hasChildDocs;
                 if (hasChildDocs) {
                     this._textToDocMap.clear();
                     this.setCollectionContext(selDoc.Document);
-- 
cgit v1.2.3-70-g09d2


From 383a8a2f017c12c578537d3cb3005e00be019bd7 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 24 Feb 2025 11:35:04 -0500
Subject: fixed adding images and giving them a height (just broken by setting
 layout_nativeDimEditable)

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

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

diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 1cc298b11..f76e10a0e 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -148,7 +148,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         this._disposers.path = reaction(
             () => ({ nativeSize: this.nativeSize, width: NumCast(this.layoutDoc._width) }),
             ({ nativeSize, width }) => {
-                if ((layoutDoc === this.layoutDoc || !this.layoutDoc._height) && !this.layoutDoc._layout_nativeDimEditable) {
+                if ((layoutDoc === this.layoutDoc && !this.layoutDoc._layout_nativeDimEditable) || !this.layoutDoc._height) {
                     this.layoutDoc._height = (width * nativeSize.nativeHeight) / nativeSize.nativeWidth;
                 }
             },
-- 
cgit v1.2.3-70-g09d2

