aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/apis/gpt/GPT.ts12
-rw-r--r--src/client/documents/DocumentTypes.ts1
-rw-r--r--src/client/documents/Documents.ts5
-rw-r--r--src/client/util/CurrentUserUtils.ts9
-rw-r--r--src/client/views/Main.tsx4
-rw-r--r--src/client/views/nodes/DiagramBox.scss88
-rw-r--r--src/client/views/nodes/DiagramBox.tsx305
7 files changed, 419 insertions, 5 deletions
diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts
index 55667684e..078ac3e55 100644
--- a/src/client/apis/gpt/GPT.ts
+++ b/src/client/apis/gpt/GPT.ts
@@ -5,6 +5,7 @@ enum GPTCallType {
SUMMARY = 'summary',
COMPLETION = 'completion',
EDIT = 'edit',
+ MERMAID = 'mermaid',
DATA = 'data',
}
@@ -24,6 +25,12 @@ const callTypeMap: { [type: string]: GPTCallOpts } = {
summary: { model: 'gpt-3.5-turbo', maxTokens: 256, temp: 0.5, prompt: 'Summarize the text given in simpler terms.' },
edit: { model: 'gpt-3.5-turbo', maxTokens: 256, temp: 0.5, prompt: 'Reword the text.' },
completion: { model: 'gpt-3.5-turbo', maxTokens: 256, temp: 0.5, prompt: "You are a helpful assistant. Answer the user's prompt." },
+ mermaid: {
+ model: 'gpt-4-turbo',
+ maxTokens: 2048,
+ temp: 0,
+ prompt: "(Heres an example of changing color of a pie chart to help you pie title Example \"Red\": 20 \"Blue\": 50 \"Green\": 30 %%{init: {'theme': 'base', 'themeVariables': {'pie1': '#0000FF', 'pie2': '#00FF00', 'pie3': '#FF0000'}}}%% keep in mind that pie1 is the highest since its sorted in descending order. Heres an example of a mindmap: mindmap root((mindmap)) Origins Long history ::icon(fa fa-book) Popularisation British popular psychology author Tony Buzan Research On effectivness<br/>and features On Automatic creation Uses Creative techniques Strategic planning Argument mapping Tools Pen and paper Mermaid. ",
+ },
data: {
model: 'gpt-3.5-turbo',
maxTokens: 256,
@@ -46,7 +53,7 @@ const gptAPICall = async (inputTextIn: string, callType: GPTCallType, prompt?: a
if (lastCall === inputText) return lastResp;
try {
const configuration: ClientOptions = {
- apiKey: process.env.OPENAI_KEY,
+ apiKey: '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',
dangerouslyAllowBrowser: true,
};
lastCall = inputText;
@@ -60,9 +67,8 @@ const gptAPICall = async (inputTextIn: string, callType: GPTCallType, prompt?: a
const response = await openai.chat.completions.create({
model: opts.model,
- max_tokens: opts.maxTokens,
+ messages: messages,
temperature: opts.temp,
- messages,
});
lastResp = response.choices[0].message.content ?? '';
return lastResp;
diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index 0520dc375..53ee87908 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -12,6 +12,7 @@ export enum DocumentType {
REC = 'recording',
PDF = 'pdf',
INK = 'ink',
+ DIAGRAM='diagram',
SCREENSHOT = 'screenshot',
FONTICON = 'fonticonbox',
SEARCH = 'search', // search query
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index ef1c709f0..19b8448f1 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -247,6 +247,8 @@ export class DocumentOptions {
layout_hideResizeHandles?: BOOLt = new BoolInfo('whether to hide the resize handles when selected');
layout_hideLinkButton?: BOOLt = new BoolInfo('whether the blue link counter button should be hidden');
layout_hideDecorationTitle?: BOOLt = new BoolInfo('whether to suppress the document decortations title when selected');
+ _layout_hideContextMenu?: BOOLt = new BoolInfo('whether the context menu can be shown');
+ layout_diagramEditor?: STRt = new StrInfo('specify the JSX string for a diagram editor view');
layout_hideContextMenu?: BOOLt = new BoolInfo('whether the context menu can be shown');
layout_borderRounding?: string;
_layout_borderRounding?: STRt = new StrInfo('amount of rounding to document view corners');
@@ -760,6 +762,9 @@ export namespace Docs {
export function ComparisonDocument(options: DocumentOptions = { title: 'Comparison Box' }) {
return InstanceFromProto(Prototypes.get(DocumentType.COMPARISON), undefined, options);
}
+ export function DiagramDocument(options: DocumentOptions = { title: 'bruh box' }) {
+ return InstanceFromProto(Prototypes.get(DocumentType.DIAGRAM), undefined, options);
+ }
// eslint-disable-next-line default-param-last
export function AudioDocument(url: string, options: DocumentOptions = {}, overwriteDoc?: Doc) {
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 09250d29d..92bfefc5f 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -21,6 +21,7 @@ import { DashboardView } from "../views/DashboardView";
import { OverlayView } from "../views/OverlayView";
import { CollectionTreeView } from "../views/collections/CollectionTreeView";
import { TreeViewType } from "../views/collections/CollectionTreeViewType";
+import { CollectionView } from "../views/collections/CollectionView";
import { Colors } from "../views/global/globalEnums";
import { mediaState } from "../views/nodes/AudioBox";
import { ButtonType, FontIconBox } from "../views/nodes/FontIconBox/FontIconBox";
@@ -361,6 +362,8 @@ pie title Minerals in my tap water
{key: "Collection", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 150, _height: 100, _layout_fitWidth: true }},
{key: "Webpage", creator: opts => Docs.Create.WebDocument("",opts), opts: { _width: 400, _height: 512, _nativeWidth: 850, data_useCors: true, }},
{key: "Comparison", creator: Docs.Create.ComparisonDocument, opts: { _width: 300, _height: 300 }},
+ {key: "Diagram", creator: Docs.Create.DiagramDocument, opts: { _width: 300, _height: 300, _type_collection: CollectionViewType.Freeform, layout_diagramEditor: CollectionView.LayoutString("data") }, scripts: { onPaint: `toggleDetail(documentView, "diagramEditor","")`}},
+ {key: "Audio", creator: opts => Docs.Create.AudioDocument(nullAudio, opts),opts: { _width: 200, _height: 100, }},
{key: "Audio", creator: opts => Docs.Create.AudioDocument(nullAudio, opts),opts: { _width: 200, _height: 100, _layout_fitWidth: true, }},
{key: "Map", creator: opts => Docs.Create.MapDocument([], opts), opts: { _width: 800, _height: 600, _layout_fitWidth: true, }},
{key: "Screengrab", creator: Docs.Create.ScreenshotDocument, opts: { _width: 400, _height: 200 }},
@@ -382,7 +385,10 @@ pie title Minerals in my tap water
{key: "Plotly", creator: plotlyView, opts: { _width: 300, _height: 300, }},
];
- emptyThings.forEach(thing => DocUtils.AssignDocField(doc, "empty"+thing.key, (opts) => thing.creator(opts), {...standardOps(thing.key), ...thing.opts}, undefined, thing.scripts, thing.funcs));
+ emptyThings.forEach(
+ thing =>{ DocUtils.AssignDocField(doc, "empty"+thing.key, (opts) => thing.creator(opts), {...standardOps(thing.key), ...thing.opts}, undefined, thing.scripts, thing.funcs);
+ console.log(thing.key)
+ });
return [
{ toolTip: "Tap or drag to create a note", title: "Note", icon: "sticky-note", dragFactory: doc.emptyNote as Doc, clickFactory: DocCast(doc.emptyNote)},
@@ -396,6 +402,7 @@ pie title Minerals in my tap water
{ toolTip: "Tap or drag to create a collection", title: "Col", icon: "folder", dragFactory: doc.emptyCollection as Doc, clickFactory: DocCast(doc.emptyTab)},
{ toolTip: "Tap or drag to create a webpage", title: "Web", icon: "globe-asia", dragFactory: doc.emptyWebpage as Doc, clickFactory: DocCast(doc.emptyWebpage)},
{ toolTip: "Tap or drag to create a comparison box", title: "Compare", icon: "columns", dragFactory: doc.emptyComparison as Doc, clickFactory: DocCast(doc.emptyComparison)},
+ { toolTip: "Tap or drag to create a diagram", title: "Diagram", icon: "tree", dragFactory: doc.emptyDiagram as Doc, clickFactory: DocCast(doc.emptyDiagram)},
{ toolTip: "Tap or drag to create an audio recorder", title: "Audio", icon: "microphone", dragFactory: doc.emptyAudio as Doc, clickFactory: DocCast(doc.emptyAudio), openFactoryLocation: OpenWhere.overlay},
{ toolTip: "Tap or drag to create a map", title: "Map", icon: "map-marker-alt", dragFactory: doc.emptyMap as Doc, clickFactory: DocCast(doc.emptyMap)},
{ toolTip: "Tap or drag to create a chat assistant", title: "Assistant Chat", icon: "book",dragFactory: doc.emptyChat as Doc, clickFactory: DocCast(doc.emptyChat)},
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 149de59b2..43b9a6b39 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -27,9 +27,10 @@ import { CollectionSchemaView } from './collections/collectionSchema/CollectionS
import { SchemaRowBox } from './collections/collectionSchema/SchemaRowBox';
import './global/globalScripts';
import { AudioBox } from './nodes/AudioBox';
-import { ComparisonBox } from './nodes/ComparisonBox';
import { ChatBox } from './nodes/ChatBox/ChatBox';
+import { ComparisonBox } from './nodes/ComparisonBox';
import { DataVizBox } from './nodes/DataVizBox/DataVizBox';
+import { DiagramBox } from './nodes/DiagramBox';
import { DocumentContentsView, HTMLtag } from './nodes/DocumentContentsView';
import { EquationBox } from './nodes/EquationBox';
import { FieldView } from './nodes/FieldView';
@@ -138,6 +139,7 @@ FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0, message: 'cache' };
ScreenshotBox,
DataVizBox,
ChatBox,
+ DiagramBox,
HTMLtag,
ComparisonBox,
LoadingBox,
diff --git a/src/client/views/nodes/DiagramBox.scss b/src/client/views/nodes/DiagramBox.scss
new file mode 100644
index 000000000..d2749f1ad
--- /dev/null
+++ b/src/client/views/nodes/DiagramBox.scss
@@ -0,0 +1,88 @@
+.DIYNodeBox {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+
+ .DIYNodeBox-wrapper {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ .DIYNodeBox {
+ /* existing code */
+
+ .DIYNodeBox-iframe {
+ height: 100%;
+ width: 100%;
+ border: none;
+
+ }
+ }
+
+ .search-bar {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ padding: 10px;
+
+ input[type="text"] {
+ flex: 1;
+ margin-right: 10px;
+ }
+
+ button {
+ padding: 5px 10px;
+ }
+ }
+
+ .content {
+ flex: 1;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width:100%;
+ height:100%;
+ .diagramBox{
+ flex: 1;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width:100%;
+ height:100%;
+ svg{
+ flex: 1;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width:100%;
+ height:100%;
+ }
+ }
+ }
+
+ .loading-circle {
+ position: relative;
+ width: 50px;
+ height: 50px;
+ border-radius: 50%;
+ border: 3px solid #ccc;
+ border-top-color: #333;
+ animation: spin 1s infinite linear;
+ }
+
+ @keyframes spin {
+ 0% {
+ transform: rotate(0deg);
+ }
+ 100% {
+ transform: rotate(360deg);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx
new file mode 100644
index 000000000..fa7e5868a
--- /dev/null
+++ b/src/client/views/nodes/DiagramBox.tsx
@@ -0,0 +1,305 @@
+import { makeObservable, observable, action, reaction } from 'mobx';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent';
+import { StyleProp } from '../StyleProvider';
+import './DiagramBox.scss';
+import { FieldView, FieldViewProps } from './FieldView';
+import { PinProps, PresBox } from './trails';
+import mermaid from 'mermaid';
+import { Doc, DocListCast } from '../../../fields/Doc';
+import { List } from '../../../fields/List';
+import { RichTextField } from '../../../fields/RichTextField';
+import { ContextMenu } from '../ContextMenu';
+import { gptAPICall, GPTCallType } from '../../apis/gpt/GPT';
+import { ChatCompletionMessageParam } from 'openai/resources/chat/completions';
+import OpenAI, { ClientOptions } from 'openai';
+import { line } from 'd3';
+import { InkingStroke } from '../InkingStroke';
+import { DocumentManager } from '../../util/DocumentManager';
+import { C } from '@fullcalendar/core/internal-common';
+import { Docs } from '../../documents/Documents';
+import { NumCast } from '../../../fields/Types';
+import { LinkManager } from '../../util/LinkManager';
+import { CsvCast, DocCast, StrCast } from '../../../fields/Types';
+import { DocumentType } from '../../documents/DocumentTypes';
+
+@observer
+export class DiagramBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
+ public static LayoutString(fieldKey: string) {
+ return FieldView.LayoutString(DiagramBox, fieldKey);
+ }
+ private _ref: React.RefObject<HTMLDivElement> = React.createRef();
+ private _dragRef = React.createRef<HTMLDivElement>();
+ constructor(props: FieldViewProps) {
+ super(props);
+ makeObservable(this);
+ }
+
+ @observable inputValue = '';
+ @observable loading = false;
+ @observable errorMessage = '';
+ @observable mermaidCode = '';
+
+ @action handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+ this.inputValue = e.target.value;
+ };
+ async componentDidMount() {
+ this._props.setContentViewBox?.(this);
+ mermaid.initialize({
+ securityLevel: 'loose',
+ startOnLoad: true,
+ flowchart: { useMaxWidth: true, htmlLabels: true, curve: 'cardinal' },
+ });
+ this.mermaidCode = 'asdasdasd';
+ let docArray: Doc[] = DocListCast(this.Document.data);
+ let mermaidCodeDoc = docArray.filter(doc => doc.type == 'rich text');
+ mermaidCodeDoc = mermaidCodeDoc.filter(doc => (doc.text as RichTextField).Text == 'mermaidCodeTitle');
+ if (mermaidCodeDoc[0]) {
+ if (typeof mermaidCodeDoc[0].title == 'string') {
+ console.log(mermaidCodeDoc[0].title);
+ if (mermaidCodeDoc[0].title != '') {
+ this.renderMermaidAsync(mermaidCodeDoc[0].title);
+ }
+ }
+ }
+ //this will create a text doc far away where the user cant to save the mermaid code, where it will then be accessed when flipped to the diagram box side
+ //the code is stored in the title since it is much easier to change than in the text
+ else {
+ DocumentManager.Instance.AddViewRenderedCb(this.Document, docViewForYourCollection => {
+ if (docViewForYourCollection && docViewForYourCollection.ComponentView) {
+ if (docViewForYourCollection.ComponentView.addDocument && docViewForYourCollection.ComponentView.removeDocument) {
+ let newDoc = Docs.Create.TextDocument('mermaidCodeTitle', { title: '', x: 9999 + NumCast(this.layoutDoc._width), y: 9999 });
+ docViewForYourCollection.ComponentView?.addDocument(newDoc);
+ }
+ }
+ });
+ }
+ console.log(this.Document.title);
+ //this is so that ever time a new doc, text node or ink node, is created, this.createMermaidCode will run which will create a save
+ reaction(
+ () => DocListCast(this.Document.data),
+ docs => {
+ console.log('reaction happened');
+ this.convertDrawingToMermaidCode();
+ },
+ { fireImmediately: true }
+ );
+ }
+ renderMermaid = async (str: string) => {
+ try {
+ const { svg, bindFunctions } = await this.mermaidDiagram(str);
+ return { svg, bindFunctions };
+ } catch (error) {
+ console.error('Error rendering mermaid diagram:', error);
+ return { svg: '', bindFunctions: undefined };
+ }
+ };
+ mermaidDiagram = async (str: string) => {
+ return await mermaid.render('graph' + Date.now(), str);
+ };
+
+ async renderMermaidAsync(mermaidCode: string) {
+ try {
+ const { svg, bindFunctions } = await this.renderMermaid(mermaidCode);
+ const dashDiv = document.getElementById('dashDiv' + this.Document.title);
+ if (dashDiv) {
+ dashDiv.innerHTML = svg;
+ if (bindFunctions) {
+ bindFunctions(dashDiv);
+ }
+ }
+ } catch (error) {
+ console.error('Error rendering Mermaid:', error);
+ }
+ }
+ @action handleRenderClick = () => {
+ this.generateMermaidCode();
+ };
+ @action async generateMermaidCode() {
+ console.log('Generating Mermaid Code');
+ this.loading = true;
+ let prompt = '';
+ // let docArray: Doc[] = DocListCast(this.Document.data);
+ // let mermaidCodeDoc = docArray.filter(doc => doc.type == 'rich text')
+ // mermaidCodeDoc=mermaidCodeDoc.filter(doc=>(doc.text as RichTextField).Text=='mermaidCodeTitle')
+ // if(mermaidCodeDoc[0]){
+ // console.log(mermaidCodeDoc[0].title)
+ // if(typeof mermaidCodeDoc[0].title=='string'){
+ // console.log(mermaidCodeDoc[0].title)
+ // if(mermaidCodeDoc[0].title!=""){
+ // prompt="Edit this code "+this.inputValue+": "+mermaidCodeDoc[0].title
+ // console.log("you have to see me")
+ // }
+ // }
+ // }
+ // else{
+ prompt = 'Write this in mermaid code and only give me the mermaid code: ' + this.inputValue;
+ console.log('there is no text save');
+ //}
+ let res = await gptAPICall(prompt, GPTCallType.MERMAID);
+ this.loading = false;
+ if (res == 'Error connecting with API.') {
+ // If GPT call failed
+ console.error('GPT call failed');
+ this.errorMessage = 'GPT call failed; please try again.';
+ } else if (res != null) {
+ // If GPT call succeeded, set htmlCode;;; TODO: check if valid html
+ if (this.isValidCode(res)) {
+ this.mermaidCode = res;
+ console.log('GPT call succeeded:' + res);
+ this.errorMessage = '';
+ } else {
+ console.error('GPT call succeeded but invalid html; please try again.');
+ this.errorMessage = 'GPT call succeeded but invalid html; please try again.';
+ }
+ }
+ this.renderMermaidAsync.call(this, this.removeWords(this.mermaidCode));
+ this.loading = false;
+ }
+ isValidCode = (html: string) => {
+ return true;
+ };
+ removeWords(inputStr: string) {
+ inputStr = inputStr.replace('```mermaid', '');
+ return inputStr.replace('```', '');
+ }
+ //method to convert the drawings on collection node side the mermaid code
+ async convertDrawingToMermaidCode() {
+ let mermaidCode = '';
+ let diagramExists = false;
+ if (this.Document.data instanceof List) {
+ let docArray: Doc[] = DocListCast(this.Document.data);
+ let rectangleArray = docArray.filter(doc => doc.title == 'rectangle' || doc.title == 'circle');
+ let lineArray = docArray.filter(doc => doc.title == 'line' || doc.title == 'stroke');
+ let textArray = docArray.filter(doc => doc.type == 'rich text');
+ const timeoutPromise = () =>
+ new Promise(resolve => {
+ setTimeout(resolve, 0);
+ });
+ await timeoutPromise();
+ let inkStrokeArray = lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).filter(inkView => inkView?.ComponentView instanceof InkingStroke);
+ console.log(inkStrokeArray.length);
+ console.log(lineArray.length);
+ if (inkStrokeArray[0] && inkStrokeArray.length == lineArray.length) {
+ mermaidCode = 'graph TD;';
+ let inkingStrokeArray = inkStrokeArray.map(stroke => stroke?.ComponentView);
+ for (let i = 0; i < rectangleArray.length; i++) {
+ const rectangle = rectangleArray[i];
+ for (let j = 0; j < lineArray.length; j++) {
+ let inkScaleX = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkScaleX;
+ let inkScaleY = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkScaleY;
+ let inkStrokeXArray = (inkingStrokeArray[j] as InkingStroke)
+ ?.inkScaledData()
+ .inkData.map(coord => coord.X)
+ .map(doc => doc * inkScaleX);
+ let inkStrokeYArray = (inkingStrokeArray[j] as InkingStroke)
+ ?.inkScaledData()
+ .inkData.map(coord => coord.Y)
+ .map(doc => doc * inkScaleY);
+ console.log(inkingStrokeArray.length);
+ console.log(lineArray.length);
+ //need to minX and minY to since the inkStroke.x and.y is not relative to the doc. so I have to do some calcluations
+ let minX: number = Math.min(...inkStrokeXArray);
+ let minY: number = Math.min(...inkStrokeYArray);
+ let startX = inkStrokeXArray[0] - minX + (lineArray[j]?.x as number);
+ let startY = inkStrokeYArray[0] - minY + (lineArray[j]?.y as number);
+ let endX = inkStrokeXArray[inkStrokeXArray.length - 1] - minX + (lineArray[j].x as number);
+ let endY = inkStrokeYArray[inkStrokeYArray.length - 1] - minY + (lineArray[j].y as number);
+ if (this.isPointInBox(rectangle, [startX, startY])) {
+ for (let k = 0; k < rectangleArray.length; k++) {
+ const rectangle2 = rectangleArray[k];
+ if (this.isPointInBox(rectangle2, [endX, endY]) && typeof rectangle.x === 'number' && typeof rectangle2.x === 'number') {
+ diagramExists = true;
+ const linkedDocs: Doc[] = LinkManager.Instance.getAllRelatedLinks(lineArray[j]).map(d => DocCast(LinkManager.getOppositeAnchor(d, lineArray[j])));
+ console.log(linkedDocs.length);
+ if (linkedDocs.length != 0) {
+ let linkedText = (linkedDocs[0].text as RichTextField).Text;
+ mermaidCode += Math.abs(rectangle.x) + this.getTextInBox(rectangle, textArray) + '-->|' + linkedText + '|' + Math.abs(rectangle2.x) + this.getTextInBox(rectangle2, textArray) + ';';
+ } else {
+ mermaidCode += Math.abs(rectangle.x) + this.getTextInBox(rectangle, textArray) + '-->' + Math.abs(rectangle2.x) + this.getTextInBox(rectangle2, textArray) + ';';
+ }
+ }
+ }
+ }
+ }
+ }
+ //this will save the text
+ DocumentManager.Instance.AddViewRenderedCb(this.Document, docViewForYourCollection => {
+ if (docViewForYourCollection && docViewForYourCollection.ComponentView) {
+ if (docViewForYourCollection.ComponentView.addDocument && docViewForYourCollection.ComponentView.removeDocument) {
+ let docArray: Doc[] = DocListCast(this.Document.data);
+ docArray = docArray.filter(doc => doc.type == 'rich text');
+ let mermaidCodeDoc = docArray.filter(doc => (doc.text as RichTextField).Text == 'mermaidCodeTitle');
+ if (mermaidCodeDoc[0]) {
+ if (diagramExists) {
+ mermaidCodeDoc[0].title = mermaidCode;
+ } else {
+ mermaidCodeDoc[0].title = '';
+ }
+ }
+ }
+ }
+ });
+ }
+ }
+ }
+ testInkingStroke = () => {
+ if (this.Document.data instanceof List) {
+ let docArray: Doc[] = DocListCast(this.Document.data);
+ let lineArray = docArray.filter(doc => doc.title == 'line' || doc.title == 'stroke');
+ setTimeout(() => {
+ let inkStrokeArray = lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).filter(inkView => inkView?.ComponentView instanceof InkingStroke);
+ console.log(inkStrokeArray);
+ });
+ }
+ };
+ getTextInBox = (box: Doc, richTextArray: Doc[]): string => {
+ for (let i = 0; i < richTextArray.length; i++) {
+ let textDoc = richTextArray[i];
+ if (typeof textDoc.x === 'number' && typeof textDoc.y === 'number' && typeof box.x === 'number' && typeof box.height === 'number' && typeof box.width === 'number' && typeof box.y === 'number') {
+ if (textDoc.x > box.x && textDoc.x < box.x + box.width && textDoc.y > box.y && textDoc.y < box.y + box.height) {
+ if (box.title == 'rectangle') {
+ return '(' + (textDoc.text as RichTextField)?.Text + ')';
+ }
+ if (box.title == 'circle') {
+ return '((' + (textDoc.text as RichTextField)?.Text + '))';
+ }
+ }
+ }
+ }
+ return '( )';
+ };
+ isPointInBox = (box: Doc, line: number[]): boolean => {
+ if (typeof line[0] === 'number' && typeof box.x === 'number' && typeof box.width === 'number' && typeof box.height === 'number' && typeof box.y === 'number' && typeof line[1] === 'number') {
+ return line[0] < box.x + box.width && line[0] > box.x && line[1] > box.y && line[1] < box.y + box.height;
+ } else {
+ return false;
+ }
+ };
+
+ render() {
+ return (
+ <div ref={this._ref} className="DIYNodeBox">
+ <div ref={this._dragRef} className="DIYNodeBox-wrapper">
+ <div className="search-bar">
+ <input type="text" value={this.inputValue} onChange={this.handleInputChange} />
+ <button onClick={this.handleRenderClick}>Generate</button>
+ </div>
+ <div className="content">
+ {this.mermaidCode ? (
+ <div id={'dashDiv' + this.Document.title} className="diagramBox"></div>
+ ) : (
+ <div>{this.loading ? <div className="loading-circle"></div> : <div>{this.errorMessage ? this.errorMessage : 'Insert prompt to generate diagram'}</div>}</div>
+ )}
+ </div>
+ </div>
+ </div>
+ );
+ }
+}
+
+Docs.Prototypes.TemplateMap.set(DocumentType.DIAGRAM, {
+ layout: { view: DiagramBox, dataField: 'dadta' },
+ options: { _height: 300, _layout_fitWidth: true, _layout_nativeDimEditable: true, _layout_reflowVertical: true, waitForDoubleClickToClick: 'always', systemIcon: 'BsGlobe' },
+});