diff options
Diffstat (limited to 'src/client/views/smartdraw/AnnotationPalette.tsx')
-rw-r--r-- | src/client/views/smartdraw/AnnotationPalette.tsx | 361 |
1 files changed, 0 insertions, 361 deletions
diff --git a/src/client/views/smartdraw/AnnotationPalette.tsx b/src/client/views/smartdraw/AnnotationPalette.tsx deleted file mode 100644 index f1e2e4f41..000000000 --- a/src/client/views/smartdraw/AnnotationPalette.tsx +++ /dev/null @@ -1,361 +0,0 @@ -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Slider, Switch } from '@mui/material'; -import { Button } from 'browndash-components'; -import { action, makeObservable, observable } from 'mobx'; -import { observer } from 'mobx-react'; -import * as React from 'react'; -import { AiOutlineSend } from 'react-icons/ai'; -import ReactLoading from 'react-loading'; -import { returnEmptyFilter, returnFalse, returnTrue } from '../../../ClientUtils'; -import { emptyFunction } from '../../../Utils'; -import { Doc, DocListCast, returnEmptyDoclist } from '../../../fields/Doc'; -import { DocData } from '../../../fields/DocSymbols'; -import { ImageCast, NumCast } from '../../../fields/Types'; -import { ImageField } from '../../../fields/URLField'; -import { DocumentType } from '../../documents/DocumentTypes'; -import { Docs } from '../../documents/Documents'; -import { makeUserTemplateButtonOrImage } from '../../util/DropConverter'; -import { SettingsManager } from '../../util/SettingsManager'; -import { Transform } from '../../util/Transform'; -import { undoBatch } from '../../util/UndoManager'; -import { ObservableReactComponent } from '../ObservableReactComponent'; -import { DefaultStyleProvider, returnEmptyDocViewList } from '../StyleProvider'; -import { DocumentView, DocumentViewInternal } from '../nodes/DocumentView'; -import { FieldView } from '../nodes/FieldView'; -import './AnnotationPalette.scss'; -import { DrawingOptions, SmartDrawHandler } from './SmartDrawHandler'; - -interface AnnotationPaletteProps { - Document: Doc; -} - -/** - * The AnnotationPalette can be toggled in the lightbox view of a document. The goal of the palette - * is to offer an easy way for users to save then drag and drop repeated annotations onto a document. - * These annotations can be of any annotation type and operate similarly to user templates. - * - * On the "add" side of the palette, there is a way to create a drawing annotation with GPT. Users can - * enter the item to draw, toggle different settings, then GPT will generate three versions of the drawing - * to choose from. These drawings can then be saved to the palette as annotations. - */ -@observer -export class AnnotationPalette extends ObservableReactComponent<AnnotationPaletteProps> { - @observable private _paletteMode: 'create' | 'view' = 'view'; - @observable private _userInput: string = ''; - @observable private _isLoading: boolean = false; - @observable private _canInteract: boolean = true; - @observable private _showRegenerate: boolean = false; - @observable private _docView: DocumentView | null = null; - @observable private _docCarouselView: DocumentView | null = null; - @observable private _opts: DrawingOptions = { text: '', complexity: 5, size: 200, autoColor: true, x: 0, y: 0 }; - private _gptRes: string[] = []; - - constructor(props: AnnotationPaletteProps) { - super(props); - makeObservable(this); - } - - public static LayoutString(fieldKey: string) { - return FieldView.LayoutString(AnnotationPalette, fieldKey); - } - - Contains = (view: DocumentView) => { - return (this._docView && (view.containerViewPath?.() ?? []).concat(view).includes(this._docView)) || (this._docCarouselView && (view.containerViewPath?.() ?? []).concat(view).includes(this._docCarouselView)); - }; - - return170 = () => 170; - - @action - handleKeyPress = async (event: React.KeyboardEvent) => { - if (event.key === 'Enter') { - await this.generateDrawings(); - } - }; - - @action - setPaletteMode = (mode: 'create' | 'view') => { - this._paletteMode = mode; - }; - - @action - setUserInput = (input: string) => { - if (!this._isLoading) this._userInput = input; - }; - - @action - setDetail = (detail: number) => { - if (this._canInteract) this._opts.complexity = detail; - }; - - @action - setColor = (autoColor: boolean) => { - if (this._canInteract) this._opts.autoColor = autoColor; - }; - - @action - setSize = (size: number) => { - if (this._canInteract) this._opts.size = size; - }; - - @action - resetPalette = (changePaletteMode: boolean) => { - if (changePaletteMode) this.setPaletteMode('view'); - this.setUserInput(''); - this.setDetail(5); - this.setColor(true); - this.setSize(200); - this._showRegenerate = false; - this._canInteract = true; - this._opts = { text: '', complexity: 5, size: 200, autoColor: true, x: 0, y: 0 }; - this._gptRes = []; - this._props.Document[DocData].data = undefined; - }; - - /** - * Adds a doc to the annotation palette. Gets a snapshot of the document to use as a preview in the palette. When this - * preview is dragged onto a parent document, a copy of that document is added as an annotation. - */ - public static addToPalette = async (doc: Doc) => { - if (!doc.savedAsAnno) { - const docView = DocumentView.getDocumentView(doc); - await docView?.ComponentView?.updateIcon?.(true); - const { clone } = await Doc.MakeClone(doc); - clone.title = doc.title; - const image = ImageCast(doc.icon, ImageCast(clone[Doc.LayoutFieldKey(clone)]))?.url?.href; - Doc.AddDocToList(Doc.MyAnnos, 'data', makeUserTemplateButtonOrImage(clone, image)); - doc.savedAsAnno = true; - } - }; - - public static getIcon(group: Doc) { - const docView = DocumentView.getDocumentView(group); - if (docView) { - docView.ComponentView?.updateIcon?.(true); - return new Promise<ImageField | undefined>(res => setTimeout(() => res(ImageCast(docView.Document.icon)), 1000)); - } - return undefined; - } - - /** - * Calls the draw with GPT functions in SmartDrawHandler to allow users to generate drawings straight from - * the annotation palette. - */ - @undoBatch - generateDrawings = action(async () => { - this._isLoading = true; - this._props.Document[DocData].data = undefined; - for (let i = 0; i < 3; i++) { - try { - SmartDrawHandler.Instance.AddDrawing = this.addDrawing; - this._canInteract = false; - if (this._showRegenerate) { - await SmartDrawHandler.Instance.regenerate(this._opts, this._gptRes[i], this._userInput); - } else { - await SmartDrawHandler.Instance.drawWithGPT({ X: 0, Y: 0 }, this._userInput, this._opts.complexity, this._opts.size, this._opts.autoColor); - } - } catch (e) { - console.log('Error generating drawing', e); - } - } - this._opts.text !== '' ? (this._opts.text = `${this._opts.text} ~~~ ${this._userInput}`) : (this._opts.text = this._userInput); - this._userInput = ''; - this._isLoading = false; - this._showRegenerate = true; - }); - - @action - addDrawing = (drawing: Doc, opts: DrawingOptions, gptRes: string) => { - this._gptRes.push(gptRes); - drawing[DocData].freeform_fitContentsToBox = true; - Doc.AddDocToList(this._props.Document, 'data', drawing); - }; - - /** - * Saves the currently showing, newly generated drawing to the annotation palette and sets the metadata. - * AddToPalette() is generically used to add any document to the palette, while this defines the behavior for when a user - * presses the "save drawing" button. - */ - saveDrawing = async () => { - const cIndex = NumCast(this._props.Document.carousel_index); - const focusedDrawing = DocListCast(this._props.Document.data)[cIndex]; - const docData = focusedDrawing[DocData]; - docData.title = this._opts.text.match(/^(.*?)~~~.*$/)?.[1] || this._opts.text; - docData.drawingInput = this._opts.text; - docData.drawingComplexity = this._opts.complexity; - docData.drawingColored = this._opts.autoColor; - docData.drawingSize = this._opts.size; - docData.drawingData = this._gptRes[cIndex]; - docData.width = this._opts.size; - docData.x = this._opts.x; - docData.y = this._opts.y; - await AnnotationPalette.addToPalette(focusedDrawing); - this.resetPalette(true); - }; - - render() { - return ( - <div className="annotation-palette" style={{ zIndex: 1000 }} onClick={e => e.stopPropagation()}> - {this._paletteMode === 'view' && ( - <> - <DocumentView - ref={r => (this._docView = r)} - Document={Doc.MyAnnos} - addDocument={undefined} - addDocTab={DocumentViewInternal.addDocTabFunc} - pinToPres={DocumentView.PinDoc} - containerViewPath={returnEmptyDocViewList} - styleProvider={DefaultStyleProvider} - removeDocument={returnFalse} - ScreenToLocalTransform={Transform.Identity} - PanelWidth={this.return170} - PanelHeight={this.return170} - renderDepth={0} - isContentActive={returnTrue} - focus={emptyFunction} - whenChildContentsActiveChanged={emptyFunction} - childFilters={returnEmptyFilter} - childFiltersByRanges={returnEmptyFilter} - searchFilterDocs={returnEmptyDoclist} - /> - <Button text="Add" icon={<FontAwesomeIcon icon="square-plus" />} color={SettingsManager.userColor} onClick={() => this.setPaletteMode('create')} /> - </> - )} - {this._paletteMode === 'create' && ( - <> - <div className="palette-create"> - <input - className="palette-create-input" - aria-label="label-input" - id="new-label" - type="text" - value={this._userInput} - onChange={e => { - this.setUserInput(e.target.value); - }} - placeholder={this._showRegenerate ? '(Optional) Enter edits' : 'Enter item to draw'} - onKeyDown={this.handleKeyPress} - /> - <Button - style={{ alignSelf: 'flex-end' }} - tooltip={this._showRegenerate ? 'Regenerate' : 'Send'} - icon={this._isLoading ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : this._showRegenerate ? <FontAwesomeIcon icon={'rotate'} /> : <AiOutlineSend />} - iconPlacement="right" - color={SettingsManager.userColor} - onClick={this.generateDrawings} - /> - </div> - <div className="palette-create-options"> - <div className="palette-color"> - Color - <Switch - sx={{ - '& .MuiSwitch-switchBase.Mui-checked': { - color: SettingsManager.userColor, - }, - '& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track': { - backgroundColor: SettingsManager.userVariantColor, - }, - }} - defaultChecked={true} - value={this._opts.autoColor} - size="small" - onChange={() => this.setColor(!this._opts.autoColor)} - /> - </div> - <div className="palette-detail"> - Detail - <Slider - sx={{ - '& .MuiSlider-thumb': { - color: SettingsManager.userColor, - '&.Mui-focusVisible, &:hover, &.Mui-active': { - boxShadow: `0px 0px 0px 8px${SettingsManager.userColor.slice(0, 7)}10`, - }, - }, - '& .MuiSlider-track': { - color: SettingsManager.userVariantColor, - }, - '& .MuiSlider-rail': { - color: SettingsManager.userColor, - }, - }} - style={{ width: '80%' }} - min={1} - max={10} - step={1} - size="small" - value={this._opts.complexity} - onChange={(e, val) => { - this.setDetail(val as number); - }} - valueLabelDisplay="auto" - /> - </div> - <div className="palette-size"> - Size - <Slider - sx={{ - '& .MuiSlider-thumb': { - color: SettingsManager.userColor, - '&.Mui-focusVisible, &:hover, &.Mui-active': { - boxShadow: `0px 0px 0px 8px${SettingsManager.userColor.slice(0, 7)}20`, - }, - }, - '& .MuiSlider-track': { - color: SettingsManager.userVariantColor, - }, - '& .MuiSlider-rail': { - color: SettingsManager.userColor, - }, - }} - style={{ width: '80%' }} - min={50} - max={500} - step={10} - size="small" - value={this._opts.size} - onChange={(e, val) => { - this.setSize(val as number); - }} - valueLabelDisplay="auto" - /> - </div> - </div> - <DocumentView - ref={r => (this._docCarouselView = r)} - Document={this._props.Document} - addDocument={undefined} - addDocTab={DocumentViewInternal.addDocTabFunc} - pinToPres={DocumentView.PinDoc} - containerViewPath={returnEmptyDocViewList} - styleProvider={DefaultStyleProvider} - removeDocument={returnFalse} - ScreenToLocalTransform={Transform.Identity} - PanelWidth={this.return170} - PanelHeight={this.return170} - renderDepth={1} - isContentActive={returnTrue} - focus={emptyFunction} - whenChildContentsActiveChanged={emptyFunction} - childFilters={returnEmptyFilter} - childFiltersByRanges={returnEmptyFilter} - searchFilterDocs={returnEmptyDoclist} - /> - <div className="palette-buttons"> - <Button text="Back" tooltip="Back to All Annotations" icon={<FontAwesomeIcon icon="reply" />} color={SettingsManager.userColor} onClick={() => this.resetPalette(true)} /> - <div className="palette-save-reset"> - <Button tooltip="Save" icon={<FontAwesomeIcon icon="file-arrow-down" />} color={SettingsManager.userColor} onClick={this.saveDrawing} /> - <Button tooltip="Reset" icon={<FontAwesomeIcon icon="rotate-left" />} color={SettingsManager.userColor} onClick={() => this.resetPalette(false)} /> - </div> - </div> - </> - )} - </div> - ); - } -} - -Docs.Prototypes.TemplateMap.set(DocumentType.ANNOPALETTE, { - layout: { view: AnnotationPalette, dataField: 'data' }, - options: { acl: '' }, -}); |