diff options
Diffstat (limited to 'src/client/views/KeywordBox.tsx')
-rw-r--r-- | src/client/views/KeywordBox.tsx | 363 |
1 files changed, 0 insertions, 363 deletions
diff --git a/src/client/views/KeywordBox.tsx b/src/client/views/KeywordBox.tsx deleted file mode 100644 index 68584a7fa..000000000 --- a/src/client/views/KeywordBox.tsx +++ /dev/null @@ -1,363 +0,0 @@ -import { Button, Colors, IconButton } from 'browndash-components'; -import { action, computed, makeObservable, observable, reaction } from 'mobx'; -import { observer } from 'mobx-react'; -import React from 'react'; -import { returnFalse, setupMoveUpEvents } from '../../ClientUtils'; -import { Doc, DocListCast } from '../../fields/Doc'; -import { DocData } from '../../fields/DocSymbols'; -import { List } from '../../fields/List'; -import { NumCast, StrCast } from '../../fields/Types'; -import { emptyFunction } from '../../Utils'; -import { DocumentType } from '../documents/DocumentTypes'; -import { DragManager } from '../util/DragManager'; -import { SnappingManager } from '../util/SnappingManager'; -import { DocumentView } from './nodes/DocumentView'; -import { ObservableReactComponent } from './ObservableReactComponent'; - -interface KeywordItemProps { - doc: Doc; - keyword: string; - keywordDoc: Doc; - setToEditing: () => void; - isEditing: boolean; -} - -/** - * A component that handles individual keywords. - */ -@observer -export class KeywordItem extends ObservableReactComponent<KeywordItemProps> { - constructor(props: any) { - super(props); - makeObservable(this); - this.ref = React.createRef(); - } - - private ref: React.RefObject<HTMLDivElement>; - - /** - * Gets the documents that a keyword is associated with. - * @returns An array of documents that contain the keyword. - */ - getKeywordCollectionDocs = () => { - for (const doc of DocListCast(Doc.ActiveDashboard?.myKeywordCollections)) { - if (doc.title === this._props.keyword) { - return doc[DocData].docs; - } - } - return null; - }; - - /** - * Creates a smart collection. - * @returns - */ - createCollection = () => { - // Get the documents that contain the keyword. - const selected = DocListCast(this.getKeywordCollectionDocs()!); - const newEmbeddings = selected.map(doc => Doc.MakeEmbedding(doc)); - - // Create a new collection and set up configurations. - const newCollection = ((doc: Doc) => { - const docData = doc[DocData]; - docData.data = new List<Doc>(newEmbeddings); - docData.title = this._props.keyword; - doc._freeform_panX = doc._freeform_panY = 0; - return doc; - })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true)); - newEmbeddings.forEach(embed => (embed.embedContainer = newCollection)); - newCollection._width = 900; - newCollection._height = 900; - newCollection.layout_fitWidth = true; - - // Add the collection to the keyword document's list of associated smart collections. - this._props.keywordDoc.collections = new List<Doc>([...DocListCast(this._props.keywordDoc.collections), newCollection]); - newCollection[DocData].data_labels = new List<string>([this._props.keyword]); - newCollection[DocData][`${this._props.keyword}`] = true; - newCollection[DocData].showLabels = true; - return newCollection; - }; - - @action - handleDragStart = (e: React.PointerEvent) => { - if (this._props.isEditing) { - const clone = this.ref.current?.cloneNode(true) as HTMLElement; - if (!clone) return; - - setupMoveUpEvents( - this, - e, - () => { - const dragData = new DragManager.DocumentDragData([this.createCollection()]); - DragManager.StartDocumentDrag([this.ref.current!], dragData, e.clientX, e.clientY, {}); - return true; - }, - returnFalse, - emptyFunction - ); - e.preventDefault(); - } - }; - - @action - removeLabel = () => { - if (this._props.doc[DocData].data_labels) { - if (this._props.doc.type === DocumentType.COL) { - const filtered_collections = new List<Doc>(DocListCast(this._props.keywordDoc.collections).filter(doc => doc !== this._props.doc)); - this._props.keywordDoc.collections = filtered_collections; - - for (const cur_doc of DocListCast(this.getKeywordCollectionDocs()!, [])) { - this._props.doc[DocData].data = new List<Doc>(DocListCast(this._props.doc[DocData].data).filter(doc => !Doc.AreProtosEqual(cur_doc, doc))); - } - } else { - const filtered_docs = new List<Doc>(DocListCast(this.getKeywordCollectionDocs()!).filter(doc => doc !== this._props.doc)); - this._props.keywordDoc[DocData].docs = filtered_docs; - - for (const collection of DocListCast(this._props.keywordDoc.collections)) { - collection[DocData].data = new List<Doc>(DocListCast(collection[DocData].data).filter(doc => !Doc.AreProtosEqual(this._props.doc, doc))); - } - } - } - this._props.doc[DocData].data_labels = (this._props.doc[DocData].data_labels as List<string>).filter(label => label !== this._props.keyword) as List<string>; - this._props.doc![DocData][`${this._props.keyword}`] = false; - }; - - render() { - return ( - <div className="keyword" onClick={this._props.setToEditing} onPointerDown={this.handleDragStart} ref={this.ref}> - {this._props.keyword} - {this.props.isEditing && <IconButton tooltip={'Remove label'} onPointerDown={this.removeLabel} icon={'X'} style={{ width: '8px', height: '8px', marginLeft: '10px' }} />} - </div> - ); - } -} - -interface KeywordBoxProps { - doc: Doc; - isEditing: boolean; -} - -/** - * A component that handles the keyword display for documents. - */ -@observer -export class KeywordBox extends ObservableReactComponent<KeywordBoxProps> { - @observable _currentInput: string = ''; - private height: number = 0; - private ref: React.RefObject<HTMLDivElement>; - - @computed - get currentScale() { - return NumCast((this._props.doc.embedContainer as Doc)?._freeform_scale, 1); - } - - @computed - get cur_height() { - return this.ref.current?.offsetHeight ? this.ref.current?.offsetHeight : 0; - } - - constructor(props: any) { - super(props); - makeObservable(this); - this.ref = React.createRef(); - - reaction( - () => this.cur_height, - () => { - this._props.doc[DocData].keywordHeight = this.height; - } - ); - } - - componentDidMount(): void { - this.height = this.ref.current?.offsetHeight ? this.ref.current?.offsetHeight : 0; - this._props.doc[DocData].keywordHeight = this.height; - } - - componentDidUpdate(prevProps: Readonly<KeywordBoxProps>): void { - this.height = this.ref.current?.offsetHeight ? this.ref.current?.offsetHeight : 0; - this._props.doc[DocData].keywordHeight = this.height; - } - - @action - setToEditing = () => { - this._props.isEditing = true; - }; - - @action - setToView = () => { - this._props.isEditing = false; - }; - - /** - * Gets the document associated with a keyword. - * @param keyword The keyword being searched for - * @returns A Doc containing keyword information - */ - getKeywordCollection = (keyword: string) => { - // Look for the keyword document. - for (const doc of DocListCast(Doc.ActiveDashboard!.myKeywordCollections)) { - if (doc.title === keyword) { - return doc; - } - } - - // If not contained, create a new document and add it to the active Dashboard's keyword list. - const keywordCollection = new Doc(); - keywordCollection.title = keyword; - keywordCollection[DocData].docs = new List<Doc>(); - keywordCollection.collections = new List<Doc>(); - if (Doc.ActiveDashboard) { - Doc.ActiveDashboard.myKeywordCollections = new List<Doc>([...DocListCast(Doc.ActiveDashboard.myKeywordCollections), keywordCollection]); - } - - return keywordCollection; - }; - - /** - * Adds the keyword to the document. - * @param keyword - */ - submitLabel = (keyword: string) => { - // If the active Dashboard does not have a keyword collection, create it. - if (Doc.ActiveDashboard && !Doc.ActiveDashboard.myKeywordCollections) { - Doc.ActiveDashboard.myKeywordCollections = new List<Doc>(); - } - - const submittedLabel = keyword.trim(); - if (submittedLabel && !this._props.doc![DocData][`${submittedLabel}`]) { - // If the keyword collection is not in active Dashboard, add it as a new doc, with the keyword as its title. - const keywordCollection = this.getKeywordCollection(submittedLabel); - - // If the document has no keywords field, create the field. - if (!this._props.doc[DocData].data_labels) { - this._props.doc[DocData].data_labels = new List<string>(); - } - - // If the document is of type COLLECTION, make it a smart collection, otherwise, add the keyword to the document. - if (this._props.doc.type === DocumentType.COL) { - keywordCollection.collections = new List<Doc>([...DocListCast(keywordCollection.collections), this._props.doc]); - - // Iterate through the keyword document's collections and add a copy of the document to each collection - for (const doc of DocListCast(keywordCollection[DocData].docs)) { - const newEmbedding = Doc.MakeEmbedding(doc); - this._props.doc[DocData].data = new List<Doc>([...DocListCast(this._props.doc[DocData].data), newEmbedding]); - newEmbedding.embedContainer = this._props.doc; - } - } else { - // Add this document to the keyword's collection of associated documents. - keywordCollection[DocData].docs = new List<Doc>([...DocListCast(keywordCollection[DocData].docs), this._props.doc]); - - // Iterate through the keyword document's collections and add a copy of the document to each collection - for (const collection of DocListCast(keywordCollection.collections)) { - const newEmbedding = Doc.MakeEmbedding(this._props.doc); - collection[DocData].data = new List<Doc>([...DocListCast(collection.data), newEmbedding]); - newEmbedding.embedContainer = collection; - } - } - - // Push the keyword to the document's keyword list field. - (this._props.doc![DocData].data_labels! as List<string>).push(submittedLabel); - this._props.doc![DocData][`${submittedLabel}`] = true; - this._currentInput = ''; // Clear the input box - } - }; - - @action - onInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { - this._currentInput = e.target.value; - }; - - render() { - const keywordsList = this._props.doc[DocData].data_labels ? this._props.doc[DocData].data_labels : new List<string>(); - const seldoc = DocumentView.SelectedDocs().lastElement(); - if (SnappingManager.IsDragging || !(seldoc === this._props.doc) || !this._props.isEditing) { - setTimeout( - action(() => { - if ((keywordsList as List<string>).length === 0) { - this._props.doc[DocData].showLabels = false; - } - this.setToView(); - }) - ); - } - - return ( - <div - className="keywords-container" - ref={this.ref} - style={{ - transformOrigin: 'top left', - overflow: 'hidden', - transform: `scale(${1 / this.currentScale})`, - backgroundColor: this._props.isEditing ? Colors.LIGHT_GRAY : Colors.TRANSPARENT, - borderColor: this._props.isEditing ? Colors.BLACK : Colors.TRANSPARENT, - maxWidth: `400px`, - }}> - <div className="keywords-content"> - <div className="keywords-list"> - {(keywordsList as List<string>).map(keyword => { - return <KeywordItem doc={this._props.doc} keyword={keyword} keywordDoc={this.getKeywordCollection(keyword)} setToEditing={this.setToEditing} isEditing={this._props.isEditing}></KeywordItem>; - })} - </div> - {this._props.isEditing ? ( - <div className="keyword-editing-box"> - <div className="keyword-input-box"> - <input - value={this._currentInput} - autoComplete="off" - onChange={this.onInputChange} - onKeyDown={e => { - e.key === 'Enter' ? this.submitLabel(this._currentInput) : null; - e.stopPropagation(); - }} - type="text" - placeholder="Input keywords for document..." - aria-label="keyword-input" - className="keyword-input" - style={{ width: '100%', borderRadius: '5px' }} - /> - </div> - {Doc.ActiveDashboard?.myKeywordCollections ? ( - <div className="keyword-suggestions-box"> - {DocListCast(Doc.ActiveDashboard?.myKeywordCollections).map(doc => { - const keyword = StrCast(doc.title); - return ( - <Button - style={{ margin: '2px 2px', border: '1px solid black', backgroundColor: 'lightblue', color: 'black' }} - text={keyword} - color={SnappingManager.userVariantColor} - tooltip={'Add existing keyword'} - onClick={() => { - this.submitLabel(keyword); - }} - /> - ); - })} - </div> - ) : ( - <div></div> - )} - <div className="keyword-buttons"> - <IconButton - tooltip={'Close Menu'} - onPointerDown={() => { - if ((keywordsList as List<string>).length === 0) { - this._props.doc[DocData].showLabels = false; - } else { - this.setToView(); - } - }} - icon={'x'} - style={{ width: '4px' }} - /> - </div> - </div> - ) : ( - <div></div> - )} - </div> - </div> - ); - } -} |