From 88caa55967b1dbf670b156dd08efc4f559067af7 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Mon, 19 Feb 2024 16:19:05 -0500 Subject: ai (updates from sophie, then added dataviz summary) --- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 32 +++++++++++++++++++- .../views/nodes/formattedText/FormattedTextBox.tsx | 34 +++++++++++++++++----- 2 files changed, 58 insertions(+), 8 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 66a08f13e..33b7dddfc 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -18,7 +18,7 @@ import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../../DocComponen import { MarqueeAnnotator } from '../../MarqueeAnnotator'; import { SidebarAnnos } from '../../SidebarAnnos'; import { AnchorMenu } from '../../pdf/AnchorMenu'; -import { GPTPopup } from '../../pdf/GPTPopup/GPTPopup'; +import { GPTPopup, GPTPopupMode } from '../../pdf/GPTPopup/GPTPopup'; import { DocumentView } from '../DocumentView'; import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView'; import { PinProps } from '../trails'; @@ -28,6 +28,8 @@ import { LineChart } from './components/LineChart'; import { PieChart } from './components/PieChart'; import { TableBox } from './components/TableBox'; import { Checkbox } from '@mui/material'; +import { ContextMenu } from '../../ContextMenu'; +import { GPTCallType, gptAPICall } from '../../../apis/gpt/GPT'; export enum DataVizView { TABLE = 'table', @@ -43,6 +45,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() im private _annotationLayer: React.RefObject = React.createRef(); private _disposers: { [name: string]: IReactionDisposer } = {}; anchorMenuClick?: () => undefined | ((anchor: Doc) => void); + sidebarAddDoc: ((doc: Doc | Doc[], sidebarKey?: string | undefined) => boolean) | undefined; crop: ((region: Doc | undefined, addCrop?: boolean) => Doc | undefined) | undefined; @observable _marqueeing: number[] | undefined = undefined; @observable _savedAnnotations = new ObservableMap(); @@ -402,6 +405,32 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() im this.layoutDoc.dataViz_schemaLive = !this.layoutDoc.dataViz_schemaLive } + specificContextMenu = (e: React.MouseEvent): void => { + const cm = ContextMenu.Instance; + const options = cm.findByDescription('Options...'); + const optionItems = options && 'subitems' in options ? options.subitems : []; + optionItems.push({ description: `Analyze with AI`, event: () => this.askGPT(), icon: 'lightbulb' }); + !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'eye' }); + } + + + askGPT = action(async () => { + GPTPopup.Instance.setVisible(true); + GPTPopup.Instance.setSidebarId('data_sidebar'); + GPTPopup.Instance.addDoc = this.sidebarAddDocument; + GPTPopup.Instance.setMode(GPTPopupMode.DATA); + GPTPopup.Instance.setLoading(true); + try { + let data = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey]).url.href); + let input = JSON.stringify(data); + let res = await gptAPICall(input, GPTCallType.DATA); + GPTPopup.Instance.setText(res || 'Something went wrong.'); + } catch (err) { + console.error(err); + } + GPTPopup.Instance.setLoading(false); + }); + render() { const scale = this._props.NativeDimScaling?.() || 1; return !this.records.length ? ( @@ -418,6 +447,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() im transform: `scale(${scale})`, position: 'absolute', }} + onContextMenu={this.specificContextMenu} onWheel={e => e.stopPropagation()} ref={this._mainCont}>
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index f2c4c6c8f..8d5b0218d 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -8,7 +8,7 @@ import { history } from 'prosemirror-history'; import { inputRules } from 'prosemirror-inputrules'; import { keymap } from 'prosemirror-keymap'; import { Fragment, Mark, Node, Slice } from 'prosemirror-model'; -import { EditorState, NodeSelection, Plugin, TextSelection, Transaction } from 'prosemirror-state'; +import { EditorState, NodeSelection, Plugin, Selection, TextSelection, Transaction } from 'prosemirror-state'; import { EditorView } from 'prosemirror-view'; import * as React from 'react'; import { BsMarkdownFill } from 'react-icons/bs'; @@ -972,9 +972,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { + if (!this._editorView) return; if (resIndex < newText.length) { - const marks = this._editorView?.state.storedMarks ?? []; - this._editorView?.dispatch(this._editorView.state.tr.setStoredMarks(marks).insertText(newText[resIndex]).setStoredMarks(marks)); + const marks = this._editorView.state.storedMarks ?? []; + this._editorView.dispatch(this._editorView.state.tr.insertText(newText[resIndex]).setStoredMarks(marks)); setTimeout(() => { this.animateRes(resIndex + 1, newText); }, 20); @@ -983,15 +984,34 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { try { - let res = await gptAPICall((this.dataDoc.text as RichTextField)?.Text, GPTCallType.COMPLETION); + // let res = await gptAPICall((this.dataDoc.text as RichTextField)?.Text, GPTCallType.COMPLETION); + + let data = { + "Weight":[69,69,65,72,67,73,70,75,74,65,73,70,74,68,74,65,69,75,67,74,66,70,69,68,67,71,67,70,74,71,73,66,72,73,68,69,69,74,70,73], + "Size":[4.39,4.21,4.09,5.85,4.7,5.68,5.56,5.11,5.36,4.27,5.79,5.47,5.53,4.47,5.22,4.48,4.66,5.25,4.18,5.5,4.13,4.83,4.61,4.08,4.25,5.35,4.01,4.22,5.25,5.26,5.78,4.68,5.72,5.17,4.83,4.11,4.76,5.48,5.59,5.03], + "Class":["orange","orange","orange","apple","orange","apple","apple","apple","apple","orange","apple","apple","apple","orange","apple","orange","orange","apple","orange","apple","orange","orange","orange","orange","orange","apple","orange","orange","apple","apple","apple","orange","apple","apple","orange","orange","orange","apple","apple","apple"] + } + let input = JSON.stringify(data); + + + let res = await gptAPICall(input, GPTCallType.DATA); + console.log('GPT Result: ', res); + console.log(res); if (!res) { - console.error('GPT call failed'); this.animateRes(0, 'Something went wrong.'); } else { - this.animateRes(0, res); + if (!this._editorView) return; + // No animation + // this._editorView.dispatch(this._editorView.state.tr.insertText(res)); + + // Animation + // Set selection at end + const sel = Selection.atEnd(this._editorView.state.doc); + this._editorView.dispatch(this._editorView.state.tr.setSelection(sel)); + this.animateRes(0, '\n\n' + res); } } catch (err) { - console.error('GPT call failed'); + console.error(err); this.animateRes(0, 'Something went wrong.'); } }); -- cgit v1.2.3-70-g09d2 From 3b6b673cf1fd1e951c28210983d0b1d6176fc013 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Mon, 26 Feb 2024 00:57:44 -0500 Subject: select title col ui --- .../views/nodes/DataVizBox/components/Chart.scss | 19 +++++++++++++------ .../views/nodes/DataVizBox/components/TableBox.tsx | 21 +++++++++++++-------- 2 files changed, 26 insertions(+), 14 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/DataVizBox/components/Chart.scss b/src/client/views/nodes/DataVizBox/components/Chart.scss index 41ce637ac..15d289abf 100644 --- a/src/client/views/nodes/DataVizBox/components/Chart.scss +++ b/src/client/views/nodes/DataVizBox/components/Chart.scss @@ -120,11 +120,18 @@ } } } -.selectAll-buttons { - display: flex; - flex-direction: row; - justify-content: flex-end; +.select-buttons { margin-top: 5px; - margin-right: 10px; - float: right; + margin-left: 25px; + display: inline-block; + .selectTitle { + display: inline-block; + + } + .selectAll { + display: flex; + flex-direction: row; + float: right; + margin-right: 10px; + } } diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index 1b239b5e5..c9491da59 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -36,6 +36,7 @@ interface TableBoxProps { export class TableBox extends ObservableReactComponent { _inputChangedDisposer?: IReactionDisposer; _containerRef: HTMLDivElement | null = null; + @observable settingTitle: boolean = false; @observable _scrollTop = -1; @observable _tableHeight = 0; @@ -155,7 +156,8 @@ export class TableBox extends ObservableReactComponent { }, emptyFunction, action(e => { - if (e.shiftKey){ + if (e.shiftKey || this.settingTitle){ + if (this.settingTitle) this.settingTitle = false; if (this._props.titleCol == col) this._props.titleCol = ""; else this._props.titleCol = col; this._props.selectTitleCol(this._props.titleCol); @@ -184,9 +186,14 @@ export class TableBox extends ObservableReactComponent { this._props.layoutDoc.dataViz_selectedRows = new List(this._tableDataIds); } }}> -
-
+
+
{ color: this._props.axes.slice().reverse().lastElement() === col ? 'darkgreen' : (this._props.axes.length>2 && this._props.axes.lastElement() === col) ? 'darkred' : (this._props.axes.lastElement()===col || (this._props.axes.length>2 && this._props.axes[1]==col))? 'darkblue' : undefined, - background: this._props.axes.slice().reverse().lastElement() === col ? '#E3fbdb' + background: this.settingTitle? 'lightgrey' + : this._props.axes.slice().reverse().lastElement() === col ? '#E3fbdb' : (this._props.axes.length>2 && this._props.axes.lastElement() === col) ? '#Fbdbdb' : (this._props.axes.lastElement()===col || (this._props.axes.length>2 && this._props.axes[1]==col))? '#c6ebf7' : undefined, - // blue: #ADD8E6 - // green: #E3fbdb - // red: #Fbdbdb fontWeight: 'bolder', border: '3px solid black', }} -- cgit v1.2.3-70-g09d2 From b7de39e877c6fc9d3604dbc363999ac91ce3fa62 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Tue, 27 Feb 2024 16:52:00 -0500 Subject: textbox ask ai fix --- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index a1e4bfacc..e5362762e 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -984,19 +984,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { try { - // let res = await gptAPICall((this.dataDoc.text as RichTextField)?.Text, GPTCallType.COMPLETION); - - let data = { - "Weight":[69,69,65,72,67,73,70,75,74,65,73,70,74,68,74,65,69,75,67,74,66,70,69,68,67,71,67,70,74,71,73,66,72,73,68,69,69,74,70,73], - "Size":[4.39,4.21,4.09,5.85,4.7,5.68,5.56,5.11,5.36,4.27,5.79,5.47,5.53,4.47,5.22,4.48,4.66,5.25,4.18,5.5,4.13,4.83,4.61,4.08,4.25,5.35,4.01,4.22,5.25,5.26,5.78,4.68,5.72,5.17,4.83,4.11,4.76,5.48,5.59,5.03], - "Class":["orange","orange","orange","apple","orange","apple","apple","apple","apple","orange","apple","apple","apple","orange","apple","orange","orange","apple","orange","apple","orange","orange","orange","orange","orange","apple","orange","orange","apple","apple","apple","orange","apple","apple","orange","orange","orange","apple","apple","apple"] - } - let input = JSON.stringify(data); - - - let res = await gptAPICall(input, GPTCallType.DATA); - console.log('GPT Result: ', res); - console.log(res); + let res = await gptAPICall((this.dataDoc.text as RichTextField)?.Text, GPTCallType.COMPLETION); if (!res) { this.animateRes(0, 'Something went wrong.'); } else { -- cgit v1.2.3-70-g09d2 From 54c597bb865aba15f16e0692c2f2119109d119aa Mon Sep 17 00:00:00 2001 From: srichman333 Date: Wed, 28 Feb 2024 19:24:22 -0500 Subject: chat with ai --- src/client/apis/gpt/GPT.ts | 5 +- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 16 ++---- src/client/views/pdf/GPTPopup/GPTPopup.tsx | 62 ++++++++++++++++++++---- 3 files changed, 59 insertions(+), 24 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts index 82436c42b..97a332294 100644 --- a/src/client/apis/gpt/GPT.ts +++ b/src/client/apis/gpt/GPT.ts @@ -33,7 +33,7 @@ const callTypeMap: { [type: string]: GPTCallOpts } = { * @param inputText Text to process * @returns AI Output */ -const gptAPICall = async (inputText: string, callType: GPTCallType) => { +const gptAPICall = async (inputText: string, callType: GPTCallType, prompt?: any) => { if (callType === GPTCallType.SUMMARY) inputText += '.'; const opts: GPTCallOpts = callTypeMap[callType]; try { @@ -43,8 +43,9 @@ const gptAPICall = async (inputText: string, callType: GPTCallType) => { }; const openai = new OpenAI(configuration); + let usePrompt = prompt? prompt: opts.prompt; let messages: ChatCompletionMessageParam[] = [ - { role: 'system', content: opts.prompt }, + { role: 'system', content: usePrompt }, { role: 'user', content: inputText }, ]; diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 33b7dddfc..0a7fe59a5 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -29,7 +29,6 @@ import { PieChart } from './components/PieChart'; import { TableBox } from './components/TableBox'; import { Checkbox } from '@mui/material'; import { ContextMenu } from '../../ContextMenu'; -import { GPTCallType, gptAPICall } from '../../../apis/gpt/GPT'; export enum DataVizView { TABLE = 'table', @@ -415,20 +414,13 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() im askGPT = action(async () => { - GPTPopup.Instance.setVisible(true); GPTPopup.Instance.setSidebarId('data_sidebar'); GPTPopup.Instance.addDoc = this.sidebarAddDocument; GPTPopup.Instance.setMode(GPTPopupMode.DATA); - GPTPopup.Instance.setLoading(true); - try { - let data = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey]).url.href); - let input = JSON.stringify(data); - let res = await gptAPICall(input, GPTCallType.DATA); - GPTPopup.Instance.setText(res || 'Something went wrong.'); - } catch (err) { - console.error(err); - } - GPTPopup.Instance.setLoading(false); + let data = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey]).url.href); + let input = JSON.stringify(data); + GPTPopup.Instance.setDataJson(input); + GPTPopup.Instance.generateDataAnalysis(); }); render() { diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx index 8c575748f..6301721e8 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx +++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Button, IconButton, Type } from 'browndash-components'; +import { Button, EditableText, IconButton, Size, Type } from 'browndash-components'; import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -28,6 +28,7 @@ interface GPTPopupProps {} @observer export class GPTPopup extends ObservableReactComponent { static Instance: GPTPopup; + @observable private chatMode: boolean = false; @observable public visible: boolean = false; @@ -53,6 +54,13 @@ export class GPTPopup extends ObservableReactComponent { public setSelectedText = (text: string) => { this.selectedText = text; }; + @observable + public dataJson: string = ''; + public dataChatPrompt: string | null = null; + @action + public setDataJson = (text: string) => { + this.dataJson = text; + }; @observable public imgDesc: string = ''; @@ -86,6 +94,7 @@ export class GPTPopup extends ObservableReactComponent { @action public setDone = (done: boolean) => { this.done = done; + this.chatMode = false; }; // change what can be a ref into a ref @@ -153,6 +162,18 @@ export class GPTPopup extends ObservableReactComponent { GPTPopup.Instance.setLoading(false); } + generateDataAnalysis = async () => { + GPTPopup.Instance.setVisible(true); + GPTPopup.Instance.setLoading(true); + try { + let res = await gptAPICall(this.dataJson, GPTCallType.DATA, this.dataChatPrompt); + GPTPopup.Instance.setText(res || 'Something went wrong.'); + } catch (err) { + console.error(err); + } + GPTPopup.Instance.setLoading(false); + } + /** * Transfers the summarization text to a sidebar annotation text document. */ @@ -197,6 +218,16 @@ export class GPTPopup extends ObservableReactComponent { DocUtils.MakeLink(textAnchor, newDoc, { link_relationship: 'Image Prompt' }); }; + /** + * Creates a chatbox for analyzing data so that users can ask specific questions. + */ + private chatWithAI = () => { + this.chatMode = true; + } + dataPromptChanged = action((e: React.ChangeEvent) => { + this.dataChatPrompt = e.target.value; + }); + private getPreviewUrl = (source: string) => source.split('.').join('_m.'); constructor(props: GPTPopupProps) { @@ -310,22 +341,33 @@ export class GPTPopup extends ObservableReactComponent {
{!this.loading && (
- {this.done ? ( + {this.done? + this.chatMode?( + { + e.key === 'Enter' ? this.generateDataAnalysis() : null; + e.stopPropagation(); + }} + type="text" + placeholder="Ask GPT a question about the data..." + id="search-input" + className="searchBox-input" + style={{width: "100%"}} + /> + ) + :( <>
)} -- cgit v1.2.3-70-g09d2 From dfef33c3f1cde9a24d734e0bd47e7f377a3ae4c9 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Tue, 5 Mar 2024 16:17:14 -0500 Subject: chat resets for new boxes to analyze --- src/client/views/nodes/DataVizBox/DataVizBox.scss | 4 ++++ src/client/views/nodes/DataVizBox/DataVizBox.tsx | 9 ++++++--- src/client/views/pdf/GPTPopup/GPTPopup.tsx | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.scss b/src/client/views/nodes/DataVizBox/DataVizBox.scss index 6b5738790..e9a346fbe 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.scss +++ b/src/client/views/nodes/DataVizBox/DataVizBox.scss @@ -32,6 +32,10 @@ .liveSchema-checkBox { margin-bottom: -35px; } + + .displaySchemaLive { + margin-bottom: 20px; + } .dataviz-sidebar { position: absolute; diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 0a7fe59a5..b4da41fa0 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -416,6 +416,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() im askGPT = action(async () => { GPTPopup.Instance.setSidebarId('data_sidebar'); GPTPopup.Instance.addDoc = this.sidebarAddDocument; + GPTPopup.Instance.setDataJson(""); GPTPopup.Instance.setMode(GPTPopupMode.DATA); let data = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey]).url.href); let input = JSON.stringify(data); @@ -450,9 +451,11 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() im {(this.layoutDoc && this.layoutDoc.dataViz_asSchema)?( -
- - Display Live Updates to Canvas +
+
+ + Display Live Updates to Canvas +
) : null} diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx index 5f399e86a..29b1ca365 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx +++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx @@ -59,6 +59,7 @@ export class GPTPopup extends ObservableReactComponent { public dataChatPrompt: string | null = null; @action public setDataJson = (text: string) => { + if (text=="") this.dataChatPrompt = ""; this.dataJson = text; }; -- cgit v1.2.3-70-g09d2 From 8fc97eb6e093d4217f28919bf836425b75fdfea3 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Sun, 10 Mar 2024 14:00:08 -0400 Subject: filter tables --- .../views/nodes/DataVizBox/components/Chart.scss | 54 +++++++++- .../views/nodes/DataVizBox/components/TableBox.tsx | 118 +++++++++++++++++++-- 2 files changed, 157 insertions(+), 15 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/DataVizBox/components/Chart.scss b/src/client/views/nodes/DataVizBox/components/Chart.scss index 15d289abf..cf0007cfd 100644 --- a/src/client/views/nodes/DataVizBox/components/Chart.scss +++ b/src/client/views/nodes/DataVizBox/components/Chart.scss @@ -120,18 +120,62 @@ } } } -.select-buttons { +.tableBox-selectButtons { margin-top: 5px; margin-left: 25px; display: inline-block; - .selectTitle { - display: inline-block; - + padding: 2px; + .tableBox-selectTitle { + display: inline-flex; + flex-direction: row; } - .selectAll { + .tableBox-filtering { display: flex; flex-direction: row; float: right; margin-right: 10px; + .tableBox-filterAll { + min-width: 75px; + } + } +} + +.tableBox-filterPopup { + background: $light-gray; + position: absolute; + min-width: 235px; + top: 60px; + display: flex; + flex-direction: column; + align-items: flex-start; + z-index: 2; + padding: 7px; + border-radius: 5px; + margin: 3px; + .tableBox-filterPopup-selectColumn { + margin-top: 5px; + flex-direction: row; + .tableBox-filterPopup-selectColumn-each { + margin-left: 25px; + border-radius: 3px; + background: $light-gray; + } + } + .tableBox-filterPopup-setValue { + margin-top: 5px; + display: flex; + flex-direction: row; + .tableBox-filterPopup-setValue-each { + margin-right: 5px; + border-radius: 3px; + background: $light-gray; + } + .tableBox-filterPopup-setValue-input { + margin: 5px; + } + } + .tableBox-filterPopup-setFilter { + margin-top: 5px; + align-self: center; } } diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index c9491da59..05429e82b 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -12,6 +12,7 @@ import { ObservableReactComponent } from '../../../ObservableReactComponent'; import { DocumentView } from '../../DocumentView'; import { DataVizView } from '../DataVizBox'; import './Chart.scss'; +import { undoBatch } from '../../../../util/UndoManager'; const { default: { DATA_VIZ_TABLE_ROW_HEIGHT } } = require('../../../global/globalCssVariables.module.scss'); // prettier-ignore interface TableBoxProps { Document: Doc; @@ -36,7 +37,13 @@ interface TableBoxProps { export class TableBox extends ObservableReactComponent { _inputChangedDisposer?: IReactionDisposer; _containerRef: HTMLDivElement | null = null; - @observable settingTitle: boolean = false; + + @observable settingTitle: boolean = false; // true when setting a title column + @observable hasRowsToFilter: boolean = false; // true when any rows are selected + @observable filtering: boolean = false; // true when the filtering menu is open + @observable filteringColumn: any = ""; // column to filter + @observable filteringType: string = "Value"; // "Value" or "Range" + filteringVal: any[] = ["", ""]; // value or range to filter the column with @observable _scrollTop = -1; @observable _tableHeight = 0; @@ -50,6 +57,8 @@ export class TableBox extends ObservableReactComponent { // if the tableData changes (ie., when records are selected by the parent (input) visulization), // then we need to remove any selected rows that are no longer part of the visualized dataset. this._inputChangedDisposer = reaction(() => this._tableData.slice(), this.filterSelectedRowsDown, { fireImmediately: true }); + const selected = NumListCast(this._props.layoutDoc.dataViz_selectedRows); + if (selected.length>0) this.hasRowsToFilter = true; this.handleScroll(); } componentWillUnmount() { @@ -65,9 +74,6 @@ export class TableBox extends ObservableReactComponent { @computed get parentViz() { return DocCast(this._props.Document.dataViz_parentViz); - // return LinkManager.Instance.getAllRelatedLinks(this._props.Document) // out of all links - // .filter(link => link.link_anchor_1 == this._props.Document.dataViz_parentViz) // get links where this chart doc is the target of the link - // .map(link => DocCast(link.link_anchor_1)); // then return the source of the link } @computed get columns() { @@ -116,6 +122,7 @@ export class TableBox extends ObservableReactComponent { } else selected?.push(rowId); } e.stopPropagation(); + this.hasRowsToFilter = (selected.length>0)? true : false; }; columnPointerDown = (e: React.PointerEvent, col: string) => { @@ -173,6 +180,88 @@ export class TableBox extends ObservableReactComponent { ); }; + /** + * These functions handle the filtering popup for when the "filter" button is pressed to select rows + */ + @undoBatch + filter = (e: any) => { + this._tableDataIds.forEach(rowID => { + if (this.filteringType=="Value"){ + if (this._props.records[rowID][this.filteringColumn]==this.filteringVal[0]) { + this.tableRowClick(e, rowID); + } + } + else { + if (this.filteringVal[0]<=this._props.records[rowID][this.filteringColumn] && this._props.records[rowID][this.filteringColumn]<=this.filteringVal[1]){ + this.tableRowClick(e, rowID); + } + } + }) + this.filtering = false; + this.filteringColumn = ""; + this.filteringVal = ["", ""]; + } + @action + setFilterColumn = (e:any) => { + this.filteringColumn = e.currentTarget.value; + } + @action + setFilterType = (e:any) => { + this.filteringType = e.currentTarget.value; + } + changeFilterValue = action((e: React.ChangeEvent) => { + this.filteringVal[0] = e.target.value; + }); + changeFilterRange0 = action((e: React.ChangeEvent) => { + this.filteringVal[0] = e.target.value; + }); + changeFilterRange1 = action((e: React.ChangeEvent) => { + this.filteringVal[1] = e.target.value; + }); + @computed get renderFiltering() { + if (this.filteringColumn==="") this.filteringColumn = this.columns[0]; + return ( +
+
+ Column: + +
+
+ + : + {this.filteringType=="Value"? + {e.stopPropagation();}} + type="text" placeholder="" id="search-input" + /> + : +
+ {e.stopPropagation();}} + type="text" placeholder="" id="search-input" style={{width: this._props.width*.15}} + /> + to + {e.stopPropagation();}} + type="text" placeholder="" id="search-input" style={{width: this._props.width*.15}} + /> +
+ } +
+
+
+
+ ) + } + render() { if (this._tableData.length > 0) { return ( @@ -186,13 +275,22 @@ export class TableBox extends ObservableReactComponent { this._props.layoutDoc.dataViz_selectedRows = new List(this._tableDataIds); } }}> -
-
-
+
+ {this.filtering? this.renderFiltering : null} +
-
-
Date: Wed, 13 Mar 2024 19:02:56 -0400 Subject: keeping rows selected fix --- src/client/views/nodes/DataVizBox/components/TableBox.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index 05429e82b..a0d8ecc6f 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -188,12 +188,16 @@ export class TableBox extends ObservableReactComponent { this._tableDataIds.forEach(rowID => { if (this.filteringType=="Value"){ if (this._props.records[rowID][this.filteringColumn]==this.filteringVal[0]) { - this.tableRowClick(e, rowID); + if (!NumListCast(this._props.layoutDoc.dataViz_selectedRows).includes(rowID)) { + this.tableRowClick(e, rowID); + } } } else { if (this.filteringVal[0]<=this._props.records[rowID][this.filteringColumn] && this._props.records[rowID][this.filteringColumn]<=this.filteringVal[1]){ - this.tableRowClick(e, rowID); + if (!NumListCast(this._props.layoutDoc.dataViz_selectedRows).includes(rowID)) { + this.tableRowClick(e, rowID); + } } } }) -- cgit v1.2.3-70-g09d2 From 4c4ab22252aba8f08d8a384e2bd0c6696db9b43b Mon Sep 17 00:00:00 2001 From: srichman333 Date: Sun, 31 Mar 2024 13:22:48 -0400 Subject: range --- src/client/views/nodes/DataVizBox/components/TableBox.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index a0d8ecc6f..26e1eeeff 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -185,6 +185,13 @@ export class TableBox extends ObservableReactComponent { */ @undoBatch filter = (e: any) => { + var start: any; + var end: any; + if (this.filteringType=="Range"){ + start = (this.filteringVal[0] as Number)? Number(this.filteringVal[0]): this.filteringVal[0] + end = (this.filteringVal[1] as Number)? Number(this.filteringVal[1]): this.filteringVal[0] + } + this._tableDataIds.forEach(rowID => { if (this.filteringType=="Value"){ if (this._props.records[rowID][this.filteringColumn]==this.filteringVal[0]) { @@ -194,7 +201,9 @@ export class TableBox extends ObservableReactComponent { } } else { - if (this.filteringVal[0]<=this._props.records[rowID][this.filteringColumn] && this._props.records[rowID][this.filteringColumn]<=this.filteringVal[1]){ + let compare = this._props.records[rowID][this.filteringColumn] + if (compare as Number) compare = Number(compare) + if (start<=compare && compare<=end){ if (!NumListCast(this._props.layoutDoc.dataViz_selectedRows).includes(rowID)) { this.tableRowClick(e, rowID); } @@ -281,7 +290,7 @@ export class TableBox extends ObservableReactComponent { }}>
-
{this.filtering? this.renderFiltering : null} -- cgit v1.2.3-70-g09d2 From d444d05ebe5eb0d72070ba21e1ae5935930b749f Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 17 Apr 2024 11:56:15 -0400 Subject: reverted fix for replacing placeholder text in a new typed note -- breaks switching from one fieldKey to another --- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 5c59f7f60..c2f3a6e4b 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1255,7 +1255,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - if (this._editorView && this._applyingChange !== this.fieldKey && incomingValue?.data !== this.dataDoc[this.fieldKey]) { + if (this._editorView && this._applyingChange !== this.fieldKey) { if (incomingValue?.data) { const updatedState = JSON.parse(incomingValue.data.Data); if (JSON.stringify(this._editorView.state.toJSON()) !== JSON.stringify(updatedState)) { -- cgit v1.2.3-70-g09d2 From 62937027183dc8acf14e489fbb4590aff6fce2cd Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 17 Apr 2024 12:25:17 -0400 Subject: fix problem where placeholder text of note wasn't being overwritten. --- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 1 + 1 file changed, 1 insertion(+) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index c2f3a6e4b..a2db2a1cc 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1484,6 +1484,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent Date: Wed, 24 Apr 2024 18:36:52 -0400 Subject: minor tweaks for merging --- src/client/apis/gpt/GPT.ts | 6 +++--- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 9 +++------ 2 files changed, 6 insertions(+), 9 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts index c97d29d6f..30194f9f8 100644 --- a/src/client/apis/gpt/GPT.ts +++ b/src/client/apis/gpt/GPT.ts @@ -43,7 +43,7 @@ const gptAPICall = async (inputText: string, callType: GPTCallType, prompt?: any }; const openai = new OpenAI(configuration); - let usePrompt = prompt? opts.prompt+prompt: opts.prompt; + let usePrompt = prompt ? opts.prompt + prompt : opts.prompt; let messages: ChatCompletionMessageParam[] = [ { role: 'system', content: usePrompt }, { role: 'user', content: inputText }, @@ -51,9 +51,9 @@ const gptAPICall = async (inputText: string, callType: GPTCallType, prompt?: any const response = await openai.chat.completions.create({ model: opts.model, - messages: messages, - temperature: opts.temp, max_tokens: opts.maxTokens, + temperature: opts.temp, + messages, }); const content = response.choices[0].message.content; return content; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index bb910737b..36c1de841 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -984,13 +984,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - if (!this._editorView) return; if (resIndex < newText.length) { - const marks = this._editorView.state.storedMarks ?? []; - this._editorView.dispatch(this._editorView.state.tr.insertText(newText[resIndex]).setStoredMarks(marks)); - setTimeout(() => { - this.animateRes(resIndex + 1, newText); - }, 20); + const marks = this._editorView?.state.storedMarks ?? []; + this._editorView?.dispatch(this._editorView?.state.tr.insertText(newText[resIndex]).setStoredMarks(marks)); + setTimeout(() => this.animateRes(resIndex + 1, newText), 20); } }; -- cgit v1.2.3-70-g09d2 From ae9404e2c80555875f2fd69f4ae55105ae51168b Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 24 Apr 2024 18:44:28 -0400 Subject: from last --- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 36c1de841..a46b19a85 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -996,15 +996,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent