aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes')
-rw-r--r--src/client/views/nodes/ComparisonBox.tsx6
-rw-r--r--src/client/views/nodes/DataVizBox/DataVizBox.tsx4
-rw-r--r--src/client/views/nodes/ImageBox.scss7
-rw-r--r--src/client/views/nodes/ImageBox.tsx82
-rw-r--r--src/client/views/nodes/WebBox.tsx4
-rw-r--r--src/client/views/nodes/calendarBox/CalendarBox.tsx44
-rw-r--r--src/client/views/nodes/chatbot/agentsystem/Agent.ts3
-rw-r--r--src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx5
-rw-r--r--src/client/views/nodes/chatbot/tools/CreateDocumentTool.ts38
-rw-r--r--src/client/views/nodes/chatbot/tools/ImageCreationTool.ts36
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx15
-rw-r--r--src/client/views/nodes/imageEditor/ImageEditor.tsx83
-rw-r--r--src/client/views/nodes/imageEditor/ImageEditorButtons.tsx4
-rw-r--r--src/client/views/nodes/imageEditor/imageEditorUtils/ImageHandler.ts1
-rw-r--r--src/client/views/nodes/imageEditor/imageEditorUtils/imageEditorInterfaces.ts5
15 files changed, 186 insertions, 151 deletions
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index cb0831d3c..5315612e1 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -291,7 +291,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
this.askGPTPhonemes(this._inputValue);
this._renderSide = this.backKey;
this._outputValue = '';
- } else if (this._inputValue) this.askGPT(GPTCallType.QUIZ);
+ } else if (this._inputValue) this.askGPT(GPTCallType.QUIZDOC);
};
onPointerMove = ({ movementX }: PointerEvent) => {
@@ -511,7 +511,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
*/
askGPT = async (callType: GPTCallType) => {
const questionText = this.frontText;
- const queryText = questionText + (callType == GPTCallType.QUIZ ? ' UserAnswer: ' + this._inputValue + '. ' + ' Rubric: ' + this.backText : '');
+ const queryText = questionText + (callType == GPTCallType.QUIZDOC ? ' UserAnswer: ' + this._inputValue + '. ' + ' Rubric: ' + this.backText : '');
this.loading = true;
const res = !this.frontText
@@ -522,7 +522,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
case GPTCallType.CHATCARD:
DocCast(this.dataDoc[this.backKey])[DocData].text = resp;
break;
- case GPTCallType.QUIZ:
+ case GPTCallType.QUIZDOC:
this._renderSide = this.backKey;
this._outputValue = resp.replace(/UserAnswer/g, "user's answer").replace(/Rubric/g, 'rubric');
break;
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index b874d077b..fa3ab73a7 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -489,7 +489,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
}
// Changing which document to add the annotation to (the currently selected PDF)
- GPTPopup.Instance.setSidebarId('data_sidebar');
+ GPTPopup.Instance.setSidebarFieldKey('data_sidebar');
GPTPopup.Instance.addDoc = this.sidebarAddDocument;
};
@@ -523,7 +523,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
};
askGPT = action(async () => {
- GPTPopup.Instance.setSidebarId('data_sidebar');
+ GPTPopup.Instance.setSidebarFieldKey('data_sidebar');
GPTPopup.Instance.addDoc = this.sidebarAddDocument;
GPTPopup.Instance.createFilteredDoc = this.createFilteredDoc;
GPTPopup.Instance.setDataJson('');
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 caefbf542..f76e10a0e 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));
};
@@ -147,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) {
+ if ((layoutDoc === this.layoutDoc && !this.layoutDoc._layout_nativeDimEditable) || !this.layoutDoc._height) {
this.layoutDoc._height = (width * nativeSize.nativeHeight) / nativeSize.nativeWidth;
}
},
@@ -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 }
@@ -315,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) {
@@ -352,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',
@@ -381,7 +383,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 +425,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 +467,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 +527,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 +547,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
</div>
)}
</div>
- {this.overlayImageIcon}
</div>
);
}
@@ -739,12 +754,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 +801,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 +818,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()}
@@ -839,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/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 6026d9ca7..e7a10cc29 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -383,7 +383,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
this._textAnnotationCreator = () => this.createTextAnnotation(sel, !sel.isCollapsed ? sel.getRangeAt(0) : undefined);
AnchorMenu.Instance.jumpTo(e.clientX * scale + mainContBounds.translateX, e.clientY * scale + mainContBounds.translateY - NumCast(this.layoutDoc._layout_scrollTop) * scale);
// Changing which document to add the annotation to (the currently selected WebBox)
- GPTPopup.Instance.setSidebarId(`${this._props.fieldKey}_${this._urlHash ? this._urlHash + '_' : ''}sidebar`);
+ GPTPopup.Instance.setSidebarFieldKey(`${this._props.fieldKey}_${this._urlHash ? this._urlHash + '_' : ''}sidebar`);
GPTPopup.Instance.addDoc = this.sidebarAddDocument;
}
} else {
@@ -446,7 +446,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
this._textAnnotationCreator = () => this.createTextAnnotation(sel, selRange);
(!sel.isCollapsed || this.marqueeing) && AnchorMenu.Instance.jumpTo(e.clientX, e.clientY);
// Changing which document to add the annotation to (the currently selected WebBox)
- GPTPopup.Instance.setSidebarId(`${this._props.fieldKey}_${this._urlHash ? this._urlHash + '_' : ''}sidebar`);
+ GPTPopup.Instance.setSidebarFieldKey(`${this._props.fieldKey}_${this._urlHash ? this._urlHash + '_' : ''}sidebar`);
GPTPopup.Instance.addDoc = this.sidebarAddDocument;
}
};
diff --git a/src/client/views/nodes/calendarBox/CalendarBox.tsx b/src/client/views/nodes/calendarBox/CalendarBox.tsx
index d38cb5423..009eb82cd 100644
--- a/src/client/views/nodes/calendarBox/CalendarBox.tsx
+++ b/src/client/views/nodes/calendarBox/CalendarBox.tsx
@@ -1,4 +1,4 @@
-import { Calendar, EventClickArg, EventSourceInput } from '@fullcalendar/core';
+import { Calendar, EventClickArg, EventDropArg, EventSourceInput } from '@fullcalendar/core';
import dayGridPlugin from '@fullcalendar/daygrid';
import multiMonthPlugin from '@fullcalendar/multimonth';
import timeGrid from '@fullcalendar/timegrid';
@@ -17,6 +17,7 @@ import { DocumentView } from '../DocumentView';
import { OpenWhere } from '../OpenWhere';
import { DragManager } from '../../../util/DragManager';
import { DocData } from '../../../../fields/DocSymbols';
+import { ContextMenu } from '../../ContextMenu';
type CalendarView = 'multiMonth' | 'dayGridMonth' | 'timeGridWeek' | 'timeGridDay';
@@ -104,32 +105,44 @@ export class CalendarBox extends CollectionSubView() {
}
// TODO: Return a different color based on the event type
- eventToColor(event: Doc): string {
+ eventToColor = (event: Doc): string => {
return 'red';
- }
+ };
- internalDocDrop(e: Event, de: DragManager.DropEvent, docDragData: DragManager.DocumentDragData) {
+ internalDocDrop = (e: Event, de: DragManager.DropEvent, docDragData: DragManager.DocumentDragData) => {
if (!super.onInternalDrop(e, de)) return false;
de.complete.docDragData?.droppedDocuments.forEach(doc => {
const today = new Date().toISOString();
if (!doc.date_range) doc[DocData].date_range = `${today}|${today}`;
});
return true;
- }
+ };
onInternalDrop = (e: Event, de: DragManager.DropEvent): boolean => {
if (de.complete.docDragData?.droppedDocuments.length) return this.internalDocDrop(e, de, de.complete.docDragData);
return false;
};
+ handleEventDrop = (arg: EventDropArg) => {
+ const doc = DocServer.GetCachedRefField(arg.event._def.groupId ?? '');
+ doc && arg.event.start && (doc.date_range = arg.event.start?.toString() + '|' + (arg.event.end ?? arg.event.start).toString());
+ };
+
handleEventClick = (arg: EventClickArg) => {
const doc = DocServer.GetCachedRefField(arg.event._def.groupId ?? '');
- DocumentView.DeselectAll();
if (doc) {
DocumentView.showDocument(doc, { openLocation: OpenWhere.lightboxAlways });
arg.jsEvent.stopPropagation();
}
};
+ handleEventContextMenu = (pageX: number, pageY: number, docid: string) => {
+ const doc = DocServer.GetCachedRefField(docid ?? '');
+ if (doc) {
+ const cm = ContextMenu.Instance;
+ cm.addItem({ description: 'Show Metadata', event: () => this._props.addDocTab(doc, OpenWhere.addRightKeyvalue), icon: 'table-columns' });
+ cm.displayMenu(pageX - 15, pageY - 15, undefined, undefined);
+ }
+ };
// https://fullcalendar.io
renderCalendar = () => {
@@ -157,6 +170,25 @@ export class CalendarBox extends CollectionSubView() {
aspectRatio: NumCast(this.Document.width) / NumCast(this.Document.height),
events: this.calendarEvents,
eventClick: this.handleEventClick,
+ eventDrop: this.handleEventDrop,
+ eventDidMount: arg => {
+ arg.el.addEventListener('pointerdown', ev => {
+ ev.button && ev.stopPropagation();
+ });
+ if (navigator.userAgent.includes('Macintosh')) {
+ arg.el.addEventListener('pointerup', ev => {
+ ev.button && ev.stopPropagation();
+ ev.button && this.handleEventContextMenu(ev.pageX, ev.pageY, arg.event._def.groupId);
+ });
+ }
+ arg.el.addEventListener('contextmenu', ev => {
+ if (!navigator.userAgent.includes('Macintosh')) {
+ this.handleEventContextMenu(ev.pageX, ev.pageY, arg.event._def.groupId);
+ }
+ ev.stopPropagation();
+ ev.preventDefault();
+ });
+ },
}));
cal?.render();
setTimeout(() => cal?.view.calendar.select(this.dateSelect.start, this.dateSelect.end));
diff --git a/src/client/views/nodes/chatbot/agentsystem/Agent.ts b/src/client/views/nodes/chatbot/agentsystem/Agent.ts
index 19fd6ae36..e93fb87db 100644
--- a/src/client/views/nodes/chatbot/agentsystem/Agent.ts
+++ b/src/client/views/nodes/chatbot/agentsystem/Agent.ts
@@ -22,6 +22,7 @@ import { ChatCompletionMessageParam } from 'openai/resources';
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';
@@ -62,7 +63,7 @@ export class Agent {
history: () => string,
csvData: () => { filename: string; id: string; text: string }[],
addLinkedUrlDoc: (url: string, id: string) => void,
- createImage: (result: any, options: DocumentOptions) => void,
+ createImage: (result: Upload.FileInformation & Upload.InspectionResults, options: DocumentOptions) => void,
addLinkedDoc: (doc: parsedDoc) => Doc | undefined,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
createCSVInDash: (url: string, title: string, id: string, data: string) => void
diff --git a/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx b/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx
index f8fe531ab..6e9307d37 100644
--- a/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx
+++ b/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx
@@ -42,6 +42,7 @@ import './ChatBox.scss';
import MessageComponentBox from './MessageComponent';
import { ProgressBar } from './ProgressBar';
import { OpenWhere } from '../../OpenWhere';
+import { Upload } from '../../../../../server/SharedMediaTypes';
dotenv.config();
@@ -412,7 +413,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
});
@action
- createImageInDash = async (result: any, options: DocumentOptions) => {
+ createImageInDash = async (result: Upload.FileInformation & Upload.InspectionResults, options: DocumentOptions) => {
const newImgSrc =
result.accessPaths.agnostic.client.indexOf('dashblobstore') === -1 //
? ClientUtils.prepend(result.accessPaths.agnostic.client)
@@ -1046,5 +1047,5 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
*/
Docs.Prototypes.TemplateMap.set(DocumentType.CHAT, {
layout: { view: ChatBox, dataField: 'data' },
- options: { acl: '', chat: '', chat_history: '', chat_thread_id: '', chat_assistant_id: '', chat_vector_store_id: '' },
+ options: { acl: '', _layout_fitWidth: true, chat: '', chat_history: '', chat_thread_id: '', chat_assistant_id: '', chat_vector_store_id: '' },
});
diff --git a/src/client/views/nodes/chatbot/tools/CreateDocumentTool.ts b/src/client/views/nodes/chatbot/tools/CreateDocumentTool.ts
index 6dc36b0d1..284879a4a 100644
--- a/src/client/views/nodes/chatbot/tools/CreateDocumentTool.ts
+++ b/src/client/views/nodes/chatbot/tools/CreateDocumentTool.ts
@@ -263,79 +263,79 @@ const standardOptions = ['title', 'backgroundColor'];
* Description of document options and data field for each type.
*/
const documentTypesInfo: { [key in supportedDocTypes]: { options: string[]; dataDescription: string } } = {
- [supportedDocTypes.comparison]: {
+ comparison: {
options: [...standardOptions, 'fontColor', 'text_align'],
dataDescription: 'an array of two documents of any kind that can be compared.',
},
- [supportedDocTypes.deck]: {
+ deck: {
options: [...standardOptions, 'fontColor', 'text_align'],
dataDescription: 'an array of flashcard docs',
},
- [supportedDocTypes.flashcard]: {
+ flashcard: {
options: [...standardOptions, 'fontColor', 'text_align'],
dataDescription: 'an array of two strings. the first string contains a question, and the second string contains an answer',
},
- [supportedDocTypes.text]: {
+ text: {
options: [...standardOptions, 'fontColor', 'text_align'],
dataDescription: 'The text content of the document.',
},
- [supportedDocTypes.web]: {
+ web: {
options: [],
dataDescription: 'A URL to a webpage. Example: https://en.wikipedia.org/wiki/Brown_University',
},
- [supportedDocTypes.html]: {
+ html: {
options: [],
dataDescription: 'The HTML-formatted text content of the document.',
},
- [supportedDocTypes.equation]: {
+ equation: {
options: [...standardOptions, 'fontColor'],
dataDescription: 'The equation content represented as a MathML string.',
},
- [supportedDocTypes.functionplot]: {
+ functionplot: {
options: [...standardOptions, 'function_definition'],
dataDescription: 'The function definition(s) for plotting. Provide as a string or array of function definitions.',
},
- [supportedDocTypes.dataviz]: {
+ dataviz: {
options: [...standardOptions, 'chartType'],
dataDescription: 'A string of comma-separated values representing the CSV data.',
},
- [supportedDocTypes.notetaking]: {
+ notetaking: {
options: standardOptions,
dataDescription: 'An array of related text documents with small amounts of text.',
},
- [supportedDocTypes.rtf]: {
+ rtf: {
options: standardOptions,
dataDescription: 'The rich text content in RTF format.',
},
- [supportedDocTypes.image]: {
+ image: {
options: standardOptions,
dataDescription: `A url string that must end with '.png', '.jpeg', '.gif', or '.jpg'`,
},
- [supportedDocTypes.pdf]: {
+ pdf: {
options: standardOptions,
dataDescription: 'the pdf content as a PDF file url.',
},
- [supportedDocTypes.audio]: {
+ audio: {
options: standardOptions,
dataDescription: 'The audio content as a file url.',
},
- [supportedDocTypes.video]: {
+ video: {
options: standardOptions,
dataDescription: 'The video content as a file url.',
},
- [supportedDocTypes.message]: {
+ message: {
options: standardOptions,
dataDescription: 'The message content of the document.',
},
- [supportedDocTypes.diagram]: {
+ diagram: {
options: standardOptions,
dataDescription: 'diagram content as a text string in Mermaid format.',
},
- [supportedDocTypes.script]: {
+ script: {
options: standardOptions,
dataDescription: 'The compilable JavaScript code. Use this for creating scripts.',
},
- [supportedDocTypes.collection]: {
+ collection: {
options: [...standardOptions, 'type_collection'],
dataDescription: 'A collection of Docs represented as an array.',
},
diff --git a/src/client/views/nodes/chatbot/tools/ImageCreationTool.ts b/src/client/views/nodes/chatbot/tools/ImageCreationTool.ts
index 177552c5c..dc6140871 100644
--- a/src/client/views/nodes/chatbot/tools/ImageCreationTool.ts
+++ b/src/client/views/nodes/chatbot/tools/ImageCreationTool.ts
@@ -1,10 +1,10 @@
-import { v4 as uuidv4 } from 'uuid';
import { RTFCast } from '../../../../../fields/Types';
import { DocumentOptions } from '../../../../documents/Documents';
import { Networking } from '../../../../Network';
import { ParametersType, ToolInfo } from '../types/tool_types';
import { Observation } from '../types/types';
import { BaseTool } from './BaseTool';
+import { Upload } from '../../../../../server/SharedMediaTypes';
const imageCreationToolParams = [
{
@@ -25,8 +25,8 @@ const imageCreationToolInfo: ToolInfo<ImageCreationToolParamsType> = {
};
export class ImageCreationTool extends BaseTool<ImageCreationToolParamsType> {
- private _createImage: (result: any, options: DocumentOptions) => void;
- constructor(createImage: (result: any, options: DocumentOptions) => void) {
+ private _createImage: (result: Upload.FileInformation & Upload.InspectionResults, options: DocumentOptions) => void;
+ constructor(createImage: (result: Upload.FileInformation & Upload.InspectionResults, options: DocumentOptions) => void) {
super(imageCreationToolInfo);
this._createImage = createImage;
}
@@ -42,23 +42,19 @@ export class ImageCreationTool extends BaseTool<ImageCreationToolParamsType> {
});
console.log('Image generation result:', result);
this._createImage(result, { text: RTFCast(image_prompt) });
- if (url) {
- const id = uuidv4();
-
- return [
- {
- type: 'image_url',
- image_url: { url },
- },
- ];
- } else {
- return [
- {
- type: 'text',
- text: `An error occurred while generating image.`,
- },
- ];
- }
+ return url
+ ? [
+ {
+ type: 'image_url',
+ image_url: { url },
+ },
+ ]
+ : [
+ {
+ type: 'text',
+ text: `An error occurred while generating image.`,
+ },
+ ];
} catch (error) {
console.log(error);
return [
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index eb1f9d07b..3abb39ff2 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -135,7 +135,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
/**
* ApplyingChange - Marks whether an interactive text edit is currently in the process of being written to the database.
- * This is needed to distinguish changes to text fields caused by editing vs those caused by changes to
+ * This is needed to distinguish changes to text fields caused by editing vs those caused by changes to
* the prototype or other external edits
*/
public ApplyingChange: string = '';
@@ -977,7 +977,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
},
icon: 'star',
});
- optionItems.push({ description: `Generate Dall-E Image`, event: () => this.generateImage(), icon: 'star' });
+ optionItems.push({ description: `Generate Dall-E Image`, event: this.generateImage, icon: 'star' });
// optionItems.push({ description: `Make AI Flashcards`, event: () => this.makeAIFlashcards(), icon: 'lightbulb' });
optionItems.push({ description: `Ask GPT-3`, event: this.askGPT, icon: 'lightbulb' });
this._props.renderDepth &&
@@ -1043,7 +1043,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
askGPT = action(async () => {
try {
- GPTPopup.Instance.setSidebarId(this.sidebarKey);
+ GPTPopup.Instance.setSidebarFieldKey(this.sidebarKey);
GPTPopup.Instance.addDoc = this.sidebarAddDocument;
const res = await gptAPICall((this.dataDoc.text as RichTextField)?.Text, GPTCallType.COMPLETION);
if (!res) {
@@ -1061,12 +1061,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}
});
- generateImage = async () => {
+ generateImage = () => {
GPTPopup.Instance?.setTextAnchor(this.getAnchor(false));
- GPTPopup.Instance?.setImgTargetDoc(this.Document);
- GPTPopup.Instance.addToCollection = this._props.addDocument;
- GPTPopup.Instance.setImgDesc((this.dataDoc.text as RichTextField)?.Text);
- GPTPopup.Instance.generateImage();
+ GPTPopup.Instance.generateImage((this.dataDoc.text as RichTextField)?.Text, this.Document, this._props.addDocument);
};
breakupDictation = () => {
@@ -1660,7 +1657,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}
};
onSelectEnd = () => {
- GPTPopup.Instance.setSidebarId(this.sidebarKey);
+ GPTPopup.Instance.setSidebarFieldKey(this.sidebarKey);
GPTPopup.Instance.addDoc = this.sidebarAddDocument;
document.removeEventListener('pointerup', this.onSelectEnd);
};
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