aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/smartdraw/AnnotationPalette.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/smartdraw/AnnotationPalette.tsx')
-rw-r--r--src/client/views/smartdraw/AnnotationPalette.tsx361
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: '' },
-});