diff options
Diffstat (limited to 'src')
9 files changed, 76 insertions, 22 deletions
diff --git a/src/client/views/nodes/DiagramBox.scss b/src/client/views/nodes/DiagramBox.scss index 8a7863c14..df1a3276f 100644 --- a/src/client/views/nodes/DiagramBox.scss +++ b/src/client/views/nodes/DiagramBox.scss @@ -3,8 +3,7 @@ height: 100%; display: flex; flex-direction: column; - align-items: center; - justify-content: center; + overflow: auto; .DIYNodeBox { /* existing code */ diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx index ea3ab2887..e77cde431 100644 --- a/src/client/views/nodes/DiagramBox.tsx +++ b/src/client/views/nodes/DiagramBox.tsx @@ -32,6 +32,7 @@ export class DiagramBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { } return false; }; + _boxRef: HTMLDivElement | null = null; constructor(props: FieldViewProps) { super(props); @@ -184,9 +185,24 @@ export class DiagramBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { return '( )'; }; + /** + * This stops scroll wheel events when they are used to scroll the face collection. + */ + onPassiveWheel = (e: WheelEvent) => e.stopPropagation(); + render() { return ( - <div className="DIYNodeBox"> + <div + className="DIYNodeBox" + style={{ + pointerEvents: this._props.isContentActive() ? undefined : 'none', + }} + ref={action((ele: HTMLDivElement | null) => { + this._boxRef?.removeEventListener('wheel', this.onPassiveWheel); + this._boxRef = ele; + // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling + ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false }); + })}> <div className="DIYNodeBox-searchbar"> <input type="text" value={this._inputValue} onKeyDown={action(e => e.key === 'Enter' && this.generateMermaidCode())} onChange={action(e => (this._inputValue = e.target.value))} /> <button type="button" onClick={this.generateMermaidCode}> @@ -218,7 +234,7 @@ Docs.Prototypes.TemplateMap.set(DocumentType.DIAGRAM, { _layout_nativeDimEditable: true, _layout_reflowVertical: true, _layout_reflowHorizontal: true, - waitForDoubleClickToClick: 'always', + waitForDoubleClickToClick: 'never', systemIcon: 'BsGlobe', }, }); diff --git a/src/client/views/nodes/chatbot/agentsystem/Agent.ts b/src/client/views/nodes/chatbot/agentsystem/Agent.ts index a7b34392b..b2b0c9aea 100644 --- a/src/client/views/nodes/chatbot/agentsystem/Agent.ts +++ b/src/client/views/nodes/chatbot/agentsystem/Agent.ts @@ -21,6 +21,7 @@ import { getReactPrompt } from './prompts'; import { ChatCompletionMessageParam } from 'openai/resources'; import { Doc } from '../../../../../fields/Doc'; import { parsedDoc } from '../chatboxcomponents/ChatBox'; +import { WebsiteInfoScraperTool } from '../tools/WebsiteInfoScraperTool'; //import { CreateTextDocTool } from '../tools/CreateTextDocumentTool'; dotenv.config(); @@ -77,11 +78,11 @@ export class Agent { calculate: new CalculateTool(), // rag: new RAGTool(this.vectorstore), dataAnalysis: new DataAnalysisTool(csvData), - // websiteInfoScraper: new WebsiteInfoScraperTool(addLinkedUrlDoc), + websiteInfoScraper: new WebsiteInfoScraperTool(addLinkedUrlDoc), searchTool: new SearchTool(addLinkedUrlDoc), // createCSV: new CreateCSVTool(createCSVInDash), noTool: new NoTool(), - //imageCreationTool: new ImageCreationTool(createImage), + imageCreationTool: new ImageCreationTool(createImage), // createTextDoc: new CreateTextDocTool(addLinkedDoc), createDoc: new CreateDocTool(addLinkedDoc), // createAnyDocument: new CreateAnyDocumentTool(addLinkedDoc), @@ -458,7 +459,7 @@ export class Agent { for (const param of this.tools[action].parameterRules) { // Check if the parameter is required and missing in the input - if (param.required && !(param.name in actionInput)) { + if (param.required && !(param.name in actionInput) && !this.tools[action].inputValidator(actionInput)) { throw new Error(`Missing required parameter: ${param.name}`); } diff --git a/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx b/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx index a9cf849cc..f8fe531ab 100644 --- a/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx +++ b/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx @@ -336,11 +336,13 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { } catch (err) { console.error('Error:', err); // Handle error in processing - this._history.push({ - role: ASSISTANT_ROLE.ASSISTANT, - content: [{ index: 0, type: TEXT_TYPE.ERROR, text: 'Sorry, I encountered an error while processing your request.', citation_ids: null }], - processing_info: [], - }); + runInAction(() => + this._history.push({ + role: ASSISTANT_ROLE.ASSISTANT, + content: [{ index: 0, type: TEXT_TYPE.ERROR, text: `Sorry, I encountered an error while processing your request: ${err} `, citation_ids: null }], + processing_info: [], + }) + ); } finally { runInAction(() => { this._isLoading = false; diff --git a/src/client/views/nodes/chatbot/chatboxcomponents/MessageComponent.tsx b/src/client/views/nodes/chatbot/chatboxcomponents/MessageComponent.tsx index 1a3d4dbc6..4f1d68973 100644 --- a/src/client/views/nodes/chatbot/chatboxcomponents/MessageComponent.tsx +++ b/src/client/views/nodes/chatbot/chatboxcomponents/MessageComponent.tsx @@ -86,6 +86,7 @@ const MessageComponentBox: React.FC<MessageComponentProps> = ({ message, onFollo } // Handle query type content + // bcz: What triggers this section? Where is 'query' added to item? Why isn't it a field? else if ('query' in item) { return ( <span key={i} className="query-text"> @@ -98,7 +99,7 @@ const MessageComponentBox: React.FC<MessageComponentProps> = ({ message, onFollo else { return ( <span key={i}> - <ReactMarkdown>{JSON.stringify(item)}</ReactMarkdown> + <ReactMarkdown>{item.text /* JSON.stringify(item)*/}</ReactMarkdown> </span> ); } diff --git a/src/client/views/nodes/chatbot/tools/BaseTool.ts b/src/client/views/nodes/chatbot/tools/BaseTool.ts index a2cb3927b..8800e2238 100644 --- a/src/client/views/nodes/chatbot/tools/BaseTool.ts +++ b/src/client/views/nodes/chatbot/tools/BaseTool.ts @@ -47,6 +47,18 @@ export abstract class BaseTool<P extends ReadonlyArray<Parameter>> { abstract execute(args: ParametersType<P>): Promise<Observation[]>; /** + * This is a hacky way for a tool to ignore required parameter errors. + * Used by crateDocTool to allow processing of simple arrays of Documents + * where the array doesn't conform to a normal Doc structure. + * @param inputParam + * @returns + */ + // eslint-disable-next-line @typescript-eslint/no-unused-vars + inputValidator(inputParam: ParametersType<readonly Parameter[]>) { + return false; + } + + /** * Generates an action rule object that describes the tool's usage. * This is useful for dynamically generating documentation or for tools that need to expose their parameters at runtime. * @returns An object containing the tool's name, description, and parameter definitions. diff --git a/src/client/views/nodes/chatbot/tools/CreateDocumentTool.ts b/src/client/views/nodes/chatbot/tools/CreateDocumentTool.ts index 34ab9206b..6dc36b0d1 100644 --- a/src/client/views/nodes/chatbot/tools/CreateDocumentTool.ts +++ b/src/client/views/nodes/chatbot/tools/CreateDocumentTool.ts @@ -1,6 +1,6 @@ import { BaseTool } from './BaseTool'; import { Observation } from '../types/types'; -import { ParametersType, ToolInfo } from '../types/tool_types'; +import { Parameter, ParametersType, ToolInfo } from '../types/tool_types'; import { parsedDoc } from '../chatboxcomponents/ChatBox'; import { CollectionViewType } from '../../../../documents/DocumentTypes'; @@ -431,7 +431,10 @@ const createDocToolInfo: ToolInfo<CreateDocToolParamsType> = { description: `Creates one or more documents that best fit the user’s request. If the user requests a "dashboard," first call the search tool and then generate a variety of document types individually, with absolutely a minimum of 20 documents with two stacks of flashcards that are small and it should have a couple nested freeform collections of things, each with different content and color schemes. - For example, create multiple individual documents like "text," "deck," "web", "equation," and "comparison." + For example, create multiple individual documents, including ${Object.keys(documentTypesInfo) + .map(t => '"' + t + '"') + .join(',')} + If the "doc_type" parameter is missing, set it to an empty string (""). Use Decks instead of Flashcards for dashboards. Decks should have at least three flashcards. Really think about what documents are useful to the user. If they ask for a dashboard about the skeletal system, include flashcards, as they would be helpful. Arrange the documents in a grid layout, ensuring that the x and y coordinates are calculated so no documents overlap but they should be directly next to each other with 20 padding in between. @@ -443,7 +446,7 @@ const createDocToolInfo: ToolInfo<CreateDocToolParamsType> = { Ensure web documents use URLs from the search tool if relevant. Each document in a dashboard should be unique and well-differentiated in type and content, without repetition of similar types in any single collection. When creating a dashboard, ensure that it consists of a broad range of document types. - Include a variety of documents, such as text, web, deck, comparison, image, simulation, and equation documents, + Include a variety of documents, such as text, web, deck, comparison, image, and equation documents, each with distinct titles and colors, following the user’s preferences. Do not overuse collections or nest all document types within a single collection; instead, represent document types individually. Use this example for reference: ${finalJsonString} . @@ -469,6 +472,9 @@ export class CreateDocTool extends BaseTool< this._addLinkedDoc = addLinkedDoc; } + override inputValidator(inputParam: ParametersType<readonly Parameter[]>) { + return !!inputParam.data; + } // Executes the tool logic for creating documents async execute( args: ParametersType< @@ -481,8 +487,8 @@ export class CreateDocTool extends BaseTool< > ): Promise<Observation[]> { try { - const parsedDocs = args instanceof Array ? args : [args]; // JSON.parse((args as any).data) as parsedDoc[]; - parsedDocs.forEach(doc => this._addLinkedDoc({ ...doc, _layout_fitWidth: false, _layout_autoHeight: true })); + const parsedDocs = args instanceof Array ? args : Object.keys(args).length === 1 && 'data' in args ? JSON.parse(args.data as string) : [args]; + parsedDocs.forEach((pdoc: parsedDoc) => this._addLinkedDoc({ ...pdoc, _layout_fitWidth: false, _layout_autoHeight: true })); return [{ type: 'text', text: 'Created document.' }]; } catch (error) { return [{ type: 'text', text: 'Error creating text document, ' + error }]; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 55ad543ca..a6870d65b 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1694,8 +1694,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB setTimeout(() => this.EditorView?.dispatch(this.EditorView.state.tr.setSelection(TextSelection.near(this.EditorView.state.doc.resolve(pos)))), 100); setTimeout(() => (this.ProseRef?.children?.[0] as HTMLElement).focus(), 200); }; + + IsFocused = false; @action onFocused = (e: React.FocusEvent): void => { + this.IsFocused = true; // applyDevTools.applyDevTools(this.EditorView); e.stopPropagation(); }; @@ -1779,6 +1782,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB @action onBlur = (e: React.FocusEvent) => { + let ele: HTMLElement | null = e.relatedTarget instanceof HTMLElement ? e.relatedTarget : null; + if (ele?.tabIndex === -1) { + for (; ele; ele = ele?.parentElement) { + if (ele?.className === 'fonticonbox') { + setTimeout(() => this._ref.current?.focus()); + break; + } + } + } + if (ele?.className !== 'fonticonbox') this.IsFocused = false; if (this.ProseRef?.children[0] !== e.nativeEvent.target) return; if (!(this.EditorView?.state.selection instanceof NodeSelection) || this.EditorView.state.selection.node.type !== this.EditorView.state.schema.nodes.footnote) { const stordMarks = this.EditorView?.state.storedMarks?.slice(); diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index c0acbe36f..09994a889 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -180,6 +180,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> { } } } + this.setActiveMarkButtons(this.getActiveMarksOnSelection()); }; // finds font sizes and families in selection @@ -366,10 +367,13 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> { setFontField = (value: string, fontField: 'fitBox' | 'fontSize' | 'fontFamily' | 'fontColor' | 'fontHighlight') => { if (this.TextView && this.view && fontField !== 'fitBox') { - const { text, paragraph } = this.view.state.schema.nodes; - const selNode = this.view.state.selection.$anchor.node(); - if (this.view.state.selection.from === 1 && this.view.state.selection.empty && [undefined, text, paragraph].includes(selNode?.type)) { - this.TextView.dataDoc[this.TextView.fieldKey + `_${fontField}`] = value; + if (!this.TextView.IsFocused) { + Array.from(new Set([...DocumentView.Selected(), this.TextView.DocumentView?.()])) + .filter(v => v?.ComponentView instanceof FormattedTextBox && v.ComponentView.EditorView?.TextView) + .map(v => v!.ComponentView as FormattedTextBox) + .forEach(view => { + view.EditorView!.TextView!.dataDoc[(view.EditorView!.TextView!.fieldKey ?? 'text') + `_${fontField}`] = value; + }); this.view.focus(); } const attrs: { [key: string]: string } = {}; |