aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/views/FilterPanel.tsx170
-rw-r--r--src/client/views/global/globalScripts.ts14
-rw-r--r--src/client/views/nodes/IconTagBox.tsx22
-rw-r--r--src/client/views/pdf/GPTPopup/GPTPopup.tsx282
4 files changed, 204 insertions, 284 deletions
diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx
index f3f447e22..8133a4d0d 100644
--- a/src/client/views/FilterPanel.tsx
+++ b/src/client/views/FilterPanel.tsx
@@ -1,34 +1,29 @@
/* eslint-disable react/jsx-props-no-spreading */
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Tooltip } from '@mui/material';
import { action, computed, makeObservable, observable, ObservableMap } from 'mobx';
-import { observer } from 'mobx-react';
+import { observer, useLocalObservable } from 'mobx-react';
import * as React from 'react';
+import { useEffect, useRef } from 'react';
import { Handles, Rail, Slider, Ticks, Tracks } from 'react-compound-slider';
import { AiOutlineMinusSquare, AiOutlinePlusSquare } from 'react-icons/ai';
import { CiCircleRemove } from 'react-icons/ci';
import { Doc, DocListCast, Field, FieldType, LinkedTo, StrListCast } from '../../fields/Doc';
+import { DocData } from '../../fields/DocSymbols';
import { Id } from '../../fields/FieldSymbols';
import { List } from '../../fields/List';
import { RichTextField } from '../../fields/RichTextField';
+import { DocCast, StrCast } from '../../fields/Types';
+import { Button, CurrentUserUtils } from '../util/CurrentUserUtils';
import { SearchUtil } from '../util/SearchUtil';
import { SnappingManager } from '../util/SnappingManager';
-import { undoable, undoBatch } from '../util/UndoManager';
+import { undoable } from '../util/UndoManager';
import { FieldsDropdown } from './FieldsDropdown';
import './FilterPanel.scss';
import { DocumentView } from './nodes/DocumentView';
+import { ButtonType } from './nodes/FontIconBox/FontIconBox';
import { Handle, Tick, TooltipRail, Track } from './nodes/SliderBox-components';
import { ObservableReactComponent } from './ObservableReactComponent';
-import { Button } from '../util/CurrentUserUtils';
-import { ButtonType } from './nodes/FontIconBox/FontIconBox';
-import { DocCast } from '../../fields/Types';
-import { CurrentUserUtils } from '../util/CurrentUserUtils';
-import { StrCast } from '../../fields/Types';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { DocData } from '../../fields/DocSymbols';
-import { Tooltip } from '@mui/material';
-import { useLocalObservable } from 'mobx-react';
-import { useRef } from 'react';
-import { useEffect } from 'react';
-
interface filterProps {
Document: Doc;
@@ -37,8 +32,7 @@ interface filterProps {
@observer
export class FilterPanel extends ObservableReactComponent<filterProps> {
@observable _selectedFacetHeaders = new Set<string>();
- public static Instance: FilterPanel;
-
+ public static Instance: FilterPanel;
constructor(props: filterProps) {
super(props);
@@ -227,7 +221,7 @@ export class FilterPanel extends ObservableReactComponent<filterProps> {
};
/**
- * Allows users to add a filter hotkey to the properties panel. Will also update the multitoggle at the top menu and the
+ * Allows users to add a filter hotkey to the properties panel. Will also update the multitoggle at the top menu and the
* icontags tht are displayed on the documents themselves
* @param hotKey tite of the new hotkey
*/
@@ -246,21 +240,20 @@ export class FilterPanel extends ObservableReactComponent<filterProps> {
scripts: { onClick: '{ return handleTags(this.toolType, _readOnly_);}' },
};
- const currHotKeys = StrListCast(Doc.UserDoc().myFilterHotKeyTitles)
+ const currHotKeys = StrListCast(Doc.UserDoc().myFilterHotKeyTitles);
- Doc.UserDoc().myFilterHotKeyTitles = new List<string>(currHotKeys.concat(hotKey))
+ Doc.UserDoc().myFilterHotKeyTitles = new List<string>(currHotKeys.concat(hotKey));
- Doc.UserDoc()[hotKey] = 'bolt'
+ Doc.UserDoc()[hotKey] = 'bolt';
const newBtn = CurrentUserUtils.setupContextMenuBtn(newKey, filter);
newBtn.isSystem = newBtn[DocData].isSystem = undefined;
- const subDocs = DocListCast(filter.data)
- const opts = subDocs[subDocs.length-1]
+ const subDocs = DocListCast(filter.data);
+ const opts = subDocs[subDocs.length - 1];
Doc.AddDocToList(filter, 'data', newBtn, opts, true);
- }
+ };
-
/**
* Renders the newly formed hotkey icon buttons
* @returns the buttons to be rendered
@@ -268,16 +261,16 @@ export class FilterPanel extends ObservableReactComponent<filterProps> {
hotKeyButtons = () => {
const selected = DocumentView.SelectedDocs().lastElement();
const hotKeys = StrListCast(Doc.UserDoc().myFilterHotKeyTitles);
-
+
// Selecting a button should make it so that the icon on the top filter panel becomes said icon
const buttons = hotKeys.map((hotKey, i) => (
<Tooltip key={hotKey} title={<div className="dash-tooltip">Click to customize this hotkey's icon</div>}>
- <HotKeyIconButton hotKey={hotKey} selected = {selected}/>
+ <HotKeyIconButton hotKey={hotKey} selected={selected} />
</Tooltip>
));
-
+
return buttons;
- }
+ };
// @observable iconPanelMap: Map<string, number> = new Map();
@@ -465,18 +458,16 @@ export class FilterPanel extends ObservableReactComponent<filterProps> {
}
}
-
-
interface HotKeyButtonProps {
hotKey: string;
- selected?: Doc
+ selected?: Doc;
}
/**
- * Renders the buttons that correspond to each icon tag in the properties view. Allows users to change the icon,
- * title, and delete.
+ * Renders the buttons that correspond to each icon tag in the properties view. Allows users to change the icon,
+ * title, and delete.
*/
-const HotKeyIconButton: React.FC<HotKeyButtonProps> = observer(({ hotKey, selected}) => {
+const HotKeyIconButton: React.FC<HotKeyButtonProps> = observer(({ hotKey, selected }) => {
const state = useLocalObservable(() => ({
isActive: false,
isEditing: false,
@@ -496,7 +487,7 @@ const HotKeyIconButton: React.FC<HotKeyButtonProps> = observer(({ hotKey, select
},
setHotKey(newHotKey: string) {
this.myHotKey = newHotKey;
- }
+ },
}));
const panelRef = useRef<HTMLDivElement>(null);
@@ -506,31 +497,29 @@ const HotKeyIconButton: React.FC<HotKeyButtonProps> = observer(({ hotKey, select
state.toggleActive();
};
- const hotKeys = StrListCast(Doc.UserDoc().myFilterHotKeyTitles)
+ const hotKeys = StrListCast(Doc.UserDoc().myFilterHotKeyTitles);
const buttons = DocCast(Doc.UserDoc().myContextMenuBtns);
const filter = DocCast(buttons.Filter);
/**
* The doc of the button in the context menu that corresponds to the current hotkey
- * @returns
+ * @returns
*/
const myHotKeyDoc = () => {
- const hotKeyDocs = DocListCast(filter.data)
- return hotKeyDocs.filter(k => StrCast(k.title) === hotKey)[0]
-
- }
+ const hotKeyDocs = DocListCast(filter.data);
+ return hotKeyDocs.filter(k => StrCast(k.title) === hotKey)[0];
+ };
/**
- * Removes a hotkey from list
+ * Removes a hotkey from list
*/
const removeHotKey = () => {
Doc.RemoveDocFromList(filter, 'data', myHotKeyDoc());
-
- }
+ };
/**
* Deselects if the user clicks outside the button
- * @param event
+ * @param event
*/
const handleClickOutside = (event: MouseEvent) => {
if (panelRef.current && !panelRef.current.contains(event.target as Node)) {
@@ -538,24 +527,23 @@ const HotKeyIconButton: React.FC<HotKeyButtonProps> = observer(({ hotKey, select
if (state.isEditing) {
state.stopEditing();
- updateFromInput()
+ updateFromInput();
}
}
};
/**
- * Updates the list of hotkeys based on the users input. replaces the old title with the new one and then assigns this new
+ * Updates the list of hotkeys based on the users input. replaces the old title with the new one and then assigns this new
* hotkey with the current icon
*/
- const updateFromInput = undoable (() => {
- const myDoc = myHotKeyDoc()
- Doc.UserDoc().myFilterHotKeyTitles = new List<string>(hotKeys.map(k => k === hotKey ? state.myHotKey : k));
- Doc.UserDoc()[state.myHotKey] = StrCast(Doc.UserDoc()[hotKey])
- Doc.UserDoc()[hotKey] = ''
- myDoc.title = state.myHotKey
- myDoc.toolTip = `Click to toggle the ${state.myHotKey}'s group's visibility`
- }, '')
-
+ const updateFromInput = undoable(() => {
+ const myDoc = myHotKeyDoc();
+ Doc.UserDoc().myFilterHotKeyTitles = new List<string>(hotKeys.map(k => (k === hotKey ? state.myHotKey : k)));
+ Doc.UserDoc()[state.myHotKey] = StrCast(Doc.UserDoc()[hotKey]);
+ Doc.UserDoc()[hotKey] = '';
+ myDoc.title = state.myHotKey;
+ myDoc.toolTip = `Click to toggle the ${state.myHotKey}'s group's visibility`;
+ }, '');
useEffect(() => {
document.addEventListener('mousedown', handleClickOutside);
@@ -564,18 +552,21 @@ const HotKeyIconButton: React.FC<HotKeyButtonProps> = observer(({ hotKey, select
};
}, []);
- const iconOpts = ['star', 'heart', 'bolt', 'satellite', 'palette', 'robot', 'lightbulb', 'highlighter', 'book', 'chalkboard' ];
+ const iconOpts = ['star', 'heart', 'bolt', 'satellite', 'palette', 'robot', 'lightbulb', 'highlighter', 'book', 'chalkboard'];
/**
* Panel of icons the user can choose from to represent their tag
*/
const iconPanel = iconOpts.map((icon, i) => (
- <button key={i} onClick={undoable((e: React.MouseEvent) => {
- e.stopPropagation;
- Doc.UserDoc()[hotKey] = icon;
- myHotKeyDoc().icon = icon
- }, '')} className='icon-panel-button'>
- <FontAwesomeIcon icon={icon as any} color = {SnappingManager.userColor}/>
+ <button
+ key={i}
+ onClick={undoable((e: React.MouseEvent) => {
+ e.stopPropagation;
+ Doc.UserDoc()[hotKey] = icon;
+ myHotKeyDoc().icon = icon;
+ }, '')}
+ className="icon-panel-button">
+ <FontAwesomeIcon icon={icon as any} color={SnappingManager.userColor} />
</button>
));
@@ -584,62 +575,57 @@ const HotKeyIconButton: React.FC<HotKeyButtonProps> = observer(({ hotKey, select
*/
return (
- <div className={`filterHotKey-button`}
- onClick={(e) => {
+ <div
+ className={`filterHotKey-button`}
+ onClick={e => {
e.stopPropagation();
state.startEditing();
setTimeout(() => inputRef.current?.focus(), 0);
- }}
- >
+ }}>
<div className={`hotKey-icon-button ${state.isActive ? 'active' : ''}`} ref={panelRef}>
<Tooltip title={<div className="dash-tooltip">Click to customize this hotkey's icon</div>}>
<button
type="button"
- className='hotKey-icon'
+ className="hotKey-icon"
onClick={(e: React.MouseEvent) => {
- e.stopPropagation();
+ e.stopPropagation();
handleClick();
- }}
- >
- <FontAwesomeIcon icon={Doc.UserDoc()[hotKey] as any} size="2xl" color={SnappingManager.userColor}/>
+ }}>
+ <FontAwesomeIcon icon={Doc.UserDoc()[hotKey] as any} size="2xl" color={SnappingManager.userColor} />
</button>
</Tooltip>
- {state.isActive && (
- <div className="icon-panel">
- {iconPanel}
- </div>
- )}
+ {state.isActive && <div className="icon-panel">{iconPanel}</div>}
</div>
{state.isEditing ? (
<input
ref={inputRef}
type="text"
value={state.myHotKey.toUpperCase()}
- onChange={(e) => state.setHotKey(e.target.value)}
+ onChange={e => state.setHotKey(e.target.value)}
onBlur={() => {
state.stopEditing();
- updateFromInput()
+ updateFromInput();
}}
- onKeyDown={(e) => {
+ onKeyDown={e => {
if (e.key === 'Enter') {
state.stopEditing();
- updateFromInput()
-
+ updateFromInput();
}
}}
- className='hotkey-title-input'
+ className="hotkey-title-input"
/>
) : (
- <p className='hotkey-title'>{hotKey.toUpperCase()}</p>
+ <p className="hotkey-title">{hotKey.toUpperCase()}</p>
)}
- <button className='hotKey-close' onClick={(e: React.MouseEvent) => {
- e.stopPropagation();
- Doc.UserDoc().myFilterHotKeyTitles = new List<string>(hotKeys.filter(k => k !== hotKey));
- removeHotKey()
-
- }}>
- <FontAwesomeIcon icon={'x' as any} color={SnappingManager.userColor}/>
+ <button
+ className="hotKey-close"
+ onClick={(e: React.MouseEvent) => {
+ e.stopPropagation();
+ Doc.UserDoc().myFilterHotKeyTitles = new List<string>(hotKeys.filter(k => k !== hotKey));
+ removeHotKey();
+ }}>
+ <FontAwesomeIcon icon={'x' as any} color={SnappingManager.userColor} />
</button>
</div>
);
-}) \ No newline at end of file
+});
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index 99bd537b1..6ccbf28f8 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -2,13 +2,13 @@
import { Colors } from 'browndash-components';
import { action, runInAction } from 'mobx';
import { aggregateBounds } from '../../../Utils';
-import { Doc, DocListCast, Opt } from '../../../fields/Doc';
+import { Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc';
import { DocData } from '../../../fields/DocSymbols';
import { InkTool } from '../../../fields/InkField';
import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types';
import { WebField } from '../../../fields/URLField';
import { Gestures } from '../../../pen-gestures/GestureTypes';
-import { DocumentType } from '../../documents/DocumentTypes';
+import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
import { LinkManager } from '../../util/LinkManager';
import { ScriptingGlobals } from '../../util/ScriptingGlobals';
import { UndoManager, undoable } from '../../util/UndoManager';
@@ -35,16 +35,12 @@ import { ImageBox } from '../nodes/ImageBox';
import { VideoBox } from '../nodes/VideoBox';
import { WebBox } from '../nodes/WebBox';
import { RichTextMenu } from '../nodes/formattedText/RichTextMenu';
-import { NumListCast, StrListCast } from '../../../fields/Doc';
-import { List } from '../../../fields/List';
-import { CollectionViewType } from '../../documents/DocumentTypes';
// import { InkTranscription } from '../InkTranscription';
import { Docs } from '../../documents/Documents';
-import { CollectionSubView } from '../collections/CollectionSubView';
-import { GPTPopup, GPTPopupMode } from '../pdf/GPTPopup/GPTPopup';
-import { PropertiesView } from '../PropertiesView';
-import { MainView } from '../MainView';
import { SnappingManager } from '../../util/SnappingManager';
+import { MainView } from '../MainView';
+import { PropertiesView } from '../PropertiesView';
+import { GPTPopup, GPTPopupMode } from '../pdf/GPTPopup/GPTPopup';
// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function IsNoneSelected() {
return DocumentView.Selected().length <= 0;
diff --git a/src/client/views/nodes/IconTagBox.tsx b/src/client/views/nodes/IconTagBox.tsx
index e6c0961ed..e076e691a 100644
--- a/src/client/views/nodes/IconTagBox.tsx
+++ b/src/client/views/nodes/IconTagBox.tsx
@@ -1,23 +1,19 @@
-import React from 'react';
-import { observer } from 'mobx-react';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Tooltip } from '@mui/material';
import { computed } from 'mobx';
-import { ObservableReactComponent } from '../ObservableReactComponent';
-import { NumCast } from '../../../fields/Types';
-import { Doc } from '../../../fields/Doc';
+import { observer } from 'mobx-react';
+import React from 'react';
import { numberRange } from '../../../Utils';
-import { Tooltip } from '@mui/material';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { undoable } from '../../util/UndoManager';
-import { BoolCast } from '../../../fields/Types';
-import { DocCast } from '../../../fields/Types';
-import './IconTagBox.scss';
+import { Doc, StrListCast } from '../../../fields/Doc';
import { DocData } from '../../../fields/DocSymbols';
-import { StrListCast } from '../../../fields/Doc';
-import { StrCast } from '../../../fields/Types';
+import { BoolCast, DocCast, NumCast, StrCast } from '../../../fields/Types';
import { CollectionViewType } from '../../documents/DocumentTypes';
import { SnappingManager } from '../../util/SnappingManager';
+import { undoable } from '../../util/UndoManager';
import { MainView } from '../MainView';
+import { ObservableReactComponent } from '../ObservableReactComponent';
import { PropertiesView } from '../PropertiesView';
+import './IconTagBox.scss';
export interface IconTagProps {
doc: Doc;
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
index 53bedbb65..ed3f99377 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
@@ -3,7 +3,7 @@ import { Button, IconButton, Type } from 'browndash-components';
import { action, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { CgClose, CgPathBack, CgArrowLeftO, CgCornerUpLeft } from 'react-icons/cg';
+import { CgClose, CgCornerUpLeft } from 'react-icons/cg';
import ReactLoading from 'react-loading';
import { TypeAnimation } from 'react-type-animation';
import { ClientUtils } from '../../../../ClientUtils';
@@ -11,16 +11,14 @@ import { Doc } from '../../../../fields/Doc';
import { NumCast, StrCast } from '../../../../fields/Types';
import { Networking } from '../../../Network';
import { GPTCallType, gptAPICall, gptImageCall } from '../../../apis/gpt/GPT';
-import { Docs } from '../../../documents/Documents';
import { DocUtils } from '../../../documents/DocUtils';
-import { ObservableReactComponent } from '../../ObservableReactComponent';
-import { AnchorMenu } from '../AnchorMenu';
-import './GPTPopup.scss';
+import { Docs } from '../../../documents/Documents';
import { SettingsManager } from '../../../util/SettingsManager';
import { SnappingManager } from '../../../util/SnappingManager';
+import { ObservableReactComponent } from '../../ObservableReactComponent';
import { DocumentView } from '../../nodes/DocumentView';
-import { DocCast } from '../../../../fields/Types';
-import { RTFCast } from '../../../../fields/Types';
+import { AnchorMenu } from '../AnchorMenu';
+import './GPTPopup.scss';
export enum GPTPopupMode {
SUMMARY,
@@ -30,21 +28,15 @@ export enum GPTPopupMode {
DATA,
CARD,
SORT,
- QUIZ
+ QUIZ,
}
export enum GPTQuizType {
CURRENT = 0,
CHOOSE = 1,
- MULTIPLE = 2
-
+ MULTIPLE = 2,
}
-
-
-
-
-
interface GPTPopupProps {}
@observer
@@ -168,30 +160,29 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
this.cardsDoneLoading = done;
}
- @observable sortRespText: string = ''
+ @observable sortRespText: string = '';
@action setSortRespText(resp: string) {
- this.sortRespText = resp
+ this.sortRespText = resp;
}
- @observable chatSortPrompt: string = ""
+ @observable chatSortPrompt: string = '';
sortPromptChanged = action((e: React.ChangeEvent<HTMLInputElement>) => {
this.chatSortPrompt = e.target.value;
});
- @observable quizAnswer: string = ""
+ @observable quizAnswer: string = '';
quizAnswerChanged = action((e: React.ChangeEvent<HTMLInputElement>) => {
this.quizAnswer = e.target.value;
});
- @observable conversationArray: string[] = ["Hi! In this pop up, you can ask ChatGPT questions about your documents and filter / sort them. "]
-
+ @observable conversationArray: string[] = ['Hi! In this pop up, you can ask ChatGPT questions about your documents and filter / sort them. '];
/**
* When the cards are in quiz mode in the card view, allows gpt to determine whether the user's answer was correct
- * @returns
+ * @returns
*/
generateQuiz = async () => {
this.setLoading(true);
@@ -201,14 +192,13 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
const selected = DocumentView.SelectedDocs().lastElement();
-
const questionText = 'Question: ' + StrCast(selected['gptInputText']);
if (StrCast(selected['gptRubric']) === '') {
- const rubricText = 'Rubric: ' + await this.generateRubric(StrCast(selected['gptInputText']), selected)
+ const rubricText = 'Rubric: ' + (await this.generateRubric(StrCast(selected['gptInputText']), selected));
}
- const rubricText = 'Rubric: ' + (StrCast(selected['gptRubric']))
+ const rubricText = 'Rubric: ' + StrCast(selected['gptRubric']);
const queryText = questionText + ' UserAnswer: ' + this.quizAnswer + '. ' + 'Rubric' + rubricText;
try {
@@ -217,23 +207,20 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
console.error('GPT call failed');
return;
}
- console.log(res)
- this.setQuizResp(res)
- this.conversationArray.push(res)
+ console.log(res);
+ this.setQuizResp(res);
+ this.conversationArray.push(res);
this.setLoading(false);
this.setSortDone(true);
-
} catch (err) {
console.error('GPT call failed');
}
-
- if (this.onQuizRandom){
- this.onQuizRandom()
+ if (this.onQuizRandom) {
+ this.onQuizRandom();
}
-
- }
+ };
/**
* Generates a rubric by which to compare the user's answer to
@@ -241,105 +228,95 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
* @param doc the doc the user is providing info about
* @returns gpt's response
*/
- generateRubric = async (inputText: string, doc:Doc) => {
+ generateRubric = async (inputText: string, doc: Doc) => {
try {
- const res = await gptAPICall(inputText, GPTCallType.RUBRIC);
- doc['gptRubric']= res;
- return res
+ const res = await gptAPICall(inputText, GPTCallType.RUBRIC);
+ doc['gptRubric'] = res;
+ return res;
} catch (err) {
console.error('GPT call failed');
}
-
- }
-
-
+ };
@observable private regenerateCallback: (() => Promise<void>) | null = null;
/**
* Callback function that causes the card view to update the childpair string list
- * @param callback
+ * @param callback
*/
@action public setRegenerateCallback(callback: () => Promise<void>) {
this.regenerateCallback = callback;
}
-
-
-
public addDoc: (doc: Doc | Doc[], sidebarKey?: string | undefined) => boolean = () => false;
public createFilteredDoc: (axes?: string[]) => boolean = () => false;
public addToCollection: ((doc: Doc | Doc[], annotationKey?: string | undefined) => boolean) | undefined;
- @observable quizRespText: string = ''
-
- @action setQuizResp (resp: string) {
- this.quizRespText = resp
+ @observable quizRespText: string = '';
+ @action setQuizResp(resp: string) {
+ this.quizRespText = resp;
}
/**
* Generates a response to the user's question depending on the type of their question
*/
generateCard = async () => {
- console.log(this.chatSortPrompt + "USER PROMPT")
+ console.log(this.chatSortPrompt + 'USER PROMPT');
this.setLoading(true);
this.setSortDone(false);
if (this.regenerateCallback) {
await this.regenerateCallback();
}
-
+
try {
// const res = await gptAPICall(this.sortDesc, GPTCallType.SORT, this.chatSortPrompt);
const questionType = await gptAPICall(this.chatSortPrompt, GPTCallType.TYPE);
- const questionNumber = questionType.split(' ')[0]
- console.log(questionType)
- let res = ''
+ const questionNumber = questionType.split(' ')[0];
+ console.log(questionType);
+ let res = '';
switch (questionNumber) {
case '1':
case '2':
case '4':
res = await gptAPICall(this.sortDesc, GPTCallType.SUBSET, this.chatSortPrompt);
- break
+ break;
case '6':
res = await gptAPICall(this.sortDesc, GPTCallType.SORT, this.chatSortPrompt);
- break
+ break;
default:
-
const selected = DocumentView.SelectedDocs().lastElement();
const questionText = StrCast(selected!['gptInputText']);
-
res = await gptAPICall(questionText, GPTCallType.INFO, this.chatSortPrompt);
- break
+ break;
}
// Trigger the callback with the result
if (this.onSortComplete) {
this.onSortComplete(res || 'Something went wrong :(', questionNumber, questionType.split(' ').slice(1).join(' '));
- let explanation = res
+ let explanation = res;
+
+ if (questionType != '5' && questionType != '3') {
+ // Extract explanation surrounded by ------ at the top or both at the top and bottom
+ const explanationMatch = res.match(/------\s*([\s\S]*?)\s*(?:------|$)/) || [];
+ explanation = explanationMatch[1] ? explanationMatch[1].trim() : 'No explanation found';
+ }
- if (questionType != '5' && questionType != '3'){
-
- // Extract explanation surrounded by ------ at the top or both at the top and bottom
- const explanationMatch = res.match(/------\s*([\s\S]*?)\s*(?:------|$)/) || [];
- explanation = explanationMatch[1] ? explanationMatch[1].trim() : 'No explanation found';
- }
-
// Set the extracted explanation to sortRespText
this.setSortRespText(explanation);
- this.conversationArray.push(this.sortRespText)
- this.scrollToBottom()
-
+ this.conversationArray.push(this.sortRespText);
+ this.scrollToBottom();
+
console.log(res);
}
} catch (err) {
console.error(err);
}
-
+
this.setLoading(false);
this.setSortDone(true);
};
@@ -476,21 +453,16 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
makeObservable(this);
GPTPopup.Instance = this;
this.messagesEndRef = React.createRef();
-
}
-
-
scrollToBottom = () => {
- setTimeout(() => {
- // Code to execute after 1 second (1000 ms)
- if (this.messagesEndRef.current) {
-
+ setTimeout(() => {
+ // Code to execute after 1 second (1000 ms)
+ if (this.messagesEndRef.current) {
this.messagesEndRef.current.scrollIntoView({ behavior: 'smooth', block: 'end' });
- }
-
- }, 50);
- }
+ }
+ }, 50);
+ };
componentDidUpdate = () => {
if (this.loading) {
@@ -498,9 +470,9 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
}
};
- @observable quizMode : GPTQuizType = GPTQuizType.CURRENT
- @action setQuizMode (g: GPTQuizType) {
- this.quizMode = g
+ @observable quizMode: GPTQuizType = GPTQuizType.CURRENT;
+ @action setQuizMode(g: GPTQuizType) {
+ this.quizMode = g;
}
cardMenu = () => (
@@ -517,21 +489,18 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
textAlign: 'center',
color: '#ffffff',
fontSize: '16px',
- marginBottom: '10px'
+ marginBottom: '10px',
}}
/>
<Button
tooltip="Test your knowledge with ChatGPT!"
text="Quiz Cards!"
onClick={() => {
- this.conversationArray = ['Define the selected card!']
- this.setMode(GPTPopupMode.QUIZ)
- if (this.onQuizRandom){
- this.onQuizRandom()
+ this.conversationArray = ['Define the selected card!'];
+ this.setMode(GPTPopupMode.QUIZ);
+ if (this.onQuizRandom) {
+ this.onQuizRandom();
}
-
-
-
}}
color={StrCast(Doc.UserDoc().userVariantColor)}
type={Type.TERT}
@@ -541,13 +510,10 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
color: '#ffffff',
fontSize: '16px',
height: '40%',
-
}}
/>
</div>
- )
-
-
+ );
handleKeyPress = async (e: React.KeyboardEvent, isSort: boolean) => {
if (e.key === 'Enter') {
@@ -556,85 +522,72 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
if (isSort) {
this.conversationArray.push(this.chatSortPrompt);
await this.generateCard();
- this.chatSortPrompt = ''
-
+ this.chatSortPrompt = '';
} else {
this.conversationArray.push(this.quizAnswer);
await this.generateQuiz();
- this.quizAnswer = ''
-
+ this.quizAnswer = '';
}
this.scrollToBottom();
}
- }
-
+ };
+
cardActual = (opt: GPTPopupMode) => {
- const isSort = opt === GPTPopupMode.SORT
- return (
-
- <div className="btns-wrapper-gpt">
- <div className="chat-wrapper">
- <div className="chat-bubbles">
- {this.conversationArray.map((message, index) => (
- <div
- key={index}
- className={`chat-bubble ${index % 2 === 1 ? 'user-message' : 'chat-message'}`}
- >
- {message}
- </div>
- ))}
- {(!this.cardsDoneLoading || this.loading) && (
- <div className={`chat-bubble chat-message`}>
- ...
- </div>
- )}
+ const isSort = opt === GPTPopupMode.SORT;
+ return (
+ <div className="btns-wrapper-gpt">
+ <div className="chat-wrapper">
+ <div className="chat-bubbles">
+ {this.conversationArray.map((message, index) => (
+ <div key={index} className={`chat-bubble ${index % 2 === 1 ? 'user-message' : 'chat-message'}`}>
+ {message}
</div>
+ ))}
+ {(!this.cardsDoneLoading || this.loading) && <div className={`chat-bubble chat-message`}>...</div>}
+ </div>
- <div ref={this.messagesEndRef} style= {{height: '100px'}} />
-
- </div>
-
- <div className="inputWrapper">
- <input
- className="searchBox-input"
- defaultValue=""
- value={isSort ? this.chatSortPrompt : this.quizAnswer} // Controlled input
- autoComplete="off"
- onChange={isSort ? this.sortPromptChanged : this.quizAnswerChanged}
- onKeyDown={(e) => {
- this.handleKeyPress(e, isSort)
+ <div ref={this.messagesEndRef} style={{ height: '100px' }} />
+ </div>
-
- }
- }
- type="text"
- placeholder={`${isSort ? 'Have ChatGPT sort, tag, define, or filter your cards for you!' : 'Define the selected card!'}`}
- />
- </div>
- </div>
- );
+ <div className="inputWrapper">
+ <input
+ className="searchBox-input"
+ defaultValue=""
+ value={isSort ? this.chatSortPrompt : this.quizAnswer} // Controlled input
+ autoComplete="off"
+ onChange={isSort ? this.sortPromptChanged : this.quizAnswerChanged}
+ onKeyDown={e => {
+ this.handleKeyPress(e, isSort);
+ }}
+ type="text"
+ placeholder={`${isSort ? 'Have ChatGPT sort, tag, define, or filter your cards for you!' : 'Define the selected card!'}`}
+ />
+ </div>
+ </div>
+ );
};
-
+
sortBox = () => (
- <div style = {{height: '80%'}}>
+ <div style={{ height: '80%' }}>
{this.heading(this.mode === GPTPopupMode.SORT ? 'SORTING' : 'QUIZ')}
<>
- {!this.cardsDoneLoading? (
+ {!this.cardsDoneLoading ? (
<div className="content-wrapper">
<div className="loading-spinner">
<ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} />
{this.loading ? <span>Loading...</span> : <span>Reading Cards...</span>}
</div>
</div>
+ ) : this.mode === GPTPopupMode.CARD ? (
+ this.cardMenu()
) : (
- (this.mode === GPTPopupMode.CARD ? this.cardMenu() : this.cardActual(this.mode)) // Call the functions to render JSX
- )}
+ this.cardActual(this.mode)
+ ) // Call the functions to render JSX
+ }
</>
</div>
);
-
-
imageBox = () => (
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
@@ -785,32 +738,25 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
<ReactLoading type="spin" color="#bcbcbc" width={14} height={14} />
) : (
<>
- {(this.mode === GPTPopupMode.SORT || this.mode === GPTPopupMode.QUIZ) && (
- <IconButton
- color={StrCast(SettingsManager.userVariantColor)}
- tooltip="back"
- icon={<CgCornerUpLeft size="16px" />}
- onClick={() => this.mode = GPTPopupMode.CARD}
- style = {{right: '50px', position: 'absolute'}}
- />
+ {(this.mode === GPTPopupMode.SORT || this.mode === GPTPopupMode.QUIZ) && (
+ <IconButton color={StrCast(SettingsManager.userVariantColor)} tooltip="back" icon={<CgCornerUpLeft size="16px" />} onClick={() => (this.mode = GPTPopupMode.CARD)} style={{ right: '50px', position: 'absolute' }} />
)}
<IconButton
color={StrCast(SettingsManager.userVariantColor)}
tooltip="close"
icon={<CgClose size="16px" />}
onClick={() => {
- this.setVisible(false)}}
+ this.setVisible(false);
+ }}
/>
-
</>
)}
</div>
);
-
render() {
let content;
-
+
switch (this.mode) {
case GPTPopupMode.SUMMARY:
content = this.summaryBox();
@@ -829,16 +775,12 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
default:
content = null;
}
-
+
return (
- <div
- className="summary-box"
- style={{ display: this.visible ? 'flex' : 'none' }}
- >
+ <div className="summary-box" style={{ display: this.visible ? 'flex' : 'none' }}>
{content}
<div className="resize-handle" />
</div>
);
}
-
}