diff options
-rw-r--r-- | eslint.config.mjs | 2 | ||||
-rw-r--r-- | src/client/views/nodes/ComparisonBox.tsx | 82 |
2 files changed, 37 insertions, 47 deletions
diff --git a/eslint.config.mjs b/eslint.config.mjs index aebdc20d0..f7063caa5 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -48,7 +48,7 @@ export default [ 'no-return-assign': 'error', 'no-await-in-loop': 'error', 'no-loop-func': 'error', - '@typescript-eslint/no-cond-assign': 'error', + 'no-cond-assign': 'error', 'no-use-before-define': 'error', '@typescript-eslint/no-explicit-any': 'error', 'no-restricted-globals': ['error', 'event'], diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 9ac8d7c52..cc20f0c57 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -1,41 +1,34 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { MathJax, MathJaxContext } from 'better-react-mathjax'; import { Tooltip } from '@mui/material'; +import axios from 'axios'; import { action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { returnFalse, returnNone, returnTrue, returnZero, setupMoveUpEvents } from '../../../ClientUtils'; +import ReactLoading from 'react-loading'; +import { returnFalse, returnNone, returnTrue, setupMoveUpEvents } from '../../../ClientUtils'; import { emptyFunction } from '../../../Utils'; import { Doc, Opt } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; +import { Id } from '../../../fields/FieldSymbols'; import { RichTextField } from '../../../fields/RichTextField'; import { DocCast, NumCast, RTFCast, StrCast, toList } from '../../../fields/Types'; +import { nullAudio } from '../../../fields/URLField'; import { GPTCallType, gptAPICall, gptImageLabel } from '../../apis/gpt/GPT'; -import '../pdf/GPTPopup/GPTPopup.scss'; -import { DocUtils } from '../../documents/DocUtils'; +import { DocUtils, FollowLinkScript } from '../../documents/DocUtils'; import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; import { Docs } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; import { dropActionType } from '../../util/DropActionTypes'; import { undoable } from '../../util/UndoManager'; +import { ContextMenu } from '../ContextMenu'; import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { PinDocView, PinProps } from '../PinFuncs'; import { StyleProp } from '../StyleProp'; +import '../pdf/GPTPopup/GPTPopup.scss'; import './ComparisonBox.scss'; import { DocumentView } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { FormattedTextBox } from './formattedText/FormattedTextBox'; -import ReactLoading from 'react-loading'; -import { ContextMenu } from '../ContextMenu'; -import { ContextMenuProps } from '../ContextMenuItem'; -import { tickStep } from 'd3'; -import { CollectionCarouselView } from '../collections/CollectionCarouselView'; -import { FollowLinkScript } from '../../documents/DocUtils'; -import { schema } from '../nodes/formattedText/schema_rts'; -import { Id } from '../../../fields/FieldSymbols'; -import axios from 'axios'; -import ReactMarkdown from 'react-markdown'; -import { WebField, nullAudio } from '../../../fields/URLField'; const API_URL = 'https://api.unsplash.com/search/photos'; @@ -118,26 +111,26 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() <div> <Tooltip title={this.frontSide ? <div className="dash-tooltip">Flip to front side to use GPT</div> : <div className="dash-tooltip">Ask GPT to create an answer on the back side of the flashcard based on your question on the front</div>}> - <div style={{ position: 'absolute', bottom: '3px', right: '50px', cursor: 'pointer' }} onPointerDown={e => (!this.frontSide ? this.findImageTags() : null)}> + <div style={{ position: 'absolute', bottom: '3px', right: '50px', cursor: 'pointer' }} onPointerDown={() => (!this.frontSide ? this.findImageTags() : null)}> <FontAwesomeIcon icon="lightbulb" size="xl" /> </div> </Tooltip> {DocCast(this.Document.embedContainer)?.type_collection === CollectionViewType.Carousel ? null : ( <div> <Tooltip title={<div>Create a flashcard pile</div>}> - <div style={{ position: 'absolute', bottom: '3px', right: '74px', cursor: 'pointer' }} onPointerDown={e => this.createFlashcardPile([this.Document], false)}> + <div style={{ position: 'absolute', bottom: '3px', right: '74px', cursor: 'pointer' }} onPointerDown={() => this.createFlashcardPile([this.Document], false)}> <FontAwesomeIcon icon="folder-plus" size="xl" /> </div> </Tooltip> <Tooltip title={<div className="dash-tooltip">Create new flashcard stack based on text</div>}> - <div style={{ position: 'absolute', bottom: '3px', right: '104px', cursor: 'pointer' }} onClick={e => this.gptFlashcardPile()}> + <div style={{ position: 'absolute', bottom: '3px', right: '104px', cursor: 'pointer' }} onClick={() => this.gptFlashcardPile()}> <FontAwesomeIcon icon="layer-group" size="xl" /> </div> </Tooltip> </div> )} <Tooltip title={<div className="dash-tooltip">Hover to reveal</div>}> - <div style={{ position: 'absolute', bottom: '3px', right: '25px', cursor: 'pointer' }} onClick={e => this.handleHover()}> + <div style={{ position: 'absolute', bottom: '3px', right: '25px', cursor: 'pointer' }} onClick={() => this.handleHover()}> <FontAwesomeIcon color={this.revealOp === 'hover' ? 'blue' : 'black'} icon="hand-point-up" size="xl" /> </div> </Tooltip> @@ -354,13 +347,13 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() openContextMenu = (x: number, y: number, evalu: boolean) => { ContextMenu.Instance.clearItems(); - ContextMenu.Instance.addItem({ description: 'English', event: e => this.setLanguage('en-US', 0), icon: 'question' }); //prettier-ignore - ContextMenu.Instance.addItem({ description: 'Spanish', event: e => this.setLanguage('es-ES', 1 ), icon: 'question'}); //prettier-ignore - ContextMenu.Instance.addItem({ description: 'French', event: e => this.setLanguage('fr-FR', 2), icon: 'question' }); //prettier-ignore - ContextMenu.Instance.addItem({ description: 'Italian', event: e => this.setLanguage('it-IT', 3), icon: 'question' }); //prettier-ignore - if (!evalu) ContextMenu.Instance.addItem({ description: 'Mandarin Chinese', event: e => this.setLanguage('zh-CH', 4), icon: 'question' }); //prettier-ignore - ContextMenu.Instance.addItem({ description: 'Japanese', event: e => this.setLanguage('ja', 5), icon: 'question' }); //prettier-ignore - ContextMenu.Instance.addItem({ description: 'Korean', event: e => this.setLanguage('ko', 6), icon: 'question' }); //prettier-ignore + ContextMenu.Instance.addItem({ description: 'English', event: () => this.setLanguage('en-US', 0), icon: 'question' }); //prettier-ignore + ContextMenu.Instance.addItem({ description: 'Spanish', event: () => this.setLanguage('es-ES', 1 ), icon: 'question'}); //prettier-ignore + ContextMenu.Instance.addItem({ description: 'French', event: () => this.setLanguage('fr-FR', 2), icon: 'question' }); //prettier-ignore + ContextMenu.Instance.addItem({ description: 'Italian', event: () => this.setLanguage('it-IT', 3), icon: 'question' }); //prettier-ignore + if (!evalu) ContextMenu.Instance.addItem({ description: 'Mandarin Chinese', event: () => this.setLanguage('zh-CH', 4), icon: 'question' }); //prettier-ignore + ContextMenu.Instance.addItem({ description: 'Japanese', event: () => this.setLanguage('ja', 5), icon: 'question' }); //prettier-ignore + ContextMenu.Instance.addItem({ description: 'Korean', event: () => this.setLanguage('ko', 6), icon: 'question' }); //prettier-ignore ContextMenu.Instance.displayMenu(x, y); }; @@ -387,7 +380,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() }; getYouTubeVideoId = (url: string) => { - const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=|\?v=)([^#\&\?]*).*/; + const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=|\?v=)([^#&?]*).*/; const match = url.match(regExp); return match && match[2].length === 11 ? match[2] : null; }; @@ -418,7 +411,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() newCol['x'] = this.layoutDoc['x']; newCol['y'] = NumCast(this.layoutDoc['y']) + 50; newCol.type_collection = 'carousel'; - for (var i = 0; i < collectionArr.length; i++) { + for (let i = 0; i < collectionArr.length; i++) { DocCast(collectionArr[i])[DocData].embedContainer = newCol; } @@ -436,10 +429,10 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() * Transfers the content of flashcards into a flashcard pile. */ gptFlashcardPile = async () => { - var text = await this.askGPT(GPTCallType.STACK); - var senArr = text?.split('Question: '); - var collectionArr: Doc[] = []; - for (let i = 1; i < senArr?.length!; i++) { + const text = await this.askGPT(GPTCallType.STACK); + const senArr = text?.split('Question: ') ?? []; + const collectionArr: Doc[] = []; + for (let i = 1; i < senArr.length; i++) { const newDoc = Docs.Create.ComparisonDocument(senArr![i], { _layout_isFlashcard: true, _width: 300, _height: 300 }); if (StrCast(senArr![i]).includes('Keyword: ')) { @@ -481,11 +474,10 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() * Calls GPT for each flashcard type. */ askGPT = async (callType: GPTCallType): Promise<string | undefined> => { - let questionText = 'Question: ' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text); + const questionText = 'Question: ' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text); const rubricText = ' Rubric: ' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_0']).text)?.Text); const queryText = questionText + ' UserAnswer: ' + this._inputValue + '. ' + rubricText; this._loading = true; - const doc = DocCast(this.dataDoc[this.props.fieldKey + '_0']); if (callType == GPTCallType.CHATCARD) { if (StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text) === '') { @@ -511,11 +503,12 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() this._loading = false; return res; } else if (callType === GPTCallType.STACK) { + /* empty */ } this._loading = false; return res; } catch (err) { - console.error('GPT call failed'); + console.error('GPT call failed', err); } this._loading = false; }; @@ -527,7 +520,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() if (c?.length === 0) await this.askGPT(GPTCallType.CHATCARD); if (c) { this._loading = true; - for (let i of c) { + for (const i of c) { console.log(i); if (i.className !== 'ProseMirror-separator') await this.getImageDesc(i.src); } @@ -653,7 +646,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() DocCast(this.dataDoc[this.props.fieldKey + '_0'])[DocData].text = response; } catch (error) { - console.log('Error'); + console.log('Error', error); } }; @@ -692,6 +685,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() return layoutTemplateString; }; + childActiveFunc = () => this.childActive; + render() { const clearButton = (which: string) => ( <Tooltip title={<div className="dash-tooltip">remove</div>}> @@ -712,7 +707,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() return targetDoc || layoutString ? ( <> <DocumentView - // eslint-disable-next-line react/jsx-props-no-spreading {...this._props} showTags={undefined} fitWidth={undefined} @@ -725,7 +719,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() removeDocument={whichSlot.endsWith('1') ? this.remDoc1 : this.remDoc2} NativeWidth={this.layoutWidth} NativeHeight={this.layoutHeight} - isContentActive={() => this.childActive} + isContentActive={this.childActiveFunc} isDocumentActive={returnFalse} dontSelect={returnTrue} whenChildContentsActiveChanged={this.whenChildContentsActiveChanged} @@ -837,13 +831,9 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() return ( <div className={`comparisonBox${this._props.isContentActive() ? '-interactive' : ''}`} /* change className to easily disable/enable pointer events in CSS */ - style={{ display: 'flex', flexDirection: 'column', overflow: 'hidden' }} - onMouseEnter={() => { - this.hoverFlip(false); - }} - onMouseLeave={() => { - this.hoverFlip(true); - }}> + style={{ display: 'flex', flexDirection: 'column' }} + onMouseEnter={() => this.hoverFlip(true)} + onMouseLeave={() => this.hoverFlip(false)}> {displayBox(`${this.fieldKey}_${side === 0 ? 1 : 0}`, side, this._props.PanelWidth() - 3)} {this._loading ? ( <div className="loading-spinner" style={{ position: 'absolute' }}> |