From 19aa61f593c896f4d3bd0ffae6dbe306c2a9546d Mon Sep 17 00:00:00 2001 From: mehekj Date: Wed, 10 Aug 2022 11:51:41 -0400 Subject: basic table in progress --- .../collectionSchema/CollectionSchemaCells.tsx | 639 ------------------- .../collectionSchema/CollectionSchemaHeaders.tsx | 513 --------------- .../CollectionSchemaMovableColumn.tsx | 138 ---- .../CollectionSchemaMovableRow.tsx | 151 ----- .../collectionSchema/CollectionSchemaView.scss | 626 ++----------------- .../collectionSchema/CollectionSchemaView.tsx | 668 ++------------------ .../collectionSchema/SchemaColumnHeader.tsx | 28 + .../collections/collectionSchema/SchemaRowBox.tsx | 33 + .../collections/collectionSchema/SchemaTable.tsx | 693 --------------------- .../collectionSchema/SchemaTableCell.tsx | 24 + 10 files changed, 182 insertions(+), 3331 deletions(-) delete mode 100644 src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx delete mode 100644 src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx delete mode 100644 src/client/views/collections/collectionSchema/CollectionSchemaMovableColumn.tsx delete mode 100644 src/client/views/collections/collectionSchema/CollectionSchemaMovableRow.tsx create mode 100644 src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx create mode 100644 src/client/views/collections/collectionSchema/SchemaRowBox.tsx delete mode 100644 src/client/views/collections/collectionSchema/SchemaTable.tsx create mode 100644 src/client/views/collections/collectionSchema/SchemaTableCell.tsx (limited to 'src/client/views/collections/collectionSchema') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx deleted file mode 100644 index adcd9e1e3..000000000 --- a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx +++ /dev/null @@ -1,639 +0,0 @@ -import React = require("react"); -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed, observable } from "mobx"; -import { observer } from "mobx-react"; -import { extname } from "path"; -import DatePicker from "react-datepicker"; -import { CellInfo } from "react-table"; -import { DateField } from "../../../../fields/DateField"; -import { Doc, DocListCast, Field, Opt } from "../../../../fields/Doc"; -import { Id } from "../../../../fields/FieldSymbols"; -import { List } from "../../../../fields/List"; -import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField"; -import { ComputedField } from "../../../../fields/ScriptField"; -import { BoolCast, Cast, DateCast, FieldValue, StrCast } from "../../../../fields/Types"; -import { ImageField } from "../../../../fields/URLField"; -import { emptyFunction, Utils } from "../../../../Utils"; -import { Docs } from "../../../documents/Documents"; -import { DocumentType } from "../../../documents/DocumentTypes"; -import { DocumentManager } from "../../../util/DocumentManager"; -import { DragManager } from "../../../util/DragManager"; -import { KeyCodes } from "../../../util/KeyCodes"; -import { CompileScript } from "../../../util/Scripting"; -import { SearchUtil } from "../../../util/SearchUtil"; -import { SnappingManager } from "../../../util/SnappingManager"; -import { undoBatch } from "../../../util/UndoManager"; -import '../../../views/DocumentDecorations.scss'; -import { EditableView } from "../../EditableView"; -import { MAX_ROW_HEIGHT } from '../../global/globalCssVariables.scss'; -import { DocumentIconContainer } from "../../nodes/DocumentIcon"; -import { OverlayView } from "../../OverlayView"; -import { CollectionView } from "../CollectionView"; -import "./CollectionSchemaView.scss"; - -// intialize cell properties -export interface CellProps { - row: number; - col: number; - rowProps: CellInfo; - // currently unused - CollectionView: Opt; - // currently unused - ContainingCollection: Opt; - Document: Doc; - // column name - fieldKey: string; - // currently unused - renderDepth: number; - // called when a button is pressed on the node itself - addDocTab: (document: Doc, where: string) => boolean; - pinToPres: (document: Doc) => void; - moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, - addDocument: (document: Doc | Doc[]) => boolean) => boolean; - isFocused: boolean; - changeFocusedCellByIndex: (row: number, col: number) => void; - // set whether the cell is in the isEditing mode - setIsEditing: (isEditing: boolean) => void; - isEditable: boolean; - setPreviewDoc: (doc: Doc) => void; - setComputed: (script: string, doc: Doc, field: string, row: number, col: number) => boolean; - getField: (row: number, col?: number) => void; - // currnetly unused - showDoc: (doc: Doc | undefined, dataDoc?: any, screenX?: number, screenY?: number) => void; -} - -@observer -export class CollectionSchemaCell extends React.Component { - // return a field key that is corrected for whether it COMMENT - public static resolvedFieldKey(column: string, rowDoc: Doc) { - const fieldKey = column; - if (fieldKey.startsWith("*")) { - const rootKey = fieldKey.substring(1); - const allKeys = [...Array.from(Object.keys(rowDoc)), ...Array.from(Object.keys(Doc.GetProto(rowDoc)))]; - const matchedKeys = allKeys.filter(key => key.includes(rootKey)); - if (matchedKeys.length) return matchedKeys[0]; - } - return fieldKey; - } - @observable protected _isEditing: boolean = false; - protected _focusRef = React.createRef(); - protected _rowDoc = this.props.rowProps.original; - // Gets the serialized data in proto form of the base proto that this document's proto inherits from - protected _rowDataDoc = Doc.GetProto(this.props.rowProps.original); - // methods for dragging and dropping - protected _dropDisposer?: DragManager.DragDropDisposer; - @observable contents: string = ""; - - componentDidMount() { document.addEventListener("keydown", this.onKeyDown); } - componentWillUnmount() { document.removeEventListener("keydown", this.onKeyDown); } - - @action - onKeyDown = (e: KeyboardEvent): void => { - // If a cell is editable and clicked, hitting enter shoudl allow the user to edit it - if (this.props.isFocused && this.props.isEditable && e.keyCode === KeyCodes.ENTER) { - document.removeEventListener("keydown", this.onKeyDown); - this._isEditing = true; - this.props.setIsEditing(true); - } - } - - @action - isEditingCallback = (isEditing: boolean): void => { - // a general method that takes a boolean that determines whether the cell should be in - // is-editing mode - // remove the event listener if it's there - document.removeEventListener("keydown", this.onKeyDown); - // it's not already in is-editing mode, re-add the event listener - isEditing && document.addEventListener("keydown", this.onKeyDown); - this._isEditing = isEditing; - this.props.setIsEditing(isEditing); - this.props.changeFocusedCellByIndex(this.props.row, this.props.col); - } - - @action - onPointerDown = async (e: React.PointerEvent): Promise => { - // pan to the cell - this.onItemDown(e); - // focus on it - this.props.changeFocusedCellByIndex(this.props.row, this.props.col); - this.props.setPreviewDoc(this.props.rowProps.original); - - let url: string; - if (url = StrCast(this.props.rowProps.row.href)) { - // opens up the the doc in a new window, blurring the old one - try { - new URL(url); - const temp = window.open(url)!; - temp.blur(); - window.focus(); - } catch { } - } - - const doc = Cast(this._rowDoc[this.renderFieldKey], Doc, null); - doc && this.props.setPreviewDoc(doc); - } - - @undoBatch - applyToDoc = (doc: Doc, row: number, col: number, run: (args?: { [name: string]: any }) => any) => { - // apply a specified change to the cell - const res = run({ this: doc, $r: row, $c: col, $: (r: number = 0, c: number = 0) => this.props.getField(r + row, c + col) }); - if (!res.success) return false; - // change what is rendered to this new changed cell content - doc[this.renderFieldKey] = res.result; - return true; - // return whether the change was successful - } - - private drop = (e: Event, de: DragManager.DropEvent) => { - // if the drag has data at its completion - if (de.complete.docDragData) { - // if only one doc was dragged - if (de.complete.docDragData.draggedDocuments.length === 1) { - // update the renderFieldKey - this._rowDataDoc[this.renderFieldKey] = de.complete.docDragData.draggedDocuments[0]; - } - else { - // create schema document reflecting the new column arrangement - const coll = Docs.Create.SchemaDocument([new SchemaHeaderField("title", "#f1efeb")], de.complete.docDragData.draggedDocuments, {}); - this._rowDataDoc[this.renderFieldKey] = coll; - } - e.stopPropagation(); - } - } - - protected dropRef = (ele: HTMLElement | null) => { - // if the drop disposer is not undefined, run its function - this._dropDisposer?.(); - // if ele is not null, give ele a non-undefined drop disposer - ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this))); - } - - returnHighlights(contents: string, positions?: number[]) { - if (positions) { - const results = []; - StrCast(this.props.Document._searchString); - const length = StrCast(this.props.Document._searchString).length; - const color = contents ? "black" : "grey"; - - results.push({contents?.slice(0, positions[0])}); - positions.forEach((num, cur) => { - results.push({contents?.slice(num, num + length)}); - let end = 0; - cur === positions.length - 1 ? end = contents.length : end = positions[cur + 1]; - results.push({contents?.slice(num + length, end)}); - } - ); - return results; - } - return {contents ? contents?.valueOf() : "undefined"}; - } - - @computed get renderFieldKey() { - // gets the resolved field key of this cell - return CollectionSchemaCell.resolvedFieldKey(this.props.rowProps.column.id!, this.props.rowProps.original); - } - - onItemDown = async (e: React.PointerEvent) => { - // if the document is a document used to change UI for search results in schema view - if (this.props.Document._searchDoc) { - const aliasdoc = await SearchUtil.GetAliasesOfDocument(this._rowDataDoc); - const targetContext = aliasdoc.length <= 0 ? undefined : Cast(aliasdoc[0].context, Doc, null); - // Jump to the this document - DocumentManager.Instance.jumpToDocument(this._rowDoc, false, emptyFunction, targetContext ? [targetContext] : [], - undefined, undefined, undefined, () => this.props.setPreviewDoc(this._rowDoc)); - } - } - - renderCellWithType(type: string | undefined) { - const dragRef: React.RefObject = React.createRef(); - - // the column - const fieldKey = this.renderFieldKey; - // the exact cell - const field = this._rowDoc[fieldKey]; - - const onPointerEnter = (e: React.PointerEvent): void => { - // e.buttons === 1 means the left moue pointer is down - if (e.buttons === 1 && SnappingManager.GetIsDragging() && (type === "document" || type === undefined)) { - dragRef.current!.className = "collectionSchemaView-cellContainer doc-drag-over"; - } - }; - const onPointerLeave = (e: React.PointerEvent): void => { - // change the class name to indicate that the cell is no longer being dragged - dragRef.current!.className = "collectionSchemaView-cellContainer"; - }; - - let contents = Field.toString(field as Field); - // display 2 hyphens instead of a blank box for empty cells - contents = contents === "" ? "--" : contents; - - // classname reflects the tatus of the cell - let className = "collectionSchemaView-cellWrapper"; - if (this._isEditing) className += " editing"; - if (this.props.isFocused && this.props.isEditable) className += " focused"; - if (this.props.isFocused && !this.props.isEditable) className += " inactive"; - - const positions = []; - if (StrCast(this.props.Document._searchString).toLowerCase() !== "") { - // term is ...promise pending... if the field is a Promise, otherwise it is the cell's contents - let term = (field instanceof Promise) ? "...promise pending..." : contents.toLowerCase(); - const search = StrCast(this.props.Document._searchString).toLowerCase(); - let start = term.indexOf(search); - let tally = 0; - // if search is found in term - if (start !== -1) { - positions.push(start); - } - // if search is found in term, continue finding all instances of search in term - while (start < contents?.length && start !== -1) { - term = term.slice(start + search.length + 1); - tally += start + search.length + 1; - start = term.indexOf(search); - positions.push(tally + start); - } - // remove the last position - if (positions.length > 1) { - positions.pop(); - } - } - const placeholder = type === "number" ? "0" : contents === "" ? "--" : "undefined"; - return ( -
this._isEditing = true)} onPointerEnter={onPointerEnter} onPointerLeave={onPointerLeave}> -
-
- {!this.props.Document._searchDoc ? - { - const cfield = ComputedField.WithoutComputed(() => FieldValue(field)); - const cscript = cfield instanceof ComputedField ? cfield.script.originalScript : undefined; - const cfinalScript = cscript?.split("return")[cscript.split("return").length - 1]; - return cscript ? (cfinalScript?.endsWith(";") ? `:=${cfinalScript?.substring(0, cfinalScript.length - 2)}` : cfinalScript) : - Field.IsField(cfield) ? Field.toScriptString(cfield) : ""; - }} - SetValue={action((value: string) => { - // sets what is displayed after the user makes an input - let retVal = false; - if (value.startsWith(":=") || value.startsWith("=:=")) { - // decides how to compute a value when given either of the above strings - const script = value.substring(value.startsWith("=:=") ? 3 : 2); - retVal = this.props.setComputed(script, value.startsWith(":=") ? this._rowDataDoc : this._rowDoc, this.renderFieldKey, this.props.row, this.props.col); - } else { - // check if the input is a number - let inputIsNum = true; - for (const s of value) { - if (isNaN(parseInt(s)) && !(s === ".") && !(s === ",")) { - inputIsNum = false; - } - } - // check if the input is a boolean - const inputIsBool: boolean = value === "false" || value === "true"; - // what to do in the case - if (!inputIsNum && !inputIsBool && !value.startsWith("=")) { - // if it's not a number, it's a string, and should be processed as such - // strips the string of quotes when it is edited to prevent quotes form being added to the text automatically - // after each edit - let valueSansQuotes = value; - if (this._isEditing) { - const vsqLength = valueSansQuotes.length; - // get rid of outer quotes - valueSansQuotes = valueSansQuotes.substring(value.startsWith("\"") ? 1 : 0, - valueSansQuotes.charAt(vsqLength - 1) === "\"" ? vsqLength - 1 : vsqLength); - } - let inputAsString = '"'; - // escape any quotes in the string - for (const i of valueSansQuotes) { - if (i === '"') { - inputAsString += '\\"'; - } else { - inputAsString += i; - } - } - // add a closing quote - inputAsString += '"'; - //two options here: we can strip off outer quotes or we can figure out what's going on with the script - const script = CompileScript(inputAsString, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); - const changeMade = inputAsString.length !== value.length || inputAsString.length - 2 !== value.length; - // change it if a change is made, otherwise, just compile using the old cell conetnts - script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); - // handle numbers and expressions - } else if (inputIsNum || value.startsWith("=")) { - //TODO: make accept numbers - const inputscript = value.substring(value.startsWith("=") ? 1 : 0); - // if commas are not stripped, the parser only considers the numbers after the last comma - let inputSansCommas = ""; - for (const s of inputscript) { - if (!(s === ",")) { - inputSansCommas += s; - } - } - const script = CompileScript(inputSansCommas, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); - const changeMade = value.length - 2 !== value.length; - script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); - // handle booleans - } else if (inputIsBool) { - const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); - const changeMade = value.length - 2 !== value.length; - script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); - } - } - if (retVal) { - this._isEditing = false; // need to set this here. otherwise, the assignment of the field will invalidate & cause render() to be called with the wrong value for 'editing' - this.props.setIsEditing(false); - } - return retVal; - })} - OnFillDown={async (value: string) => { - // computes all of the value preceded by := - const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); - script.compiled && DocListCast(this.props.Document[this.props.fieldKey]). - forEach((doc, i) => value.startsWith(":=") ? - this.props.setComputed(value.substring(2), Doc.GetProto(doc), this.renderFieldKey, i, this.props.col) : - this.applyToDoc(Doc.GetProto(doc), i, this.props.col, script.run)); - }} - /> - : - this.returnHighlights(contents, positions) - } -
-
-
- ); - } - - render() { return this.renderCellWithType(undefined); } -} - -@observer -export class CollectionSchemaNumberCell extends CollectionSchemaCell { render() { return this.renderCellWithType("number"); } } - -@observer -export class CollectionSchemaBooleanCell extends CollectionSchemaCell { render() { return this.renderCellWithType("boolean"); } } - -@observer -export class CollectionSchemaStringCell extends CollectionSchemaCell { render() { return this.renderCellWithType("string"); } } - -@observer -export class CollectionSchemaDateCell extends CollectionSchemaCell { - @computed get _date(): Opt { - // if the cell is a date field, cast then contents to a date. Otherrwwise, make the contents undefined. - return this._rowDoc[this.renderFieldKey] instanceof DateField ? DateCast(this._rowDoc[this.renderFieldKey]) : undefined; - } - - @action - handleChange = (date: any) => { - // const script = CompileScript(date.toString(), { requiredType: "Date", addReturn: true, params: { this: Doc.name } }); - // if (script.compiled) { - // this.applyToDoc(this._document, this.props.row, this.props.col, script.run); - // } else { - // ^ DateCast is always undefined for some reason, but that is what the field should be set to - this._rowDoc[this.renderFieldKey] = new DateField(date as Date); - //} - } - - render() { - return !this.props.isFocused ? {this._date ? Field.toString(this._date as Field) : "--"} : - this.handleChange(date)} - onChange={date => this.handleChange(date)} - />; - } -} - -@observer -export class CollectionSchemaDocCell extends CollectionSchemaCell { - - _overlayDisposer?: () => void; - - @computed get _doc() { return FieldValue(Cast(this._rowDoc[this.renderFieldKey], Doc)); } - - @action - onSetValue = (value: string) => { - this._doc && (Doc.GetProto(this._doc).title = value); - - const script = CompileScript(value, { - addReturn: true, - typecheck: true, - transformer: DocumentIconContainer.getTransformer() - }); - // compile the script - const results = script.compiled && script.run(); - // if the script was compiled and run - if (results && results.success) { - this._rowDoc[this.renderFieldKey] = results.result; - return true; - } - return false; - } - - componentWillUnmount() { this.onBlur(); } - - onBlur = () => { this._overlayDisposer?.(); }; - onFocus = () => { - this.onBlur(); - this._overlayDisposer = OverlayView.Instance.addElement(, { x: 0, y: 0 }); - } - - @action - isEditingCallback = (isEditing: boolean): void => { - // the isEditingCallback from a general CollectionSchemaCell - document.removeEventListener("keydown", this.onKeyDown); - isEditing && document.addEventListener("keydown", this.onKeyDown); - this._isEditing = isEditing; - this.props.setIsEditing(isEditing); - this.props.changeFocusedCellByIndex(this.props.row, this.props.col); - } - - render() { - // if there's a doc, render it - return !this._doc ? this.renderCellWithType("document") : -
-
- StrCast(this._doc?.title)} - SetValue={action((value: string) => { - this.onSetValue(value); - return true; - })} - /> -
-
this._doc && this.props.addDocTab(this._doc, "add:right")} className="collectionSchemaView-cellContents-docButton"> - -
-
; - } -} - -@observer -export class CollectionSchemaImageCell extends CollectionSchemaCell { - - choosePath(url: URL) { - if (url.protocol === "data") return url.href; // if the url ises the data protocol, just return the href - if (url.href.indexOf(window.location.origin) === -1) return Utils.CorsProxy(url.href); // otherwise, put it through the cors proxy erver - if (!/\.(png|jpg|jpeg|gif|webp)$/.test(url.href.toLowerCase())) return url.href;//Why is this here — good question - - const ext = extname(url.href); - return url.href.replace(ext, "_o" + ext); - } - - render() { - const field = Cast(this._rowDoc[this.renderFieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc - const alts = DocListCast(this._rowDoc[this.renderFieldKey + "-alternates"]); // retrieve alternate documents that may be rendered as alternate images - const altpaths = alts.map(doc => Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url).filter(url => url).map(url => this.choosePath(url)); // access the primary layout data of the alternate documents - const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths; - // If there is a path, follow it; otherwise, follow a link to a default image icon - const url = paths.length ? paths : [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")]; - - const aspect = Doc.NativeAspect(this._rowDoc); // aspect ratio - let width = Math.min(75, this.props.rowProps.width); // get a with that is no smaller than 75px - const height = Math.min(75, width / aspect); // get a height either proportional to that or 75 px - width = height * aspect; // increase the width of the image if necessary to maintain proportionality - - const reference = React.createRef(); - return
-
- -
-
; - } -} - - -@observer -export class CollectionSchemaListCell extends CollectionSchemaCell { - _overlayDisposer?: () => void; - - @computed get _field() { return this._rowDoc[this.renderFieldKey]; } - @computed get _optionsList() { return this._field as List; } - @observable private _opened = false; // whether the list is opened - @observable private _text = "select an item"; - @observable private _selectedNum = 0; // the index of the list item selected - - @action - onSetValue = (value: string) => { - // change if it's a document - this._optionsList[this._selectedNum] = this._text = value; - - (this._field as List).splice(this._selectedNum, 1, value); - } - - @action - onSelected = (element: string, index: number) => { - // if an item is selected, the private variables should update to reflect this - this._text = element; - this._selectedNum = index; - } - - onFocus = () => { - this._overlayDisposer?.(); - this._overlayDisposer = OverlayView.Instance.addElement(, { x: 0, y: 0 }); - } - - render() { - const link = false; - const reference = React.createRef(); - - // if the list is not opened, don't display it; otherwise, do. - if (this._optionsList?.length) { - const options = !this._opened ? (null) : -
- {this._optionsList.map((element, index) => { - const val = Field.toString(element); - return
this.onSelected(StrCast(element), index)} > - {val} -
; - })} -
; - - const plainText =
{this._text}
; - const textarea =
- this._text} - SetValue={action((value: string) => { - // add special for params - this.onSetValue(value); - return true; - })} - /> -
; - - //☰ - return ( -
-
-
- -
{link ? plainText : textarea}
-
- {options} -
-
- ); - } - return this.renderCellWithType("list"); - } -} - - -@observer -export class CollectionSchemaCheckboxCell extends CollectionSchemaCell { - @computed get _isChecked() { return BoolCast(this._rowDoc[this.renderFieldKey]); } - - render() { - const reference = React.createRef(); - return ( -
- this._rowDoc[this.renderFieldKey] = e.target.checked} /> -
- ); - } -} - - -@observer -export class CollectionSchemaButtons extends CollectionSchemaCell { - // the navigation buttons for schema view when it is used for search. - render() { - return !this.props.Document._searchDoc || ![DocumentType.PDF, DocumentType.RTF].includes(StrCast(this._rowDoc.type) as DocumentType) ? <> : -
- - -
; - } -} diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx deleted file mode 100644 index 9653f2808..000000000 --- a/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx +++ /dev/null @@ -1,513 +0,0 @@ -import React = require("react"); -import { IconProp } from "@fortawesome/fontawesome-svg-core"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed, observable, runInAction, trace } from "mobx"; -import { observer } from "mobx-react"; -import { Doc, DocListCast, Opt, StrListCast } from "../../../../fields/Doc"; -import { listSpec } from "../../../../fields/Schema"; -import { PastelSchemaPalette, SchemaHeaderField } from "../../../../fields/SchemaHeaderField"; -import { ScriptField } from "../../../../fields/ScriptField"; -import { Cast, StrCast } from "../../../../fields/Types"; -import { undoBatch } from "../../../util/UndoManager"; -import { CollectionView } from "../CollectionView"; -import { ColumnType } from "./CollectionSchemaView"; -import "./CollectionSchemaView.scss"; - -const higflyout = require("@hig/flyout"); -export const { anchorPoints } = higflyout; -export const Flyout = higflyout.default; - - -export interface AddColumnHeaderProps { - createColumn: () => void; -} - -@observer -export class CollectionSchemaAddColumnHeader extends React.Component { - // the button that allows the user to add a column - render() { - return ; - } -} - -export interface ColumnMenuProps { - columnField: SchemaHeaderField; - // keyValue: string; - possibleKeys: string[]; - existingKeys: string[]; - // keyType: ColumnType; - typeConst: boolean; - menuButtonContent: JSX.Element; - addNew: boolean; - onSelect: (oldKey: string, newKey: string, addnew: boolean) => void; - setIsEditing: (isEditing: boolean) => void; - deleteColumn: (column: string) => void; - onlyShowOptions: boolean; - setColumnType: (column: SchemaHeaderField, type: ColumnType) => void; - setColumnSort: (column: SchemaHeaderField, desc: boolean | undefined) => void; - anchorPoint?: any; - setColumnColor: (column: SchemaHeaderField, color: string) => void; -} -@observer -export class CollectionSchemaColumnMenu extends React.Component { - @observable private _isOpen: boolean = false; - @observable private _node: HTMLDivElement | null = null; - - componentDidMount() { document.addEventListener("pointerdown", this.detectClick); } - - componentWillUnmount() { document.removeEventListener("pointerdown", this.detectClick); } - - @action - detectClick = (e: PointerEvent) => { - !this._node?.contains(e.target as Node) && this.props.setIsEditing(this._isOpen = false); - } - - @action - toggleIsOpen = (): void => { - this.props.setIsEditing(this._isOpen = !this._isOpen); - } - - changeColumnType = (type: ColumnType) => { - this.props.setColumnType(this.props.columnField, type); - } - - changeColumnSort = (desc: boolean | undefined) => { - this.props.setColumnSort(this.props.columnField, desc); - } - - changeColumnColor = (color: string) => { - this.props.setColumnColor(this.props.columnField, color); - } - - @action - setNode = (node: HTMLDivElement): void => { - if (node) { - this._node = node; - } - } - - renderTypes = () => { - if (this.props.typeConst) return (null); - - const type = this.props.columnField.type; - return ( -
- -
-
this.changeColumnType(ColumnType.Any)}> - - Any -
-
this.changeColumnType(ColumnType.Number)}> - - Number -
-
this.changeColumnType(ColumnType.String)}> - - Text -
-
this.changeColumnType(ColumnType.Boolean)}> - - Checkbox -
-
this.changeColumnType(ColumnType.List)}> - - List -
-
this.changeColumnType(ColumnType.Doc)}> - - Document -
-
this.changeColumnType(ColumnType.Image)}> - - Image -
-
this.changeColumnType(ColumnType.Date)}> - - Date -
-
-
- ); - } - - renderSorting = () => { - const sort = this.props.columnField.desc; - return ( -
- -
-
this.changeColumnSort(true)}> - - Sort descending -
-
this.changeColumnSort(false)}> - - Sort ascending -
-
this.changeColumnSort(undefined)}> - - Clear sorting -
-
-
- ); - } - - renderColors = () => { - const selected = this.props.columnField.color; - - const pink = PastelSchemaPalette.get("pink2"); - const purple = PastelSchemaPalette.get("purple2"); - const blue = PastelSchemaPalette.get("bluegreen1"); - const yellow = PastelSchemaPalette.get("yellow4"); - const red = PastelSchemaPalette.get("red2"); - const gray = "#f1efeb"; - - return ( -
- -
-
this.changeColumnColor(pink!)}>
-
this.changeColumnColor(purple!)}>
-
this.changeColumnColor(blue!)}>
-
this.changeColumnColor(yellow!)}>
-
this.changeColumnColor(red!)}>
-
this.changeColumnColor(gray)}>
-
-
- ); - } - - renderContent = () => { - return ( -
- {this.props.onlyShowOptions ? <> : - <> - {this.renderTypes()} - {this.renderSorting()} - {this.renderColors()} -
- -
- - } -
- ); - } - - render() { - return ( -
- -
this.toggleIsOpen()}>{this.props.menuButtonContent}
- -
- ); - } -} - - -export interface KeysDropdownProps { - keyValue: string; - possibleKeys: string[]; - existingKeys: string[]; - canAddNew: boolean; - addNew: boolean; - onSelect: (oldKey: string, newKey: string, addnew: boolean, filter?: string) => void; - setIsEditing: (isEditing: boolean) => void; - width?: string; - docs?: Doc[]; - Document: Doc; - dataDoc: Doc | undefined; - fieldKey: string; - ContainingCollectionDoc: Doc | undefined; - ContainingCollectionView: Opt; - active?: (outsideReaction?: boolean) => boolean | undefined; - openHeader: (column: any, screenx: number, screeny: number) => void; - col: SchemaHeaderField; - icon: IconProp; -} -@observer -export class KeysDropdown extends React.Component { - @observable private _key: string = this.props.keyValue; - @observable private _searchTerm: string = this.props.keyValue + ":"; - @observable private _isOpen: boolean = false; - @observable private _node: HTMLDivElement | null = null; - @observable private _inputRef: React.RefObject = React.createRef(); - - @action setSearchTerm = (value: string): void => { this._searchTerm = value; }; - @action setKey = (key: string): void => { this._key = key; }; - @action setIsOpen = (isOpen: boolean): void => { this._isOpen = isOpen; }; - - @action - onSelect = (key: string): void => { - this.props.onSelect(this._key, key, this.props.addNew); - this.setKey(key); - this._isOpen = false; - this.props.setIsEditing(false); - } - - @action - setNode = (node: HTMLDivElement): void => { - if (node) { - this._node = node; - } - } - - componentDidMount() { - document.addEventListener("pointerdown", this.detectClick); - const filters = Cast(this.props.Document._docFilters, listSpec("string")); - if (filters?.some(filter => filter.split(":")[0] === this._key)) { - runInAction(() => this.closeResultsVisibility = "contents"); - } - } - - @action - detectClick = (e: PointerEvent): void => { - if (this._node && this._node.contains(e.target as Node)) { - } else { - this._isOpen = false; - this.props.setIsEditing(false); - } - } - - private tempfilter: string = ""; - @undoBatch - onKeyDown = (e: React.KeyboardEvent): void => { - if (e.key === "Enter") { - e.stopPropagation(); - if (this._searchTerm.includes(":")) { - const colpos = this._searchTerm.indexOf(":"); - const temp = this._searchTerm.slice(colpos + 1, this._searchTerm.length); - if (temp === "") { - Doc.setDocFilter(this.props.Document, this._key, this.tempfilter, "remove"); - this.updateFilter(); - } - else { - Doc.setDocFilter(this.props.Document, this._key, this.tempfilter, "remove"); - this.tempfilter = temp; - Doc.setDocFilter(this.props.Document, this._key, temp, "check"); - this.props.col.setColor("green"); - this.closeResultsVisibility = "contents"; - } - } - else { - Doc.setDocFilter(this.props.Document, this._key, this.tempfilter, "remove"); - this.updateFilter(); - if (this.showKeys.length) { - this.onSelect(this.showKeys[0]); - } else if (this._searchTerm !== "" && this.props.canAddNew) { - this.setSearchTerm(this._searchTerm || this._key); - this.onSelect(this._searchTerm); - } - } - } - } - - onChange = (val: string): void => { - this.setSearchTerm(val); - } - - @action - onFocus = (e: React.FocusEvent): void => { - this._isOpen = true; - this.props.setIsEditing(true); - } - - @computed get showKeys() { - const whitelistKeys = ["context", "author", "*lastModified", "text", "data", "tags", "creationDate"]; - const keyOptions = this._searchTerm === "" ? this.props.possibleKeys : this.props.possibleKeys.filter(key => key.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1); - const showKeys = new Set(); - [...keyOptions, ...whitelistKeys].forEach(key => (!Doc.noviceMode || - whitelistKeys.includes(key) - || ((!key.startsWith("_") && key[0] === key[0].toUpperCase()) || key[0] === "#")) ? showKeys.add(key) : null); - return Array.from(showKeys.keys()).filter(key => !this._searchTerm || key.includes(this._searchTerm)); - } - - @computed get renderOptions() { - if (!this._isOpen) { - this.defaultMenuHeight = 0; - return (null); - } - const options = this.showKeys.map(key => { - return
{ - e.stopPropagation(); - }} - onClick={() => { - this.onSelect(key); - this.setSearchTerm(""); - }}>{key}
; - }); - - // if search term does not already exist as a group type, give option to create new group type - - if (this._key !== this._searchTerm.slice(0, this._key.length)) { - if (this._searchTerm !== "" && this.props.canAddNew) { - options.push(
{ this.onSelect(this._searchTerm); this.setSearchTerm(""); }}> - Create "{this._searchTerm}" key
); - } - } - - if (options.length === 0) { - this.defaultMenuHeight = 0; - } - else { - if (this.props.docs) { - const panesize = this.props.docs.length * 30; - options.length * 20 + 8 - 10 > panesize ? this.defaultMenuHeight = panesize : this.defaultMenuHeight = options.length * 20 + 8; - } - else { - options.length > 5 ? this.defaultMenuHeight = 108 : this.defaultMenuHeight = options.length * 20 + 8; - } - } - return options; - } - - @computed get docSafe() { return DocListCast(this.props.dataDoc?.[this.props.fieldKey]); } - - @computed get renderFilterOptions() { - if (!this._isOpen || !this.props.dataDoc) { - this.defaultMenuHeight = 0; - return (null); - } - const keyOptions: string[] = []; - const colpos = this._searchTerm.indexOf(":"); - const temp = this._searchTerm.slice(colpos + 1, this._searchTerm.length); - this.docSafe.forEach(doc => { - const key = StrCast(doc[this._key]); - if (keyOptions.includes(key) === false && key.includes(temp) && key !== "") { - keyOptions.push(key); - } - }); - - const filters = StrListCast(this.props.Document._docFilters); - if (filters.some(filter => filter.split(":")[0] === this._key) === false) { - this.props.col.setColor("rgb(241, 239, 235)"); - this.closeResultsVisibility = "none"; - } - for (let i = 0; i < (filters?.length ?? 0) - 1; i++) { - if (filters[i] === this.props.col.heading && keyOptions.includes(filters[i].split(":")[1]) === false) { - keyOptions.push(filters[i + 1]); - } - } - const options = keyOptions.map(key => { - let bool = false; - if (filters !== undefined) { - const ind = filters.findIndex(filter => filter.split(":")[1] === key); - const fields = ind === -1 ? undefined : filters[ind].split(":"); - bool = fields ? fields[2] === "check" : false; - } - return
- e.stopPropagation()} - onClick={e => e.stopPropagation()} - onChange={action(e => { - if (e.target.checked) { - Doc.setDocFilter(this.props.Document, this._key, key, "check"); - this.closeResultsVisibility = "contents"; - this.props.col.setColor("green"); - } else { - Doc.setDocFilter(this.props.Document, this._key, key, "remove"); - this.updateFilter(); - } - })} - checked={bool} - /> - - {key} - - -
; - }); - if (options.length === 0) { - this.defaultMenuHeight = 0; - } - else { - if (this.props.docs) { - const panesize = this.props.docs.length * 30; - options.length * 20 + 8 - 10 > panesize ? this.defaultMenuHeight = panesize : this.defaultMenuHeight = options.length * 20 + 8; - } - else { - options.length > 5 ? this.defaultMenuHeight = 108 : this.defaultMenuHeight = options.length * 20 + 8; - } - - } - return options; - } - - @observable defaultMenuHeight = 0; - - - updateFilter() { - const filters = Cast(this.props.Document._docFilters, listSpec("string")); - if (filters === undefined || filters.length === 0 || filters.some(filter => filter.split(":")[0] === this._key) === false) { - this.props.col.setColor("rgb(241, 239, 235)"); - this.closeResultsVisibility = "none"; - } - } - - @computed get scriptField() { - const scriptText = "setDocFilter(containingTreeView, heading, this.title, checked)"; - const script = ScriptField.MakeScript(scriptText, { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name }); - return script ? () => script : undefined; - } - filterBackground = () => "rgba(105, 105, 105, 0.432)"; - @observable filterOpen: boolean | undefined = undefined; - closeResultsVisibility: string = "none"; - - removeFilters = (e: React.PointerEvent): void => { - const keyOptions: string[] = []; - this.docSafe.forEach(doc => { - const key = StrCast(doc[this._key]); - if (keyOptions.includes(key) === false) { - keyOptions.push(key); - } - }); - - Doc.setDocFilter(this.props.Document, this._key, "", "remove"); - this.props.col.setColor("rgb(241, 239, 235)"); - this.closeResultsVisibility = "none"; - } - render() { - return ( -
-
{ this.props.openHeader(this.props.col, e.clientX, e.clientY); e.stopPropagation(); }}> - -
- -
- this.onChange(e.target.value)} - onClick={(e) => { e.stopPropagation(); this._inputRef.current?.focus(); }} - onFocus={this.onFocus} > -
- -
- {!this._isOpen ? (null) :
- {this._searchTerm.includes(":") ? this.renderFilterOptions : this.renderOptions} -
} -
-
- ); - } -} diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaMovableColumn.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaMovableColumn.tsx deleted file mode 100644 index 28d2e6ab1..000000000 --- a/src/client/views/collections/collectionSchema/CollectionSchemaMovableColumn.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import React = require('react'); -import { action } from 'mobx'; -import { SchemaHeaderField } from '../../../../fields/SchemaHeaderField'; -import { DragManager } from '../../../util/DragManager'; -import { SnappingManager } from '../../../util/SnappingManager'; -import { Transform } from '../../../util/Transform'; -import './CollectionSchemaView.scss'; - -export interface MovableColumnProps { - columnRenderer: React.ReactNode; - columnValue: SchemaHeaderField; - allColumns: SchemaHeaderField[]; - reorderColumns: (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columns: SchemaHeaderField[]) => void; - ScreenToLocalTransform: () => Transform; -} -export class MovableColumn extends React.Component { - // The header of the column - private _header?: React.RefObject = React.createRef(); - // The container of the function that is responsible for moving the column over to a new plac - private _colDropDisposer?: DragManager.DragDropDisposer; - // initial column position - private _startDragPosition: { x: number; y: number } = { x: 0, y: 0 }; - // sensitivity to being dragged, in pixels - private _sensitivity: number = 16; - // Column reference ID - private _dragRef: React.RefObject = React.createRef(); - - onPointerEnter = (e: React.PointerEvent): void => { - // if the column is left-clicked and it is being dragged - if (e.buttons === 1 && SnappingManager.GetIsDragging()) { - this._header!.current!.className = 'collectionSchema-col-wrapper'; - document.addEventListener('pointermove', this.onDragMove, true); - } - }; - - onPointerLeave = (e: React.PointerEvent): void => { - this._header!.current!.className = 'collectionSchema-col-wrapper'; - document.removeEventListener('pointermove', this.onDragMove, true); - !e.buttons && document.removeEventListener('pointermove', this.onPointerMove); - }; - - onDragMove = (e: PointerEvent): void => { - // only take into account the horizonal direction when a column is dragged - const x = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY); - const rect = this._header!.current!.getBoundingClientRect(); - // Now store the point at the top center of the column when it was in its original position - const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left + (rect.right - rect.left) / 2, rect.top); - // to be compared with its new horizontal position - const before = x[0] < bounds[0]; - this._header!.current!.className = 'collectionSchema-col-wrapper'; - if (before) this._header!.current!.className += ' col-before'; - if (!before) this._header!.current!.className += ' col-after'; - e.stopPropagation(); - }; - - createColDropTarget = (ele: HTMLDivElement) => { - this._colDropDisposer?.(); - if (ele) { - this._colDropDisposer = DragManager.MakeDropTarget(ele, this.colDrop.bind(this)); - } - }; - - colDrop = (e: Event, de: DragManager.DropEvent) => { - document.removeEventListener('pointermove', this.onDragMove, true); - // we only care about whether the column is shifted to the side - const x = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y); - // get the dimensions of the smallest rectangle that bounds the header - const rect = this._header!.current!.getBoundingClientRect(); - const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left + (rect.right - rect.left) / 2, rect.top); - // get whether the column was dragged before or after where it is now - const before = x[0] < bounds[0]; - const colDragData = de.complete.columnDragData; - // if there is colDragData, which happen when the drag is complete, reorder the columns according to the established variables - if (colDragData) { - e.stopPropagation(); - this.props.reorderColumns(colDragData.colKey, this.props.columnValue, before, this.props.allColumns); - return true; - } - return false; - }; - - onPointerMove = (e: PointerEvent) => { - const onRowMove = (e: PointerEvent) => { - e.stopPropagation(); - e.preventDefault(); - - document.removeEventListener('pointermove', onRowMove); - document.removeEventListener('pointerup', onRowUp); - const dragData = new DragManager.ColumnDragData(this.props.columnValue); - DragManager.StartColumnDrag(this._dragRef.current!, dragData, e.x, e.y); - }; - const onRowUp = (): void => { - document.removeEventListener('pointermove', onRowMove); - document.removeEventListener('pointerup', onRowUp); - }; - // if the left mouse button is the one being held - if (e.buttons === 1) { - const [dx, dy] = this.props.ScreenToLocalTransform().transformDirection(e.clientX - this._startDragPosition.x, e.clientY - this._startDragPosition.y); - // If the movemnt of the drag exceeds the sensitivity value - if (Math.abs(dx) + Math.abs(dy) > this._sensitivity) { - document.removeEventListener('pointermove', this.onPointerMove); - e.stopPropagation(); - - document.addEventListener('pointermove', onRowMove); - document.addEventListener('pointerup', onRowUp); - } - } - }; - - onPointerUp = (e: React.PointerEvent) => { - document.removeEventListener('pointermove', this.onPointerMove); - }; - - @action - onPointerDown = (e: React.PointerEvent, ref: React.RefObject) => { - this._dragRef = ref; - const [dx, dy] = this.props.ScreenToLocalTransform().transformDirection(e.clientX, e.clientY); - // If the cell thing dragged is not being edited - if (!(e.target as any)?.tagName.includes('INPUT')) { - this._startDragPosition = { x: dx, y: dy }; - document.addEventListener('pointermove', this.onPointerMove); - } - }; - - render() { - const reference = React.createRef(); - - return ( -
-
-
this.onPointerDown(e, reference)} onPointerUp={this.onPointerUp}> - {this.props.columnRenderer} -
-
-
- ); - } -} diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaMovableRow.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaMovableRow.tsx deleted file mode 100644 index f872637e5..000000000 --- a/src/client/views/collections/collectionSchema/CollectionSchemaMovableRow.tsx +++ /dev/null @@ -1,151 +0,0 @@ -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action } from 'mobx'; -import * as React from 'react'; -import { ReactTableDefaults, RowInfo } from 'react-table'; -import { Doc } from '../../../../fields/Doc'; -import { Cast, FieldValue, StrCast } from '../../../../fields/Types'; -import { DocumentManager } from '../../../util/DocumentManager'; -import { DragManager, dropActionType, SetupDrag } from '../../../util/DragManager'; -import { SnappingManager } from '../../../util/SnappingManager'; -import { Transform } from '../../../util/Transform'; -import { undoBatch } from '../../../util/UndoManager'; -import { ContextMenu } from '../../ContextMenu'; -import './CollectionSchemaView.scss'; - -export interface MovableRowProps { - rowInfo: RowInfo; - ScreenToLocalTransform: () => Transform; - addDoc: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean; - removeDoc: (doc: Doc | Doc[]) => boolean; - rowFocused: boolean; - textWrapRow: (doc: Doc) => void; - rowWrapped: boolean; - dropAction: string; - addDocTab: any; -} - -export class MovableRow extends React.Component> { - private _header?: React.RefObject = React.createRef(); - private _rowDropDisposer?: DragManager.DragDropDisposer; - - // Event listeners are only necessary when the user is hovering over the table - // Create one when the mouse starts hovering... - onPointerEnter = (e: React.PointerEvent): void => { - if (e.buttons === 1 && SnappingManager.GetIsDragging()) { - this._header!.current!.className = 'collectionSchema-row-wrapper'; - document.addEventListener('pointermove', this.onDragMove, true); - } - }; - // ... and delete it when the mouse leaves - onPointerLeave = (e: React.PointerEvent): void => { - this._header!.current!.className = 'collectionSchema-row-wrapper'; - document.removeEventListener('pointermove', this.onDragMove, true); - }; - // The method for the event listener, reorders columns when dragged to their new locations. - onDragMove = (e: PointerEvent): void => { - const x = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY); - const rect = this._header!.current!.getBoundingClientRect(); - const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2); - const before = x[1] < bounds[1]; - this._header!.current!.className = 'collectionSchema-row-wrapper'; - if (before) this._header!.current!.className += ' row-above'; - if (!before) this._header!.current!.className += ' row-below'; - e.stopPropagation(); - }; - componentWillUnmount() { - this._rowDropDisposer?.(); - } - // - createRowDropTarget = (ele: HTMLDivElement) => { - this._rowDropDisposer?.(); - if (ele) { - this._rowDropDisposer = DragManager.MakeDropTarget(ele, this.rowDrop.bind(this)); - } - }; - // Controls what hppens when a row is dragged and dropped - rowDrop = (e: Event, de: DragManager.DropEvent) => { - this.onPointerLeave(e as any); - const rowDoc = FieldValue(Cast(this.props.rowInfo.original, Doc)); - if (!rowDoc) return false; - - const x = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y); - const rect = this._header!.current!.getBoundingClientRect(); - const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2); - const before = x[1] < bounds[1]; - - const docDragData = de.complete.docDragData; - if (docDragData) { - e.stopPropagation(); - if (docDragData.draggedDocuments[0] === rowDoc) return true; - const addDocument = (doc: Doc | Doc[]) => this.props.addDoc(doc, rowDoc, before); - const movedDocs = docDragData.draggedDocuments; - return docDragData.dropAction || docDragData.userDropAction - ? docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDoc(d, rowDoc, before) || added, false) - : docDragData.moveDocument - ? movedDocs.reduce((added: boolean, d) => docDragData.moveDocument?.(d, rowDoc, addDocument) || added, false) - : docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDoc(d, rowDoc, before), false); - } - return false; - }; - - onRowContextMenu = (e: React.MouseEvent): void => { - const description = this.props.rowWrapped ? 'Unwrap text on row' : 'Text wrap row'; - ContextMenu.Instance.addItem({ description: description, event: () => this.props.textWrapRow(this.props.rowInfo.original), icon: 'file-pdf' }); - }; - - @undoBatch - @action - move: DragManager.MoveFunction = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDoc) => { - const targetView = targetCollection && DocumentManager.Instance.getDocumentView(targetCollection); - return doc !== targetCollection && doc !== targetView?.props.ContainingCollectionDoc && this.props.removeDoc(doc) && addDoc(doc); - }; - - @action - onKeyDown = (e: React.KeyboardEvent) => { - console.log('yes'); - if (e.key === 'Backspace' || e.key === 'Delete') { - undoBatch(() => this.props.removeDoc(this.props.rowInfo.original)); - } - }; - - render() { - const { children = null, rowInfo } = this.props; - - if (!rowInfo) { - return {children}; - } - - const { original } = rowInfo; - const doc = FieldValue(Cast(original, Doc)); - - if (!doc) return null; - - const reference = React.createRef(); - const onItemDown = SetupDrag(reference, () => doc, this.move, StrCast(this.props.dropAction) as dropActionType); - - let className = 'collectionSchema-row'; - if (this.props.rowFocused) className += ' row-focused'; - if (this.props.rowWrapped) className += ' row-wrapped'; - - return ( -
-
- -
-
this.props.removeDoc(this.props.rowInfo.original))}> - -
-
- -
-
this.props.addDocTab(this.props.rowInfo.original, 'add:right')}> - -
-
- {children} -
-
-
- ); - } -} diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss index 19401c7f0..0a51aea4e 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss @@ -1,599 +1,59 @@ @import '../../global/globalCssVariables.scss'; -@import '../../../../../node_modules/react-table/react-table.css'; -.collectionSchemaView-container { - border-width: $COLLECTION_BORDER_WIDTH; - border-color: $medium-gray; - border-style: solid; - border-radius: $border-radius; - box-sizing: border-box; - position: relative; - top: 0; - width: 100%; - height: 100%; - margin-top: 0; - transition: top 0.5s; - display: flex; - justify-content: space-between; - flex-wrap: nowrap; - touch-action: none; - div { - touch-action: none; - } - .collectionSchemaView-tableContainer { - width: 100%; - height: 100%; - } - .collectionSchemaView-dividerDragger { - position: relative; - height: 100%; - width: $SCHEMA_DIVIDER_WIDTH; - z-index: 20; - right: 0; - top: 0; - background: gray; - cursor: col-resize; - } - // .documentView-node:first-child { - // background: $white; - // } -} - -.collectionSchemaView-searchContainer { - border-width: $COLLECTION_BORDER_WIDTH; - border-color: $medium-gray; - border-style: solid; - border-radius: $border-radius; - box-sizing: border-box; - position: relative; - top: 0; - width: 100%; - height: 100%; - margin-top: 0; - transition: top 0.5s; - display: flex; - justify-content: space-between; - flex-wrap: nowrap; - touch-action: none; - padding: 2px; - div { - touch-action: none; - } - .collectionSchemaView-tableContainer { - width: 100%; - height: 100%; - } - .collectionSchemaView-dividerDragger { - position: relative; - height: 100%; - width: 20px; - z-index: 20; - right: 0; - top: 0; - background: gray; - cursor: col-resize; - } - // .documentView-node:first-child { - // background: $white; - // } -} - -.ReactTable { - width: 100%; - background: white; - box-sizing: border-box; - border: none !important; - float: none !important; - .rt-table { - height: 100%; - display: -webkit-inline-box; - direction: ltr; - overflow: visible; - } - .rt-noData { - display: none; - } - .rt-thead { - width: 100%; - z-index: 100; - overflow-y: visible; - &.-header { - font-size: 12px; - height: 30px; - box-shadow: none; - z-index: 100; - overflow-y: visible; - } - .rt-resizable-header-content { - height: 100%; - overflow: visible; - } - .rt-th { - padding: 0; - border-left: solid 1px $light-gray; - } - } - .rt-th { - font-size: 13px; - text-align: center; - &:last-child { - overflow: visible; - } - } - .rt-tbody { - width: 100%; - direction: rtl; - overflow: visible; - .rt-td { - border-right: 1px solid rgba(0, 0, 0, 0.2); - } - } - .rt-tr-group { - direction: ltr; - flex: 0 1 auto; - min-height: 30px; - border: 0 !important; - } - .rt-tr-group:nth-of-type(even) { - direction: ltr; - flex: 0 1 auto; - min-height: 30px; - border: 0 !important; - background-color: red; - } - .rt-tr { - width: 100%; - min-height: 30px; - } - .rt-td { - padding: 0; - font-size: 13px; - text-align: center; - white-space: nowrap; - display: flex; - align-items: center; - .imageBox-cont { - position: relative; - max-height: 100%; - } - .imageBox-cont img { - object-fit: contain; - max-width: 100%; - height: 100%; - } - .videoBox-cont { - object-fit: contain; - width: auto; - height: 100%; - } - } - .rt-td.rt-expandable { - display: flex; - align-items: center; - height: inherit; - } - .rt-resizer { - width: 8px; - right: -4px; - } - .rt-resizable-header { - padding: 0; - height: 30px; - } - .rt-resizable-header:last-child { - overflow: visible; - .rt-resizer { - width: 5px !important; - } - } -} - -.documentView-node-topmost { - text-align: left; - transform-origin: center top; - display: inline-block; -} - -.collectionSchema-col { - height: 100%; -} - -.collectionSchema-header-menu { - height: auto; - z-index: 100; - position: absolute; - background: white; - padding: 5px; - position: fixed; - background: white; - border: black 1px solid; - .collectionSchema-header-toggler { - z-index: 100; - width: 100%; - height: 100%; - padding: 4px; - letter-spacing: 2px; - text-transform: uppercase; - svg { - margin-right: 4px; - } - } -} - -.collectionSchemaView-header { - height: 100%; - color: gray; - z-index: 100; - overflow-y: visible; - display: flex; - justify-content: space-between; - flex-wrap: wrap; -} - -button.add-column { - width: 28px; -} -.collectionSchemaView-menuOptions-wrapper { - background: rgb(241, 239, 235); - display: flex; +.collectionSchemaView { cursor: default; - height: 100%; - align-content: center; - align-items: center; -} -.collectionSchema-header-menuOptions { - color: black; - width: 180px; - text-align: left; - .collectionSchema-headerMenu-group { - padding: 7px 0; - border-bottom: 1px solid lightgray; - cursor: pointer; - &:first-child { - padding-top: 0; - } - &:last-child { - border: none; - text-align: center; - padding: 12px 0 0 0; - } - } - label { - color: $medium-gray; - font-weight: normal; - letter-spacing: 2px; - text-transform: uppercase; - } - input { - color: black; - width: 100%; - } - .columnMenu-option { - cursor: pointer; - padding: 3px; - background-color: white; - transition: background-color 0.2s; - &:hover { - background-color: $light-gray; - } - &.active { - font-weight: bold; - border: 2px solid $light-gray; - } - svg { - color: gray; - margin-right: 5px; - width: 10px; - } - } + .schema-table { + background-color: $white; - .keys-dropdown { - position: relative; - //width: 100%; - background-color: white; - input { - border: 2px solid $light-gray; - padding: 3px; - height: 28px; - font-weight: bold; - letter-spacing: '2px'; - text-transform: 'uppercase'; - &:focus { - font-weight: normal; - } - } - } - .columnMenu-colors { - display: flex; - justify-content: space-between; - flex-wrap: wrap; - .columnMenu-colorPicker { - cursor: pointer; - width: 20px; - height: 20px; - border-radius: 10px; - &.active { - border: 2px solid white; - box-shadow: 0 0 0 2px lightgray; + .schema-header-row, + .schema-row { + display: flex; + flex-direction: row; + + .schema-column-header, + .schema-table-cell, + .row-menu { + min-width: 50px; + border: 1px solid $medium-gray; + padding: 5px; + overflow: hidden; } } - } -} - -.schema-icon { - cursor: pointer; - width: 25px; - height: 25px; - display: flex; - align-items: center; - justify-content: center; - align-content: center; - background-color: $medium-blue; - color: white; - margin-right: 5px; - font-size: 10px; - border-radius: 3px; -} -.keys-options-wrapper { - position: absolute; - text-align: left; - height: fit-content; - top: 100%; - z-index: 21; - background-color: #ffffff; - box-shadow: 0px 3px 4px rgba(0, 0, 0, 30%); - padding: 1px; - .key-option { - cursor: pointer; - color: #000000; - width: 100%; - height: 25px; - font-weight: 400; - display: flex; - justify-content: left; - align-items: center; - padding-left: 5px; - &:hover { - background-color: $light-gray; - } - } -} + .schema-header-row { + justify-content: flex-end; -.collectionSchema-row { - height: 100%; - background-color: white; - &.row-focused .rt-td { - background-color: $light-blue; //$light-gray; - overflow: visible; - } - &.row-wrapped { - .rt-td { - white-space: normal; - } - } - .row-dragger { - display: flex; - justify-content: space-evenly; - width: 58px; - position: absolute; - /* max-width: 50px; */ - min-height: 30px; - align-items: center; - color: lightgray; - background-color: white; - transition: color 0.1s ease; - .row-option { - color: black; - cursor: pointer; - position: relative; - transition: color 0.1s ease; - display: flex; - flex-direction: column; - justify-content: center; - z-index: 2; - border-radius: 3px; - padding: 3px; - &:hover { - background-color: $light-gray; + .schema-column-header { + font-weight: bold; } } - } - .collectionSchema-row-wrapper { - &.row-above { - border-top: 1px solid $medium-blue; - } - &.row-below { - border-bottom: 1px solid $medium-blue; - } - &.row-inside { - border: 2px dashed $medium-blue; - } - .row-dragging { - background-color: blue; - } - } -} - -.collectionSchemaView-cellContainer { - width: 100%; - height: unset; -} -.collectionSchemaView-cellContents { - width: 100%; -} + .schema-row { + justify-content: space-evenly; + + .row-menu { + display: flex; + flex-direction: row; + justify-content: center; + width: 100px; + + .row-button { + width: 20px; + height: 20px; + border-radius: 100%; + background-color: $dark-gray; + color: white; + padding: 5px; + cursor: pointer; + } + } -.collectionSchemaView-cellWrapper { - display: flex; - height: 100%; - text-align: left; - padding-left: 19px; - position: relative; - align-items: center; - align-content: center; - &:focus { - outline: none; - } - &.editing { - padding: 0; - box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.3); - transform: scale(1.1); - z-index: 40; - input { - outline: 0; - border: none; - background-color: $white; - width: 100%; - height: fit-content; - min-height: 26px; - } - } - &.focused { - overflow: hidden; - &.inactive { - border: none; - } - } - p { - width: 100%; - height: 100%; - } - &:hover .collectionSchemaView-cellContents-docExpander { - display: block; - } - .collectionSchemaView-cellContents-document { - display: inline-block; - } - .collectionSchemaView-cellContents-docButton { - float: right; - width: '15px'; - height: '15px'; - } - .collectionSchemaView-dropdownWrapper { - border: grey; - border-style: solid; - border-width: 1px; - height: 30px; - .collectionSchemaView-dropdownButton { - //display: inline-block; - float: left; - height: 100%; - } - .collectionSchemaView-dropdownText { - display: inline-block; - //float: right; - height: 100%; - display: 'flex'; - font-size: 13; - justify-content: 'center'; - align-items: 'center'; - } - } - .collectionSchemaView-dropdownContainer { - position: absolute; - border: 1px solid rgba(0, 0, 0, 0.04); - box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14); - .collectionSchemaView-dropdownOption:hover { - background-color: rgba(0, 0, 0, 0.14); - cursor: pointer; + .row-cells { + display: flex; + flex-direction: row; + justify-content: flex-end; + } } } } - -.collectionSchemaView-cellContents-docExpander { - height: 30px; - width: 30px; - display: none; - position: absolute; - top: 0; - right: 0; - background-color: lightgray; -} - -.doc-drag-over { - background-color: red; -} - -.collectionSchemaView-toolbar { - z-index: 100; -} - -.collectionSchemaView-toolbar { - height: 30px; - display: flex; - justify-content: flex-end; - padding: 0 10px; - border-bottom: 2px solid gray; - .collectionSchemaView-toolbar-item { - display: flex; - flex-direction: column; - justify-content: center; - } -} - -#preview-schema-checkbox-div { - margin-left: 20px; - font-size: 12px; -} - -.collectionSchemaView-table { - width: 100%; - height: 100%; - overflow: auto; - padding: 3px; -} - -.rt-td.rt-expandable { - overflow: visible; - position: relative; - height: 100%; - z-index: 1; -} - -.reactTable-sub { - background-color: rgb(252, 252, 252); - width: 100%; - .rt-thead { - display: none; - } - .row-dragger { - background-color: rgb(252, 252, 252); - } - .rt-table { - background-color: rgb(252, 252, 252); - } - .collectionSchemaView-table { - width: 100%; - border: solid 1px; - overflow: visible; - padding: 0px; - } -} - -.collectionSchemaView-expander { - height: 100%; - min-height: 30px; - position: absolute; - color: gray; - width: 20; - height: auto; - left: 55; - svg { - position: absolute; - top: 50%; - left: 10; - transform: translate(-50%, -50%); - } -} - -.collectionSchemaView-addRow { - color: gray; - letter-spacing: 2px; - text-transform: uppercase; - cursor: pointer; - font-size: 10.5px; - margin-left: 50px; - margin-top: 10px; -} diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index c4ee1805f..7e903ca92 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -1,647 +1,87 @@ import React = require('react'); -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, observable, untracked } from 'mobx'; import { observer } from 'mobx-react'; -import Measure from 'react-measure'; -import { Resize } from 'react-table'; -import { Doc, Opt } from '../../../../fields/Doc'; -import { List } from '../../../../fields/List'; -import { listSpec } from '../../../../fields/Schema'; -import { PastelSchemaPalette, SchemaHeaderField } from '../../../../fields/SchemaHeaderField'; -import { Cast, NumCast } from '../../../../fields/Types'; -import { TraceMobx } from '../../../../fields/util'; -import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents } from '../../../../Utils'; -import { DocUtils } from '../../../documents/Documents'; -import { SelectionManager } from '../../../util/SelectionManager'; -import { SnappingManager } from '../../../util/SnappingManager'; -import { Transform } from '../../../util/Transform'; -import { undoBatch } from '../../../util/UndoManager'; -import { ContextMenu } from '../../ContextMenu'; -import { ContextMenuProps } from '../../ContextMenuItem'; -import { COLLECTION_BORDER_WIDTH, SCHEMA_DIVIDER_WIDTH } from '../../global/globalCssVariables.scss'; -import { DocumentView } from '../../nodes/DocumentView'; -import { DefaultStyleProvider } from '../../StyleProvider'; +import { Doc } from '../../../../fields/Doc'; import { CollectionSubView } from '../CollectionSubView'; import './CollectionSchemaView.scss'; -import { SchemaTable } from './SchemaTable'; -// bcz: need to add drag and drop of rows and columns. This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657 +import { SchemaRowBox } from './SchemaRowBox'; +import { action, computed, observable } from 'mobx'; +import { BoolCast, Cast, StrCast } from '../../../../fields/Types'; +import { listSpec } from '../../../../fields/Schema'; +import { SchemaColumnHeader } from './SchemaColumnHeader'; +import { List } from '../../../../fields/List'; +import { dropActionType } from '../../../util/DragManager'; export enum ColumnType { - Any, Number, String, Boolean, Doc, Image, - List, - Date, } -// this map should be used for keys that should have a const type of value -const columnTypes: Map = new Map([ - ['title', ColumnType.String], - ['x', ColumnType.Number], - ['y', ColumnType.Number], - ['_width', ColumnType.Number], - ['_height', ColumnType.Number], - ['_nativeWidth', ColumnType.Number], - ['_nativeHeight', ColumnType.Number], - ['isPrototype', ColumnType.Boolean], - ['_curPage', ColumnType.Number], - ['_currentTimecode', ColumnType.Number], - ['zIndex', ColumnType.Number], -]); + +const defaultColumnKeys: string[] = ['title', 'type', 'author', 'text', 'data', 'tags']; @observer export class CollectionSchemaView extends CollectionSubView() { - private _previewCont?: HTMLDivElement; - - @observable _previewDoc: Doc | undefined = undefined; - @observable _focusedTable: Doc = this.props.Document; - @observable _col: any = ''; - @observable _menuWidth = 0; - @observable _headerOpen = false; - @observable _headerIsEditing = false; - @observable _menuHeight = 0; - @observable _pointerX = 0; - @observable _pointerY = 0; - @observable _openTypes: boolean = false; - - @computed get previewWidth() { - return () => NumCast(this.props.Document.schemaPreviewWidth); - } - @computed get previewHeight() { - return () => this.props.PanelHeight() - 2 * this.borderWidth; - } - @computed get tableWidth() { - return this.props.PanelWidth() - 2 * this.borderWidth - Number(SCHEMA_DIVIDER_WIDTH) - this.previewWidth(); - } - @computed get borderWidth() { - return Number(COLLECTION_BORDER_WIDTH); - } - @computed get scale() { - return this.props.ScreenToLocalTransform().Scale; - } - @computed get columns() { - return Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []); - } - set columns(columns: SchemaHeaderField[]) { - this.props.Document._schemaHeaders = new List(columns); - } + isChildContentActive = () => (this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive)) ? true : undefined); - @computed get menuCoordinates() { - let searchx = 0; - let searchy = 0; - if (this.props.Document._searchDoc) { - const el = document.getElementsByClassName('collectionSchemaView-searchContainer')[0]; - if (el !== undefined) { - const rect = el.getBoundingClientRect(); - searchx = rect.x; - searchy = rect.y; - } - } - const x = Math.max(0, Math.min(document.body.clientWidth - this._menuWidth, this._pointerX)) - searchx; - const y = Math.max(0, Math.min(document.body.clientHeight - this._menuHeight, this._pointerY)) - searchy; - return this.props.ScreenToLocalTransform().transformPoint(x, y); + @computed get layoutDoc() { + return Doc.Layout(this.props.Document); } - get documentKeys() { - const docs = this.childDocs; - const keys: { [key: string]: boolean } = {}; - // bcz: ugh. this is untracked since otherwise a large collection of documents will blast the server for all their fields. - // then as each document's fields come back, we update the documents _proxies. Each time we do this, the whole schema will be - // invalidated and re-rendered. This workaround will inquire all of the document fields before the options button is clicked. - // then by the time the options button is clicked, all of the fields should be in place. If a new field is added while this menu - // is displayed (unlikely) it won't show up until something else changes. - //TODO Types - untracked(() => docs.map(doc => Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => (keys[key] = false))))); - - this.columns.forEach(key => (keys[key.heading] = true)); - return Array.from(Object.keys(keys)); + @computed get columnKeys() { + return Cast(this.props.Document.columnKeys, listSpec('string'), defaultColumnKeys); } - @action setHeaderIsEditing = (isEditing: boolean) => (this._headerIsEditing = isEditing); - - @undoBatch - setColumnType = action((columnField: SchemaHeaderField, type: ColumnType): void => { - this._openTypes = false; - if (columnTypes.get(columnField.heading)) return; - - const columns = this.columns; - const index = columns.indexOf(columnField); - if (index > -1) { - columnField.setType(NumCast(type)); - columns[index] = columnField; - this.columns = columns; - } - }); - - @undoBatch - setColumnColor = (columnField: SchemaHeaderField, color: string): void => { - const columns = this.columns; - const index = columns.indexOf(columnField); - if (index > -1) { - columnField.setColor(color); - columns[index] = columnField; - this.columns = columns; // need to set the columns to trigger rerender - } - }; - - @undoBatch - @action - setColumnSort = (columnField: SchemaHeaderField, descending: boolean | undefined) => { - const columns = this.columns; - columns.forEach(col => col.setDesc(undefined)); - - const index = columns.findIndex(c => c.heading === columnField.heading); - const column = columns[index]; - column.setDesc(descending); - columns[index] = column; - this.columns = columns; - }; - - renderTypes = (col: any) => { - if (columnTypes.get(col.heading)) return null; - - const type = col.type; - - const anyType = ( -
this.setColumnType(col, ColumnType.Any)}> - - Any -
- ); - - const numType = ( -
this.setColumnType(col, ColumnType.Number)}> - - Number -
- ); - - const textType = ( -
this.setColumnType(col, ColumnType.String)}> - - Text -
- ); - - const boolType = ( -
this.setColumnType(col, ColumnType.Boolean)}> - - Checkbox -
- ); - - const listType = ( -
this.setColumnType(col, ColumnType.List)}> - - List -
- ); - - const docType = ( -
this.setColumnType(col, ColumnType.Doc)}> - - Document -
- ); - - const imageType = ( -
this.setColumnType(col, ColumnType.Image)}> - - Image -
- ); - - const dateType = ( -
this.setColumnType(col, ColumnType.Date)}> - - Date -
- ); - - const allColumnTypes = ( -
- {anyType} - {numType} - {textType} - {boolType} - {listType} - {docType} - {imageType} - {dateType} -
- ); - - const justColType = - type === ColumnType.Any - ? anyType - : type === ColumnType.Number - ? numType - : type === ColumnType.String - ? textType - : type === ColumnType.Boolean - ? boolType - : type === ColumnType.List - ? listType - : type === ColumnType.Doc - ? docType - : type === ColumnType.Date - ? dateType - : imageType; - - return ( -
(this._openTypes = !this._openTypes))}> -
- - -
- {this._openTypes ? allColumnTypes : justColType} -
- ); - }; - - renderSorting = (col: any) => { - const sort = col.desc; - return ( -
- -
-
this.setColumnSort(col, true)}> - - Sort descending -
-
this.setColumnSort(col, false)}> - - Sort ascending -
-
this.setColumnSort(col, undefined)}> - - Clear sorting -
-
-
- ); - }; - - renderColors = (col: any) => { - const selected = col.color; - - const pink = PastelSchemaPalette.get('pink2'); - const purple = PastelSchemaPalette.get('purple2'); - const blue = PastelSchemaPalette.get('bluegreen1'); - const yellow = PastelSchemaPalette.get('yellow4'); - const red = PastelSchemaPalette.get('red2'); - const gray = '#f1efeb'; - - return ( -
- -
-
this.setColumnColor(col, pink!)}>
-
this.setColumnColor(col, purple!)}>
-
this.setColumnColor(col, blue!)}>
-
this.setColumnColor(col, yellow!)}>
-
this.setColumnColor(col, red!)}>
-
this.setColumnColor(col, gray)}>
-
-
- ); - }; - - @undoBatch - @action - changeColumns = (oldKey: string, newKey: string, addNew: boolean, filter?: string) => { - const columns = this.columns; - if (columns === undefined) { - this.columns = new List([new SchemaHeaderField(newKey, 'f1efeb')]); - } else { - if (addNew) { - columns.push(new SchemaHeaderField(newKey, 'f1efeb')); - this.columns = columns; - } else { - const index = columns.map(c => c.heading).indexOf(oldKey); - if (index > -1) { - const column = columns[index]; - column.setHeading(newKey); - columns[index] = column; - this.columns = columns; - if (filter) { - Doc.setDocFilter(this.props.Document, newKey, filter, 'match'); - } else { - this.props.Document._docFilters = undefined; - } - } - } - } - }; - - @action - openHeader = (col: any, screenx: number, screeny: number) => { - this._col = col; - this._headerOpen = true; - this._pointerX = screenx; - this._pointerY = screeny; - }; - - @action - closeHeader = () => { - this._headerOpen = false; - }; - - @undoBatch - @action - deleteColumn = (key: string) => { - const columns = this.columns; - if (columns === undefined) { - this.columns = new List([]); - } else { - const index = columns.map(c => c.heading).indexOf(key); - if (index > -1) { - columns.splice(index, 1); - this.columns = columns; - } - } - this.closeHeader(); - }; - - getPreviewTransform = (): Transform => { - return this.props.ScreenToLocalTransform().translate(-this.borderWidth - NumCast(COLLECTION_BORDER_WIDTH) - this.tableWidth, -this.borderWidth); - }; - - @action - onHeaderClick = (e: React.PointerEvent) => { - e.stopPropagation(); - }; - - @action - onWheel(e: React.WheelEvent) { - const scale = this.props.ScreenToLocalTransform().Scale; - this.props.isContentActive(true) && e.stopPropagation(); - } - - @computed get renderMenuContent() { - TraceMobx(); - return ( -
- {this.renderTypes(this._col)} - {this.renderColors(this._col)} -
- -
-
- ); - } - - private createTarget = (ele: HTMLDivElement) => { - this._previewCont = ele; - super.CreateDropTarget(ele); - }; - - isFocused = (doc: Doc, outsideReaction: boolean): boolean => this.props.isSelected(outsideReaction) && doc === this._focusedTable; - - @action setFocused = (doc: Doc) => (this._focusedTable = doc); - - @action setPreviewDoc = (doc: Opt) => { - SelectionManager.SelectSchemaViewDoc(doc); - this._previewDoc = doc; - }; - - //toggles preview side-panel of schema - @action - toggleExpander = () => { - this.props.Document.schemaPreviewWidth = this.previewWidth() === 0 ? Math.min(this.tableWidth / 3, 200) : 0; - }; - - onDividerDown = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, this.onDividerMove, emptyFunction, this.toggleExpander); - }; - @action - onDividerMove = (e: PointerEvent, down: number[], delta: number[]) => { - const nativeWidth = this._previewCont!.getBoundingClientRect(); - const minWidth = 40; - const maxWidth = 1000; - const movedWidth = this.props.ScreenToLocalTransform().transformDirection(nativeWidth.right - e.clientX, 0)[0]; - const width = movedWidth < minWidth ? minWidth : movedWidth > maxWidth ? maxWidth : movedWidth; - this.props.Document.schemaPreviewWidth = width; - return false; - }; - - onPointerDown = (e: React.PointerEvent): void => { - if (e.button === 0 && !e.altKey && !e.ctrlKey && !e.metaKey) { - if (this.props.isSelected(true)) e.stopPropagation(); - else this.props.select(false); - } - }; - - @computed - get previewDocument(): Doc | undefined { - return this._previewDoc; - } - - @computed - get dividerDragger() { - return this.previewWidth() === 0 ? null : ( -
-
-
- ); - } - - @computed - get previewPanel() { - return ( -
- {!this.previewDocument ? null : ( - - )} -
- ); - } - - @computed - get schemaTable() { - return ( - - ); - } - - @computed - public get schemaToolbar() { - return ( -
-
-
- - Show Preview -
-
-
+ @computed get columnWidths() { + return Cast( + this.props.Document.columnWidths, + listSpec('number'), + this.columnKeys.map(() => (this.props.PanelWidth() - 100) / this.columnKeys.length) ); } - onSpecificMenu = (e: React.MouseEvent) => { - if ((e.target as any)?.className?.includes?.('collectionSchemaView-cell') || e.target instanceof HTMLSpanElement) { - const cm = ContextMenu.Instance; - const options = cm.findByDescription('Options...'); - const optionItems: ContextMenuProps[] = options && 'subitems' in options ? options.subitems : []; - optionItems.push({ description: 'remove', event: () => this._previewDoc && this.props.removeDocument?.(this._previewDoc), icon: 'trash' }); - !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'compass' }); - cm.displayMenu(e.clientX, e.clientY); - (e.nativeEvent as any).SchemaHandled = true; // not sure why this is needed, but if you right-click quickly on a cell, the Document/Collection contextMenu handlers still fire without this. - e.stopPropagation(); - } - }; - @action - onTableClick = (e: React.MouseEvent): void => { - if (!(e.target as any)?.className?.includes?.('collectionSchemaView-cell') && !(e.target instanceof HTMLSpanElement)) { - this.setPreviewDoc(undefined); - } else { - e.stopPropagation(); - } - this.setFocused(this.props.Document); - this.closeHeader(); + changeColumnKey = (index: number, newKey: string) => { + let currKeys = this.columnKeys; + currKeys[index] = newKey; + this.layoutDoc.columnKeys = new List(currKeys); + return true; }; - onResizedChange = (newResized: Resize[], event: any) => { - const columns = this.columns; - newResized.forEach(resized => { - const index = columns.findIndex(c => c.heading === resized.id); - const column = columns[index]; - column.setWidth(resized.value); - columns[index] = column; - }); - this.columns = columns; - }; - - @action - setColumns = (columns: SchemaHeaderField[]) => (this.columns = columns); - - @undoBatch - reorderColumns = (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columnsValues: SchemaHeaderField[]) => { - const columns = [...columnsValues]; - const oldIndex = columns.indexOf(toMove); - const relIndex = columns.indexOf(relativeTo); - const newIndex = oldIndex > relIndex && !before ? relIndex + 1 : oldIndex < relIndex && before ? relIndex - 1 : relIndex; - - if (oldIndex === newIndex) return; - - columns.splice(newIndex, 0, columns.splice(oldIndex, 1)[0]); - this.columns = columns; - }; - - onZoomMenu = (e: React.WheelEvent) => this.props.isContentActive(true) && e.stopPropagation(); - render() { - TraceMobx(); - if (!this.props.isContentActive()) setTimeout(() => this.closeHeader(), 0); - const menuContent = this.renderMenuContent; - const menu = ( -
this.onZoomMenu(e)} onPointerDown={e => this.onHeaderClick(e)} style={{ transform: `translate(${this.menuCoordinates[0]}px, ${this.menuCoordinates[1]}px)` }}> - { - const dim = this.props.ScreenToLocalTransform().inverse().transformDirection(r.offset.width, r.offset.height); - this._menuWidth = dim[0]; - this._menuHeight = dim[1]; - })}> - {({ measureRef }) =>
{menuContent}
} -
-
- ); return ( -
-
this.props.isContentActive(true) && e.stopPropagation()} - onDrop={e => this.onExternalDrop(e, {})} - ref={this.createTarget}> - {this.schemaTable} +
+
+
+ {this.columnKeys.map((key, index) => ( + + ))} +
+
+ {this.childDocs.map((doc: Doc) => ( + + ))} +
- {this.dividerDragger} - {!this.previewWidth() ? null : this.previewPanel} - {this._headerOpen && this.props.isContentActive() ? menu : null}
); } } +function DocListCast(childDocs: Doc[]): any { + throw new Error('Function not implemented.'); +} diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx new file mode 100644 index 000000000..9bd1b843f --- /dev/null +++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx @@ -0,0 +1,28 @@ +import React = require('react'); +import { observer } from 'mobx-react'; +import './CollectionSchemaView.scss'; +import { EditableView } from '../../EditableView'; +import { emptyFunction } from '../../../../Utils'; +import { action, computed } from 'mobx'; + +export interface SchemaColumnHeaderProps { + columnKeys: string[]; + columnWidths: number[]; + columnIndex: number; + changeColumnKey: (index: number, newKey: string) => boolean; +} + +@observer +export class SchemaColumnHeader extends React.Component { + @computed get fieldKey() { + return this.props.columnKeys[this.props.columnIndex]; + } + + render() { + return ( +
+ this.props.changeColumnKey(this.props.columnIndex, newKey)} GetValue={() => this.fieldKey} contents={this.fieldKey} /> +
+ ); + } +} diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx new file mode 100644 index 000000000..50e2502dc --- /dev/null +++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx @@ -0,0 +1,33 @@ +import React = require('react'); +import { observer } from 'mobx-react'; +import './CollectionSchemaView.scss'; +import { ViewBoxAnnotatableComponent, ViewBoxBaseComponent } from '../../DocComponent'; +import { FieldViewProps } from '../../nodes/FieldView'; +import { SchemaTableCell } from './SchemaTableCell'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { undoBatch } from '../../../util/UndoManager'; + +export interface SchemaRowBoxProps extends FieldViewProps { + columnKeys: string[]; + columnWidths: number[]; +} + +@observer +export class SchemaRowBox extends ViewBoxAnnotatableComponent() { + render() { + return ( +
+
+
this.props.removeDocument?.(this.props.Document))}> + +
+
+
+ {this.props.columnKeys.map((key, index) => ( + + ))} +
+
+ ); + } +} diff --git a/src/client/views/collections/collectionSchema/SchemaTable.tsx b/src/client/views/collections/collectionSchema/SchemaTable.tsx deleted file mode 100644 index fafea5ce3..000000000 --- a/src/client/views/collections/collectionSchema/SchemaTable.tsx +++ /dev/null @@ -1,693 +0,0 @@ -import { IconProp } from '@fortawesome/fontawesome-svg-core'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, observable } from 'mobx'; -import { observer } from 'mobx-react'; -import * as React from 'react'; -import ReactTable, { CellInfo, Column, ComponentPropsGetterR, Resize, SortingRule } from 'react-table'; -import { DateField } from '../../../../fields/DateField'; -import { AclPrivate, AclReadonly, DataSym, Doc, DocListCast, Field, Opt } from '../../../../fields/Doc'; -import { Id } from '../../../../fields/FieldSymbols'; -import { List } from '../../../../fields/List'; -import { listSpec } from '../../../../fields/Schema'; -import { SchemaHeaderField } from '../../../../fields/SchemaHeaderField'; -import { ComputedField } from '../../../../fields/ScriptField'; -import { Cast, FieldValue, NumCast, StrCast } from '../../../../fields/Types'; -import { ImageField } from '../../../../fields/URLField'; -import { GetEffectiveAcl } from '../../../../fields/util'; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../../../Utils'; -import { Docs, DocumentOptions, DocUtils } from '../../../documents/Documents'; -import { DocumentType } from '../../../documents/DocumentTypes'; -import { CompileScript, Transformer, ts } from '../../../util/Scripting'; -import { Transform } from '../../../util/Transform'; -import { undoBatch } from '../../../util/UndoManager'; -import '../../../views/DocumentDecorations.scss'; -import { ContextMenu } from '../../ContextMenu'; -import { COLLECTION_BORDER_WIDTH, SCHEMA_DIVIDER_WIDTH } from '../../global/globalCssVariables.scss'; -import { DocumentView } from '../../nodes/DocumentView'; -import { DefaultStyleProvider } from '../../StyleProvider'; -import { CollectionView } from '../CollectionView'; -import { - CellProps, - CollectionSchemaButtons, - CollectionSchemaCell, - CollectionSchemaCheckboxCell, - CollectionSchemaDateCell, - CollectionSchemaDocCell, - CollectionSchemaImageCell, - CollectionSchemaListCell, - CollectionSchemaNumberCell, - CollectionSchemaStringCell, -} from './CollectionSchemaCells'; -import { CollectionSchemaAddColumnHeader, KeysDropdown } from './CollectionSchemaHeaders'; -import { MovableColumn } from './CollectionSchemaMovableColumn'; -import { MovableRow } from './CollectionSchemaMovableRow'; -import './CollectionSchemaView.scss'; - -enum ColumnType { - Any, - Number, - String, - Boolean, - Doc, - Image, - List, - Date, -} - -// this map should be used for keys that should have a const type of value -const columnTypes: Map = new Map([ - ['title', ColumnType.String], - ['x', ColumnType.Number], - ['y', ColumnType.Number], - ['_width', ColumnType.Number], - ['_height', ColumnType.Number], - ['_nativeWidth', ColumnType.Number], - ['_nativeHeight', ColumnType.Number], - ['isPrototype', ColumnType.Boolean], - ['_curPage', ColumnType.Number], - ['_currentTimecode', ColumnType.Number], - ['zIndex', ColumnType.Number], -]); - -export interface SchemaTableProps { - Document: Doc; // child doc - dataDoc?: Doc; - PanelHeight: () => number; - PanelWidth: () => number; - childDocs?: Doc[]; - CollectionView: Opt; - ContainingCollectionView: Opt; - ContainingCollectionDoc: Opt; - fieldKey: string; - renderDepth: number; - deleteDocument?: (document: Doc | Doc[]) => boolean; - addDocument?: (document: Doc | Doc[]) => boolean; - moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; - ScreenToLocalTransform: () => Transform; - active: (outsideReaction: boolean | undefined) => boolean | undefined; - onDrop: (e: React.DragEvent, options: DocumentOptions, completed?: (() => void) | undefined) => void; - addDocTab: (document: Doc, where: string) => boolean; - pinToPres: (document: Doc) => void; - isSelected: (outsideReaction?: boolean) => boolean; - isFocused: (document: Doc, outsideReaction: boolean) => boolean; - setFocused: (document: Doc) => void; - setPreviewDoc: (document: Opt) => void; - columns: SchemaHeaderField[]; - documentKeys: any[]; - headerIsEditing: boolean; - openHeader: (column: any, screenx: number, screeny: number) => void; - onClick: (e: React.MouseEvent) => void; - onPointerDown: (e: React.PointerEvent) => void; - onResizedChange: (newResized: Resize[], event: any) => void; - setColumns: (columns: SchemaHeaderField[]) => void; - reorderColumns: (toMove: SchemaHeaderField, relativeTo: SchemaHeaderField, before: boolean, columnsValues: SchemaHeaderField[]) => void; - changeColumns: (oldKey: string, newKey: string, addNew: boolean) => void; - setHeaderIsEditing: (isEditing: boolean) => void; - changeColumnSort: (columnField: SchemaHeaderField, descending: boolean | undefined) => void; -} - -@observer -export class SchemaTable extends React.Component { - @observable _cellIsEditing: boolean = false; - @observable _focusedCell: { row: number; col: number } = { row: 0, col: 0 }; - @observable _openCollections: Set = new Set(); - - @observable _showDoc: Doc | undefined; - @observable _showDataDoc: any = ''; - @observable _showDocPos: number[] = []; - - @observable _showTitleDropdown: boolean = false; - - @computed get previewWidth() { - return () => NumCast(this.props.Document.schemaPreviewWidth); - } - @computed get previewHeight() { - return () => this.props.PanelHeight() - 2 * this.borderWidth; - } - @computed get tableWidth() { - return this.props.PanelWidth() - 2 * this.borderWidth - Number(SCHEMA_DIVIDER_WIDTH) - this.previewWidth(); - } - - @computed get childDocs() { - if (this.props.childDocs) return this.props.childDocs; - - const doc = this.props.dataDoc ? this.props.dataDoc : this.props.Document; - return DocListCast(doc[this.props.fieldKey]); - } - set childDocs(docs: Doc[]) { - const doc = this.props.dataDoc ? this.props.dataDoc : this.props.Document; - doc[this.props.fieldKey] = new List(docs); - } - - @computed get textWrappedRows() { - return Cast(this.props.Document.textwrappedSchemaRows, listSpec('string'), []); - } - set textWrappedRows(textWrappedRows: string[]) { - this.props.Document.textwrappedSchemaRows = new List(textWrappedRows); - } - - @computed get resized(): { id: string; value: number }[] { - return this.props.columns.reduce((resized, shf) => { - shf.width > -1 && resized.push({ id: shf.heading, value: shf.width }); - return resized; - }, [] as { id: string; value: number }[]); - } - @computed get sorted(): SortingRule[] { - return this.props.columns.reduce((sorted, shf) => { - shf.desc !== undefined && sorted.push({ id: shf.heading, desc: shf.desc }); - return sorted; - }, [] as SortingRule[]); - } - - @action - changeSorting = (col: any) => { - this.props.changeColumnSort(col, col.desc === true ? false : col.desc === false ? undefined : true); - }; - - @action - changeTitleMode = () => (this._showTitleDropdown = !this._showTitleDropdown); - - @computed get borderWidth() { - return Number(COLLECTION_BORDER_WIDTH); - } - @computed get tableColumns(): Column[] { - const possibleKeys = this.props.documentKeys.filter(key => this.props.columns.findIndex(existingKey => existingKey.heading.toUpperCase() === key.toUpperCase()) === -1); - const columns: Column[] = []; - const tableIsFocused = this.props.isFocused(this.props.Document, false); - const focusedRow = this._focusedCell.row; - const focusedCol = this._focusedCell.col; - const isEditable = !this.props.headerIsEditing; - - columns.push({ - expander: true, - Header: '', - width: 58, - Expander: rowInfo => { - return rowInfo.original.type !== DocumentType.COL ? null : ( -
this._openCollections[rowInfo.isExpanded ? 'delete' : 'add'](rowInfo.viewIndex))}> - -
- ); - }, - }); - columns.push( - ...this.props.columns.map(col => { - const icon: IconProp = - this.getColumnType(col) === ColumnType.Number - ? 'hashtag' - : this.getColumnType(col) === ColumnType.String - ? 'font' - : this.getColumnType(col) === ColumnType.Boolean - ? 'check-square' - : this.getColumnType(col) === ColumnType.Doc - ? 'file' - : this.getColumnType(col) === ColumnType.Image - ? 'image' - : this.getColumnType(col) === ColumnType.List - ? 'list-ul' - : this.getColumnType(col) === ColumnType.Date - ? 'calendar' - : 'align-justify'; - - const keysDropdown = ( - c.heading)} - canAddNew={true} - addNew={false} - onSelect={this.props.changeColumns} - setIsEditing={this.props.setHeaderIsEditing} - docs={this.props.childDocs} - Document={this.props.Document} - dataDoc={this.props.dataDoc} - fieldKey={this.props.fieldKey} - ContainingCollectionDoc={this.props.ContainingCollectionDoc} - ContainingCollectionView={this.props.ContainingCollectionView} - active={this.props.active} - openHeader={this.props.openHeader} - icon={icon} - col={col} - // try commenting this out - width={'100%'} - /> - ); - - const sortIcon = col.desc === undefined ? 'caret-right' : col.desc === true ? 'caret-down' : 'caret-up'; - const header = ( -
- {keysDropdown} -
this.changeSorting(col)} style={{ width: 21, padding: 1, display: 'inline', zIndex: 1, background: 'inherit', cursor: 'pointer' }}> - -
- {/* {this.props.Document._chromeHidden || this.props.addDocument == returnFalse ? undefined :
+ new
} */} -
- ); - - return { - Header: , - accessor: (doc: Doc) => (doc ? Field.toString(doc[col.heading] as Field) : 0), - id: col.heading, - Cell: (rowProps: CellInfo) => { - const rowIndex = rowProps.index; - const columnIndex = this.props.columns.map(c => c.heading).indexOf(rowProps.column.id!); - const isFocused = focusedRow === rowIndex && focusedCol === columnIndex && tableIsFocused; - - const props: CellProps = { - row: rowIndex, - col: columnIndex, - rowProps: rowProps, - isFocused: isFocused, - changeFocusedCellByIndex: this.changeFocusedCellByIndex, - CollectionView: this.props.CollectionView, - ContainingCollection: this.props.ContainingCollectionView, - Document: this.props.Document, - fieldKey: this.props.fieldKey, - renderDepth: this.props.renderDepth, - addDocTab: this.props.addDocTab, - pinToPres: this.props.pinToPres, - moveDocument: this.props.moveDocument, - setIsEditing: this.setCellIsEditing, - isEditable: isEditable, - setPreviewDoc: this.props.setPreviewDoc, - setComputed: this.setComputed, - getField: this.getField, - showDoc: this.showDoc, - }; - - switch (this.getColumnType(col, rowProps.original, rowProps.column.id)) { - case ColumnType.Number: - return ; - case ColumnType.String: - return ; - case ColumnType.Boolean: - return ; - case ColumnType.Doc: - return ; - case ColumnType.Image: - return ; - case ColumnType.List: - return ; - case ColumnType.Date: - return ; - default: - return ; - } - }, - minWidth: 200, - }; - }) - ); - columns.push({ - Header: , - accessor: (doc: Doc) => 0, - id: 'add', - Cell: (rowProps: CellInfo) => { - const rowIndex = rowProps.index; - const columnIndex = this.props.columns.map(c => c.heading).indexOf(rowProps.column.id!); - const isFocused = focusedRow === rowIndex && focusedCol === columnIndex && tableIsFocused; - return ( - - ); - }, - width: 28, - resizable: false, - }); - return columns; - } - - constructor(props: SchemaTableProps) { - super(props); - if (this.props.Document._schemaHeaders === undefined) { - this.props.Document._schemaHeaders = new List([ - new SchemaHeaderField('title', '#f1efeb'), - new SchemaHeaderField('author', '#f1efeb'), - new SchemaHeaderField('*lastModified', '#f1efeb', ColumnType.Date), - new SchemaHeaderField('text', '#f1efeb', ColumnType.String), - new SchemaHeaderField('type', '#f1efeb'), - new SchemaHeaderField('context', '#f1efeb', ColumnType.Doc), - ]); - } - } - - componentDidMount() { - document.addEventListener('keydown', this.onKeyDown); - } - - componentWillUnmount() { - document.removeEventListener('keydown', this.onKeyDown); - } - - tableAddDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => { - const tableDoc = this.props.Document[DataSym]; - const effectiveAcl = GetEffectiveAcl(tableDoc); - - if (effectiveAcl !== AclPrivate && effectiveAcl !== AclReadonly) { - doc.context = this.props.Document; - tableDoc[this.props.fieldKey + '-lastModified'] = new DateField(new Date(Date.now())); - return Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before); - } - return false; - }; - - private getTrProps: ComponentPropsGetterR = (state, rowInfo) => { - return !rowInfo - ? {} - : { - ScreenToLocalTransform: this.props.ScreenToLocalTransform, - addDoc: this.tableAddDoc, - removeDoc: this.props.deleteDocument, - rowInfo, - rowFocused: !this.props.headerIsEditing && rowInfo.index === this._focusedCell.row && this.props.isFocused(this.props.Document, true), - textWrapRow: this.toggleTextWrapRow, - rowWrapped: this.textWrappedRows.findIndex(id => rowInfo.original[Id] === id) > -1, - dropAction: StrCast(this.props.Document.childDropAction), - addDocTab: this.props.addDocTab, - }; - }; - - private getTdProps: ComponentPropsGetterR = (state, rowInfo, column, instance) => { - if (!rowInfo || column) return {}; - - const row = rowInfo.index; - //@ts-ignore - const col = this.columns.map(c => c.heading).indexOf(column!.id); - const isFocused = this._focusedCell.row === row && this._focusedCell.col === col && this.props.isFocused(this.props.Document, true); - // TODO: editing border doesn't work :( - return { - style: { border: !this.props.headerIsEditing && isFocused ? '2px solid rgb(255, 160, 160)' : '1px solid #f1efeb' }, - }; - }; - - @action setCellIsEditing = (isEditing: boolean) => (this._cellIsEditing = isEditing); - - @action - onKeyDown = (e: KeyboardEvent): void => { - if (!this._cellIsEditing && !this.props.headerIsEditing && this.props.isFocused(this.props.Document, true)) { - // && this.props.isSelected(true)) { - const direction = e.key === 'Tab' ? 'tab' : e.which === 39 ? 'right' : e.which === 37 ? 'left' : e.which === 38 ? 'up' : e.which === 40 ? 'down' : ''; - this._focusedCell = this.changeFocusedCellByDirection(direction, this._focusedCell.row, this._focusedCell.col); - - if (direction) { - const pdoc = FieldValue(this.childDocs[this._focusedCell.row]); - pdoc && this.props.setPreviewDoc(pdoc); - e.stopPropagation(); - } - } else if (e.keyCode === 27) { - this.props.setPreviewDoc(undefined); - e.stopPropagation(); // stopPropagation for left/right arrows - } - }; - - changeFocusedCellByDirection = (direction: string, curRow: number, curCol: number) => { - switch (direction) { - case 'tab': - return { row: curRow + 1 === this.childDocs.length ? 0 : curRow + 1, col: curCol + 1 === this.props.columns.length ? 0 : curCol + 1 }; - case 'right': - return { row: curRow, col: curCol + 1 === this.props.columns.length ? curCol : curCol + 1 }; - case 'left': - return { row: curRow, col: curCol === 0 ? curCol : curCol - 1 }; - case 'up': - return { row: curRow === 0 ? curRow : curRow - 1, col: curCol }; - case 'down': - return { row: curRow + 1 === this.childDocs.length ? curRow : curRow + 1, col: curCol }; - } - return this._focusedCell; - }; - - @action - changeFocusedCellByIndex = (row: number, col: number): void => { - if (this._focusedCell.row !== row || this._focusedCell.col !== col) { - this._focusedCell = { row: row, col: col }; - } - this.props.setFocused(this.props.Document); - }; - - @undoBatch - createRow = action(() => { - this.props.addDocument?.(Docs.Create.TextDocument('', { title: '', _width: 100, _height: 30 })); - this._focusedCell = { row: this.childDocs.length, col: this._focusedCell.col }; - }); - - @undoBatch - @action - createColumn = () => { - const newFieldName = (index: number) => `New field${index ? ` (${index})` : ''}`; - for (let index = 0; index < 100; index++) { - if (this.props.columns.findIndex(col => col.heading === newFieldName(index)) === -1) { - this.props.columns.push(new SchemaHeaderField(newFieldName(index), '#f1efeb')); - break; - } - } - }; - - @action - getColumnType = (column: SchemaHeaderField, doc?: Doc, field?: string): ColumnType => { - if (doc && field && column.type === ColumnType.Any) { - const val = doc[CollectionSchemaCell.resolvedFieldKey(field, doc)]; - if (val instanceof ImageField) return ColumnType.Image; - if (val instanceof Doc) return ColumnType.Doc; - if (val instanceof DateField) return ColumnType.Date; - if (val instanceof List) return ColumnType.List; - } - if (column.type && column.type !== 0) { - return column.type; - } - if (columnTypes.get(column.heading)) { - return (column.type = columnTypes.get(column.heading)!); - } - return (column.type = ColumnType.Any); - }; - - @undoBatch - @action - toggleTextwrap = async () => { - const textwrappedRows = Cast(this.props.Document.textwrappedSchemaRows, listSpec('string'), []); - if (textwrappedRows.length) { - this.props.Document.textwrappedSchemaRows = new List([]); - } else { - const docs = DocListCast(this.props.Document[this.props.fieldKey]); - const allRows = docs instanceof Doc ? [docs[Id]] : docs.map(doc => doc[Id]); - this.props.Document.textwrappedSchemaRows = new List(allRows); - } - }; - - @action - toggleTextWrapRow = (doc: Doc): void => { - const textWrapped = this.textWrappedRows; - const index = textWrapped.findIndex(id => doc[Id] === id); - - index > -1 ? textWrapped.splice(index, 1) : textWrapped.push(doc[Id]); - - this.textWrappedRows = textWrapped; - }; - - @computed - get reactTable() { - const children = this.childDocs; - const hasCollectionChild = children.reduce((found, doc) => found || doc.type === DocumentType.COL, false); - const expanded: { [name: string]: any } = {}; - Array.from(this._openCollections.keys()).map(col => (expanded[col.toString()] = true)); - const rerender = [...this.textWrappedRows]; // TODO: get component to rerender on text wrap change without needign to console.log :(((( - - return ( - - row.original.type !== DocumentType.COL ? null : ( -
- -
- ) - } - /> - ); - } - - onContextMenu = (e: React.MouseEvent): void => { - ContextMenu.Instance.addItem({ description: 'Toggle text wrapping', event: this.toggleTextwrap, icon: 'table' }); - }; - - getField = (row: number, col?: number) => { - const docs = this.childDocs; - - row = row % docs.length; - while (row < 0) row += docs.length; - const columns = this.props.columns; - const doc = docs[row]; - if (col === undefined) { - return doc; - } - if (col >= 0 && col < columns.length) { - const column = this.props.columns[col].heading; - return doc[column]; - } - return undefined; - }; - - createTransformer = (row: number, col: number): Transformer => { - const self = this; - const captures: { [name: string]: Field } = {}; - - const transformer: ts.TransformerFactory = context => { - return root => { - function visit(node: ts.Node) { - node = ts.visitEachChild(node, visit, context); - if (ts.isIdentifier(node)) { - const isntPropAccess = !ts.isPropertyAccessExpression(node.parent) || node.parent.expression === node; - const isntPropAssign = !ts.isPropertyAssignment(node.parent) || node.parent.name !== node; - if (isntPropAccess && isntPropAssign) { - if (node.text === '$r') { - return ts.createNumericLiteral(row.toString()); - } else if (node.text === '$c') { - return ts.createNumericLiteral(col.toString()); - } else if (node.text === '$') { - if (ts.isCallExpression(node.parent)) { - // captures.doc = self.props.Document; - // captures.key = self.props.fieldKey; - } - } - } - } - - return node; - } - return ts.visitNode(root, visit); - }; - }; - - // const getVars = () => { - // return { capturedVariables: captures }; - // }; - - return { transformer /*getVars*/ }; - }; - - setComputed = (script: string, doc: Doc, field: string, row: number, col: number): boolean => { - script = `const $ = (row:number, col?:number) => { - const rval = (doc as any)[key][row + ${row}]; - return col === undefined ? rval : rval[(doc as any)._schemaHeaders[col + ${col}].heading]; - } - return ${script}`; - const compiled = CompileScript(script, { params: { this: Doc.name }, capturedVariables: { doc: this.props.Document, key: this.props.fieldKey }, typecheck: false, transformer: this.createTransformer(row, col) }); - if (compiled.compiled) { - doc[field] = new ComputedField(compiled); - return true; - } - return false; - }; - - @action - showDoc = (doc: Doc | undefined, dataDoc?: Doc, screenX?: number, screenY?: number) => { - this._showDoc = doc; - if (dataDoc && screenX && screenY) { - this._showDocPos = this.props.ScreenToLocalTransform().transformPoint(screenX, screenY); - } - }; - - onOpenClick = () => { - this._showDoc && this.props.addDocTab(this._showDoc, 'add:right'); - }; - - getPreviewTransform = (): Transform => { - return this.props.ScreenToLocalTransform().translate(-this.borderWidth - 4 - this.tableWidth, -this.borderWidth); - }; - - render() { - const preview = ''; - return ( -
this.props.active(true) && e.stopPropagation()} - onDrop={e => this.props.onDrop(e, {})} - onContextMenu={this.onContextMenu}> - {this.reactTable} - {this.props.Document._chromeHidden || this.props.addDocument === returnFalse ? undefined : ( -
- + new -
- )} - {!this._showDoc ? null : ( -
- 150} - PanelHeight={() => 150} - ScreenToLocalTransform={this.getPreviewTransform} - docFilters={returnEmptyFilter} - docRangeFilters={returnEmptyFilter} - searchFilterDocs={returnEmptyDoclist} - ContainingCollectionDoc={this.props.CollectionView?.props.Document} - ContainingCollectionView={this.props.CollectionView} - moveDocument={this.props.moveDocument} - whenChildContentsActiveChanged={emptyFunction} - addDocTab={this.props.addDocTab} - pinToPres={this.props.pinToPres} - bringToFront={returnFalse}> -
- )} -
- ); - } -} diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx new file mode 100644 index 000000000..1eb5e0e01 --- /dev/null +++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx @@ -0,0 +1,24 @@ +import React = require('react'); +import { observer } from 'mobx-react'; +import { Doc, Field } from '../../../../fields/Doc'; +import { StrCast } from '../../../../fields/Types'; +import './CollectionSchemaView.scss'; + +export interface SchemaTableCellProps { + Document: Doc; + fieldKey: string; + columnWidth: number; +} + +@observer +export class SchemaTableCell extends React.Component { + render() { + return ( +
+ {/* {StrCast(this.props.Document[this.props.fieldKey])} */} + {/* Field.toKeyValueString(this.props.Document, this.props.fieldKey) */} + {Field.toString(this.props.Document[this.props.fieldKey] as Field)} +
+ ); + } +} -- cgit v1.2.3-70-g09d2 From 9f39b14b2e321e09d071ad1c5bf8e3978ff7f181 Mon Sep 17 00:00:00 2001 From: mehekj Date: Wed, 10 Aug 2022 19:33:19 -0400 Subject: basic selection complete --- .../collections/CollectionStackedTimeline.scss | 1 + .../collections/CollectionStackedTimeline.tsx | 2 +- .../collectionSchema/CollectionSchemaView.scss | 1 - .../collectionSchema/CollectionSchemaView.tsx | 57 ++++++++++++++-------- .../collections/collectionSchema/SchemaRowBox.tsx | 35 +++++++++---- src/client/views/nodes/AudioBox.tsx | 1 + 6 files changed, 65 insertions(+), 32 deletions(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/src/client/views/collections/CollectionStackedTimeline.scss b/src/client/views/collections/CollectionStackedTimeline.scss index 6611477e5..c296e1172 100644 --- a/src/client/views/collections/CollectionStackedTimeline.scss +++ b/src/client/views/collections/CollectionStackedTimeline.scss @@ -2,6 +2,7 @@ .collectionStackedTimeline-timelineContainer { height: 100%; + position: absolute; overflow-x: auto; overflow-y: hidden; border: none; diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 48e3abbc7..2543624d3 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -668,7 +668,7 @@ export class CollectionStackedTimeline extends CollectionSubView
-
+
{formatTime(this._hoverTime - this.clipStart)}
{this._thumbnail && }
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss index 0a51aea4e..0f4053127 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss @@ -36,7 +36,6 @@ display: flex; flex-direction: row; justify-content: center; - width: 100px; .row-button { width: 20px; diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 7e903ca92..20d809232 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -1,15 +1,14 @@ import React = require('react'); +import { action, computed, observable, ObservableMap, ObservableSet } from 'mobx'; import { observer } from 'mobx-react'; import { Doc } from '../../../../fields/Doc'; +import { List } from '../../../../fields/List'; +import { listSpec } from '../../../../fields/Schema'; +import { Cast } from '../../../../fields/Types'; import { CollectionSubView } from '../CollectionSubView'; import './CollectionSchemaView.scss'; -import { SchemaRowBox } from './SchemaRowBox'; -import { action, computed, observable } from 'mobx'; -import { BoolCast, Cast, StrCast } from '../../../../fields/Types'; -import { listSpec } from '../../../../fields/Schema'; import { SchemaColumnHeader } from './SchemaColumnHeader'; -import { List } from '../../../../fields/List'; -import { dropActionType } from '../../../util/DragManager'; +import { SchemaRowBox } from './SchemaRowBox'; export enum ColumnType { Number, @@ -23,11 +22,10 @@ const defaultColumnKeys: string[] = ['title', 'type', 'author', 'text', 'data', @observer export class CollectionSchemaView extends CollectionSubView() { - isChildContentActive = () => (this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive)) ? true : undefined); + private _lastSelectedRow: number | undefined; - @computed get layoutDoc() { - return Doc.Layout(this.props.Document); - } + @observable _rowMenuWidth: number = 60; + @observable _selectedDocs: ObservableSet = new ObservableSet(); @computed get columnKeys() { return Cast(this.props.Document.columnKeys, listSpec('string'), defaultColumnKeys); @@ -37,7 +35,7 @@ export class CollectionSchemaView extends CollectionSubView() { return Cast( this.props.Document.columnWidths, listSpec('number'), - this.columnKeys.map(() => (this.props.PanelWidth() - 100) / this.columnKeys.length) + this.columnKeys.map(() => (this.props.PanelWidth() - this._rowMenuWidth) / this.columnKeys.length) ); } @@ -49,6 +47,30 @@ export class CollectionSchemaView extends CollectionSubView() { return true; }; + @action + selectRow = (doc: Doc, ctrl?: boolean, shift?: boolean) => { + if (shift && this._lastSelectedRow !== undefined) { + const currSelectedRow = this.childDocs.indexOf(doc); + const startRow = Math.min(this._lastSelectedRow, currSelectedRow); + const endRow = Math.max(this._lastSelectedRow, currSelectedRow); + for (let i = startRow; i <= endRow; i++) { + const currDoc = this.childDocs[i]; + if (!this._selectedDocs.has(currDoc)) this._selectedDocs.add(currDoc); + } + } else if (ctrl) { + if (!this._selectedDocs.has(doc)) { + this._selectedDocs.add(doc); + this._lastSelectedRow = this.childDocs.indexOf(doc); + } else { + this._selectedDocs.delete(doc); + } + } else { + this._selectedDocs.clear(); + this._selectedDocs.add(doc); + this._lastSelectedRow = this.childDocs.indexOf(doc); + } + }; + render() { return (
@@ -63,17 +85,13 @@ export class CollectionSchemaView extends CollectionSubView() { ))}
@@ -82,6 +100,3 @@ export class CollectionSchemaView extends CollectionSubView() { ); } } -function DocListCast(childDocs: Doc[]): any { - throw new Error('Function not implemented.'); -} diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx index 50e2502dc..33f4e0bfc 100644 --- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx +++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx @@ -1,25 +1,42 @@ import React = require('react'); +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { action, ObservableMap, ObservableSet } from 'mobx'; import { observer } from 'mobx-react'; -import './CollectionSchemaView.scss'; -import { ViewBoxAnnotatableComponent, ViewBoxBaseComponent } from '../../DocComponent'; +import { Doc } from '../../../../fields/Doc'; +import { undoBatch } from '../../../util/UndoManager'; +import { ViewBoxBaseComponent } from '../../DocComponent'; +import { Colors } from '../../global/globalEnums'; import { FieldViewProps } from '../../nodes/FieldView'; +import './CollectionSchemaView.scss'; import { SchemaTableCell } from './SchemaTableCell'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { undoBatch } from '../../../util/UndoManager'; export interface SchemaRowBoxProps extends FieldViewProps { columnKeys: string[]; columnWidths: number[]; + rowMenuWidth: number; + selectedRows: ObservableSet; + selectRow: (doc: Doc, cmd?: boolean, shift?: boolean) => void; } @observer -export class SchemaRowBox extends ViewBoxAnnotatableComponent() { +export class SchemaRowBox extends ViewBoxBaseComponent() { + isSelected = () => this.props.selectedRows.has(this.props.Document); + + @action + onRowPointerDown = (e: React.PointerEvent) => { + e.stopPropagation(); + this.props.selectRow(this.props.Document, e.ctrlKey || e.metaKey, e.shiftKey); + } + render() { return ( -
-
-
this.props.removeDocument?.(this.props.Document))}> - +
+
+
{e.stopPropagation(); this.props.removeDocument?.(this.props.Document)})}> + +
+
{e.stopPropagation(); this.props.addDocTab(this.props.Document, 'add:right')}}> +
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 8437736ae..7bbd7c055 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -18,6 +18,7 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import './AudioBox.scss'; import { FieldView, FieldViewProps } from './FieldView'; +import { SelectionManager } from '../../util/SelectionManager'; /** * AudioBox -- cgit v1.2.3-70-g09d2 From 5c4b22b50e4693419daac777669b258b155f6ea9 Mon Sep 17 00:00:00 2001 From: mehekj Date: Thu, 11 Aug 2022 13:08:56 -0400 Subject: bad dragging code in progress --- .../collectionSchema/CollectionSchemaView.tsx | 75 ++++++++++++++++++++-- .../collections/collectionSchema/SchemaRowBox.tsx | 53 ++++++++++++++- 2 files changed, 119 insertions(+), 9 deletions(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 20d809232..9ca1644e3 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -9,6 +9,10 @@ import { CollectionSubView } from '../CollectionSubView'; import './CollectionSchemaView.scss'; import { SchemaColumnHeader } from './SchemaColumnHeader'; import { SchemaRowBox } from './SchemaRowBox'; +import { DragManager } from '../../../util/DragManager'; +import { PresBox } from '../../nodes/trails/PresBox'; +import { UndoManager } from '../../../util/UndoManager'; +import { returnFalse } from '../../../../Utils'; export enum ColumnType { Number, @@ -25,7 +29,8 @@ export class CollectionSchemaView extends CollectionSubView() { private _lastSelectedRow: number | undefined; @observable _rowMenuWidth: number = 60; - @observable _selectedDocs: ObservableSet = new ObservableSet(); + @observable _selectedDocs: ObservableSet = new ObservableSet(); + @observable _isDragging: boolean = false; @computed get columnKeys() { return Cast(this.props.Document.columnKeys, listSpec('string'), defaultColumnKeys); @@ -48,15 +53,18 @@ export class CollectionSchemaView extends CollectionSubView() { }; @action - selectRow = (doc: Doc, ctrl?: boolean, shift?: boolean) => { + selectRow = (e: React.PointerEvent, doc: Doc) => { + const ctrl = e.ctrlKey || e.metaKey; + const shift = e.shiftKey; if (shift && this._lastSelectedRow !== undefined) { - const currSelectedRow = this.childDocs.indexOf(doc); - const startRow = Math.min(this._lastSelectedRow, currSelectedRow); - const endRow = Math.max(this._lastSelectedRow, currSelectedRow); + const currRowIndex = this.childDocs.indexOf(doc); + const startRow = Math.min(this._lastSelectedRow, currRowIndex); + const endRow = Math.max(this._lastSelectedRow, currRowIndex); for (let i = startRow; i <= endRow; i++) { - const currDoc = this.childDocs[i]; + const currDoc: Doc = this.childDocs[i]; if (!this._selectedDocs.has(currDoc)) this._selectedDocs.add(currDoc); } + this._lastSelectedRow = endRow; } else if (ctrl) { if (!this._selectedDocs.has(doc)) { this._selectedDocs.add(doc); @@ -71,6 +79,58 @@ export class CollectionSchemaView extends CollectionSubView() { } }; + @action + sortedSelectedDocs = (): Doc[] => { + return this.childDocs.filter(doc => this._selectedDocs.has(doc)); + }; + + @action.bound + moveDocument = (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => { + console.log('hello'); + console.log(targetCollection?.title); + if (Doc.AreProtosEqual(this.props.Document, targetCollection)) { + console.log('hi'); + return true; + } + const first = document instanceof Doc ? document : document[0]; + if (!first?._stayInCollection && addDocument !== returnFalse) { + UndoManager.RunInTempBatch(() => this.props.removeDocument?.(document) && addDocument(document)); + return true; + } + return false; + }; + + @action + startDrag = (e: React.PointerEvent, doc: Doc) => { + if (this._selectedDocs.size === 0) this._selectedDocs.add(doc); + this._isDragging = true; + const dragData = new DragManager.DocumentDragData(this.sortedSelectedDocs(), 'move'); + dragData.moveDocument = this.moveDocument; + const dragItem: HTMLElement[] = []; + const dragDiv = document.createElement('div'); + dragDiv.className = 'presItem-multiDrag'; + dragDiv.innerText = 'Move ' + this._selectedDocs.size + ' rows'; + dragDiv.style.position = 'absolute'; + dragDiv.style.top = e.clientY + 'px'; + dragDiv.style.left = e.clientX - 50 + 'px'; + dragItem.push(dragDiv); + + DragManager.StartDocumentDrag( + dragItem.map(ele => ele), + dragData, + e.clientX, + e.clientY, + undefined + ); + this._isDragging = false; + return true; + }; + + @action + endDrag = (e: React.PointerEvent) => { + // this._isDragging = false; + }; + render() { return (
@@ -92,6 +152,9 @@ export class CollectionSchemaView extends CollectionSubView() { rowMenuWidth={this._rowMenuWidth} selectedRows={this._selectedDocs} selectRow={this.selectRow} + startDrag={this.startDrag} + endDrag={this.endDrag} + dragging={this._isDragging} /> ))}
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx index 33f4e0bfc..0065a0938 100644 --- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx +++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx @@ -9,28 +9,75 @@ import { Colors } from '../../global/globalEnums'; import { FieldViewProps } from '../../nodes/FieldView'; import './CollectionSchemaView.scss'; import { SchemaTableCell } from './SchemaTableCell'; +import { emptyFunction, setupMoveUpEvents } from '../../../../Utils'; +import { DragManager } from '../../../util/DragManager'; export interface SchemaRowBoxProps extends FieldViewProps { columnKeys: string[]; columnWidths: number[]; rowMenuWidth: number; selectedRows: ObservableSet; - selectRow: (doc: Doc, cmd?: boolean, shift?: boolean) => void; + selectRow: (e: any, doc: Doc) => void; + startDrag: (e: any, doc: Doc) => boolean; + endDrag: (e: any) => void + dragging: boolean; } @observer export class SchemaRowBox extends ViewBoxBaseComponent() { + private _ref: HTMLDivElement | null = null; + isSelected = () => this.props.selectedRows.has(this.props.Document); + bounds = () => this._ref?.getBoundingClientRect(); @action onRowPointerDown = (e: React.PointerEvent) => { e.stopPropagation(); - this.props.selectRow(this.props.Document, e.ctrlKey || e.metaKey, e.shiftKey); + + setupMoveUpEvents( + this, e, + (e) => this.props.startDrag(e, this.props.Document), + emptyFunction, + (e) => this.props.selectRow(e, this.props.Document) + ) } + onPointerEnter = (e: any) => { + document.removeEventListener('pointermove', this.onPointerMove); + document.addEventListener('pointermove', this.onPointerMove); + }; + + onPointerMove = (e: any) => { + let dragIsRow: boolean = true; + DragManager.docsBeingDragged.forEach(doc => { + dragIsRow = this.props.selectedRows.has(doc); + }) + if (this._ref && dragIsRow) { + const rect = this._ref.getBoundingClientRect(); + const y = e.clientY - rect.top; //y position within the element. + const height = this._ref.clientHeight; + const halfLine = height / 2; + if (y <= halfLine) { + this._ref.style.borderTop = `solid 2px ${Colors.MEDIUM_BLUE}`; + this._ref.style.borderBottom = '0px'; + } else if (y > halfLine) { + this._ref.style.borderTop = '0px'; + this._ref.style.borderBottom = `solid 2px ${Colors.MEDIUM_BLUE}`; + } + } + }; + + onPointerLeave = (e: any) => { + if (this._ref) { + this._ref.style.borderTop = '0px'; + this._ref.style.borderBottom = '0px'; + } + document.removeEventListener('pointermove', this.onPointerMove); + }; + render() { return ( -
+
(this._ref = row)}>
{e.stopPropagation(); this.props.removeDocument?.(this.props.Document)})}> -- cgit v1.2.3-70-g09d2 From ee77b8ff032d4b06c2f0b6ac8153a32e54ab8355 Mon Sep 17 00:00:00 2001 From: mehekj Date: Thu, 11 Aug 2022 14:28:09 -0400 Subject: drag and drop rows works, needs cleaning up --- .../collectionSchema/CollectionSchemaView.scss | 1 + .../collectionSchema/CollectionSchemaView.tsx | 78 ++++++++++++---------- .../collections/collectionSchema/SchemaRowBox.tsx | 14 +++- 3 files changed, 54 insertions(+), 39 deletions(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss index 0f4053127..5ead99c02 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss @@ -2,6 +2,7 @@ .collectionSchemaView { cursor: default; + height: 100%; .schema-table { background-color: $white; diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 9ca1644e3..dc0cd8eac 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -1,18 +1,15 @@ import React = require('react'); -import { action, computed, observable, ObservableMap, ObservableSet } from 'mobx'; +import { action, computed, observable, ObservableSet } from 'mobx'; import { observer } from 'mobx-react'; import { Doc } from '../../../../fields/Doc'; import { List } from '../../../../fields/List'; import { listSpec } from '../../../../fields/Schema'; import { Cast } from '../../../../fields/Types'; +import { DragManager } from '../../../util/DragManager'; import { CollectionSubView } from '../CollectionSubView'; import './CollectionSchemaView.scss'; import { SchemaColumnHeader } from './SchemaColumnHeader'; import { SchemaRowBox } from './SchemaRowBox'; -import { DragManager } from '../../../util/DragManager'; -import { PresBox } from '../../nodes/trails/PresBox'; -import { UndoManager } from '../../../util/UndoManager'; -import { returnFalse } from '../../../../Utils'; export enum ColumnType { Number, @@ -26,9 +23,12 @@ const defaultColumnKeys: string[] = ['title', 'type', 'author', 'text', 'data', @observer export class CollectionSchemaView extends CollectionSubView() { + private _ref: HTMLDivElement | null = null; private _lastSelectedRow: number | undefined; + private _selectedDocSortedArray: Doc[] = []; + private _closestDropIndex: number = 0; - @observable _rowMenuWidth: number = 60; + @observable _rowMenuWidth: number = 100; @observable _selectedDocs: ObservableSet = new ObservableSet(); @observable _isDragging: boolean = false; @@ -53,13 +53,12 @@ export class CollectionSchemaView extends CollectionSubView() { }; @action - selectRow = (e: React.PointerEvent, doc: Doc) => { + selectRow = (e: React.PointerEvent, doc: Doc, index: number) => { const ctrl = e.ctrlKey || e.metaKey; const shift = e.shiftKey; if (shift && this._lastSelectedRow !== undefined) { - const currRowIndex = this.childDocs.indexOf(doc); - const startRow = Math.min(this._lastSelectedRow, currRowIndex); - const endRow = Math.max(this._lastSelectedRow, currRowIndex); + const startRow = Math.min(this._lastSelectedRow, index); + const endRow = Math.max(this._lastSelectedRow, index); for (let i = startRow; i <= endRow; i++) { const currDoc: Doc = this.childDocs[i]; if (!this._selectedDocs.has(currDoc)) this._selectedDocs.add(currDoc); @@ -68,14 +67,14 @@ export class CollectionSchemaView extends CollectionSubView() { } else if (ctrl) { if (!this._selectedDocs.has(doc)) { this._selectedDocs.add(doc); - this._lastSelectedRow = this.childDocs.indexOf(doc); + this._lastSelectedRow = index; } else { this._selectedDocs.delete(doc); } } else { this._selectedDocs.clear(); this._selectedDocs.add(doc); - this._lastSelectedRow = this.childDocs.indexOf(doc); + this._lastSelectedRow = index; } }; @@ -84,17 +83,19 @@ export class CollectionSchemaView extends CollectionSubView() { return this.childDocs.filter(doc => this._selectedDocs.has(doc)); }; - @action.bound - moveDocument = (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => { - console.log('hello'); - console.log(targetCollection?.title); - if (Doc.AreProtosEqual(this.props.Document, targetCollection)) { - console.log('hi'); - return true; - } - const first = document instanceof Doc ? document : document[0]; - if (!first?._stayInCollection && addDocument !== returnFalse) { - UndoManager.RunInTempBatch(() => this.props.removeDocument?.(document) && addDocument(document)); + setDropIndex = (index: number) => { + this._closestDropIndex = index; + }; + + @action + onInternalDrop = (e: Event, de: DragManager.DropEvent) => { + if (super.onInternalDrop(e, de)) { + this._isDragging = false; + const pushedDocs: Doc[] = this.childDocs.filter((doc: Doc, index: number) => index >= this._closestDropIndex && !this._selectedDocs.has(doc)); + this.props.removeDocument?.(pushedDocs); + this.props.removeDocument?.(this._selectedDocSortedArray); + this.addDocument(this._selectedDocSortedArray); + this.addDocument(pushedDocs); return true; } return false; @@ -102,14 +103,18 @@ export class CollectionSchemaView extends CollectionSubView() { @action startDrag = (e: React.PointerEvent, doc: Doc) => { - if (this._selectedDocs.size === 0) this._selectedDocs.add(doc); + if (!this._selectedDocs.has(doc)) { + this._selectedDocs.clear(); + this._selectedDocs.add(doc); + } this._isDragging = true; - const dragData = new DragManager.DocumentDragData(this.sortedSelectedDocs(), 'move'); - dragData.moveDocument = this.moveDocument; + this._selectedDocSortedArray = this.sortedSelectedDocs(); + const dragData = new DragManager.DocumentDragData(this._selectedDocSortedArray, 'move'); + dragData.moveDocument = this.props.moveDocument; const dragItem: HTMLElement[] = []; const dragDiv = document.createElement('div'); dragDiv.className = 'presItem-multiDrag'; - dragDiv.innerText = 'Move ' + this._selectedDocs.size + ' rows'; + dragDiv.innerText = 'Move ' + this._selectedDocs.size + ' row' + (this._selectedDocs.size > 1 ? 's' : ''); dragDiv.style.position = 'absolute'; dragDiv.style.top = e.clientY + 'px'; dragDiv.style.left = e.clientX - 50 + 'px'; @@ -122,18 +127,18 @@ export class CollectionSchemaView extends CollectionSubView() { e.clientY, undefined ); - this._isDragging = false; return true; }; - @action - endDrag = (e: React.PointerEvent) => { - // this._isDragging = false; - }; - render() { return ( -
+
{ + this._ref = ele; + this.createDashEventsTarget(ele); + }} + onPointerDown={() => this._selectedDocs.clear()}>
{this.columnKeys.map((key, index) => ( @@ -141,20 +146,21 @@ export class CollectionSchemaView extends CollectionSubView() { ))}
- {this.childDocs.map((doc: Doc) => ( + {this.childDocs.map((doc: Doc, index: number) => ( ))}
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx index 0065a0938..8b658d834 100644 --- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx +++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx @@ -13,14 +13,15 @@ import { emptyFunction, setupMoveUpEvents } from '../../../../Utils'; import { DragManager } from '../../../util/DragManager'; export interface SchemaRowBoxProps extends FieldViewProps { + rowIndex: number; columnKeys: string[]; columnWidths: number[]; rowMenuWidth: number; selectedRows: ObservableSet; - selectRow: (e: any, doc: Doc) => void; + selectRow: (e: any, doc: Doc, index: number) => void; startDrag: (e: any, doc: Doc) => boolean; - endDrag: (e: any) => void dragging: boolean; + dropIndex: (index: number) => void; } @observer @@ -38,16 +39,18 @@ export class SchemaRowBox extends ViewBoxBaseComponent() { this, e, (e) => this.props.startDrag(e, this.props.Document), emptyFunction, - (e) => this.props.selectRow(e, this.props.Document) + (e) => this.props.selectRow(e, this.props.Document, this.props.rowIndex) ) } onPointerEnter = (e: any) => { + if (!this.props.dragging) return; document.removeEventListener('pointermove', this.onPointerMove); document.addEventListener('pointermove', this.onPointerMove); }; onPointerMove = (e: any) => { + if (!this.props.dragging) return; let dragIsRow: boolean = true; DragManager.docsBeingDragged.forEach(doc => { dragIsRow = this.props.selectedRows.has(doc); @@ -60,9 +63,11 @@ export class SchemaRowBox extends ViewBoxBaseComponent() { if (y <= halfLine) { this._ref.style.borderTop = `solid 2px ${Colors.MEDIUM_BLUE}`; this._ref.style.borderBottom = '0px'; + this.props.dropIndex(this.props.rowIndex); } else if (y > halfLine) { this._ref.style.borderTop = '0px'; this._ref.style.borderBottom = `solid 2px ${Colors.MEDIUM_BLUE}`; + this.props.dropIndex(this.props.rowIndex + 1); } } }; @@ -85,6 +90,9 @@ export class SchemaRowBox extends ViewBoxBaseComponent() {
{e.stopPropagation(); this.props.addDocTab(this.props.Document, 'add:right')}}>
+
+ {this.props.rowIndex} +
{this.props.columnKeys.map((key, index) => ( -- cgit v1.2.3-70-g09d2 From d0d10426510e1bc8397eea927a65714b5b48f966 Mon Sep 17 00:00:00 2001 From: mehekj Date: Mon, 15 Aug 2022 22:36:56 -0400 Subject: add new doc as schema row --- .../collectionSchema/CollectionSchemaView.scss | 11 ++- .../collectionSchema/CollectionSchemaView.tsx | 107 ++++++++++++++++++++- .../collections/collectionSchema/SchemaRowBox.tsx | 7 +- 3 files changed, 111 insertions(+), 14 deletions(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss index 5ead99c02..4f644717b 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss @@ -31,7 +31,7 @@ } .schema-row { - justify-content: space-evenly; + justify-content: flex-end; .row-menu { display: flex; @@ -39,13 +39,16 @@ justify-content: center; .row-button { - width: 20px; - height: 20px; + width: 25px; + height: 25px; border-radius: 100%; background-color: $dark-gray; color: white; - padding: 5px; + margin: 3px; cursor: pointer; + display: flex; + align-items: center; + justify-content: center; } } diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index dc0cd8eac..02bc55e7a 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -1,15 +1,26 @@ import React = require('react'); import { action, computed, observable, ObservableSet } from 'mobx'; import { observer } from 'mobx-react'; -import { Doc } from '../../../../fields/Doc'; +import { Doc, DocListCast } from '../../../../fields/Doc'; import { List } from '../../../../fields/List'; import { listSpec } from '../../../../fields/Schema'; -import { Cast } from '../../../../fields/Types'; +import { Cast, StrCast } from '../../../../fields/Types'; import { DragManager } from '../../../util/DragManager'; import { CollectionSubView } from '../CollectionSubView'; import './CollectionSchemaView.scss'; import { SchemaColumnHeader } from './SchemaColumnHeader'; import { SchemaRowBox } from './SchemaRowBox'; +import { SelectionManager } from '../../../util/SelectionManager'; +import { undoBatch } from '../../../util/UndoManager'; +import { EditableView } from '../../EditableView'; +import { returnEmptyString } from '../../../../Utils'; +import { Docs, DocUtils } from '../../../documents/Documents'; +import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; +import { ContextMenu } from '../../ContextMenu'; +import { ContextMenuProps } from '../../ContextMenuItem'; +import { Id } from '../../../../fields/FieldSymbols'; +import { RichTextField } from '../../../../fields/RichTextField'; +import { ImageField } from '../../../../fields/URLField'; export enum ColumnType { Number, @@ -33,18 +44,19 @@ export class CollectionSchemaView extends CollectionSubView() { @observable _isDragging: boolean = false; @computed get columnKeys() { - return Cast(this.props.Document.columnKeys, listSpec('string'), defaultColumnKeys); + return Cast(this.layoutDoc.columnKeys, listSpec('string'), defaultColumnKeys); } @computed get columnWidths() { return Cast( - this.props.Document.columnWidths, + this.layoutDoc.columnWidths, listSpec('number'), this.columnKeys.map(() => (this.props.PanelWidth() - this._rowMenuWidth) / this.columnKeys.length) ); } @action + @undoBatch changeColumnKey = (index: number, newKey: string) => { let currKeys = this.columnKeys; currKeys[index] = newKey; @@ -76,6 +88,13 @@ export class CollectionSchemaView extends CollectionSubView() { this._selectedDocs.add(doc); this._lastSelectedRow = index; } + + if (this._lastSelectedRow && this._selectedDocs.size > 0) { + SelectionManager.SelectSchemaViewDoc(this.childDocs[this._lastSelectedRow]); + } + else { + SelectionManager.SelectSchemaViewDoc(undefined); + } }; @action @@ -106,6 +125,8 @@ export class CollectionSchemaView extends CollectionSubView() { if (!this._selectedDocs.has(doc)) { this._selectedDocs.clear(); this._selectedDocs.add(doc); + this._lastSelectedRow = this.childDocs.indexOf(doc); + SelectionManager.SelectSchemaViewDoc(doc); } this._isDragging = true; this._selectedDocSortedArray = this.sortedSelectedDocs(); @@ -130,6 +151,83 @@ export class CollectionSchemaView extends CollectionSubView() { return true; }; + @action + addNewTextDoc = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => { + if (!value && !forceEmptyNote) return false; + const newDoc = Docs.Create.TextDocument(value, {title: value}); + FormattedTextBox.SelectOnLoad = newDoc[Id]; + FormattedTextBox.SelectOnLoadChar = forceEmptyNote ? '' : ' '; + return this.props.addDocument?.(newDoc) || false; + }; + + menuCallback = (x: number, y: number) => { + ContextMenu.Instance.clearItems(); + const layoutItems: ContextMenuProps[] = []; + const docItems: ContextMenuProps[] = []; + const dataDoc = this.props.DataDoc || this.props.Document; + + DocUtils.addDocumentCreatorMenuItems( + doc => { + FormattedTextBox.SelectOnLoad = StrCast(doc[Id]); + return this.addDocument(doc); + }, + this.addDocument, + x, + y, + true + ); + + Array.from(Object.keys(Doc.GetProto(dataDoc))) + .filter(fieldKey => dataDoc[fieldKey] instanceof RichTextField || dataDoc[fieldKey] instanceof ImageField || typeof dataDoc[fieldKey] === 'string') + .map(fieldKey => + docItems.push({ + description: ':' + fieldKey, + event: () => { + const created = DocUtils.DocumentFromField(dataDoc, fieldKey, Doc.GetProto(this.props.Document)); + if (created) { + if (this.props.Document.isTemplateDoc) { + Doc.MakeMetadataFieldTemplate(created, this.props.Document); + } + return this.props.addDocument?.(created); + } + }, + icon: 'compress-arrows-alt', + }) + ); + Array.from(Object.keys(Doc.GetProto(dataDoc))) + .filter(fieldKey => DocListCast(dataDoc[fieldKey]).length) + .map(fieldKey => + docItems.push({ + description: ':' + fieldKey, + event: () => { + const created = Docs.Create.CarouselDocument([], { _width: 400, _height: 200, title: fieldKey }); + if (created) { + const container = this.props.Document.resolvedDataDoc ? Doc.GetProto(this.props.Document) : this.props.Document; + if (container.isTemplateDoc) { + Doc.MakeMetadataFieldTemplate(created, container); + return Doc.AddDocToList(container, Doc.LayoutFieldKey(container), created); + } + return this.props.addDocument?.(created) || false; + } + }, + icon: 'compress-arrows-alt', + }) + ); + !Doc.noviceMode && ContextMenu.Instance.addItem({ description: 'Doc Fields ...', subitems: docItems, icon: 'eye' }); + !Doc.noviceMode && ContextMenu.Instance.addItem({ description: 'Containers ...', subitems: layoutItems, icon: 'eye' }); + ContextMenu.Instance.setDefaultItem('::', (name: string): void => { + Doc.GetProto(this.props.Document)[name] = ''; + const created = Docs.Create.TextDocument('', { title: name, _width: 250, _autoHeight: true }); + if (created) { + if (this.props.Document.isTemplateDoc) { + Doc.MakeMetadataFieldTemplate(created, this.props.Document); + } + this.props.addDocument?.(created); + } + }); + ContextMenu.Instance.displayMenu(x, y, undefined, true); + }; + render() { return (
+
); } diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx index 8b658d834..ea2ebed7a 100644 --- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx +++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx @@ -90,14 +90,9 @@ export class SchemaRowBox extends ViewBoxBaseComponent() {
{e.stopPropagation(); this.props.addDocTab(this.props.Document, 'add:right')}}>
-
- {this.props.rowIndex} -
- {this.props.columnKeys.map((key, index) => ( - - ))} + {this.props.columnKeys.map((key, index) => ())}
); -- cgit v1.2.3-70-g09d2 From a20a40b86bf5df9200218cb713f48e593c41b0ae Mon Sep 17 00:00:00 2001 From: mehekj Date: Tue, 16 Aug 2022 17:28:33 -0400 Subject: got formatter to work --- package-lock.json | 1349 +++++++------------- .../collectionSchema/CollectionSchemaView.tsx | 7 +- .../collectionSchema/SchemaColumnHeader.tsx | 5 +- .../collections/collectionSchema/SchemaRowBox.tsx | 41 +- .../collectionSchema/SchemaTableCell.tsx | 1 - 5 files changed, 500 insertions(+), 903 deletions(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/package-lock.json b/package-lock.json index cafeebd3e..da921592a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5050,16 +5050,6 @@ "integrity": "sha512-NJGVKPS81XejHcLhaLJS7plab0fK3slPh11mESeeDq2W4ZI5kUKK/LRRdVDvjJseojbPB7ZwjnyOybg3Igea/A==", "dev": true }, - "d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dev": true, - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, "d3-array": { "version": "2.12.1", "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", @@ -6112,8 +6102,8 @@ "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==" }, "equation-editor-react": { - "version": "github:bobzel/equation-editor-react#75915e852b4b36a6a4cd3e1cbc80598da6b65227", - "from": "github:bobzel/equation-editor-react#useLocally", + "version": "git+ssh://git@github.com/bobzel/equation-editor-react.git#75915e852b4b36a6a4cd3e1cbc80598da6b65227", + "from": "equation-editor-react@github:bobzel/equation-editor-react#useLocally", "requires": { "jquery": "^3.4.1", "mathquill": "^0.10.1-a" @@ -6210,9 +6200,9 @@ } }, "es5-ext": { - "version": "0.10.61", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.61.tgz", - "integrity": "sha512-yFhIqQAzu2Ca2I4SE2Au3rxVfmohU9Y7wqGR+s7+H7krk26NXhIRAZDgqd6xqjCEFUomDEA3/Bo/7fKmIkW1kA==", + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", "dev": true, "requires": { "es6-iterator": "^2.0.3", @@ -6229,6 +6219,18 @@ "d": "1", "es5-ext": "^0.10.35", "es6-symbol": "^3.1.1" + }, + "dependencies": { + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + } } }, "es6-promise": { @@ -6244,6 +6246,18 @@ "requires": { "d": "^1.0.1", "ext": "^1.1.2" + }, + "dependencies": { + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + } } }, "escalade": { @@ -9500,14 +9514,14 @@ "resolved": "https://registry.npmjs.org/image-size-stream/-/image-size-stream-1.1.0.tgz", "integrity": "sha512-N505B5FSy2Xf5l/Haef+99TwfJqTu40hnU560+rC0Cm6cxtwVz2yRFh9WpOk1YEjfv3dI0PgVYAH0hmXQmjDcw==", "requires": { - "image-size": "github:netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1", + "image-size": "image-size@git+https://github.com/netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1", "readable-stream": "^1.0.33", "tryit": "^1.0.1" }, "dependencies": { "image-size": { - "version": "github:netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1", - "from": "github:netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1" + "version": "git+ssh://git@github.com/netroy/image-size.git#da2c863807a3e9602617bdd357b0de3ab4a064c1", + "from": "image-size@git+https://github.com/netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1" }, "isarray": { "version": "0.0.1", @@ -12505,70 +12519,59 @@ }, "abbrev": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + "bundled": true }, "agent-base": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "bundled": true, "requires": { "es6-promisify": "^5.0.0" } }, "agentkeepalive": { "version": "3.5.2", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", - "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", + "bundled": true, "requires": { "humanize-ms": "^1.2.1" } }, "ansi-align": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", - "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", + "bundled": true, "requires": { "string-width": "^2.0.0" } }, "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + "bundled": true }, "ansi-styles": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "bundled": true, "requires": { "color-convert": "^1.9.0" } }, "ansicolors": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", - "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=" + "bundled": true }, "ansistyles": { "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ansistyles/-/ansistyles-0.1.3.tgz", - "integrity": "sha1-XeYEFb2gcbs3EnhUyGT0GyMlRTk=" + "bundled": true }, "aproba": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + "bundled": true }, "archy": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=" + "bundled": true }, "are-we-there-yet": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", - "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", + "bundled": true, "requires": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" @@ -12576,8 +12579,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -12590,8 +12592,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "requires": { "safe-buffer": "~5.1.0" } @@ -12600,46 +12601,38 @@ }, "asap": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + "bundled": true }, "asn1": { "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "bundled": true, "requires": { "safer-buffer": "~2.1.0" } }, "assert-plus": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + "bundled": true }, "asynckit": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "bundled": true }, "aws-sign2": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + "bundled": true }, "aws4": { "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" + "bundled": true }, "balanced-match": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "bundled": true }, "bcrypt-pbkdf": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "bundled": true, "optional": true, "requires": { "tweetnacl": "^0.14.3" @@ -12647,8 +12640,7 @@ }, "bin-links": { "version": "1.1.8", - "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-1.1.8.tgz", - "integrity": "sha512-KgmVfx+QqggqP9dA3iIc5pA4T1qEEEL+hOhOhNPaUm77OTrJoOXE/C05SJLNJe6m/2wUK7F1tDSou7n5TfCDzQ==", + "bundled": true, "requires": { "bluebird": "^3.5.3", "cmd-shim": "^3.0.0", @@ -12660,13 +12652,11 @@ }, "bluebird": { "version": "3.5.5", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", - "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==" + "bundled": true }, "boxen": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", - "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", + "bundled": true, "requires": { "ansi-align": "^2.0.0", "camelcase": "^4.0.0", @@ -12679,8 +12669,7 @@ }, "brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "bundled": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -12688,28 +12677,23 @@ }, "buffer-from": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz", - "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==" + "bundled": true }, "builtins": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", - "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=" + "bundled": true }, "byline": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz", - "integrity": "sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE=" + "bundled": true }, "byte-size": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-5.0.1.tgz", - "integrity": "sha512-/XuKeqWocKsYa/cBY1YbSJSWWqTi4cFgr9S6OyM7PBaPbr9zvNGwWP33vt0uqGhwDdN+y3yhbXVILEUpnwEWGw==" + "bundled": true }, "cacache": { "version": "12.0.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz", - "integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==", + "bundled": true, "requires": { "bluebird": "^3.5.5", "chownr": "^1.1.1", @@ -12730,28 +12714,23 @@ }, "call-limit": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/call-limit/-/call-limit-1.1.1.tgz", - "integrity": "sha512-5twvci5b9eRBw2wCfPtN0GmlR2/gadZqyFpPhOK6CvMFoFgA+USnZ6Jpu1lhG9h85pQ3Ouil3PfXWRD4EUaRiQ==" + "bundled": true }, "camelcase": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" + "bundled": true }, "capture-stack-trace": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz", - "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=" + "bundled": true }, "caseless": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + "bundled": true }, "chalk": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "bundled": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -12760,31 +12739,26 @@ }, "chownr": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + "bundled": true }, "ci-info": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + "bundled": true }, "cidr-regex": { "version": "2.0.10", - "resolved": "https://registry.npmjs.org/cidr-regex/-/cidr-regex-2.0.10.tgz", - "integrity": "sha512-sB3ogMQXWvreNPbJUZMRApxuRYd+KoIo4RGQ81VatjmMW6WJPo+IJZ2846FGItr9VzKo5w7DXzijPLGtSd0N3Q==", + "bundled": true, "requires": { "ip-regex": "^2.1.0" } }, "cli-boxes": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", - "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=" + "bundled": true }, "cli-columns": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/cli-columns/-/cli-columns-3.1.2.tgz", - "integrity": "sha1-ZzLZcpee/CrkRKHwjgj6E5yWoY4=", + "bundled": true, "requires": { "string-width": "^2.0.0", "strip-ansi": "^3.0.1" @@ -12792,8 +12766,7 @@ }, "cli-table3": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", - "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "bundled": true, "requires": { "colors": "^1.1.2", "object-assign": "^4.1.0", @@ -12802,8 +12775,7 @@ }, "cliui": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "bundled": true, "requires": { "string-width": "^3.1.0", "strip-ansi": "^5.2.0", @@ -12812,18 +12784,15 @@ "dependencies": { "ansi-regex": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==" + "bundled": true }, "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "bundled": true }, "string-width": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "bundled": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -12832,8 +12801,7 @@ }, "strip-ansi": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "bundled": true, "requires": { "ansi-regex": "^4.1.0" } @@ -12842,13 +12810,11 @@ }, "clone": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" + "bundled": true }, "cmd-shim": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-3.0.3.tgz", - "integrity": "sha512-DtGg+0xiFhQIntSBRzL2fRQBnmtAVwXIDo4Qq46HPpObYquxMaZS4sb82U9nH91qJrlosC1wa9gwr0QyL/HypA==", + "bundled": true, "requires": { "graceful-fs": "^4.1.2", "mkdirp": "~0.5.0" @@ -12856,32 +12822,27 @@ }, "code-point-at": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + "bundled": true }, "color-convert": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "bundled": true, "requires": { "color-name": "^1.1.1" } }, "color-name": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "bundled": true }, "colors": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", - "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==", + "bundled": true, "optional": true }, "columnify": { "version": "1.5.4", - "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz", - "integrity": "sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs=", + "bundled": true, "requires": { "strip-ansi": "^3.0.0", "wcwidth": "^1.0.0" @@ -12889,21 +12850,18 @@ }, "combined-stream": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "bundled": true, "requires": { "delayed-stream": "~1.0.0" } }, "concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "bundled": true }, "concat-stream": { "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "bundled": true, "requires": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", @@ -12913,8 +12871,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -12927,8 +12884,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "requires": { "safe-buffer": "~5.1.0" } @@ -12937,8 +12893,7 @@ }, "config-chain": { "version": "1.1.12", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", - "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", + "bundled": true, "requires": { "ini": "^1.3.4", "proto-list": "~1.2.1" @@ -12946,8 +12901,7 @@ }, "configstore": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.5.tgz", - "integrity": "sha512-nlOhI4+fdzoK5xmJ+NY+1gZK56bwEaWZr8fYuXohZ9Vkc1o3a4T/R3M+yE/w7x/ZVJ1zF8c+oaOvF0dztdUgmA==", + "bundled": true, "requires": { "dot-prop": "^4.2.1", "graceful-fs": "^4.1.2", @@ -12959,13 +12913,11 @@ }, "console-control-strings": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + "bundled": true }, "copy-concurrently": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "bundled": true, "requires": { "aproba": "^1.1.1", "fs-write-stream-atomic": "^1.0.8", @@ -12977,33 +12929,28 @@ "dependencies": { "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + "bundled": true }, "iferr": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" + "bundled": true } } }, "core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "bundled": true }, "create-error-class": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", - "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "bundled": true, "requires": { "capture-stack-trace": "^1.0.0" } }, "cross-spawn": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "bundled": true, "requires": { "lru-cache": "^4.0.1", "shebang-command": "^1.2.0", @@ -13012,8 +12959,7 @@ "dependencies": { "lru-cache": { "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "bundled": true, "requires": { "pseudomap": "^1.0.2", "yallist": "^2.1.2" @@ -13021,104 +12967,87 @@ }, "yallist": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + "bundled": true } } }, "crypto-random-string": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", - "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=" + "bundled": true }, "cyclist": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", - "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=" + "bundled": true }, "dashdash": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "bundled": true, "requires": { "assert-plus": "^1.0.0" } }, "debug": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "bundled": true, "requires": { "ms": "2.0.0" }, "dependencies": { "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "bundled": true } } }, "debuglog": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=" + "bundled": true }, "decamelize": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + "bundled": true }, "decode-uri-component": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + "bundled": true }, "deep-extend": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + "bundled": true }, "defaults": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "bundled": true, "requires": { "clone": "^1.0.2" } }, "define-properties": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "bundled": true, "requires": { "object-keys": "^1.0.12" } }, "delayed-stream": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + "bundled": true }, "delegates": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + "bundled": true }, "detect-indent": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", - "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50=" + "bundled": true }, "detect-newline": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=" + "bundled": true }, "dezalgo": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", - "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", + "bundled": true, "requires": { "asap": "^2.0.0", "wrappy": "1" @@ -13126,26 +13055,22 @@ }, "dot-prop": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.1.tgz", - "integrity": "sha512-l0p4+mIuJIua0mhxGoh4a+iNL9bmeK5DvnSVQa6T0OhrVmaEa1XScX5Etc673FePCJOArq/4Pa2cLGODUWTPOQ==", + "bundled": true, "requires": { "is-obj": "^1.0.0" } }, "dotenv": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz", - "integrity": "sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow==" + "bundled": true }, "duplexer3": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + "bundled": true }, "duplexify": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz", - "integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==", + "bundled": true, "requires": { "end-of-stream": "^1.0.0", "inherits": "^2.0.1", @@ -13155,8 +13080,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -13169,8 +13093,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "requires": { "safe-buffer": "~5.1.0" } @@ -13179,8 +13102,7 @@ }, "ecc-jsbn": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "bundled": true, "optional": true, "requires": { "jsbn": "~0.1.0", @@ -13189,52 +13111,44 @@ }, "editor": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/editor/-/editor-1.0.0.tgz", - "integrity": "sha1-YMf4e9YrzGqJT6jM1q+3gjok90I=" + "bundled": true }, "emoji-regex": { "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + "bundled": true }, "encoding": { "version": "0.1.12", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", - "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "bundled": true, "requires": { "iconv-lite": "~0.4.13" } }, "end-of-stream": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "bundled": true, "requires": { "once": "^1.4.0" } }, "env-paths": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz", - "integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==" + "bundled": true }, "err-code": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", - "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=" + "bundled": true }, "errno": { "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "bundled": true, "requires": { "prr": "~1.0.1" } }, "es-abstract": { "version": "1.12.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", - "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", + "bundled": true, "requires": { "es-to-primitive": "^1.1.1", "function-bind": "^1.1.1", @@ -13245,8 +13159,7 @@ }, "es-to-primitive": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "bundled": true, "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -13255,26 +13168,22 @@ }, "es6-promise": { "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + "bundled": true }, "es6-promisify": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "bundled": true, "requires": { "es6-promise": "^4.0.3" } }, "escape-string-regexp": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "bundled": true }, "execa": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "bundled": true, "requires": { "cross-spawn": "^5.0.1", "get-stream": "^3.0.0", @@ -13287,40 +13196,33 @@ "dependencies": { "get-stream": { "version": "3.0.0", - "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" + "bundled": true } } }, "extend": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + "bundled": true }, "extsprintf": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + "bundled": true }, "fast-json-stable-stringify": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + "bundled": true }, "figgy-pudding": { "version": "3.5.1", - "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", - "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==" + "bundled": true }, "find-npm-prefix": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz", - "integrity": "sha512-KEftzJ+H90x6pcKtdXZEPsQse8/y/UnvzRKrOSQFprnrGaFuJ62fVkP34Iu2IYuMvyauCyoLTNkJZgrrGA2wkA==" + "bundled": true }, "flush-write-stream": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", - "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==", + "bundled": true, "requires": { "inherits": "^2.0.1", "readable-stream": "^2.0.4" @@ -13328,8 +13230,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -13342,8 +13243,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "requires": { "safe-buffer": "~5.1.0" } @@ -13352,13 +13252,11 @@ }, "forever-agent": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + "bundled": true }, "form-data": { "version": "2.3.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", - "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "bundled": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "1.0.6", @@ -13367,8 +13265,7 @@ }, "from2": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "bundled": true, "requires": { "inherits": "^2.0.1", "readable-stream": "^2.0.0" @@ -13376,8 +13273,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -13390,8 +13286,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "requires": { "safe-buffer": "~5.1.0" } @@ -13400,16 +13295,14 @@ }, "fs-minipass": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", - "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "bundled": true, "requires": { "minipass": "^2.6.0" }, "dependencies": { "minipass": { "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "bundled": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -13419,8 +13312,7 @@ }, "fs-vacuum": { "version": "1.2.10", - "resolved": "https://registry.npmjs.org/fs-vacuum/-/fs-vacuum-1.2.10.tgz", - "integrity": "sha1-t2Kb7AekAxolSP35n17PHMizHjY=", + "bundled": true, "requires": { "graceful-fs": "^4.1.2", "path-is-inside": "^1.0.1", @@ -13429,8 +13321,7 @@ }, "fs-write-stream-atomic": { "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "bundled": true, "requires": { "graceful-fs": "^4.1.2", "iferr": "^0.1.5", @@ -13440,13 +13331,11 @@ "dependencies": { "iferr": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" + "bundled": true }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -13459,8 +13348,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "requires": { "safe-buffer": "~5.1.0" } @@ -13469,18 +13357,15 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "bundled": true }, "function-bind": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "bundled": true }, "gauge": { "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "bundled": true, "requires": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", @@ -13494,13 +13379,11 @@ "dependencies": { "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + "bundled": true }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "bundled": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -13511,13 +13394,11 @@ }, "genfun": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz", - "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==" + "bundled": true }, "gentle-fs": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/gentle-fs/-/gentle-fs-2.3.1.tgz", - "integrity": "sha512-OlwBBwqCFPcjm33rF2BjW+Pr6/ll2741l+xooiwTCeaX2CA1ZuclavyMBe0/KlR21/XGsgY6hzEQZ15BdNa13Q==", + "bundled": true, "requires": { "aproba": "^1.1.2", "chownr": "^1.1.2", @@ -13534,41 +13415,35 @@ "dependencies": { "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + "bundled": true }, "iferr": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" + "bundled": true } } }, "get-caller-file": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + "bundled": true }, "get-stream": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "bundled": true, "requires": { "pump": "^3.0.0" } }, "getpass": { "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "bundled": true, "requires": { "assert-plus": "^1.0.0" } }, "glob": { "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "bundled": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -13580,16 +13455,14 @@ }, "global-dirs": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "bundled": true, "requires": { "ini": "^1.3.4" } }, "got": { "version": "6.7.1", - "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", - "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", + "bundled": true, "requires": { "create-error-class": "^3.0.0", "duplexer3": "^0.1.4", @@ -13606,25 +13479,21 @@ "dependencies": { "get-stream": { "version": "3.0.0", - "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" + "bundled": true } } }, "graceful-fs": { "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" + "bundled": true }, "har-schema": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + "bundled": true }, "har-validator": { "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "bundled": true, "requires": { "ajv": "^6.12.3", "har-schema": "^2.0.0" @@ -13632,8 +13501,7 @@ "dependencies": { "ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "bundled": true, "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -13643,53 +13511,44 @@ }, "fast-deep-equal": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "bundled": true }, "json-schema-traverse": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "bundled": true } } }, "has": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "bundled": true, "requires": { "function-bind": "^1.1.1" } }, "has-flag": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "bundled": true }, "has-symbols": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" + "bundled": true }, "has-unicode": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + "bundled": true }, "hosted-git-info": { "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" + "bundled": true }, "http-cache-semantics": { "version": "3.8.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", - "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==" + "bundled": true }, "http-proxy-agent": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", - "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "bundled": true, "requires": { "agent-base": "4", "debug": "3.1.0" @@ -13697,8 +13556,7 @@ }, "http-signature": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "bundled": true, "requires": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", @@ -13707,8 +13565,7 @@ }, "https-proxy-agent": { "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "bundled": true, "requires": { "agent-base": "^4.3.0", "debug": "^3.1.0" @@ -13716,52 +13573,44 @@ }, "humanize-ms": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "bundled": true, "requires": { "ms": "^2.0.0" } }, "iconv-lite": { "version": "0.4.23", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", - "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "bundled": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } }, "iferr": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-1.0.2.tgz", - "integrity": "sha512-9AfeLfji44r5TKInjhz3W9DyZI1zR1JAf2hVBMGhddAKPqBsupb89jGfbCTHIGZd6fGZl9WlHdn4AObygyMKwg==" + "bundled": true }, "ignore-walk": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", - "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", + "bundled": true, "requires": { "minimatch": "^3.0.4" } }, "import-lazy": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=" + "bundled": true }, "imurmurhash": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + "bundled": true }, "infer-owner": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" + "bundled": true }, "inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "bundled": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -13769,18 +13618,15 @@ }, "inherits": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "bundled": true }, "ini": { "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + "bundled": true }, "init-package-json": { "version": "1.10.3", - "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-1.10.3.tgz", - "integrity": "sha512-zKSiXKhQveNteyhcj1CoOP8tqp1QuxPIPBl8Bid99DGLFqA1p87M6lNgfjJHSBoWJJlidGOv5rWjyYKEB3g2Jw==", + "bundled": true, "requires": { "glob": "^7.1.1", "npm-package-arg": "^4.0.0 || ^5.0.0 || ^6.0.0", @@ -13794,59 +13640,50 @@ }, "ip": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + "bundled": true }, "ip-regex": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=" + "bundled": true }, "is-callable": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" + "bundled": true }, "is-ci": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", - "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", + "bundled": true, "requires": { "ci-info": "^1.5.0" }, "dependencies": { "ci-info": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", - "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==" + "bundled": true } } }, "is-cidr": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-cidr/-/is-cidr-3.0.0.tgz", - "integrity": "sha512-8Xnnbjsb0x462VoYiGlhEi+drY8SFwrHiSYuzc/CEwco55vkehTaxAyIjEdpi3EMvLPPJAJi9FlzP+h+03gp0Q==", + "bundled": true, "requires": { "cidr-regex": "^2.0.10" } }, "is-date-object": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" + "bundled": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "bundled": true, "requires": { "number-is-nan": "^1.0.0" } }, "is-installed-globally": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", - "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", + "bundled": true, "requires": { "global-dirs": "^0.1.0", "is-path-inside": "^1.0.0" @@ -13854,103 +13691,85 @@ }, "is-npm": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", - "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=" + "bundled": true }, "is-obj": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" + "bundled": true }, "is-path-inside": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "bundled": true, "requires": { "path-is-inside": "^1.0.1" } }, "is-redirect": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", - "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=" + "bundled": true }, "is-regex": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "bundled": true, "requires": { "has": "^1.0.1" } }, "is-retry-allowed": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", - "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==" + "bundled": true }, "is-stream": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + "bundled": true }, "is-symbol": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "bundled": true, "requires": { "has-symbols": "^1.0.0" } }, "is-typedarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + "bundled": true }, "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "bundled": true }, "isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + "bundled": true }, "isstream": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + "bundled": true }, "jsbn": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "bundled": true, "optional": true }, "json-parse-better-errors": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + "bundled": true }, "json-schema": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + "bundled": true }, "json-stringify-safe": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + "bundled": true }, "jsonparse": { "version": "1.3.1", - "resolved": false, - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" + "bundled": true }, "jsprim": { "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "bundled": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -13960,21 +13779,18 @@ }, "latest-version": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", - "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", + "bundled": true, "requires": { "package-json": "^4.0.0" } }, "lazy-property": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lazy-property/-/lazy-property-1.0.0.tgz", - "integrity": "sha1-hN3Es3Bnm6i9TNz6TAa0PVcREUc=" + "bundled": true }, "libcipm": { "version": "4.0.8", - "resolved": "https://registry.npmjs.org/libcipm/-/libcipm-4.0.8.tgz", - "integrity": "sha512-IN3hh2yDJQtZZ5paSV4fbvJg4aHxCCg5tcZID/dSVlTuUiWktsgaldVljJv6Z5OUlYspx6xQkbR0efNodnIrOA==", + "bundled": true, "requires": { "bin-links": "^1.1.2", "bluebird": "^3.5.1", @@ -13995,8 +13811,7 @@ }, "libnpm": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/libnpm/-/libnpm-3.0.1.tgz", - "integrity": "sha512-d7jU5ZcMiTfBqTUJVZ3xid44fE5ERBm9vBnmhp2ECD2Ls+FNXWxHSkO7gtvrnbLO78gwPdNPz1HpsF3W4rjkBQ==", + "bundled": true, "requires": { "bin-links": "^1.1.2", "bluebird": "^3.5.3", @@ -14022,8 +13837,7 @@ }, "libnpmaccess": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-3.0.2.tgz", - "integrity": "sha512-01512AK7MqByrI2mfC7h5j8N9V4I7MHJuk9buo8Gv+5QgThpOgpjB7sQBDDkeZqRteFb1QM/6YNdHfG7cDvfAQ==", + "bundled": true, "requires": { "aproba": "^2.0.0", "get-stream": "^4.0.0", @@ -14033,8 +13847,7 @@ }, "libnpmconfig": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/libnpmconfig/-/libnpmconfig-1.2.1.tgz", - "integrity": "sha512-9esX8rTQAHqarx6qeZqmGQKBNZR5OIbl/Ayr0qQDy3oXja2iFVQQI81R6GZ2a02bSNZ9p3YOGX1O6HHCb1X7kA==", + "bundled": true, "requires": { "figgy-pudding": "^3.5.1", "find-up": "^3.0.0", @@ -14043,16 +13856,14 @@ "dependencies": { "find-up": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "bundled": true, "requires": { "locate-path": "^3.0.0" } }, "locate-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "bundled": true, "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" @@ -14060,31 +13871,27 @@ }, "p-limit": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "bundled": true, "requires": { "p-try": "^2.0.0" } }, "p-locate": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "bundled": true, "requires": { "p-limit": "^2.0.0" } }, "p-try": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + "bundled": true } } }, "libnpmhook": { "version": "5.0.3", - "resolved": "https://registry.npmjs.org/libnpmhook/-/libnpmhook-5.0.3.tgz", - "integrity": "sha512-UdNLMuefVZra/wbnBXECZPefHMGsVDTq5zaM/LgKNE9Keyl5YXQTnGAzEo+nFOpdRqTWI9LYi4ApqF9uVCCtuA==", + "bundled": true, "requires": { "aproba": "^2.0.0", "figgy-pudding": "^3.4.1", @@ -14094,8 +13901,7 @@ }, "libnpmorg": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/libnpmorg/-/libnpmorg-1.0.1.tgz", - "integrity": "sha512-0sRUXLh+PLBgZmARvthhYXQAWn0fOsa6T5l3JSe2n9vKG/lCVK4nuG7pDsa7uMq+uTt2epdPK+a2g6btcY11Ww==", + "bundled": true, "requires": { "aproba": "^2.0.0", "figgy-pudding": "^3.4.1", @@ -14105,8 +13911,7 @@ }, "libnpmpublish": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-1.1.2.tgz", - "integrity": "sha512-2yIwaXrhTTcF7bkJKIKmaCV9wZOALf/gsTDxVSu/Gu/6wiG3fA8ce8YKstiWKTxSFNC0R7isPUb6tXTVFZHt2g==", + "bundled": true, "requires": { "aproba": "^2.0.0", "figgy-pudding": "^3.5.1", @@ -14121,8 +13926,7 @@ }, "libnpmsearch": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/libnpmsearch/-/libnpmsearch-2.0.2.tgz", - "integrity": "sha512-VTBbV55Q6fRzTdzziYCr64+f8AopQ1YZ+BdPOv16UegIEaE8C0Kch01wo4s3kRTFV64P121WZJwgmBwrq68zYg==", + "bundled": true, "requires": { "figgy-pudding": "^3.5.1", "get-stream": "^4.0.0", @@ -14131,8 +13935,7 @@ }, "libnpmteam": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/libnpmteam/-/libnpmteam-1.0.2.tgz", - "integrity": "sha512-p420vM28Us04NAcg1rzgGW63LMM6rwe+6rtZpfDxCcXxM0zUTLl7nPFEnRF3JfFBF5skF/yuZDUthTsHgde8QA==", + "bundled": true, "requires": { "aproba": "^2.0.0", "figgy-pudding": "^3.4.1", @@ -14142,8 +13945,7 @@ }, "libnpx": { "version": "10.2.4", - "resolved": "https://registry.npmjs.org/libnpx/-/libnpx-10.2.4.tgz", - "integrity": "sha512-BPc0D1cOjBeS8VIBKUu5F80s6njm0wbVt7CsGMrIcJ+SI7pi7V0uVPGpEMH9H5L8csOcclTxAXFE2VAsJXUhfA==", + "bundled": true, "requires": { "dotenv": "^5.0.1", "npm-package-arg": "^6.0.0", @@ -14157,8 +13959,7 @@ }, "lock-verify": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lock-verify/-/lock-verify-2.1.0.tgz", - "integrity": "sha512-vcLpxnGvrqisKvLQ2C2v0/u7LVly17ak2YSgoK4PrdsYBXQIax19vhKiLfvKNFx7FRrpTnitrpzF/uuCMuorIg==", + "bundled": true, "requires": { "npm-package-arg": "^6.1.0", "semver": "^5.4.1" @@ -14166,21 +13967,18 @@ }, "lockfile": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lockfile/-/lockfile-1.0.4.tgz", - "integrity": "sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA==", + "bundled": true, "requires": { "signal-exit": "^3.0.2" } }, "lodash._baseindexof": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz", - "integrity": "sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw=" + "bundled": true }, "lodash._baseuniq": { "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz", - "integrity": "sha1-DrtE5FaBSveQXGIS+iybLVG4Qeg=", + "bundled": true, "requires": { "lodash._createset": "~4.0.0", "lodash._root": "~3.0.0" @@ -14188,87 +13986,72 @@ }, "lodash._bindcallback": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", - "integrity": "sha1-5THCdkTPi1epnhftlbNcdIeJOS4=" + "bundled": true }, "lodash._cacheindexof": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz", - "integrity": "sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI=" + "bundled": true }, "lodash._createcache": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz", - "integrity": "sha1-VtagZAF2JeeevKa4AY4XRAvc8JM=", + "bundled": true, "requires": { "lodash._getnative": "^3.0.0" } }, "lodash._createset": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/lodash._createset/-/lodash._createset-4.0.3.tgz", - "integrity": "sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=" + "bundled": true }, "lodash._getnative": { "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=" + "bundled": true }, "lodash._root": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=" + "bundled": true }, "lodash.clonedeep": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" + "bundled": true }, "lodash.restparam": { "version": "3.6.1", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=" + "bundled": true }, "lodash.union": { "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=" + "bundled": true }, "lodash.uniq": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" + "bundled": true }, "lodash.without": { "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.without/-/lodash.without-4.4.0.tgz", - "integrity": "sha1-PNRXSgC2e643OpS3SHcmQFB7eqw=" + "bundled": true }, "lowercase-keys": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" + "bundled": true }, "lru-cache": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "bundled": true, "requires": { "yallist": "^3.0.2" } }, "make-dir": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "bundled": true, "requires": { "pify": "^3.0.0" } }, "make-fetch-happen": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz", - "integrity": "sha512-07JHC0r1ykIoruKO8ifMXu+xEU8qOXDFETylktdug6vJDACnP+HKevOu3PXyNPzFyTSlz8vrBYlBO1JZRe8Cag==", + "bundled": true, "requires": { "agentkeepalive": "^3.4.1", "cacache": "^12.0.0", @@ -14285,47 +14068,40 @@ }, "meant": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/meant/-/meant-1.0.2.tgz", - "integrity": "sha512-KN+1uowN/NK+sT/Lzx7WSGIj2u+3xe5n2LbwObfjOhPZiA+cCfCm6idVl0RkEfjThkw5XJ96CyRcanq6GmKtUg==" + "bundled": true }, "mime-db": { "version": "1.35.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz", - "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==" + "bundled": true }, "mime-types": { "version": "2.1.19", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", - "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", + "bundled": true, "requires": { "mime-db": "~1.35.0" } }, "minimatch": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "bundled": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + "bundled": true }, "minizlib": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", - "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "bundled": true, "requires": { "minipass": "^2.9.0" }, "dependencies": { "minipass": { "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "bundled": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -14335,8 +14111,7 @@ }, "mississippi": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", - "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "bundled": true, "requires": { "concat-stream": "^1.5.0", "duplexify": "^3.4.2", @@ -14352,23 +14127,20 @@ }, "mkdirp": { "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "bundled": true, "requires": { "minimist": "^1.2.5" }, "dependencies": { "minimist": { "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + "bundled": true } } }, "move-concurrently": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", - "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "bundled": true, "requires": { "aproba": "^1.1.1", "copy-concurrently": "^1.0.0", @@ -14380,25 +14152,21 @@ "dependencies": { "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + "bundled": true } } }, "ms": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "bundled": true }, "mute-stream": { "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" + "bundled": true }, "node-fetch-npm": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz", - "integrity": "sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw==", + "bundled": true, "requires": { "encoding": "^0.1.11", "json-parse-better-errors": "^1.0.0", @@ -14407,8 +14175,7 @@ }, "node-gyp": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.0.tgz", - "integrity": "sha512-OUTryc5bt/P8zVgNUmC6xdXiDJxLMAW8cF5tLQOT9E5sOQj+UeQxnnPy74K3CLCa/SOjjBlbuzDLR8ANwA+wmw==", + "bundled": true, "requires": { "env-paths": "^2.2.0", "glob": "^7.1.4", @@ -14425,8 +14192,7 @@ }, "nopt": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "bundled": true, "requires": { "abbrev": "1", "osenv": "^0.1.4" @@ -14434,8 +14200,7 @@ }, "normalize-package-data": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "bundled": true, "requires": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", @@ -14445,8 +14210,7 @@ "dependencies": { "resolve": { "version": "1.10.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", - "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", + "bundled": true, "requires": { "path-parse": "^1.0.6" } @@ -14455,8 +14219,7 @@ }, "npm-audit-report": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/npm-audit-report/-/npm-audit-report-1.3.3.tgz", - "integrity": "sha512-8nH/JjsFfAWMvn474HB9mpmMjrnKb1Hx/oTAdjv4PT9iZBvBxiZ+wtDUapHCJwLqYGQVPaAfs+vL5+5k9QndXw==", + "bundled": true, "requires": { "cli-table3": "^0.5.0", "console-control-strings": "^1.1.0" @@ -14464,29 +14227,25 @@ }, "npm-bundled": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", - "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", + "bundled": true, "requires": { "npm-normalize-package-bin": "^1.0.1" } }, "npm-cache-filename": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz", - "integrity": "sha1-3tMGxbC/yHCp6fr4I7xfKD4FrhE=" + "bundled": true }, "npm-install-checks": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-3.0.2.tgz", - "integrity": "sha512-E4kzkyZDIWoin6uT5howP8VDvkM+E8IQDcHAycaAxMbwkqhIg5eEYALnXOl3Hq9MrkdQB/2/g1xwBINXdKSRkg==", + "bundled": true, "requires": { "semver": "^2.3.0 || 3.x || 4 || 5" } }, "npm-lifecycle": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/npm-lifecycle/-/npm-lifecycle-3.1.5.tgz", - "integrity": "sha512-lDLVkjfZmvmfvpvBzA4vzee9cn+Me4orq0QF8glbswJVEbIcSNWib7qGOffolysc3teCqbbPZZkzbr3GQZTL1g==", + "bundled": true, "requires": { "byline": "^5.0.0", "graceful-fs": "^4.1.15", @@ -14500,18 +14259,15 @@ }, "npm-logical-tree": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/npm-logical-tree/-/npm-logical-tree-1.2.1.tgz", - "integrity": "sha512-AJI/qxDB2PWI4LG1CYN579AY1vCiNyWfkiquCsJWqntRu/WwimVrC8yXeILBFHDwxfOejxewlmnvW9XXjMlYIg==" + "bundled": true }, "npm-normalize-package-bin": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" + "bundled": true }, "npm-package-arg": { "version": "6.1.1", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", - "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", + "bundled": true, "requires": { "hosted-git-info": "^2.7.1", "osenv": "^0.1.5", @@ -14521,8 +14277,7 @@ }, "npm-packlist": { "version": "1.4.8", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", - "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", + "bundled": true, "requires": { "ignore-walk": "^3.0.1", "npm-bundled": "^1.0.1", @@ -14531,8 +14286,7 @@ }, "npm-pick-manifest": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz", - "integrity": "sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw==", + "bundled": true, "requires": { "figgy-pudding": "^3.5.1", "npm-package-arg": "^6.0.0", @@ -14541,8 +14295,7 @@ }, "npm-profile": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/npm-profile/-/npm-profile-4.0.4.tgz", - "integrity": "sha512-Ta8xq8TLMpqssF0H60BXS1A90iMoM6GeKwsmravJ6wYjWwSzcYBTdyWa3DZCYqPutacBMEm7cxiOkiIeCUAHDQ==", + "bundled": true, "requires": { "aproba": "^1.1.2 || 2", "figgy-pudding": "^3.4.1", @@ -14551,8 +14304,7 @@ }, "npm-registry-fetch": { "version": "4.0.7", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.7.tgz", - "integrity": "sha512-cny9v0+Mq6Tjz+e0erFAB+RYJ/AVGzkjnISiobqP8OWj9c9FLoZZu8/SPSKJWE17F1tk4018wfjV+ZbIbqC7fQ==", + "bundled": true, "requires": { "JSONStream": "^1.3.4", "bluebird": "^3.5.1", @@ -14565,28 +14317,24 @@ "dependencies": { "safe-buffer": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + "bundled": true } } }, "npm-run-path": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "bundled": true, "requires": { "path-key": "^2.0.0" } }, "npm-user-validate": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-user-validate/-/npm-user-validate-1.0.1.tgz", - "integrity": "sha512-uQwcd/tY+h1jnEaze6cdX/LrhWhoBxfSknxentoqmIuStxUExxjWd3ULMLFPiFUrZKbOVMowH6Jq2FRWfmhcEw==" + "bundled": true }, "npmlog": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "bundled": true, "requires": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -14596,28 +14344,23 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + "bundled": true }, "oauth-sign": { "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + "bundled": true }, "object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "bundled": true }, "object-keys": { "version": "1.0.12", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", - "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==" + "bundled": true }, "object.getownpropertydescriptors": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "bundled": true, "requires": { "define-properties": "^1.1.2", "es-abstract": "^1.5.1" @@ -14625,31 +14368,26 @@ }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "bundled": true, "requires": { "wrappy": "1" } }, "opener": { "version": "1.5.2", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", - "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==" + "bundled": true }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + "bundled": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + "bundled": true }, "osenv": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "bundled": true, "requires": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" @@ -14657,13 +14395,11 @@ }, "p-finally": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + "bundled": true }, "package-json": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", - "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", + "bundled": true, "requires": { "got": "^6.7.1", "registry-auth-token": "^3.0.1", @@ -14673,8 +14409,7 @@ }, "pacote": { "version": "9.5.12", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.5.12.tgz", - "integrity": "sha512-BUIj/4kKbwWg4RtnBncXPJd15piFSVNpTzY0rysSr3VnMowTYgkGKcaHrbReepAkjTr8lH2CVWRi58Spg2CicQ==", + "bundled": true, "requires": { "bluebird": "^3.5.3", "cacache": "^12.0.2", @@ -14710,8 +14445,7 @@ "dependencies": { "minipass": { "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "bundled": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -14721,8 +14455,7 @@ }, "parallel-transform": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", - "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", + "bundled": true, "requires": { "cyclist": "~0.2.2", "inherits": "^2.0.3", @@ -14731,8 +14464,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -14745,8 +14477,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "requires": { "safe-buffer": "~5.1.0" } @@ -14755,58 +14486,47 @@ }, "path-exists": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + "bundled": true }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "bundled": true }, "path-is-inside": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" + "bundled": true }, "path-key": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + "bundled": true }, "path-parse": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "bundled": true }, "performance-now": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + "bundled": true }, "pify": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + "bundled": true }, "prepend-http": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" + "bundled": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + "bundled": true }, "promise-inflight": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" + "bundled": true }, "promise-retry": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", - "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=", + "bundled": true, "requires": { "err-code": "^1.0.0", "retry": "^0.10.0" @@ -14814,51 +14534,43 @@ "dependencies": { "retry": { "version": "0.10.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", - "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=" + "bundled": true } } }, "promzard": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz", - "integrity": "sha1-JqXW7ox97kyxIggwWs+5O6OCqe4=", + "bundled": true, "requires": { "read": "1" } }, "proto-list": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" + "bundled": true }, "protoduck": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz", - "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==", + "bundled": true, "requires": { "genfun": "^5.0.0" } }, "prr": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" + "bundled": true }, "pseudomap": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + "bundled": true }, "psl": { "version": "1.1.29", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", - "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==" + "bundled": true }, "pump": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "bundled": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -14866,8 +14578,7 @@ }, "pumpify": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "bundled": true, "requires": { "duplexify": "^3.6.0", "inherits": "^2.0.3", @@ -14876,8 +14587,7 @@ "dependencies": { "pump": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "bundled": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -14887,23 +14597,19 @@ }, "punycode": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + "bundled": true }, "qrcode-terminal": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz", - "integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==" + "bundled": true }, "qs": { "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + "bundled": true }, "query-string": { "version": "6.8.2", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.8.2.tgz", - "integrity": "sha512-J3Qi8XZJXh93t2FiKyd/7Ec6GNifsjKXUsVFkSBj/kjLsDylWhnCz4NT1bkPcKotttPW+QbKGqqPH8OoI2pdqw==", + "bundled": true, "requires": { "decode-uri-component": "^0.2.0", "split-on-first": "^1.0.0", @@ -14912,13 +14618,11 @@ }, "qw": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/qw/-/qw-1.0.1.tgz", - "integrity": "sha1-77/cdA+a0FQwRCassYNBLMi5ltQ=" + "bundled": true }, "rc": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "bundled": true, "requires": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -14928,24 +14632,21 @@ }, "read": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", - "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", + "bundled": true, "requires": { "mute-stream": "~0.0.4" } }, "read-cmd-shim": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.5.tgz", - "integrity": "sha512-v5yCqQ/7okKoZZkBQUAfTsQ3sVJtXdNfbPnI5cceppoxEVLYA3k+VtV2omkeo8MS94JCy4fSiUwlRBAwCVRPUA==", + "bundled": true, "requires": { "graceful-fs": "^4.1.2" } }, "read-installed": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", - "integrity": "sha1-/5uLZ/GH0eTCm5/rMfayI6zRkGc=", + "bundled": true, "requires": { "debuglog": "^1.0.1", "graceful-fs": "^4.1.2", @@ -14958,8 +14659,7 @@ }, "read-package-json": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.1.tgz", - "integrity": "sha512-dAiqGtVc/q5doFz6096CcnXhpYk0ZN8dEKVkGLU0CsASt8SrgF6SF7OTKAYubfvFhWaqofl+Y8HK19GR8jwW+A==", + "bundled": true, "requires": { "glob": "^7.1.1", "graceful-fs": "^4.1.2", @@ -14970,8 +14670,7 @@ }, "read-package-tree": { "version": "5.3.1", - "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz", - "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==", + "bundled": true, "requires": { "read-package-json": "^2.0.0", "readdir-scoped-modules": "^1.0.0", @@ -14980,8 +14679,7 @@ }, "readable-stream": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "bundled": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -14990,8 +14688,7 @@ }, "readdir-scoped-modules": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", - "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", + "bundled": true, "requires": { "debuglog": "^1.0.1", "dezalgo": "^1.0.0", @@ -15001,8 +14698,7 @@ }, "registry-auth-token": { "version": "3.4.0", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", - "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", + "bundled": true, "requires": { "rc": "^1.1.6", "safe-buffer": "^5.0.1" @@ -15010,16 +14706,14 @@ }, "registry-url": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", - "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", + "bundled": true, "requires": { "rc": "^1.0.1" } }, "request": { "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "bundled": true, "requires": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", @@ -15045,115 +14739,96 @@ }, "require-directory": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + "bundled": true }, "require-main-filename": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + "bundled": true }, "resolve-from": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + "bundled": true }, "retry": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" + "bundled": true }, "rimraf": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "bundled": true, "requires": { "glob": "^7.1.3" } }, "run-queue": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", - "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "bundled": true, "requires": { "aproba": "^1.1.1" }, "dependencies": { "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + "bundled": true } } }, "safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "bundled": true }, "safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "bundled": true }, "semver": { "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "bundled": true }, "semver-diff": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", - "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", + "bundled": true, "requires": { "semver": "^5.0.3" } }, "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + "bundled": true }, "sha": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/sha/-/sha-3.0.0.tgz", - "integrity": "sha512-DOYnM37cNsLNSGIG/zZWch5CKIRNoLdYUQTQlcgkRkoYIUwDYjqDyye16YcDZg/OPdcbUgTKMjc4SY6TB7ZAPw==", + "bundled": true, "requires": { "graceful-fs": "^4.1.2" } }, "shebang-command": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "bundled": true, "requires": { "shebang-regex": "^1.0.0" } }, "shebang-regex": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + "bundled": true }, "signal-exit": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + "bundled": true }, "slide": { "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=" + "bundled": true }, "smart-buffer": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", - "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==" + "bundled": true }, "socks": { "version": "2.3.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz", - "integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==", + "bundled": true, "requires": { "ip": "1.1.5", "smart-buffer": "^4.1.0" @@ -15161,8 +14836,7 @@ }, "socks-proxy-agent": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz", - "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==", + "bundled": true, "requires": { "agent-base": "~4.2.1", "socks": "~2.3.2" @@ -15170,8 +14844,7 @@ "dependencies": { "agent-base": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", - "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "bundled": true, "requires": { "es6-promisify": "^5.0.0" } @@ -15180,13 +14853,11 @@ }, "sorted-object": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/sorted-object/-/sorted-object-2.0.1.tgz", - "integrity": "sha1-fWMfS9OnmKJK8d/8+/6DM3pd9fw=" + "bundled": true }, "sorted-union-stream": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/sorted-union-stream/-/sorted-union-stream-2.1.3.tgz", - "integrity": "sha1-x3lMfgd4gAUv9xqNSi27Sppjisc=", + "bundled": true, "requires": { "from2": "^1.3.0", "stream-iterate": "^1.1.0" @@ -15194,8 +14865,7 @@ "dependencies": { "from2": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-1.3.0.tgz", - "integrity": "sha1-iEE7qqX5pZfP3pIh2GmGzTwGHf0=", + "bundled": true, "requires": { "inherits": "~2.0.1", "readable-stream": "~1.1.10" @@ -15203,13 +14873,11 @@ }, "isarray": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + "bundled": true }, "readable-stream": { "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "bundled": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", @@ -15219,15 +14887,13 @@ }, "string_decoder": { "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + "bundled": true } } }, "spdx-correct": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", - "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", + "bundled": true, "requires": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -15235,13 +14901,11 @@ }, "spdx-exceptions": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==" + "bundled": true }, "spdx-expression-parse": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "bundled": true, "requires": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -15249,18 +14913,15 @@ }, "spdx-license-ids": { "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==" + "bundled": true }, "split-on-first": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", - "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==" + "bundled": true }, "sshpk": { "version": "1.14.2", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", - "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", + "bundled": true, "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -15275,16 +14936,14 @@ }, "ssri": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", - "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", + "bundled": true, "requires": { "figgy-pudding": "^3.5.1" } }, "stream-each": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.2.tgz", - "integrity": "sha512-mc1dbFhGBxvTM3bIWmAAINbqiuAk9TATcfIQC8P+/+HJefgaiTlMn2dHvkX8qlI12KeYKSQ1Ua9RrIqrn1VPoA==", + "bundled": true, "requires": { "end-of-stream": "^1.1.0", "stream-shift": "^1.0.0" @@ -15292,8 +14951,7 @@ }, "stream-iterate": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/stream-iterate/-/stream-iterate-1.2.0.tgz", - "integrity": "sha1-K9fHcpbBcCpGSIuK1B95hl7s1OE=", + "bundled": true, "requires": { "readable-stream": "^2.1.5", "stream-shift": "^1.0.0" @@ -15301,8 +14959,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -15315,8 +14972,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "requires": { "safe-buffer": "~5.1.0" } @@ -15325,18 +14981,15 @@ }, "stream-shift": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", - "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" + "bundled": true }, "strict-uri-encode": { "version": "2.0.0", - "resolved": false, - "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=" + "bundled": true }, "string-width": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "bundled": true, "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" @@ -15344,18 +14997,15 @@ "dependencies": { "ansi-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + "bundled": true }, "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "bundled": true }, "strip-ansi": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "bundled": true, "requires": { "ansi-regex": "^3.0.0" } @@ -15377,39 +15027,33 @@ }, "stringify-package": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stringify-package/-/stringify-package-1.0.1.tgz", - "integrity": "sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg==" + "bundled": true }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "bundled": true, "requires": { "ansi-regex": "^2.0.0" } }, "strip-eof": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" + "bundled": true }, "strip-json-comments": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + "bundled": true }, "supports-color": { "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "bundled": true, "requires": { "has-flag": "^3.0.0" } }, "tar": { "version": "4.4.19", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", - "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", + "bundled": true, "requires": { "chownr": "^1.1.4", "fs-minipass": "^1.2.7", @@ -15422,8 +15066,7 @@ "dependencies": { "minipass": { "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "bundled": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -15431,38 +15074,32 @@ }, "safe-buffer": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + "bundled": true }, "yallist": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "bundled": true } } }, "term-size": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", - "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", + "bundled": true, "requires": { "execa": "^0.7.0" } }, "text-table": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + "bundled": true }, "through": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + "bundled": true }, "through2": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "bundled": true, "requires": { "readable-stream": "^2.1.5", "xtend": "~4.0.1" @@ -15470,8 +15107,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -15484,8 +15120,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "requires": { "safe-buffer": "~5.1.0" } @@ -15494,18 +15129,15 @@ }, "timed-out": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" + "bundled": true }, "tiny-relative-date": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz", - "integrity": "sha512-MOQHpzllWxDCHHaDno30hhLfbouoYlOI8YlMNtvKe1zXbjEVhbcEovQxvZrPvtiYW630GQDoMMarCnjfyfHA+A==" + "bundled": true }, "tough-cookie": { "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "bundled": true, "requires": { "psl": "^1.1.24", "punycode": "^1.4.1" @@ -15513,71 +15145,60 @@ }, "tunnel-agent": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "bundled": true, "requires": { "safe-buffer": "^5.0.1" } }, "tweetnacl": { "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "bundled": true, "optional": true }, "typedarray": { "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + "bundled": true }, "uid-number": { "version": "0.0.6", - "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", - "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=" + "bundled": true }, "umask": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz", - "integrity": "sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0=" + "bundled": true }, "unique-filename": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "bundled": true, "requires": { "unique-slug": "^2.0.0" } }, "unique-slug": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.0.tgz", - "integrity": "sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=", + "bundled": true, "requires": { "imurmurhash": "^0.1.4" } }, "unique-string": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", - "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "bundled": true, "requires": { "crypto-random-string": "^1.0.0" } }, "unpipe": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + "bundled": true }, "unzip-response": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", - "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=" + "bundled": true }, "update-notifier": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", - "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", + "bundled": true, "requires": { "boxen": "^1.2.1", "chalk": "^2.0.1", @@ -15593,54 +15214,46 @@ }, "uri-js": { "version": "4.4.0", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", - "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "bundled": true, "requires": { "punycode": "^2.1.0" }, "dependencies": { "punycode": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + "bundled": true } } }, "url-parse-lax": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "bundled": true, "requires": { "prepend-http": "^1.0.1" } }, "util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "bundled": true }, "util-extend": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", - "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=" + "bundled": true }, "util-promisify": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz", - "integrity": "sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=", + "bundled": true, "requires": { "object.getownpropertydescriptors": "^2.0.3" } }, "uuid": { "version": "3.3.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", - "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" + "bundled": true }, "validate-npm-package-license": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "bundled": true, "requires": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -15648,16 +15261,14 @@ }, "validate-npm-package-name": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", - "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", + "bundled": true, "requires": { "builtins": "^1.0.3" } }, "verror": { "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "bundled": true, "requires": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", @@ -15666,37 +15277,32 @@ }, "wcwidth": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "bundled": true, "requires": { "defaults": "^1.0.3" } }, "which": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "bundled": true, "requires": { "isexe": "^2.0.0" } }, "which-module": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + "bundled": true }, "wide-align": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", - "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", + "bundled": true, "requires": { "string-width": "^1.0.2" }, "dependencies": { "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "bundled": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -15707,24 +15313,21 @@ }, "widest-line": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", - "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", + "bundled": true, "requires": { "string-width": "^2.1.1" } }, "worker-farm": { "version": "1.7.0", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", - "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "bundled": true, "requires": { "errno": "~0.1.7" } }, "wrap-ansi": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "bundled": true, "requires": { "ansi-styles": "^3.2.0", "string-width": "^3.0.0", @@ -15733,18 +15336,15 @@ "dependencies": { "ansi-regex": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==" + "bundled": true }, "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "bundled": true }, "string-width": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "bundled": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -15753,8 +15353,7 @@ }, "strip-ansi": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "bundled": true, "requires": { "ansi-regex": "^4.1.0" } @@ -15763,13 +15362,11 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "bundled": true }, "write-file-atomic": { "version": "2.4.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "bundled": true, "requires": { "graceful-fs": "^4.1.11", "imurmurhash": "^0.1.4", @@ -15778,28 +15375,23 @@ }, "xdg-basedir": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", - "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=" + "bundled": true }, "xtend": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + "bundled": true }, "y18n": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==" + "bundled": true }, "yallist": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" + "bundled": true }, "yargs": { "version": "14.2.3", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz", - "integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==", + "bundled": true, "requires": { "cliui": "^5.0.0", "decamelize": "^1.2.0", @@ -15816,26 +15408,22 @@ "dependencies": { "ansi-regex": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + "bundled": true }, "find-up": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "bundled": true, "requires": { "locate-path": "^3.0.0" } }, "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "bundled": true }, "locate-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "bundled": true, "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" @@ -15843,29 +15431,25 @@ }, "p-limit": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "bundled": true, "requires": { "p-try": "^2.0.0" } }, "p-locate": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "bundled": true, "requires": { "p-limit": "^2.0.0" } }, "p-try": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + "bundled": true }, "string-width": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "bundled": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -15874,8 +15458,7 @@ }, "strip-ansi": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "bundled": true, "requires": { "ansi-regex": "^4.1.0" } @@ -15884,8 +15467,7 @@ }, "yargs-parser": { "version": "15.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.1.tgz", - "integrity": "sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw==", + "bundled": true, "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" @@ -15893,8 +15475,7 @@ "dependencies": { "camelcase": { "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + "bundled": true } } } diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 02bc55e7a..bcfa695f0 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -88,11 +88,10 @@ export class CollectionSchemaView extends CollectionSubView() { this._selectedDocs.add(doc); this._lastSelectedRow = index; } - + if (this._lastSelectedRow && this._selectedDocs.size > 0) { SelectionManager.SelectSchemaViewDoc(this.childDocs[this._lastSelectedRow]); - } - else { + } else { SelectionManager.SelectSchemaViewDoc(undefined); } }; @@ -154,7 +153,7 @@ export class CollectionSchemaView extends CollectionSubView() { @action addNewTextDoc = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => { if (!value && !forceEmptyNote) return false; - const newDoc = Docs.Create.TextDocument(value, {title: value}); + const newDoc = Docs.Create.TextDocument(value, { title: value }); FormattedTextBox.SelectOnLoad = newDoc[Id]; FormattedTextBox.SelectOnLoadChar = forceEmptyNote ? '' : ' '; return this.props.addDocument?.(newDoc) || false; diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx index 9bd1b843f..b9dbf4f57 100644 --- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx +++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx @@ -1,9 +1,8 @@ import React = require('react'); +import { computed } from 'mobx'; import { observer } from 'mobx-react'; -import './CollectionSchemaView.scss'; import { EditableView } from '../../EditableView'; -import { emptyFunction } from '../../../../Utils'; -import { action, computed } from 'mobx'; +import './CollectionSchemaView.scss'; export interface SchemaColumnHeaderProps { columnKeys: string[]; diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx index ea2ebed7a..3d1fa0ee2 100644 --- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx +++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx @@ -36,12 +36,13 @@ export class SchemaRowBox extends ViewBoxBaseComponent() { e.stopPropagation(); setupMoveUpEvents( - this, e, - (e) => this.props.startDrag(e, this.props.Document), + this, + e, + e => this.props.startDrag(e, this.props.Document), emptyFunction, - (e) => this.props.selectRow(e, this.props.Document, this.props.rowIndex) - ) - } + e => this.props.selectRow(e, this.props.Document, this.props.rowIndex) + ); + }; onPointerEnter = (e: any) => { if (!this.props.dragging) return; @@ -54,7 +55,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent() { let dragIsRow: boolean = true; DragManager.docsBeingDragged.forEach(doc => { dragIsRow = this.props.selectedRows.has(doc); - }) + }); if (this._ref && dragIsRow) { const rect = this._ref.getBoundingClientRect(); const y = e.clientY - rect.top; //y position within the element. @@ -82,17 +83,35 @@ export class SchemaRowBox extends ViewBoxBaseComponent() { render() { return ( -
(this._ref = row)}> -
-
{e.stopPropagation(); this.props.removeDocument?.(this.props.Document)})}> +
(this._ref = row)}> +
+
{ + e.stopPropagation(); + this.props.removeDocument?.(this.props.Document); + })}>
-
{e.stopPropagation(); this.props.addDocTab(this.props.Document, 'add:right')}}> +
{ + e.stopPropagation(); + this.props.addDocTab(this.props.Document, 'add:right'); + }}>
- {this.props.columnKeys.map((key, index) => ())} + {this.props.columnKeys.map((key, index) => ( + + ))}
); diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx index 1eb5e0e01..7e2fa1f6f 100644 --- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx @@ -1,7 +1,6 @@ import React = require('react'); import { observer } from 'mobx-react'; import { Doc, Field } from '../../../../fields/Doc'; -import { StrCast } from '../../../../fields/Types'; import './CollectionSchemaView.scss'; export interface SchemaTableCellProps { -- cgit v1.2.3-70-g09d2 From fb1e291b1bed4b60a645030b4a79c0760ba73fdc Mon Sep 17 00:00:00 2001 From: mehekj Date: Tue, 16 Aug 2022 18:10:15 -0400 Subject: add and remove columns (remove buggy for same named headers) --- .vscode/settings.json | 5 ++- .../collectionSchema/CollectionSchemaView.scss | 40 +++++++++++++++------- .../collectionSchema/CollectionSchemaView.tsx | 20 +++++++++-- .../collectionSchema/SchemaColumnHeader.tsx | 20 +++++++++++ 4 files changed, 69 insertions(+), 16 deletions(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/.vscode/settings.json b/.vscode/settings.json index f0cebd6fd..8849f30dd 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,5 +10,8 @@ "editor.detectIndentation": false, "search.usePCRE2": true, "typescript.tsdk": "node_modules/typescript/lib", - "editor.defaultFormatter": "esbenp.prettier-vscode" + "editor.defaultFormatter": "esbenp.prettier-vscode", + "[typescriptreact]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + } } diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss index 4f644717b..83164a82a 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss @@ -27,6 +27,10 @@ .schema-column-header { font-weight: bold; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; } } @@ -37,19 +41,6 @@ display: flex; flex-direction: row; justify-content: center; - - .row-button { - width: 25px; - height: 25px; - border-radius: 100%; - background-color: $dark-gray; - color: white; - margin: 3px; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - } } .row-cells { @@ -58,5 +49,28 @@ justify-content: flex-end; } } + + .schema-header-menu { + display: flex; + flex-direction: row; + } + + .row-button, + .schema-header-button { + width: 20px; + height: 20px; + border-radius: 100%; + background-color: $dark-gray; + color: white; + margin: 3px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + + svg { + width: 12px; + } + } } } diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index bcfa695f0..4d96d5f7e 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -55,8 +55,8 @@ export class CollectionSchemaView extends CollectionSubView() { ); } - @action @undoBatch + @action changeColumnKey = (index: number, newKey: string) => { let currKeys = this.columnKeys; currKeys[index] = newKey; @@ -64,6 +64,22 @@ export class CollectionSchemaView extends CollectionSubView() { return true; }; + @undoBatch + @action + addColumn = (index: number) => { + let currKeys = this.columnKeys; + currKeys.splice(index, 0, 'title'); + this.layoutDoc.columnKeys = new List(currKeys); + }; + + @undoBatch + @action + removeColumn = (index: number) => { + let currKeys = this.columnKeys; + currKeys.splice(index, 1); + this.layoutDoc.columnKeys = new List(currKeys); + }; + @action selectRow = (e: React.PointerEvent, doc: Doc, index: number) => { const ctrl = e.ctrlKey || e.metaKey; @@ -239,7 +255,7 @@ export class CollectionSchemaView extends CollectionSubView() {
{this.columnKeys.map((key, index) => ( - + ))}
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx index b9dbf4f57..f93a3d13d 100644 --- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx +++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx @@ -3,12 +3,15 @@ import { computed } from 'mobx'; import { observer } from 'mobx-react'; import { EditableView } from '../../EditableView'; import './CollectionSchemaView.scss'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; export interface SchemaColumnHeaderProps { columnKeys: string[]; columnWidths: number[]; columnIndex: number; changeColumnKey: (index: number, newKey: string) => boolean; + addColumn: (index: number) => void; + removeColumn: (index: number) => void; } @observer @@ -21,6 +24,23 @@ export class SchemaColumnHeader extends React.Component return (
this.props.changeColumnKey(this.props.columnIndex, newKey)} GetValue={() => this.fieldKey} contents={this.fieldKey} /> + +
+
{ + this.props.addColumn(this.props.columnIndex + 1); + }}> + +
+
{ + this.props.removeColumn(this.props.columnIndex); + }}> + +
+
); } -- cgit v1.2.3-70-g09d2 From 330752fa253b61136b78ce7147e09e9d6004f833 Mon Sep 17 00:00:00 2001 From: mehekj Date: Thu, 18 Aug 2022 14:08:31 -0400 Subject: added external drop and column resize --- .../collectionSchema/CollectionSchemaView.scss | 32 ++++++- .../collectionSchema/CollectionSchemaView.tsx | 105 ++++++++++++++++++--- .../collectionSchema/SchemaColumnHeader.tsx | 8 +- .../collections/collectionSchema/SchemaRowBox.tsx | 6 +- 4 files changed, 133 insertions(+), 18 deletions(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss index 83164a82a..1d0ab459d 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss @@ -11,11 +11,12 @@ .schema-row { display: flex; flex-direction: row; + max-height: 70px; + overflow: auto; .schema-column-header, .schema-table-cell, .row-menu { - min-width: 50px; border: 1px solid $medium-gray; padding: 5px; overflow: hidden; @@ -31,6 +32,34 @@ flex-direction: row; justify-content: space-between; align-items: center; + padding: 0; + + .schema-column-title { + flex-grow: 2; + margin: 5px; + } + + .schema-header-menu { + margin: 5px; + } + + .schema-column-resizer { + height: 100%; + width: 3px; + cursor: ew-resize; + + &:hover { + background-color: $light-blue; + } + } + + .schema-column-resizer.right { + align-self: flex-end; + } + + .schema-column-resizer.left { + align-self: flex-start; + } } } @@ -41,6 +70,7 @@ display: flex; flex-direction: row; justify-content: center; + min-width: 50px; } .row-cells { diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 4d96d5f7e..a09d2722c 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -2,25 +2,25 @@ import React = require('react'); import { action, computed, observable, ObservableSet } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, DocListCast } from '../../../../fields/Doc'; +import { Id } from '../../../../fields/FieldSymbols'; import { List } from '../../../../fields/List'; +import { RichTextField } from '../../../../fields/RichTextField'; import { listSpec } from '../../../../fields/Schema'; import { Cast, StrCast } from '../../../../fields/Types'; +import { ImageField } from '../../../../fields/URLField'; +import { emptyFunction, returnEmptyString, setupMoveUpEvents } from '../../../../Utils'; +import { Docs, DocUtils } from '../../../documents/Documents'; import { DragManager } from '../../../util/DragManager'; -import { CollectionSubView } from '../CollectionSubView'; -import './CollectionSchemaView.scss'; -import { SchemaColumnHeader } from './SchemaColumnHeader'; -import { SchemaRowBox } from './SchemaRowBox'; import { SelectionManager } from '../../../util/SelectionManager'; import { undoBatch } from '../../../util/UndoManager'; -import { EditableView } from '../../EditableView'; -import { returnEmptyString } from '../../../../Utils'; -import { Docs, DocUtils } from '../../../documents/Documents'; -import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { ContextMenu } from '../../ContextMenu'; import { ContextMenuProps } from '../../ContextMenuItem'; -import { Id } from '../../../../fields/FieldSymbols'; -import { RichTextField } from '../../../../fields/RichTextField'; -import { ImageField } from '../../../../fields/URLField'; +import { EditableView } from '../../EditableView'; +import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; +import { CollectionSubView } from '../CollectionSubView'; +import './CollectionSchemaView.scss'; +import { SchemaColumnHeader } from './SchemaColumnHeader'; +import { SchemaRowBox } from './SchemaRowBox'; export enum ColumnType { Number, @@ -38,16 +38,18 @@ export class CollectionSchemaView extends CollectionSubView() { private _lastSelectedRow: number | undefined; private _selectedDocSortedArray: Doc[] = []; private _closestDropIndex: number = 0; + private _minColWidth: number = 120; @observable _rowMenuWidth: number = 100; @observable _selectedDocs: ObservableSet = new ObservableSet(); @observable _isDragging: boolean = false; + @observable _displayColumnWidths: number[] | undefined; @computed get columnKeys() { return Cast(this.layoutDoc.columnKeys, listSpec('string'), defaultColumnKeys); } - @computed get columnWidths() { + @computed get storedColumnWidths() { return Cast( this.layoutDoc.columnWidths, listSpec('number'), @@ -55,6 +57,10 @@ export class CollectionSchemaView extends CollectionSubView() { ); } + @computed get displayColumnWidths() { + return this._displayColumnWidths ?? this.storedColumnWidths; + } + @undoBatch @action changeColumnKey = (index: number, newKey: string) => { @@ -80,6 +86,51 @@ export class CollectionSchemaView extends CollectionSubView() { this.layoutDoc.columnKeys = new List(currKeys); }; + @action + startResize = (e: any, index: number, left: boolean) => { + this._displayColumnWidths = this.storedColumnWidths; + setupMoveUpEvents(this, e, (e, delta) => this.resizeColumn(e, index, left), this.finishResize, emptyFunction); + }; + + @action + resizeColumn = (e: PointerEvent, index: number, left: boolean) => { + if (this._displayColumnWidths) { + let shrinking; + let growing; + + let change = e.movementX; + + if (left && index !== 0) { + growing = change < 0 ? index : index - 1; + shrinking = change < 0 ? index - 1 : index; + } else if (!left && index !== this.columnKeys.length - 1) { + growing = change > 0 ? index : index + 1; + shrinking = change > 0 ? index + 1 : index; + } + + if (shrinking === undefined || growing === undefined) return true; + + change = Math.abs(change); + if (this._displayColumnWidths[shrinking] - change < this._minColWidth) { + change = this._displayColumnWidths[shrinking] - this._minColWidth; + } + + this._displayColumnWidths[shrinking] -= change; + this._displayColumnWidths[growing] += change; + + return false; + } + return true; + }; + + // @undoBatch + @action + finishResize = () => { + console.log('finished'); + this.layoutDoc.columnWidths = new List(this._displayColumnWidths); + this._displayColumnWidths = undefined; + }; + @action selectRow = (e: React.PointerEvent, doc: Doc, index: number) => { const ctrl = e.ctrlKey || e.metaKey; @@ -135,6 +186,21 @@ export class CollectionSchemaView extends CollectionSubView() { return false; }; + @action + onExternalDrop = async (e: React.DragEvent): Promise => { + console.log('hello'); + super.onExternalDrop( + e, + {}, + undoBatch( + action(docus => { + this._isDragging = false; + docus.map((doc: Doc) => this.addDocument(doc)); + }) + ) + ); + }; + @action startDrag = (e: React.PointerEvent, doc: Doc) => { if (!this._selectedDocs.has(doc)) { @@ -251,11 +317,20 @@ export class CollectionSchemaView extends CollectionSubView() { this._ref = ele; this.createDashEventsTarget(ele); }} - onPointerDown={() => this._selectedDocs.clear()}> + onPointerDown={() => this._selectedDocs.clear()} + onDrop={this.onExternalDrop.bind(this)}>
{this.columnKeys.map((key, index) => ( - + ))}
@@ -267,7 +342,7 @@ export class CollectionSchemaView extends CollectionSubView() { ContainingCollectionView={this.props.CollectionView} rowIndex={index} columnKeys={this.columnKeys} - columnWidths={this.columnWidths} + columnWidths={this.displayColumnWidths} rowMenuWidth={this._rowMenuWidth} selectedRows={this._selectedDocs} selectRow={this.selectRow} diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx index f93a3d13d..bee76bb24 100644 --- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx +++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx @@ -12,6 +12,7 @@ export interface SchemaColumnHeaderProps { changeColumnKey: (index: number, newKey: string) => boolean; addColumn: (index: number) => void; removeColumn: (index: number) => void; + resizeColumn: (e: any, index: number, left: boolean) => void; } @observer @@ -23,7 +24,10 @@ export class SchemaColumnHeader extends React.Component render() { return (
- this.props.changeColumnKey(this.props.columnIndex, newKey)} GetValue={() => this.fieldKey} contents={this.fieldKey} /> +
this.props.resizeColumn(e, this.props.columnIndex, true)}>
+
+ this.props.changeColumnKey(this.props.columnIndex, newKey)} GetValue={() => this.fieldKey} contents={this.fieldKey} /> +
+ +
this.props.resizeColumn(e, this.props.columnIndex, false)}>
); } diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx index 3d1fa0ee2..661056553 100644 --- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx +++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx @@ -6,7 +6,7 @@ import { Doc } from '../../../../fields/Doc'; import { undoBatch } from '../../../util/UndoManager'; import { ViewBoxBaseComponent } from '../../DocComponent'; import { Colors } from '../../global/globalEnums'; -import { FieldViewProps } from '../../nodes/FieldView'; +import { FieldView, FieldViewProps } from '../../nodes/FieldView'; import './CollectionSchemaView.scss'; import { SchemaTableCell } from './SchemaTableCell'; import { emptyFunction, setupMoveUpEvents } from '../../../../Utils'; @@ -26,6 +26,10 @@ export interface SchemaRowBoxProps extends FieldViewProps { @observer export class SchemaRowBox extends ViewBoxBaseComponent() { + public static LayoutString(fieldKey: string) { + return FieldView.LayoutString(SchemaRowBox, fieldKey); + } + private _ref: HTMLDivElement | null = null; isSelected = () => this.props.selectedRows.has(this.props.Document); -- cgit v1.2.3-70-g09d2 From 14a938e8bf543ddaf7b8a9ae0c35cd725b5bdb77 Mon Sep 17 00:00:00 2001 From: mehekj Date: Thu, 18 Aug 2022 14:28:58 -0400 Subject: col widths update on add/remove --- .../collectionSchema/CollectionSchemaView.tsx | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index a09d2722c..69a49598d 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -76,6 +76,15 @@ export class CollectionSchemaView extends CollectionSubView() { let currKeys = this.columnKeys; currKeys.splice(index, 0, 'title'); this.layoutDoc.columnKeys = new List(currKeys); + + const newColWidth = this._minColWidth; + let currWidths = this.storedColumnWidths; + currWidths = currWidths.map(w => { + const proportion = w / (this.props.PanelWidth() - this._rowMenuWidth); + return proportion * (this.props.PanelWidth() - this._rowMenuWidth - newColWidth); + }); + currWidths.splice(index, 0, newColWidth); + this.layoutDoc.columnWidths = new List(currWidths); }; @undoBatch @@ -84,6 +93,15 @@ export class CollectionSchemaView extends CollectionSubView() { let currKeys = this.columnKeys; currKeys.splice(index, 1); this.layoutDoc.columnKeys = new List(currKeys); + + let currWidths = this.storedColumnWidths; + const removedColWidth = currWidths[index]; + currWidths = currWidths.map(w => { + const proportion = w / (this.props.PanelWidth() - this._rowMenuWidth - removedColWidth); + return proportion * (this.props.PanelWidth() - this._rowMenuWidth); + }); + currWidths.splice(index, 1); + this.layoutDoc.columnWidths = new List(currWidths); }; @action @@ -123,7 +141,6 @@ export class CollectionSchemaView extends CollectionSubView() { return true; }; - // @undoBatch @action finishResize = () => { console.log('finished'); -- cgit v1.2.3-70-g09d2 From 5425b61d62beef22d068e259ae3e2003f08e0c05 Mon Sep 17 00:00:00 2001 From: mehekj Date: Mon, 24 Oct 2022 15:06:47 -0400 Subject: switched drag element to show rows --- .../collectionSchema/CollectionSchemaView.scss | 98 +++++++++++----------- .../collectionSchema/CollectionSchemaView.tsx | 34 ++++---- .../collections/collectionSchema/SchemaRowBox.tsx | 14 ++-- 3 files changed, 73 insertions(+), 73 deletions(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss index 1d0ab459d..4d7e8c39f 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss @@ -7,22 +7,6 @@ .schema-table { background-color: $white; - .schema-header-row, - .schema-row { - display: flex; - flex-direction: row; - max-height: 70px; - overflow: auto; - - .schema-column-header, - .schema-table-cell, - .row-menu { - border: 1px solid $medium-gray; - padding: 5px; - overflow: hidden; - } - } - .schema-header-row { justify-content: flex-end; @@ -63,44 +47,60 @@ } } - .schema-row { - justify-content: flex-end; - - .row-menu { - display: flex; - flex-direction: row; - justify-content: center; - min-width: 50px; - } - - .row-cells { - display: flex; - flex-direction: row; - justify-content: flex-end; - } - } - .schema-header-menu { display: flex; flex-direction: row; } + } +} - .row-button, - .schema-header-button { - width: 20px; - height: 20px; - border-radius: 100%; - background-color: $dark-gray; - color: white; - margin: 3px; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; +.schema-header-row, +.schema-row { + display: flex; + flex-direction: row; + max-height: 70px; + overflow: auto; + + .schema-column-header, + .schema-table-cell, + .row-menu { + border: 1px solid $medium-gray; + padding: 5px; + overflow: hidden; + } +} - svg { - width: 12px; - } - } +.schema-row { + justify-content: flex-end; + + .row-menu { + display: flex; + flex-direction: row; + justify-content: center; + min-width: 50px; + } + + .row-cells { + display: flex; + flex-direction: row; + justify-content: flex-end; + } +} + +.schema-row-button, +.schema-header-button { + width: 20px; + height: 20px; + border-radius: 100%; + background-color: $dark-gray; + color: white; + margin: 3px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + + svg { + width: 12px; } } diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 69a49598d..84a69d4b9 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -1,5 +1,5 @@ import React = require('react'); -import { action, computed, observable, ObservableSet } from 'mobx'; +import { action, computed, observable, ObservableMap, ObservableSet } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, DocListCast } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; @@ -41,7 +41,7 @@ export class CollectionSchemaView extends CollectionSubView() { private _minColWidth: number = 120; @observable _rowMenuWidth: number = 100; - @observable _selectedDocs: ObservableSet = new ObservableSet(); + @observable _selectedDocs: ObservableMap = new ObservableMap(); @observable _isDragging: boolean = false; @observable _displayColumnWidths: number[] | undefined; @@ -149,7 +149,7 @@ export class CollectionSchemaView extends CollectionSubView() { }; @action - selectRow = (e: React.PointerEvent, doc: Doc, index: number) => { + selectRow = (e: React.PointerEvent, doc: Doc, ref: HTMLDivElement, index: number) => { const ctrl = e.ctrlKey || e.metaKey; const shift = e.shiftKey; if (shift && this._lastSelectedRow !== undefined) { @@ -157,19 +157,19 @@ export class CollectionSchemaView extends CollectionSubView() { const endRow = Math.max(this._lastSelectedRow, index); for (let i = startRow; i <= endRow; i++) { const currDoc: Doc = this.childDocs[i]; - if (!this._selectedDocs.has(currDoc)) this._selectedDocs.add(currDoc); + if (!this._selectedDocs.has(currDoc)) this._selectedDocs.set(currDoc, ref); } this._lastSelectedRow = endRow; } else if (ctrl) { if (!this._selectedDocs.has(doc)) { - this._selectedDocs.add(doc); + this._selectedDocs.set(doc, ref); this._lastSelectedRow = index; } else { this._selectedDocs.delete(doc); } } else { this._selectedDocs.clear(); - this._selectedDocs.add(doc); + this._selectedDocs.set(doc, ref); this._lastSelectedRow = index; } @@ -219,25 +219,25 @@ export class CollectionSchemaView extends CollectionSubView() { }; @action - startDrag = (e: React.PointerEvent, doc: Doc) => { + startDrag = (e: React.PointerEvent, doc: Doc, ref: HTMLDivElement, index: number) => { if (!this._selectedDocs.has(doc)) { this._selectedDocs.clear(); - this._selectedDocs.add(doc); - this._lastSelectedRow = this.childDocs.indexOf(doc); + this._selectedDocs.set(doc, ref); + this._lastSelectedRow = index; SelectionManager.SelectSchemaViewDoc(doc); } this._isDragging = true; this._selectedDocSortedArray = this.sortedSelectedDocs(); const dragData = new DragManager.DocumentDragData(this._selectedDocSortedArray, 'move'); dragData.moveDocument = this.props.moveDocument; - const dragItem: HTMLElement[] = []; - const dragDiv = document.createElement('div'); - dragDiv.className = 'presItem-multiDrag'; - dragDiv.innerText = 'Move ' + this._selectedDocs.size + ' row' + (this._selectedDocs.size > 1 ? 's' : ''); - dragDiv.style.position = 'absolute'; - dragDiv.style.top = e.clientY + 'px'; - dragDiv.style.left = e.clientX - 50 + 'px'; - dragItem.push(dragDiv); + const dragItem: HTMLElement[] = Array.from(this._selectedDocs.values()); + // const dragDiv = document.createElement('div'); + // dragDiv.className = 'presItem-multiDrag'; + // dragDiv.innerText = 'Move ' + this._selectedDocs.size + ' row' + (this._selectedDocs.size > 1 ? 's' : ''); + // dragDiv.style.position = 'absolute'; + // dragDiv.style.top = e.clientY + 'px'; + // dragDiv.style.left = e.clientX - 50 + 'px'; + // dragItem.push(dragDiv); DragManager.StartDocumentDrag( dragItem.map(ele => ele), diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx index 661056553..66cc3a47a 100644 --- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx +++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx @@ -17,9 +17,9 @@ export interface SchemaRowBoxProps extends FieldViewProps { columnKeys: string[]; columnWidths: number[]; rowMenuWidth: number; - selectedRows: ObservableSet; - selectRow: (e: any, doc: Doc, index: number) => void; - startDrag: (e: any, doc: Doc) => boolean; + selectedRows: ObservableMap; + selectRow: (e: any, doc: Doc, ref: HTMLDivElement, index: number) => void; + startDrag: (e: any, doc: Doc, ref: HTMLDivElement, index: number) => boolean; dragging: boolean; dropIndex: (index: number) => void; } @@ -42,9 +42,9 @@ export class SchemaRowBox extends ViewBoxBaseComponent() { setupMoveUpEvents( this, e, - e => this.props.startDrag(e, this.props.Document), + e => this.props.startDrag(e, this.props.Document, this._ref!, this.props.rowIndex), emptyFunction, - e => this.props.selectRow(e, this.props.Document, this.props.rowIndex) + e => this.props.selectRow(e, this.props.Document, this._ref!, this.props.rowIndex) ); }; @@ -96,7 +96,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent() { ref={(row: HTMLDivElement | null) => (this._ref = row)}>
{ e.stopPropagation(); this.props.removeDocument?.(this.props.Document); @@ -104,7 +104,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent() {
{ e.stopPropagation(); this.props.addDocTab(this.props.Document, 'add:right'); -- cgit v1.2.3-70-g09d2 From 213a92ba3aa39d144754029fde32b9d69b0f51cf Mon Sep 17 00:00:00 2001 From: mehekj Date: Mon, 7 Nov 2022 12:57:44 -0500 Subject: basic key selection menu created --- .../collectionSchema/CollectionSchemaView.scss | 8 ++ .../collectionSchema/CollectionSchemaView.tsx | 150 +++++++++++++++------ .../collectionSchema/SchemaColumnHeader.tsx | 105 +++++++++++++-- .../collections/collectionSchema/SchemaRowBox.tsx | 12 +- 4 files changed, 223 insertions(+), 52 deletions(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss index 4d7e8c39f..0631cd21d 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss @@ -44,6 +44,13 @@ .schema-column-resizer.left { align-self: flex-start; } + + .schema-column-menu { + background: $light-gray; + width: inherit; + position: absolute; + top: 35px; + } } } @@ -72,6 +79,7 @@ .schema-row { justify-content: flex-end; + background: white; .row-menu { display: flex; diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 84a69d4b9..7516b95b8 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -1,7 +1,7 @@ import React = require('react'); -import { action, computed, observable, ObservableMap, ObservableSet } from 'mobx'; +import { action, computed, observable, ObservableMap, ObservableSet, untracked } from 'mobx'; import { observer } from 'mobx-react'; -import { Doc, DocListCast } from '../../../../fields/Doc'; +import { Doc, DocListCast, StrListCast } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; import { List } from '../../../../fields/List'; import { RichTextField } from '../../../../fields/RichTextField'; @@ -41,10 +41,26 @@ export class CollectionSchemaView extends CollectionSubView() { private _minColWidth: number = 120; @observable _rowMenuWidth: number = 100; - @observable _selectedDocs: ObservableMap = new ObservableMap(); + @observable _selectedDocs: ObservableSet = new ObservableSet(); + @observable _rowEles: ObservableMap = new ObservableMap(); @observable _isDragging: boolean = false; @observable _displayColumnWidths: number[] | undefined; + get documentKeys() { + const docs = this.childDocs; + const keys: { [key: string]: boolean } = {}; + // bcz: ugh. this is untracked since otherwise a large collection of documents will blast the server for all their fields. + // then as each document's fields come back, we update the documents _proxies. Each time we do this, the whole schema will be + // invalidated and re-rendered. This workaround will inquire all of the document fields before the options button is clicked. + // then by the time the options button is clicked, all of the fields should be in place. If a new field is added while this menu + // is displayed (unlikely) it won't show up until something else changes. + //TODO Types + untracked(() => docs.map(doc => Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => (keys[key] = false))))); + + // this.columns.forEach(key => (keys[key.heading] = true)); + return Array.from(Object.keys(keys)); + } + @computed get columnKeys() { return Cast(this.layoutDoc.columnKeys, listSpec('string'), defaultColumnKeys); } @@ -64,6 +80,10 @@ export class CollectionSchemaView extends CollectionSubView() { @undoBatch @action changeColumnKey = (index: number, newKey: string) => { + if (!this.documentKeys.includes(newKey)) { + this.addNewKey(newKey); + } + let currKeys = this.columnKeys; currKeys[index] = newKey; this.layoutDoc.columnKeys = new List(currKeys); @@ -72,10 +92,10 @@ export class CollectionSchemaView extends CollectionSubView() { @undoBatch @action - addColumn = (index: number) => { - let currKeys = this.columnKeys; - currKeys.splice(index, 0, 'title'); - this.layoutDoc.columnKeys = new List(currKeys); + addColumn = (index: number, key: string) => { + if (!this.documentKeys.includes(key)) { + this.addNewKey(key); + } const newColWidth = this._minColWidth; let currWidths = this.storedColumnWidths; @@ -83,17 +103,22 @@ export class CollectionSchemaView extends CollectionSubView() { const proportion = w / (this.props.PanelWidth() - this._rowMenuWidth); return proportion * (this.props.PanelWidth() - this._rowMenuWidth - newColWidth); }); - currWidths.splice(index, 0, newColWidth); + currWidths.splice(index + 1, 0, newColWidth); this.layoutDoc.columnWidths = new List(currWidths); + + let currKeys = this.columnKeys; + currKeys.splice(index + 1, 0, key); + this.layoutDoc.columnKeys = new List(currKeys); + }; + + @action + addNewKey = (key: string) => { + this.childDocs.forEach(doc => (doc[key] = key + ' default val')); }; @undoBatch @action removeColumn = (index: number) => { - let currKeys = this.columnKeys; - currKeys.splice(index, 1); - this.layoutDoc.columnKeys = new List(currKeys); - let currWidths = this.storedColumnWidths; const removedColWidth = currWidths[index]; currWidths = currWidths.map(w => { @@ -102,6 +127,10 @@ export class CollectionSchemaView extends CollectionSubView() { }); currWidths.splice(index, 1); this.layoutDoc.columnWidths = new List(currWidths); + + let currKeys = this.columnKeys; + currKeys.splice(index, 1); + this.layoutDoc.columnKeys = new List(currKeys); }; @action @@ -143,11 +172,55 @@ export class CollectionSchemaView extends CollectionSubView() { @action finishResize = () => { - console.log('finished'); this.layoutDoc.columnWidths = new List(this._displayColumnWidths); this._displayColumnWidths = undefined; }; + @undoBatch + @action + swapColumns = (index1: number, index2: number) => { + console.log(index1, index2); + const tempKey = this.columnKeys[index1]; + const tempWidth = this.storedColumnWidths[index1]; + + let currKeys = this.columnKeys; + currKeys[index1] = currKeys[index2]; + currKeys[index2] = tempKey; + this.layoutDoc.columnKeys = new List(currKeys); + + let currWidths = this.storedColumnWidths; + currWidths[index1] = currWidths[index2]; + currWidths[index2] = tempWidth; + this.layoutDoc.columnWidths = new List(currWidths); + }; + + @action + dragColumn = (e: any, index: number) => { + console.log(index); + e.stopPropagation(); + e.preventDefault(); + const rect = e.target.getBoundingClientRect(); + if (e.clientX < rect.x) { + console.log('left', e.clientX, rect.x); + if (index < 1) return true; + this.swapColumns(index - 1, index); + return true; + } + if (e.clientX > rect.x + rect.width) { + console.log('right', e.clientX, rect.x + rect.width); + if (index === this.columnKeys.length) return true; + console.log(index); + this.swapColumns(index, index + 1); + return true; + } + return false; + }; + + @action + addRowRef = (doc: Doc, ref: HTMLDivElement) => { + this._rowEles.set(doc, ref); + }; + @action selectRow = (e: React.PointerEvent, doc: Doc, ref: HTMLDivElement, index: number) => { const ctrl = e.ctrlKey || e.metaKey; @@ -157,19 +230,19 @@ export class CollectionSchemaView extends CollectionSubView() { const endRow = Math.max(this._lastSelectedRow, index); for (let i = startRow; i <= endRow; i++) { const currDoc: Doc = this.childDocs[i]; - if (!this._selectedDocs.has(currDoc)) this._selectedDocs.set(currDoc, ref); + if (!this._selectedDocs.has(currDoc)) this._selectedDocs.add(currDoc); } this._lastSelectedRow = endRow; } else if (ctrl) { if (!this._selectedDocs.has(doc)) { - this._selectedDocs.set(doc, ref); + this._selectedDocs.add(doc); this._lastSelectedRow = index; } else { this._selectedDocs.delete(doc); } } else { this._selectedDocs.clear(); - this._selectedDocs.set(doc, ref); + this._selectedDocs.add(doc); this._lastSelectedRow = index; } @@ -205,7 +278,6 @@ export class CollectionSchemaView extends CollectionSubView() { @action onExternalDrop = async (e: React.DragEvent): Promise => { - console.log('hello'); super.onExternalDrop( e, {}, @@ -222,7 +294,7 @@ export class CollectionSchemaView extends CollectionSubView() { startDrag = (e: React.PointerEvent, doc: Doc, ref: HTMLDivElement, index: number) => { if (!this._selectedDocs.has(doc)) { this._selectedDocs.clear(); - this._selectedDocs.set(doc, ref); + this._selectedDocs.add(doc); this._lastSelectedRow = index; SelectionManager.SelectSchemaViewDoc(doc); } @@ -230,14 +302,7 @@ export class CollectionSchemaView extends CollectionSubView() { this._selectedDocSortedArray = this.sortedSelectedDocs(); const dragData = new DragManager.DocumentDragData(this._selectedDocSortedArray, 'move'); dragData.moveDocument = this.props.moveDocument; - const dragItem: HTMLElement[] = Array.from(this._selectedDocs.values()); - // const dragDiv = document.createElement('div'); - // dragDiv.className = 'presItem-multiDrag'; - // dragDiv.innerText = 'Move ' + this._selectedDocs.size + ' row' + (this._selectedDocs.size > 1 ? 's' : ''); - // dragDiv.style.position = 'absolute'; - // dragDiv.style.top = e.clientY + 'px'; - // dragDiv.style.left = e.clientX - 50 + 'px'; - // dragItem.push(dragDiv); + const dragItem: HTMLElement[] = Array.from(this._selectedDocs.values()).map((doc: Doc) => this._rowEles.get(doc)); DragManager.StartDocumentDrag( dragItem.map(ele => ele), @@ -334,21 +399,27 @@ export class CollectionSchemaView extends CollectionSubView() { this._ref = ele; this.createDashEventsTarget(ele); }} - onPointerDown={() => this._selectedDocs.clear()} + onPointerDown={action(() => { + this._selectedDocs.clear(); + })} onDrop={this.onExternalDrop.bind(this)}>
- {this.columnKeys.map((key, index) => ( - - ))} + {this.columnKeys.map((key, index) => { + return ( + + ); + })}
{this.childDocs.map((doc: Doc, index: number) => ( @@ -361,11 +432,12 @@ export class CollectionSchemaView extends CollectionSubView() { columnKeys={this.columnKeys} columnWidths={this.displayColumnWidths} rowMenuWidth={this._rowMenuWidth} - selectedRows={this._selectedDocs} + selectedDocs={this._selectedDocs} selectRow={this.selectRow} startDrag={this.startDrag} dragging={this._isDragging} dropIndex={this.setDropIndex} + addRowRef={this.addRowRef} /> ))}
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx index bee76bb24..a6140bafd 100644 --- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx +++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx @@ -1,39 +1,124 @@ import React = require('react'); -import { computed } from 'mobx'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; -import { EditableView } from '../../EditableView'; +import { emptyFunction, setupMoveUpEvents } from '../../../../Utils'; import './CollectionSchemaView.scss'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; export interface SchemaColumnHeaderProps { columnKeys: string[]; columnWidths: number[]; columnIndex: number; + possibleKeys: string[]; changeColumnKey: (index: number, newKey: string) => boolean; - addColumn: (index: number) => void; + addColumn: (index: number, key: string) => void; removeColumn: (index: number) => void; resizeColumn: (e: any, index: number, left: boolean) => void; + dragColumn: (e: any, index: number) => boolean; } @observer export class SchemaColumnHeader extends React.Component { + @observable _menuVisible: boolean = false; + @observable _menuValue: string = ''; + @observable _menuOptions: string[] = []; + private _makeNewColumn = false; + @computed get fieldKey() { return this.props.columnKeys[this.props.columnIndex]; } + @computed get renderColumnMenu() { + return ( +
+ e.stopPropagation()} /> + {this._menuOptions.map(key => ( +
{ + e.stopPropagation(); + this.setKey(key); + }}> + {key} +
+ ))} +
{ + e.stopPropagation(); + this.setKey(this._menuValue); + }}> + + new field +
+
+ ); + } + + onSearchKeyDown = (e: React.KeyboardEvent) => { + switch (e.key) { + case 'Enter': + this.setKey(this._menuOptions.length > 0 ? this._menuOptions[0] : this._menuValue); + break; + case 'Escape': + this.toggleColumnMenu(); + break; + } + }; + + @action + setKey = (key: string) => { + if (this._makeNewColumn) { + this.props.addColumn(this.props.columnIndex, key); + } else { + this.props.changeColumnKey(this.props.columnIndex, key); + } + this.toggleColumnMenu(); + }; + + @action + updateKeySearch = (e: React.ChangeEvent) => { + this._menuValue = e.target.value; + this._menuOptions = this.props.possibleKeys.filter(value => value.toLowerCase().includes(this._menuValue.toLowerCase())); + }; + + @action + onPointerDown = (e: React.PointerEvent) => { + e.stopPropagation(); + + setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction); + }; + + @action + toggleColumnMenu = (newCol?: boolean) => { + this._makeNewColumn = false; + if (this._menuVisible) { + this._menuVisible = false; + } else { + this._menuVisible = true; + this._menuValue = this.fieldKey; + this._menuOptions = this.props.possibleKeys; + if (newCol) { + this._makeNewColumn = true; + } + } + }; + render() { return ( -
+
this.props.resizeColumn(e, this.props.columnIndex, true)}>
-
- this.props.changeColumnKey(this.props.columnIndex, newKey)} GetValue={() => this.fieldKey} contents={this.fieldKey} /> -
+
{this.fieldKey}
{ - this.props.addColumn(this.props.columnIndex + 1); + this.toggleColumnMenu(); + }}> + +
+
{ + this.toggleColumnMenu(true); }}>
@@ -47,6 +132,8 @@ export class SchemaColumnHeader extends React.Component
this.props.resizeColumn(e, this.props.columnIndex, false)}>
+ + {this._menuVisible && this.renderColumnMenu}
); } diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx index 66cc3a47a..bfce61952 100644 --- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx +++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx @@ -17,11 +17,12 @@ export interface SchemaRowBoxProps extends FieldViewProps { columnKeys: string[]; columnWidths: number[]; rowMenuWidth: number; - selectedRows: ObservableMap; + selectedDocs: ObservableSet; selectRow: (e: any, doc: Doc, ref: HTMLDivElement, index: number) => void; startDrag: (e: any, doc: Doc, ref: HTMLDivElement, index: number) => boolean; dragging: boolean; dropIndex: (index: number) => void; + addRowRef: (doc: Doc, ref: HTMLDivElement) => void; } @observer @@ -32,7 +33,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent() { private _ref: HTMLDivElement | null = null; - isSelected = () => this.props.selectedRows.has(this.props.Document); + isSelected = () => this.props.selectedDocs.has(this.props.Document); bounds = () => this._ref?.getBoundingClientRect(); @action @@ -58,7 +59,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent() { if (!this.props.dragging) return; let dragIsRow: boolean = true; DragManager.docsBeingDragged.forEach(doc => { - dragIsRow = this.props.selectedRows.has(doc); + dragIsRow = this.props.selectedDocs.has(doc); }); if (this._ref && dragIsRow) { const rect = this._ref.getBoundingClientRect(); @@ -93,7 +94,10 @@ export class SchemaRowBox extends ViewBoxBaseComponent() { onPointerDown={this.onRowPointerDown} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave} - ref={(row: HTMLDivElement | null) => (this._ref = row)}> + ref={(row: HTMLDivElement | null) => { + row && this.props.addRowRef(this.props.Document, row); + this._ref = row; + }}>
Date: Mon, 14 Nov 2022 10:22:29 -0500 Subject: added menu for creating new keys --- .../collectionSchema/CollectionSchemaView.scss | 2 + .../collectionSchema/CollectionSchemaView.tsx | 16 ++-- .../collectionSchema/SchemaColumnHeader.tsx | 103 +++++++++++++++++---- 3 files changed, 93 insertions(+), 28 deletions(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss index 0631cd21d..696bfd67c 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss @@ -50,6 +50,8 @@ width: inherit; position: absolute; top: 35px; + min-width: 200px; + padding: 10px; } } } diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 7516b95b8..0466ce343 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -79,26 +79,25 @@ export class CollectionSchemaView extends CollectionSubView() { @undoBatch @action - changeColumnKey = (index: number, newKey: string) => { + changeColumnKey = (index: number, newKey: string, defaultVal?: any) => { if (!this.documentKeys.includes(newKey)) { - this.addNewKey(newKey); + this.addNewKey(newKey, defaultVal); } let currKeys = this.columnKeys; currKeys[index] = newKey; this.layoutDoc.columnKeys = new List(currKeys); - return true; }; @undoBatch @action - addColumn = (index: number, key: string) => { + addColumn = (index: number, key: string, defaultVal?: any) => { if (!this.documentKeys.includes(key)) { - this.addNewKey(key); + this.addNewKey(key, defaultVal); } - const newColWidth = this._minColWidth; let currWidths = this.storedColumnWidths; + const newColWidth = this.props.PanelWidth() / (currWidths.length + 1); currWidths = currWidths.map(w => { const proportion = w / (this.props.PanelWidth() - this._rowMenuWidth); return proportion * (this.props.PanelWidth() - this._rowMenuWidth - newColWidth); @@ -112,8 +111,9 @@ export class CollectionSchemaView extends CollectionSubView() { }; @action - addNewKey = (key: string) => { - this.childDocs.forEach(doc => (doc[key] = key + ' default val')); + addNewKey = (key: string, defaultVal: any) => { + console.log(defaultVal); + this.childDocs.forEach(doc => (doc[key] = defaultVal)); }; @undoBatch diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx index a6140bafd..cdae79d0c 100644 --- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx +++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx @@ -4,14 +4,15 @@ import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import { emptyFunction, setupMoveUpEvents } from '../../../../Utils'; import './CollectionSchemaView.scss'; +import { ColumnType } from './CollectionSchemaView'; export interface SchemaColumnHeaderProps { columnKeys: string[]; columnWidths: number[]; columnIndex: number; possibleKeys: string[]; - changeColumnKey: (index: number, newKey: string) => boolean; - addColumn: (index: number, key: string) => void; + changeColumnKey: (index: number, newKey: string, defaultVal?: any) => void; + addColumn: (index: number, key: string, defaultVal?: any) => void; removeColumn: (index: number) => void; resizeColumn: (e: any, index: number, left: boolean) => void; dragColumn: (e: any, index: number) => boolean; @@ -20,6 +21,9 @@ export interface SchemaColumnHeaderProps { @observer export class SchemaColumnHeader extends React.Component { @observable _menuVisible: boolean = false; + @observable _makeNewField: boolean = false; + @observable _newFieldType: ColumnType = ColumnType.Number; + @observable _newFieldDefault: any = 0; @observable _menuValue: string = ''; @observable _menuOptions: string[] = []; private _makeNewColumn = false; @@ -28,26 +32,85 @@ export class SchemaColumnHeader extends React.Component return this.props.columnKeys[this.props.columnIndex]; } + @computed get fieldDefaultInput() { + switch (this._newFieldType) { + case ColumnType.Number: + return e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.value))} />; + case ColumnType.Boolean: + return e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.value))} />; + case ColumnType.String: + return e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.value))} />; + } + } + @computed get renderColumnMenu() { return (
e.stopPropagation()} /> - {this._menuOptions.map(key => ( -
{ - e.stopPropagation(); - this.setKey(key); - }}> - {key} + {this._makeNewField ? ( +
+ { + this._newFieldType = ColumnType.Number; + this._newFieldDefault = 0; + })} + />{' '} + math + { + this._newFieldType = ColumnType.Boolean; + this._newFieldDefault = false; + })} + />{' '} + boolean + { + this._newFieldType = ColumnType.String; + this._newFieldDefault = ''; + })} + />{' '} + string + {this.fieldDefaultInput} +
{ + this.setKey(this._menuValue, this._newFieldDefault); + this._makeNewField = false; + })}> + done +
- ))} -
{ - e.stopPropagation(); - this.setKey(this._menuValue); - }}> - + new field -
+ ) : ( +
+
{ + e.stopPropagation(); + this._makeNewField = true; + })}> + + new field +
+ {this._menuOptions.map(key => ( +
{ + e.stopPropagation(); + this.setKey(key); + }}> + {key} +
+ ))} +
+ )}
); } @@ -64,11 +127,11 @@ export class SchemaColumnHeader extends React.Component }; @action - setKey = (key: string) => { + setKey = (key: string, defaultVal?: any) => { if (this._makeNewColumn) { - this.props.addColumn(this.props.columnIndex, key); + this.props.addColumn(this.props.columnIndex, key, defaultVal); } else { - this.props.changeColumnKey(this.props.columnIndex, key); + this.props.changeColumnKey(this.props.columnIndex, key, defaultVal); } this.toggleColumnMenu(); }; -- cgit v1.2.3-70-g09d2 From a58e71a9eea2717151e1a8c73e27068b02256390 Mon Sep 17 00:00:00 2001 From: mehekj Date: Mon, 14 Nov 2022 11:19:48 -0500 Subject: cleanup --- .../collectionSchema/CollectionSchemaView.scss | 56 ++++++++++- .../collectionSchema/CollectionSchemaView.tsx | 2 +- .../collectionSchema/SchemaColumnHeader.tsx | 107 ++++++++++++--------- 3 files changed, 118 insertions(+), 47 deletions(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss index 696bfd67c..99f49eb0e 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss @@ -51,7 +51,61 @@ position: absolute; top: 35px; min-width: 200px; - padding: 10px; + display: flex; + flex-direction: column; + align-items: flex-start; + + .schema-key-search-input { + width: calc(100% - 20px); + margin: 10px; + } + + .schema-key-search-result { + cursor: pointer; + padding: 2px 10px; + width: 100%; + + &:hover { + background-color: $medium-gray; + } + } + + .schema-key-search, + .schema-new-key-options { + width: 100%; + display: flex; + flex-direction: column; + align-items: flex-start; + } + + .schema-key-list { + width: 100%; + max-height: 300px; + overflow-y: auto; + } + + .schema-key-type-option { + margin: 2px 10px; + + input { + margin-right: 5px; + } + } + + .schema-key-default-val { + margin: 5px 10px; + } + + .schema-column-menu-button { + cursor: pointer; + padding: 2px 5px; + background: $medium-blue; + border-radius: 9999px; + color: $white; + width: fit-content; + margin: 5px; + align-self: center; + } } } } diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 0466ce343..24008a21d 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -38,7 +38,7 @@ export class CollectionSchemaView extends CollectionSubView() { private _lastSelectedRow: number | undefined; private _selectedDocSortedArray: Doc[] = []; private _closestDropIndex: number = 0; - private _minColWidth: number = 120; + private _minColWidth: number = 150; @observable _rowMenuWidth: number = 100; @observable _selectedDocs: ObservableSet = new ObservableSet(); diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx index cdae79d0c..b9e25a473 100644 --- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx +++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx @@ -37,7 +37,12 @@ export class SchemaColumnHeader extends React.Component case ColumnType.Number: return e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.value))} />; case ColumnType.Boolean: - return e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.value))} />; + return ( + <> + e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.value))} /> + {this._newFieldDefault ? 'true' : 'false'} + + ); case ColumnType.String: return e.stopPropagation()} onChange={action(e => (this._newFieldDefault = e.target.value))} />; } @@ -46,44 +51,51 @@ export class SchemaColumnHeader extends React.Component @computed get renderColumnMenu() { return (
- e.stopPropagation()} /> + e.stopPropagation()} /> {this._makeNewField ? (
- { - this._newFieldType = ColumnType.Number; - this._newFieldDefault = 0; - })} - />{' '} - math - { - this._newFieldType = ColumnType.Boolean; - this._newFieldDefault = false; - })} - />{' '} - boolean - { - this._newFieldType = ColumnType.String; - this._newFieldDefault = ''; - })} - />{' '} - string - {this.fieldDefaultInput} +
+ { + this._newFieldType = ColumnType.Number; + this._newFieldDefault = 0; + })} + /> + number +
+
+ { + this._newFieldType = ColumnType.Boolean; + this._newFieldDefault = false; + })} + /> + boolean +
+
+ { + this._newFieldType = ColumnType.String; + this._newFieldDefault = ''; + })} + /> + string +
+
value: {this.fieldDefaultInput}
{ this.setKey(this._menuValue, this._newFieldDefault); this._makeNewField = false; @@ -94,21 +106,25 @@ export class SchemaColumnHeader extends React.Component ) : (
{ e.stopPropagation(); this._makeNewField = true; })}> + new field
- {this._menuOptions.map(key => ( -
{ - e.stopPropagation(); - this.setKey(key); - }}> - {key} -
- ))} +
+ {this._menuOptions.map(key => ( +
{ + e.stopPropagation(); + this.setKey(key); + }}> + {key} +
+ ))} +
)}
@@ -158,6 +174,7 @@ export class SchemaColumnHeader extends React.Component this._menuVisible = true; this._menuValue = this.fieldKey; this._menuOptions = this.props.possibleKeys; + this._makeNewField = false; if (newCol) { this._makeNewColumn = true; } -- cgit v1.2.3-70-g09d2 From b7d4f932d826d48aca4c7c058e05ceaea9c43057 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 17 Nov 2022 14:35:13 -0500 Subject: mostly changing strings to enums --- src/client/util/DictationManager.ts | 6 +- src/client/util/LinkFollower.ts | 4 +- src/client/views/LightboxView.tsx | 16 +- src/client/views/MainView.tsx | 28 +- .../views/PropertiesDocBacklinksSelector.tsx | 45 ++- src/client/views/PropertiesDocContextSelector.tsx | 6 +- src/client/views/PropertiesView.tsx | 4 +- .../views/collections/CollectionDockingView.tsx | 26 +- .../views/collections/CollectionNoteTakingView.tsx | 12 +- .../views/collections/CollectionPileView.tsx | 22 +- .../views/collections/CollectionStackingView.tsx | 4 +- .../views/collections/CollectionTimeView.tsx | 351 +++++++++------- src/client/views/collections/CollectionView.tsx | 11 +- src/client/views/collections/TabDocView.tsx | 34 +- src/client/views/collections/TreeView.tsx | 8 +- .../CollectionFreeFormLayoutEngines.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 23 +- .../CollectionMulticolumnView.tsx | 9 +- .../collectionSchema/CollectionSchemaCells.tsx | 447 +++++++++++---------- .../CollectionSchemaMovableRow.tsx | 3 +- .../collections/collectionSchema/SchemaTable.tsx | 6 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 4 +- src/client/views/nodes/DocumentView.tsx | 35 +- src/client/views/nodes/KeyValueBox.tsx | 5 +- src/client/views/nodes/KeyValuePair.tsx | 65 +-- src/client/views/nodes/LinkAnchorBox.tsx | 5 +- src/client/views/nodes/LinkDocPreview.tsx | 4 +- src/client/views/nodes/VideoBox.tsx | 3 +- src/client/views/nodes/button/FontIconBox.tsx | 3 +- .../views/nodes/formattedText/DashFieldView.tsx | 3 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 4 +- .../formattedText/ProsemirrorExampleTransfer.ts | 3 +- src/client/views/nodes/trails/PresBox.tsx | 13 +- src/mobile/MobileInterface.tsx | 2 +- 34 files changed, 668 insertions(+), 550 deletions(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts index 0a61f3478..203d4ad62 100644 --- a/src/client/util/DictationManager.ts +++ b/src/client/util/DictationManager.ts @@ -11,7 +11,7 @@ import { Utils } from '../../Utils'; import { Docs } from '../documents/Documents'; import { DocumentType } from '../documents/DocumentTypes'; import { DictationOverlay } from '../views/DictationOverlay'; -import { DocumentView } from '../views/nodes/DocumentView'; +import { DocumentView, OpenWhere, OpenWhereMod } from '../views/nodes/DocumentView'; import { SelectionManager } from './SelectionManager'; import { UndoManager } from './UndoManager'; @@ -328,7 +328,7 @@ export namespace DictationManager { { action: (target: DocumentView) => { const kvp = Docs.Create.KVPDocument(target.props.Document, { _width: 300, _height: 300 }); - target.props.addDocTab(kvp, 'add:right'); + target.props.addDocTab(kvp, OpenWhere.addRight); }, }, ], @@ -345,7 +345,7 @@ export namespace DictationManager { const proseMirrorState = `{"doc":{"type":"doc","content":[{"type":"ordered_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"type":"text","text":"${prompt}"}]}]}]}]},"selection":{"type":"text","anchor":${anchor},"head":${head}}}`; proto.data = new RichTextField(proseMirrorState); proto.backgroundColor = '#eeffff'; - target.props.addDocTab(newBox, 'add:right'); + target.props.addDocTab(newBox, OpenWhere.addRight); }, }, ], diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index 68716a207..a3eb7ed7a 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -4,7 +4,7 @@ import { BoolCast, Cast, DocCast, StrCast } from '../../fields/Types'; import { DocumentType } from '../documents/DocumentTypes'; import { DocumentDecorations } from '../views/DocumentDecorations'; import { LightboxView } from '../views/LightboxView'; -import { DocumentViewSharedProps, ViewAdjustment } from '../views/nodes/DocumentView'; +import { DocumentViewSharedProps, OpenWhere, ViewAdjustment } from '../views/nodes/DocumentView'; import { DocumentManager } from './DocumentManager'; import { LinkManager } from './LinkManager'; import { UndoManager } from './UndoManager'; @@ -32,7 +32,7 @@ export class LinkFollower { const createViewFunc = (doc: Doc, followLoc: string, finished?: Opt<() => void>) => { const createTabForTarget = (didFocus: boolean) => new Promise(res => { - const where = LightboxView.LightboxDoc ? 'inPlace' : StrCast(sourceDoc.followLinkLocation, followLoc); + const where = LightboxView.LightboxDoc ? OpenWhere.inPlace : (StrCast(sourceDoc.followLinkLocation, followLoc) as OpenWhere); docViewProps.addDocTab(doc, where); setTimeout(() => { const targDocView = DocumentManager.Instance.getFirstDocumentView(doc); // get first document view available within the lightbox if that's open, or anywhere otherwise. diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index 5660a34e9..1f58763d1 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -18,7 +18,7 @@ import { TabDocView } from './collections/TabDocView'; import { GestureOverlay } from './GestureOverlay'; import './LightboxView.scss'; import { MainView } from './MainView'; -import { DocumentView } from './nodes/DocumentView'; +import { DocumentView, OpenWhere, OpenWhereMod } from './nodes/DocumentView'; import { DefaultStyleProvider, wavyBorderPath } from './StyleProvider'; interface LightboxViewProps { @@ -141,11 +141,13 @@ export class LightboxView extends React.Component { this._docFilters = (f => (this._docFilters ? [this._docFilters.push(f) as any, this._docFilters][1] : [f]))(`cookies:${cookie}:provide`); } } - public static AddDocTab = (doc: Doc, location: string, layoutTemplate?: Doc, openInTabFunc?: any) => { - const inPlaceView = DocCast(doc.context) ? DocumentManager.Instance.getFirstDocumentView(DocCast(doc.context)) : undefined; - if (inPlaceView) { - inPlaceView.dataDoc[Doc.LayoutFieldKey(inPlaceView.rootDoc)] = new List([doc]); - return true; + public static AddDocTab = (doc: Doc, location: OpenWhere, layoutTemplate?: Doc, openInTabFunc?: any) => { + if (location !== OpenWhere.lightbox) { + const inPlaceView = DocCast(doc.context) ? DocumentManager.Instance.getFirstDocumentView(DocCast(doc.context)) : undefined; + if (inPlaceView) { + inPlaceView.dataDoc[Doc.LayoutFieldKey(inPlaceView.rootDoc)] = new List([doc]); + return true; + } } LightboxView.openInTabFunc = openInTabFunc; SelectionManager.DeselectAll(); @@ -360,7 +362,7 @@ export class LightboxView extends React.Component { title={'open in tab'} onClick={e => { e.stopPropagation(); - CollectionDockingView.AddSplit(LightboxView._docTarget || LightboxView._doc!, ''); + CollectionDockingView.AddSplit(LightboxView._docTarget || LightboxView._doc!, OpenWhereMod.none); //LightboxView.openInTabFunc(LightboxView._docTarget || LightboxView._doc!, "inPlace"); SelectionManager.DeselectAll(); LightboxView.SetLightboxDoc(undefined); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 392b4eeeb..c151aebcd 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -49,7 +49,7 @@ import { LinkMenu } from './linking/LinkMenu'; import './MainView.scss'; import { AudioBox } from './nodes/AudioBox'; import { DocumentLinksButton } from './nodes/DocumentLinksButton'; -import { DocumentView } from './nodes/DocumentView'; +import { DocumentView, OpenWhere, OpenWhereMod } from './nodes/DocumentView'; import { DashFieldViewMenu } from './nodes/formattedText/DashFieldView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import { RichTextMenu } from './nodes/formattedText/RichTextMenu'; @@ -538,7 +538,7 @@ export class MainView extends React.Component { @action createNewPresentation = () => { const pres = Doc.MakeCopy(Doc.UserDoc().emptyTrail as Doc, true); - CollectionDockingView.AddSplit(pres, 'right'); + CollectionDockingView.AddSplit(pres, OpenWhereMod.right); Doc.MyTrails && Doc.AddDocToList(Doc.MyTrails, 'data', pres); // Doc.MyTrails should be created in createDashboard Doc.ActivePresentation = pres; }; @@ -546,7 +546,7 @@ export class MainView extends React.Component { @action openPresentation = (pres: Doc) => { if (pres.type === DocumentType.PRES) { - CollectionDockingView.AddSplit(pres, 'right'); + CollectionDockingView.AddSplit(pres, OpenWhereMod.right); Doc.MyTrails && (Doc.ActivePresentation = pres); Doc.AddDocToList(Doc.MyTrails, 'data', pres); this.closeFlyout(); @@ -683,20 +683,20 @@ export class MainView extends React.Component { sidebarScreenToLocal = () => new Transform(0, -this.topOfSidebarDoc, 1); mainContainerXf = () => this.sidebarScreenToLocal().translate(-this.leftScreenOffsetOfMainDocView, 0); - addDocTabFunc = (doc: Doc, location: string): boolean => { - const locationFields = doc._viewType === CollectionViewType.Docking ? ['dashboard'] : location.split(':'); - const locationParams = locationFields.length > 1 ? locationFields[1] : ''; + addDocTabFunc = (doc: Doc, location: OpenWhere): boolean => { + const whereFields = doc._viewType === CollectionViewType.Docking ? [OpenWhere.dashboard] : location.split(':'); + const whereMods = whereFields.length > 1 ? whereFields[1] : ''; if (doc.dockingConfig) return DashboardView.openDashboard(doc); // prettier-ignore - switch (locationFields[0]) { + switch (whereFields[0]) { default: - case 'inPlace': - case 'lightbox': return LightboxView.AddDocTab(doc, location); - case 'add': return CollectionDockingView.AddSplit(doc, locationParams); - case 'dashboard': return DashboardView.openDashboard(doc); - case 'close': return CollectionDockingView.CloseSplit(doc, locationParams); - case 'fullScreen': return CollectionDockingView.OpenFullScreen(doc); - case 'toggle': return CollectionDockingView.ToggleSplit(doc, locationParams); + case OpenWhere.inPlace: + case OpenWhere.lightbox: return LightboxView.AddDocTab(doc, location); + case OpenWhere.add: return CollectionDockingView.AddSplit(doc, whereMods as OpenWhereMod); + case OpenWhere.dashboard: return DashboardView.openDashboard(doc); + case OpenWhere.close: return CollectionDockingView.CloseSplit(doc, whereMods); + case OpenWhere.fullScreen: return CollectionDockingView.OpenFullScreen(doc); + case OpenWhere.toggle: return CollectionDockingView.ToggleSplit(doc, whereMods as OpenWhereMod); } }; diff --git a/src/client/views/PropertiesDocBacklinksSelector.tsx b/src/client/views/PropertiesDocBacklinksSelector.tsx index 4ead8eaf0..25ac44078 100644 --- a/src/client/views/PropertiesDocBacklinksSelector.tsx +++ b/src/client/views/PropertiesDocBacklinksSelector.tsx @@ -1,20 +1,21 @@ -import { computed } from "mobx"; -import { observer } from "mobx-react"; -import * as React from "react"; -import { Doc, DocListCast } from "../../fields/Doc"; -import { Cast } from "../../fields/Types"; -import { emptyFunction } from "../../Utils"; -import { DocumentType } from "../documents/DocumentTypes"; -import { LinkManager } from "../util/LinkManager"; -import { SelectionManager } from "../util/SelectionManager"; -import { LinkMenu } from "./linking/LinkMenu"; +import { computed } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; +import { Doc, DocListCast } from '../../fields/Doc'; +import { Cast } from '../../fields/Types'; +import { emptyFunction } from '../../Utils'; +import { DocumentType } from '../documents/DocumentTypes'; +import { LinkManager } from '../util/LinkManager'; +import { SelectionManager } from '../util/SelectionManager'; +import { LinkMenu } from './linking/LinkMenu'; +import { OpenWhere, OpenWhereMod } from './nodes/DocumentView'; import './PropertiesDocBacklinksSelector.scss'; type PropertiesDocBacklinksSelectorProps = { - Document: Doc, - Stack?: any, - hideTitle?: boolean, - addDocTab(doc: Doc, location: string): void + Document: Doc; + Stack?: any; + hideTitle?: boolean; + addDocTab(doc: Doc, location: OpenWhere): void; }; @observer @@ -40,14 +41,16 @@ export class PropertiesDocBacklinksSelector extends React.Component - {this.props.hideTitle ? (null) :

Contexts:

} - -
; + return !SelectionManager.Views().length ? null : ( +
+ {this.props.hideTitle ? null :

Contexts:

} + +
+ ); } -} \ No newline at end of file +} diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx index 9d89ee036..2c7da5931 100644 --- a/src/client/views/PropertiesDocContextSelector.tsx +++ b/src/client/views/PropertiesDocContextSelector.tsx @@ -7,14 +7,14 @@ import { Cast, NumCast, StrCast } from '../../fields/Types'; import { CollectionViewType } from '../documents/DocumentTypes'; import { DocFocusOrOpen } from '../util/DocumentManager'; import { CollectionDockingView } from './collections/CollectionDockingView'; -import { DocumentView } from './nodes/DocumentView'; +import { DocumentView, OpenWhere, OpenWhereMod } from './nodes/DocumentView'; import './PropertiesDocContextSelector.scss'; type PropertiesDocContextSelectorProps = { DocView?: DocumentView; Stack?: any; hideTitle?: boolean; - addDocTab(doc: Doc, location: string): void; + addDocTab(doc: Doc, location: OpenWhere): void; }; @observer @@ -53,7 +53,7 @@ export class PropertiesDocContextSelector extends React.Component DocFocusOrOpen(Doc.GetProto(this.props.DocView!.props.Document), col), 100); }; diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index e5ff9e267..93a3fd253 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -24,7 +24,7 @@ import { Transform } from '../util/Transform'; import { undoBatch, UndoManager } from '../util/UndoManager'; import { EditableView } from './EditableView'; import { InkStrokeProperties } from './InkStrokeProperties'; -import { DocumentView, StyleProviderFunc } from './nodes/DocumentView'; +import { DocumentView, OpenWhere, StyleProviderFunc } from './nodes/DocumentView'; import { FilterBox } from './nodes/FilterBox'; import { KeyValueBox } from './nodes/KeyValueBox'; import { PresBox } from './nodes/trails'; @@ -42,7 +42,7 @@ interface PropertiesViewProps { width: number; height: number; styleProvider?: StyleProviderFunc; - addDocTab: (doc: Doc, where: string) => boolean; + addDocTab: (doc: Doc, where: OpenWhere) => boolean; } @observer diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 434466505..8cbe548c7 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -25,6 +25,7 @@ import { CollectionFreeFormView } from './collectionFreeForm'; import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; import { TabDocView } from './TabDocView'; import React = require('react'); +import { OpenWhere, OpenWhereMod } from '../nodes/DocumentView'; const _global = (window /* browser */ || global) /* node */ as any; @observer @@ -142,7 +143,7 @@ export class CollectionDockingView extends CollectionSubView() { @undoBatch @action - public static ReplaceTab(document: Doc, panelName: string, stack: any, addToSplit?: boolean): boolean { + public static ReplaceTab(document: Doc, panelName: OpenWhereMod, stack: any, addToSplit?: boolean): boolean { const instance = CollectionDockingView.Instance; if (!instance) return false; const newConfig = CollectionDockingView.makeDocumentConfig(document, panelName); @@ -164,7 +165,7 @@ export class CollectionDockingView extends CollectionSubView() { } @undoBatch - public static ToggleSplit(doc: Doc, location: string, stack?: any, panelName?: string) { + public static ToggleSplit(doc: Doc, location: OpenWhereMod, stack?: any, panelName?: string) { return CollectionDockingView.Instance && Array.from(CollectionDockingView.Instance.tabMap.keys()).findIndex(tab => tab.DashDoc === doc) !== -1 ? CollectionDockingView.CloseSplit(doc) : CollectionDockingView.AddSplit(doc, location, stack, panelName); @@ -175,7 +176,7 @@ export class CollectionDockingView extends CollectionSubView() { // @undoBatch @action - public static AddSplit(document: Doc, pullSide: string, stack?: any, panelName?: string) { + public static AddSplit(document: Doc, pullSide: OpenWhereMod, stack?: any, panelName?: string) { if (document?._viewType === CollectionViewType.Docking) return DashboardView.openDashboard(document); if (!CollectionDockingView.Instance) return false; const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === document); @@ -208,14 +209,15 @@ export class CollectionDockingView extends CollectionSubView() { // if row switch (pullSide) { default: - case 'right': + case OpenWhereMod.none: + case OpenWhereMod.right: glayRoot.contentItems[0].addChild(newContentItem()); break; - case 'left': + case OpenWhereMod.left: glayRoot.contentItems[0].addChild(newContentItem(), 0); break; - case 'top': - case 'bottom': + case OpenWhereMod.top: + case OpenWhereMod.bottom: // if not going in a row layout, must add already existing content into column const rowlayout = glayRoot.contentItems[0]; const newColumn = rowlayout.layoutManager.createContentItem({ type: 'column' }, instance._goldenLayout); @@ -496,7 +498,7 @@ export class CollectionDockingView extends CollectionSubView() { title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`, }); this.props.Document.isShared && inheritParentAcls(this.props.Document, docToAdd); - CollectionDockingView.AddSplit(docToAdd, '', stack); + CollectionDockingView.AddSplit(docToAdd, OpenWhereMod.none, stack); } }); @@ -539,7 +541,7 @@ export class CollectionDockingView extends CollectionSubView() { title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`, }); this.props.Document.isShared && inheritParentAcls(this.props.Document, docToAdd); - CollectionDockingView.AddSplit(docToAdd, '', stack); + CollectionDockingView.AddSplit(docToAdd, OpenWhereMod.none, stack); } }) ); @@ -568,14 +570,14 @@ export class CollectionDockingView extends CollectionSubView() { ScriptingGlobals.add( function openInLightbox(doc: any) { - LightboxView.AddDocTab(doc, 'lightbox'); + LightboxView.AddDocTab(doc, OpenWhere.lightbox); }, 'opens up document in a lightbox', '(doc: any)' ); ScriptingGlobals.add( function openOnRight(doc: any) { - return CollectionDockingView.AddSplit(doc, 'right'); + return CollectionDockingView.AddSplit(doc, OpenWhereMod.right); }, 'opens up document in tab on right side of the screen', '(doc: any)' @@ -588,5 +590,5 @@ ScriptingGlobals.add( '(doc: any)' ); ScriptingGlobals.add(function useRightSplit(doc: any, shiftKey?: boolean) { - CollectionDockingView.ReplaceTab(doc, 'right', undefined, shiftKey); + CollectionDockingView.ReplaceTab(doc, OpenWhereMod.right, undefined, shiftKey); }); diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index b0f64ed60..29670a1a7 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -19,7 +19,7 @@ import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { LightboxView } from '../LightboxView'; -import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment } from '../nodes/DocumentView'; +import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, ViewAdjustment } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { StyleProp } from '../StyleProvider'; @@ -180,14 +180,6 @@ export class CollectionNoteTakingView extends CollectionSubView() { return () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); } - addDocTab = (doc: Doc, where: string) => { - if (where === 'inPlace' && this.layoutDoc.isInPlaceContainer) { - this.dataDoc[this.props.fieldKey] = new List([doc]); - return true; - } - return this.props.addDocTab(doc, where); - }; - scrollToBottom = () => { smoothScroll(500, this._mainCont!, this._mainCont!.scrollHeight); }; @@ -274,7 +266,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { removeDocument={this.props.removeDocument} contentPointerEvents={StrCast(this.layoutDoc.contentPointerEvents)} whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged} - addDocTab={this.addDocTab} + addDocTab={this.props.addDocTab} bringToFront={returnFalse} scriptContext={this.props.scriptContext} pinToPres={this.props.pinToPres} diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index 38e240ac6..e95622630 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -12,6 +12,8 @@ import './CollectionPileView.scss'; import { CollectionSubView } from './CollectionSubView'; import React = require('react'); import { ScriptField } from '../../../fields/ScriptField'; +import { OpenWhere } from '../nodes/DocumentView'; +import { computePassLayout, computeStarburstLayout } from './collectionFreeForm'; @observer export class CollectionPileView extends CollectionSubView() { @@ -19,8 +21,8 @@ export class CollectionPileView extends CollectionSubView() { _disposers: { [name: string]: IReactionDisposer } = {}; componentDidMount() { - if (this.layoutEngine() !== 'pass' && this.layoutEngine() !== 'starburst') { - this.Document._pileLayoutEngine = 'pass'; + if (this.layoutEngine() !== computePassLayout.name && this.layoutEngine() !== computeStarburstLayout.name) { + this.Document._pileLayoutEngine = computePassLayout.name; } this._originalChrome = this.layoutDoc._chromeHidden; this.layoutDoc._chromeHidden = true; @@ -56,7 +58,7 @@ export class CollectionPileView extends CollectionSubView() { // returns the contents of the pileup in a CollectionFreeFormView @computed get contents() { - const isStarburst = this.layoutEngine() === 'starburst'; + const isStarburst = this.layoutEngine() === computeStarburstLayout.name; return (
{ - if (this.layoutEngine() === 'starburst') { + if (this.layoutEngine() === computeStarburstLayout.name) { const defaultSize = 110; this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[WidthSym]() / 2 - NumCast(this.layoutDoc._starburstPileWidth, defaultSize) / 2; this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[HeightSym]() / 2 - NumCast(this.layoutDoc._starburstPileHeight, defaultSize) / 2; @@ -83,12 +85,12 @@ export class CollectionPileView extends CollectionSubView() { DocUtils.pileup(this.childDocs, undefined, undefined, NumCast(this.layoutDoc._width) / 2, false); this.layoutDoc._panX = 0; this.layoutDoc._panY = -10; - this.props.Document._pileLayoutEngine = 'pass'; + this.props.Document._pileLayoutEngine = computePassLayout.name; } else { const defaultSize = 25; !this.layoutDoc._starburstRadius && (this.layoutDoc._starburstRadius = 250); !this.layoutDoc._starburstDocScale && (this.layoutDoc._starburstDocScale = 2.5); - if (this.layoutEngine() === 'pass') { + if (this.layoutEngine() === computePassLayout.name) { this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[WidthSym]() / 2 - defaultSize / 2; this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[HeightSym]() / 2 - defaultSize / 2; this.layoutDoc._starburstPileWidth = this.layoutDoc[WidthSym](); @@ -96,7 +98,7 @@ export class CollectionPileView extends CollectionSubView() { } this.layoutDoc._panX = this.layoutDoc._panY = 0; this.layoutDoc._width = this.layoutDoc._height = defaultSize; - this.props.Document._pileLayoutEngine = 'starburst'; + this.props.Document._pileLayoutEngine = computeStarburstLayout.name; } }); @@ -118,7 +120,7 @@ export class CollectionPileView extends CollectionSubView() { const doc = this.childDocs[0]; doc.x = e.clientX; doc.y = e.clientY; - this.props.addDocTab(doc, 'inParent') && (this.props.removeDocument?.(doc) || false); + this.props.addDocTab(doc, OpenWhere.inParent) && (this.props.removeDocument?.(doc) || false); dist = 0; } } @@ -130,8 +132,8 @@ export class CollectionPileView extends CollectionSubView() { SnappingManager.SetIsDragging(false); }, emptyFunction, - e.shiftKey && this.layoutEngine() === 'pass', - this.layoutEngine() === 'pass' && e.shiftKey + e.shiftKey && this.layoutEngine() === computePassLayout.name, + this.layoutEngine() === computePassLayout.name && e.shiftKey ); // this sets _doubleTap }; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 175051d5c..aa4583af6 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -22,7 +22,7 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { EditableView } from '../EditableView'; import { LightboxView } from '../LightboxView'; import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView'; -import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment } from '../nodes/DocumentView'; +import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, ViewAdjustment } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { StyleProp } from '../StyleProvider'; @@ -241,7 +241,7 @@ export class CollectionStackingView extends CollectionSubView this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); } - addDocTab = (doc: Doc, where: string) => { + addDocTab = (doc: Doc, where: OpenWhere) => { if (where === 'inPlace' && this.layoutDoc.isInPlaceContainer) { this.dataDoc[this.props.fieldKey] = new List([doc]); return true; diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 3dd9d2d84..ac896a8fd 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -1,32 +1,32 @@ -import { toUpper } from "lodash"; -import { action, computed, observable, runInAction } from "mobx"; -import { observer } from "mobx-react"; -import { Doc, Opt, StrListCast } from "../../../fields/Doc"; -import { List } from "../../../fields/List"; -import { ObjectField } from "../../../fields/ObjectField"; -import { RichTextField } from "../../../fields/RichTextField"; -import { listSpec } from "../../../fields/Schema"; -import { ComputedField, ScriptField } from "../../../fields/ScriptField"; -import { Cast, NumCast, StrCast } from "../../../fields/Types"; -import { emptyFunction, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents } from "../../../Utils"; -import { Docs } from "../../documents/Documents"; -import { DocumentType } from "../../documents/DocumentTypes"; -import { DocumentManager } from "../../util/DocumentManager"; -import { ScriptingGlobals } from "../../util/ScriptingGlobals"; -import { ContextMenu } from "../ContextMenu"; -import { ContextMenuProps } from "../ContextMenuItem"; -import { EditableView } from "../EditableView"; -import { ViewSpecPrefix } from "../nodes/DocumentView"; -import { ViewDefBounds } from "./collectionFreeForm/CollectionFreeFormLayoutEngines"; -import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; -import { CollectionSubView } from "./CollectionSubView"; -import "./CollectionTimeView.scss"; -import React = require("react"); +import { toUpper } from 'lodash'; +import { action, computed, observable, runInAction } from 'mobx'; +import { observer } from 'mobx-react'; +import { Doc, Opt, StrListCast } from '../../../fields/Doc'; +import { List } from '../../../fields/List'; +import { ObjectField } from '../../../fields/ObjectField'; +import { RichTextField } from '../../../fields/RichTextField'; +import { listSpec } from '../../../fields/Schema'; +import { ComputedField, ScriptField } from '../../../fields/ScriptField'; +import { Cast, NumCast, StrCast } from '../../../fields/Types'; +import { emptyFunction, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents } from '../../../Utils'; +import { Docs } from '../../documents/Documents'; +import { DocumentType } from '../../documents/DocumentTypes'; +import { DocumentManager } from '../../util/DocumentManager'; +import { ScriptingGlobals } from '../../util/ScriptingGlobals'; +import { ContextMenu } from '../ContextMenu'; +import { ContextMenuProps } from '../ContextMenuItem'; +import { EditableView } from '../EditableView'; +import { ViewSpecPrefix } from '../nodes/DocumentView'; +import { computePivotLayout, computeTimelineLayout, ViewDefBounds } from './collectionFreeForm/CollectionFreeFormLayoutEngines'; +import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; +import { CollectionSubView } from './CollectionSubView'; +import './CollectionTimeView.scss'; +import React = require('react'); @observer export class CollectionTimeView extends CollectionSubView() { _changing = false; - @observable _layoutEngine = "pivot"; + @observable _layoutEngine = computePivotLayout.name; @observable _collapsed: boolean = false; @observable _childClickedScript: Opt; @observable _viewDefDivClick: Opt; @@ -35,7 +35,7 @@ export class CollectionTimeView extends CollectionSubView() { getAnchor = () => { const anchor = Docs.Create.HTMLAnchorDocument([], { title: ComputedField.MakeFunction(`"${this.pivotField}"])`) as any, - annotationOn: this.rootDoc + annotationOn: this.rootDoc, }); // save view spec information for anchor @@ -43,81 +43,103 @@ export class CollectionTimeView extends CollectionSubView() { proto.pivotField = this.pivotField; proto.docFilters = ObjectField.MakeCopy(this.layoutDoc._docFilters as ObjectField) || new List([]); proto.docRangeFilters = ObjectField.MakeCopy(this.layoutDoc._docRangeFilters as ObjectField) || new List([]); - proto[ViewSpecPrefix + "_viewType"] = this.layoutDoc._viewType; + proto[ViewSpecPrefix + '_viewType'] = this.layoutDoc._viewType; // store anchor in annotations list of document (not technically needed since these anchors are never drawn) - if (Cast(this.dataDoc[this.props.fieldKey + "-annotations"], listSpec(Doc), null) !== undefined) { - Cast(this.dataDoc[this.props.fieldKey + "-annotations"], listSpec(Doc), []).push(anchor); + if (Cast(this.dataDoc[this.props.fieldKey + '-annotations'], listSpec(Doc), null) !== undefined) { + Cast(this.dataDoc[this.props.fieldKey + '-annotations'], listSpec(Doc), []).push(anchor); } else { - this.dataDoc[this.props.fieldKey + "-annotations"] = new List([anchor]); + this.dataDoc[this.props.fieldKey + '-annotations'] = new List([anchor]); } return anchor; - } + }; async componentDidMount() { this.props.setContentView?.(this); //const detailView = (await DocCastAsync(this.props.Document.childClickedOpenTemplateView)) || DocUtils.findTemplate("detailView", StrCast(this.rootDoc.type), ""); ///const childText = "const alias = getAlias(self); switchView(alias, detailView); alias.dropAction='alias'; alias.removeDropProperties=new List(['dropAction']); useRightSplit(alias, shiftKey); "; runInAction(() => { - this._childClickedScript = ScriptField.MakeScript("openInLightbox(self)", { this: Doc.name }); - this._viewDefDivClick = ScriptField.MakeScript("pivotColumnClick(this,payload)", { payload: "any" }); + this._childClickedScript = ScriptField.MakeScript('openInLightbox(self)', { this: Doc.name }); + this._viewDefDivClick = ScriptField.MakeScript('pivotColumnClick(this,payload)', { payload: 'any' }); }); } - get pivotField() { return this._focusPivotField || StrCast(this.layoutDoc._pivotField); } + get pivotField() { + return this._focusPivotField || StrCast(this.layoutDoc._pivotField); + } @action setViewSpec = (anchor: Doc, preview: boolean) => { - if (preview) { // if in preview, then override document's fields with view spec + if (preview) { + // if in preview, then override document's fields with view spec this._focusFilters = StrListCast(Doc.GetProto(anchor).docFilters); this._focusRangeFilters = StrListCast(Doc.GetProto(anchor).docRangeFilters); this._focusPivotField = StrCast(anchor.pivotField); - } else if (anchor.pivotField !== undefined) { // otherwise set document's fields based on anchor view spec + } else if (anchor.pivotField !== undefined) { + // otherwise set document's fields based on anchor view spec this.layoutDoc._prevFilterIndex = 1; this.layoutDoc._pivotField = StrCast(anchor.pivotField); this.layoutDoc._docFilters = new List(StrListCast(anchor.docFilters)); this.layoutDoc._docRangeFilters = new List(StrListCast(anchor.docRangeFilters)); } return 0; - } + }; layoutEngine = () => this._layoutEngine; - toggleVisibility = action(() => this._collapsed = !this._collapsed); + toggleVisibility = action(() => (this._collapsed = !this._collapsed)); onMinDown = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => { - const minReq = NumCast(this.props.Document[this.props.fieldKey + "-timelineMinReq"], NumCast(this.props.Document[this.props.fieldKey + "-timelineMin"], 0)); - const maxReq = NumCast(this.props.Document[this.props.fieldKey + "-timelineMaxReq"], NumCast(this.props.Document[this.props.fieldKey + "-timelineMax"], 10)); - this.props.Document[this.props.fieldKey + "-timelineMinReq"] = minReq + (maxReq - minReq) * delta[0] / this.props.PanelWidth(); - this.props.Document[this.props.fieldKey + "-timelineSpan"] = undefined; - return false; - }), returnFalse, emptyFunction); - } + setupMoveUpEvents( + this, + e, + action((e: PointerEvent, down: number[], delta: number[]) => { + const minReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMinReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMin'], 0)); + const maxReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMaxReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMax'], 10)); + this.props.Document[this.props.fieldKey + '-timelineMinReq'] = minReq + ((maxReq - minReq) * delta[0]) / this.props.PanelWidth(); + this.props.Document[this.props.fieldKey + '-timelineSpan'] = undefined; + return false; + }), + returnFalse, + emptyFunction + ); + }; onMaxDown = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => { - const minReq = NumCast(this.props.Document[this.props.fieldKey + "-timelineMinReq"], NumCast(this.props.Document[this.props.fieldKey + "-timelineMin"], 0)); - const maxReq = NumCast(this.props.Document[this.props.fieldKey + "-timelineMaxReq"], NumCast(this.props.Document[this.props.fieldKey + "-timelineMax"], 10)); - this.props.Document[this.props.fieldKey + "-timelineMaxReq"] = maxReq + (maxReq - minReq) * delta[0] / this.props.PanelWidth(); - return false; - }), returnFalse, emptyFunction); - } + setupMoveUpEvents( + this, + e, + action((e: PointerEvent, down: number[], delta: number[]) => { + const minReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMinReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMin'], 0)); + const maxReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMaxReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMax'], 10)); + this.props.Document[this.props.fieldKey + '-timelineMaxReq'] = maxReq + ((maxReq - minReq) * delta[0]) / this.props.PanelWidth(); + return false; + }), + returnFalse, + emptyFunction + ); + }; onMidDown = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => { - const minReq = NumCast(this.props.Document[this.props.fieldKey + "-timelineMinReq"], NumCast(this.props.Document[this.props.fieldKey + "-timelineMin"], 0)); - const maxReq = NumCast(this.props.Document[this.props.fieldKey + "-timelineMaxReq"], NumCast(this.props.Document[this.props.fieldKey + "-timelineMax"], 10)); - this.props.Document[this.props.fieldKey + "-timelineMinReq"] = minReq - (maxReq - minReq) * delta[0] / this.props.PanelWidth(); - this.props.Document[this.props.fieldKey + "-timelineMaxReq"] = maxReq - (maxReq - minReq) * delta[0] / this.props.PanelWidth(); - return false; - }), returnFalse, emptyFunction); - } + setupMoveUpEvents( + this, + e, + action((e: PointerEvent, down: number[], delta: number[]) => { + const minReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMinReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMin'], 0)); + const maxReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMaxReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMax'], 10)); + this.props.Document[this.props.fieldKey + '-timelineMinReq'] = minReq - ((maxReq - minReq) * delta[0]) / this.props.PanelWidth(); + this.props.Document[this.props.fieldKey + '-timelineMaxReq'] = maxReq - ((maxReq - minReq) * delta[0]) / this.props.PanelWidth(); + return false; + }), + returnFalse, + emptyFunction + ); + }; goTo = (prevFilterIndex: number) => { - this.layoutDoc._pivotField = this.layoutDoc["_prevPivotFields" + prevFilterIndex]; - this.layoutDoc._docFilters = ObjectField.MakeCopy(this.layoutDoc["_prevDocFilter" + prevFilterIndex] as ObjectField); - this.layoutDoc._docRangeFilters = ObjectField.MakeCopy(this.layoutDoc["_prevDocRangeFilters" + prevFilterIndex] as ObjectField); + this.layoutDoc._pivotField = this.layoutDoc['_prevPivotFields' + prevFilterIndex]; + this.layoutDoc._docFilters = ObjectField.MakeCopy(this.layoutDoc['_prevDocFilter' + prevFilterIndex] as ObjectField); + this.layoutDoc._docRangeFilters = ObjectField.MakeCopy(this.layoutDoc['_prevDocRangeFilters' + prevFilterIndex] as ObjectField); this.layoutDoc._prevFilterIndex = prevFilterIndex; - } + }; @action contentsDown = (e: React.MouseEvent) => { @@ -127,37 +149,58 @@ export class CollectionTimeView extends CollectionSubView() { } else { this.layoutDoc._docFilters = new List([]); } - } + }; dontScaleFilter = (doc: Doc) => doc.type === DocumentType.RTF; @computed get contents() { - return
- -
; + return ( +
+ +
+ ); } public static SyncTimelineToPresentation(doc: Doc) { const fieldKey = Doc.LayoutFieldKey(doc); - doc[fieldKey + "-timelineCur"] = ComputedField.MakeFunction("(activePresentationItem()[this._pivotField || 'year'] || 0)"); + doc[fieldKey + '-timelineCur'] = ComputedField.MakeFunction("(activePresentationItem()[this._pivotField || 'year'] || 0)"); } specificMenu = (e: React.MouseEvent) => { const layoutItems: ContextMenuProps[] = []; const doc = this.layoutDoc; - layoutItems.push({ description: "Force Timeline", event: () => { doc._forceRenderEngine = "timeline"; }, icon: "compress-arrows-alt" }); - layoutItems.push({ description: "Force Pivot", event: () => { doc._forceRenderEngine = "pivot"; }, icon: "compress-arrows-alt" }); - layoutItems.push({ description: "Auto Time/Pivot layout", event: () => { doc._forceRenderEngine = undefined; }, icon: "compress-arrows-alt" }); - layoutItems.push({ description: "Sync with presentation", event: () => CollectionTimeView.SyncTimelineToPresentation(doc), icon: "compress-arrows-alt" }); + layoutItems.push({ + description: 'Force Timeline', + event: () => { + doc._forceRenderEngine = computeTimelineLayout.name; + }, + icon: 'compress-arrows-alt', + }); + layoutItems.push({ + description: 'Force Pivot', + event: () => { + doc._forceRenderEngine = computePivotLayout.name; + }, + icon: 'compress-arrows-alt', + }); + layoutItems.push({ + description: 'Auto Time/Pivot layout', + event: () => { + doc._forceRenderEngine = undefined; + }, + icon: 'compress-arrows-alt', + }); + layoutItems.push({ description: 'Sync with presentation', event: () => CollectionTimeView.SyncTimelineToPresentation(doc), icon: 'compress-arrows-alt' }); - ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "eye" }); - } + ContextMenu.Instance.addItem({ description: 'Options...', subitems: layoutItems, icon: 'eye' }); + }; @computed get _allFacets() { const facets = new Set(); this.childDocs.forEach(child => Object.keys(Doc.GetProto(child)).forEach(key => facets.add(key))); @@ -169,37 +212,40 @@ export class CollectionTimeView extends CollectionSubView() { const docItems: ContextMenuProps[] = []; const keySet: Set = new Set(); - this.childLayoutPairs.map(pair => this._allFacets.filter(fieldKey => - pair.layout[fieldKey] instanceof RichTextField || - typeof (pair.layout[fieldKey]) === "number" || - typeof (pair.layout[fieldKey]) === "boolean" || - typeof (pair.layout[fieldKey]) === "string").filter(fieldKey => fieldKey[0] !== "_" && (fieldKey[0] !== "#" || fieldKey === "#") && (fieldKey === "tags" || fieldKey[0] === toUpper(fieldKey)[0])).map(fieldKey => keySet.add(fieldKey))); - Array.from(keySet).map(fieldKey => - docItems.push({ description: ":" + fieldKey, event: () => this.layoutDoc._pivotField = fieldKey, icon: "compress-arrows-alt" })); - docItems.push({ description: ":default", event: () => this.layoutDoc._pivotField = undefined, icon: "compress-arrows-alt" }); - ContextMenu.Instance.addItem({ description: "Pivot Fields ...", subitems: docItems, icon: "eye" }); + this.childLayoutPairs.map(pair => + this._allFacets + .filter(fieldKey => pair.layout[fieldKey] instanceof RichTextField || typeof pair.layout[fieldKey] === 'number' || typeof pair.layout[fieldKey] === 'boolean' || typeof pair.layout[fieldKey] === 'string') + .filter(fieldKey => fieldKey[0] !== '_' && (fieldKey[0] !== '#' || fieldKey === '#') && (fieldKey === 'tags' || fieldKey[0] === toUpper(fieldKey)[0])) + .map(fieldKey => keySet.add(fieldKey)) + ); + Array.from(keySet).map(fieldKey => docItems.push({ description: ':' + fieldKey, event: () => (this.layoutDoc._pivotField = fieldKey), icon: 'compress-arrows-alt' })); + docItems.push({ description: ':default', event: () => (this.layoutDoc._pivotField = undefined), icon: 'compress-arrows-alt' }); + ContextMenu.Instance.addItem({ description: 'Pivot Fields ...', subitems: docItems, icon: 'eye' }); const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(x, y); - ContextMenu.Instance.displayMenu(x, y, ":"); - } + ContextMenu.Instance.displayMenu(x, y, ':'); + }; @computed get pivotKeyUI() { - return
- { - if (value?.length) { - this.layoutDoc._pivotField = value; - return true; - } - return false; - }} - toggle={this.toggleVisibility} - background={"#f1efeb"} // this.props.headingObject ? this.props.headingObject.color : "#f1efeb"; - contents={":" + StrCast(this.layoutDoc._pivotField)} - showMenuOnLoad={true} - display={"inline"} - menuCallback={this.menuCallback} /> -
; + return ( +
+ { + if (value?.length) { + this.layoutDoc._pivotField = value; + return true; + } + return false; + }} + toggle={this.toggleVisibility} + background={'#f1efeb'} // this.props.headingObject ? this.props.headingObject.color : "#f1efeb"; + contents={':' + StrCast(this.layoutDoc._pivotField)} + showMenuOnLoad={true} + display={'inline'} + menuCallback={this.menuCallback} + /> +
+ ); } render() { @@ -211,55 +257,62 @@ export class CollectionTimeView extends CollectionSubView() { } }); const forceLayout = StrCast(this.layoutDoc._forceRenderEngine); - const doTimeline = forceLayout ? (forceLayout === "timeline") : nonNumbers / this.childDocs.length < 0.1 && this.props.PanelWidth() / this.props.PanelHeight() > 6; - if (doTimeline !== (this._layoutEngine === "timeline")) { + const doTimeline = forceLayout ? forceLayout === computeTimelineLayout.name : nonNumbers / this.childDocs.length < 0.1 && this.props.PanelWidth() / this.props.PanelHeight() > 6; + if (doTimeline !== (this._layoutEngine === computeTimelineLayout.name)) { if (!this._changing) { this._changing = true; - setTimeout(action(() => { - this._layoutEngine = doTimeline ? "timeline" : "pivot"; - this._changing = false; - }), 0); + setTimeout( + action(() => { + this._layoutEngine = doTimeline ? computeTimelineLayout.name : computePivotLayout.name; + this._changing = false; + }), + 0 + ); } } - return
- {this.pivotKeyUI} - {this.contents} - {!this.props.isSelected() || !doTimeline ? (null) : <> -
-
-
- } -
; + return ( +
+ {this.pivotKeyUI} + {this.contents} + {!this.props.isSelected() || !doTimeline ? null : ( + <> +
+
+
+ + )} +
+ ); } } ScriptingGlobals.add(function pivotColumnClick(pivotDoc: Doc, bounds: ViewDefBounds) { - const pivotField = StrCast(pivotDoc._pivotField) || "author"; + const pivotField = StrCast(pivotDoc._pivotField) || 'author'; let prevFilterIndex = NumCast(pivotDoc._prevFilterIndex); const originalFilter = StrListCast(ObjectField.MakeCopy(pivotDoc._docFilters as ObjectField)); - pivotDoc["_prevDocFilter" + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docFilters as ObjectField); - pivotDoc["_prevDocRangeFilters" + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docRangeFilters as ObjectField); - pivotDoc["_prevPivotFields" + prevFilterIndex] = pivotField; + pivotDoc['_prevDocFilter' + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docFilters as ObjectField); + pivotDoc['_prevDocRangeFilters' + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docRangeFilters as ObjectField); + pivotDoc['_prevPivotFields' + prevFilterIndex] = pivotField; pivotDoc._prevFilterIndex = ++prevFilterIndex; pivotDoc._docFilters = new List(); - setTimeout(action(() => { - const filterVals = (bounds.payload as string[]); - filterVals.map(filterVal => Doc.setDocFilter(pivotDoc, pivotField, filterVal, "check")); - const pivotView = DocumentManager.Instance.getDocumentView(pivotDoc); - if (pivotDoc && pivotView?.ComponentView instanceof CollectionTimeView && filterVals.length === 1) { - if (pivotView?.ComponentView.childDocs.length && pivotView.ComponentView.childDocs[0][filterVals[0]]) { - pivotDoc._pivotField = filterVals[0]; + setTimeout( + action(() => { + const filterVals = bounds.payload as string[]; + filterVals.map(filterVal => Doc.setDocFilter(pivotDoc, pivotField, filterVal, 'check')); + const pivotView = DocumentManager.Instance.getDocumentView(pivotDoc); + if (pivotDoc && pivotView?.ComponentView instanceof CollectionTimeView && filterVals.length === 1) { + if (pivotView?.ComponentView.childDocs.length && pivotView.ComponentView.childDocs[0][filterVals[0]]) { + pivotDoc._pivotField = filterVals[0]; + } } - } - const newFilters = StrListCast(pivotDoc._docFilters); - if (newFilters.length && originalFilter.length && - newFilters.lastElement() === originalFilter.lastElement()) { - pivotDoc._prevFilterIndex = --prevFilterIndex; - pivotDoc["_prevDocFilter" + prevFilterIndex] = undefined; - pivotDoc["_prevDocRangeFilters" + prevFilterIndex] = undefined; - pivotDoc["_prevPivotFields" + prevFilterIndex] = undefined; - } - })); -}); \ No newline at end of file + const newFilters = StrListCast(pivotDoc._docFilters); + if (newFilters.length && originalFilter.length && newFilters.lastElement() === originalFilter.lastElement()) { + pivotDoc._prevFilterIndex = --prevFilterIndex; + pivotDoc['_prevDocFilter' + prevFilterIndex] = undefined; + pivotDoc['_prevDocRangeFilters' + prevFilterIndex] = undefined; + pivotDoc['_prevPivotFields' + prevFilterIndex] = undefined; + } + }) + ); +}); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 625d4e9e5..917d7618c 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -16,6 +16,7 @@ import { InteractionUtils } from '../../util/InteractionUtils'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; +import { OpenWhere, OpenWhereMod } from '../nodes/DocumentView'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import { CollectionCarousel3DView } from './CollectionCarousel3DView'; import { CollectionCarouselView } from './CollectionCarouselView'; @@ -174,7 +175,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent { const newRendition = Doc.MakeAlias(this.rootDoc); newRendition._viewType = vtype; - this.props.addDocTab(newRendition, 'add:right'); + this.props.addDocTab(newRendition, OpenWhere.addRight); return newRendition; }, false @@ -184,17 +185,17 @@ export class CollectionView extends ViewBoxAnnotatableComponent (this.rootDoc.forceActive = !this.rootDoc.forceActive), icon: 'project-diagram' }) : null; if (this.rootDoc.childLayout instanceof Doc) { - optionItems.push({ description: 'View Child Layout', event: () => this.props.addDocTab(this.rootDoc.childLayout as Doc, 'add:right'), icon: 'project-diagram' }); + optionItems.push({ description: 'View Child Layout', event: () => this.props.addDocTab(this.rootDoc.childLayout as Doc, OpenWhere.addRight), icon: 'project-diagram' }); } if (this.rootDoc.childClickedOpenTemplateView instanceof Doc) { - optionItems.push({ description: 'View Child Detailed Layout', event: () => this.props.addDocTab(this.rootDoc.childClickedOpenTemplateView as Doc, 'add:right'), icon: 'project-diagram' }); + optionItems.push({ description: 'View Child Detailed Layout', event: () => this.props.addDocTab(this.rootDoc.childClickedOpenTemplateView as Doc, OpenWhere.addRight), icon: 'project-diagram' }); } !Doc.noviceMode && optionItems.push({ description: `${this.rootDoc.isInPlaceContainer ? 'Unset' : 'Set'} inPlace Container`, event: () => (this.rootDoc.isInPlaceContainer = !this.rootDoc.isInPlaceContainer), icon: 'project-diagram' }); if (!Doc.noviceMode && false) { optionItems.push({ description: 'Create Branch', - event: async () => this.props.addDocTab(await BranchCreate(this.rootDoc), 'add:right'), + event: async () => this.props.addDocTab(await BranchCreate(this.rootDoc), OpenWhere.addRight), icon: 'project-diagram', }); optionItems.push({ @@ -225,7 +226,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent { const alias = Doc.MakeAlias(this.rootDoc); DocUtils.makeCustomViewClicked(alias, undefined, func.key); - this.props.addDocTab(alias, 'add:right'); + this.props.addDocTab(alias, OpenWhere.addRight); }, }) ); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index e21649648..2cc588b78 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -26,7 +26,7 @@ import { DashboardView } from '../DashboardView'; import { Colors, Shadows } from '../global/globalEnums'; import { LightboxView } from '../LightboxView'; import { MainView } from '../MainView'; -import { DocFocusOptions, DocumentView, DocumentViewProps } from '../nodes/DocumentView'; +import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, OpenWhereMod } from '../nodes/DocumentView'; import { DashFieldView } from '../nodes/formattedText/DashFieldView'; import { PinProps, PresBox, PresMovement } from '../nodes/trails'; import { DefaultStyleProvider, StyleProp } from '../StyleProvider'; @@ -296,7 +296,7 @@ export class TabDocView extends React.Component { ) { const docs = Cast(Doc.MyOverlayDocs.data, listSpec(Doc), []); if (docs.includes(curPres)) docs.splice(docs.indexOf(curPres), 1); - CollectionDockingView.AddSplit(curPres, 'right'); + CollectionDockingView.AddSplit(curPres, OpenWhereMod.right); setTimeout(() => DocumentManager.Instance.jumpToDocument(docList.lastElement(), false, undefined, []), 100); // keeps the pinned doc in view since the sidebar shifts things } setTimeout(batch.end, 500); // need to wait until dockingview (goldenlayout) updates all its structurs @@ -343,34 +343,30 @@ export class TabDocView extends React.Component { // "replace:right" - will replace the stack on the right named "right" if it exists, or create a stack on the right with that name, // "replace:monkeys" - will replace any tab that has the label 'monkeys', or a tab with that label will be created by default on the right // inPlace - will add the document to any collection along the path from the document to the docking view that has a field isInPlaceContainer. if none is found, inPlace adds a tab to current stack - addDocTab = (doc: Doc, location: string) => { + addDocTab = (doc: Doc, location: OpenWhere) => { SelectionManager.DeselectAll(); - const locationFields = doc._viewType === CollectionViewType.Docking ? ['dashboard'] : location.split(':'); - const locationParams = locationFields.length > 1 ? locationFields[1] : ''; + const locationFields = doc._viewType === CollectionViewType.Docking ? [OpenWhere.dashboard] : location.split(':'); + const locationParams: OpenWhereMod = locationFields.length > 1 ? (locationFields[1] as OpenWhereMod) : OpenWhereMod.none; switch (locationFields[0]) { - case 'dashboard': + case OpenWhere.dashboard: return DashboardView.openDashboard(doc); - case 'close': + case OpenWhere.close: return CollectionDockingView.CloseSplit(doc, locationParams); - case 'fullScreen': + case OpenWhere.fullScreen: return CollectionDockingView.OpenFullScreen(doc); - case 'replace': + case OpenWhere.replace: return CollectionDockingView.ReplaceTab(doc, locationParams, this.stack); - // case "lightbox": { - // // TabDocView.PinDoc(doc, { hidePresBox: true }); - // return LightboxView.AddDocTab(doc, location, undefined, this.addDocTab); - // } - case 'inPlace': + case OpenWhere.inPlace: const inPlaceView = DocCast(doc.context) ? DocumentManager.Instance.getFirstDocumentView(DocCast(doc.context)) : undefined; if (inPlaceView) { inPlaceView.dataDoc[Doc.LayoutFieldKey(inPlaceView.rootDoc)] = new List([doc]); return true; - } - case 'lightbox': + } // fall through to lightbox + case OpenWhere.lightbox: return LightboxView.AddDocTab(doc, location, undefined, this.addDocTab); - case 'toggle': + case OpenWhere.toggle: return CollectionDockingView.ToggleSplit(doc, locationParams, this.stack); - case 'add': + case OpenWhere.add: default: return CollectionDockingView.AddSplit(doc, locationParams, this.stack); } @@ -509,7 +505,7 @@ interface TabMinimapViewProps { document: Doc; hideMinimap: () => boolean; tabView: () => DocumentView | undefined; - addDocTab: (doc: Doc, where: string) => boolean; + addDocTab: (doc: Doc, where: OpenWhere) => boolean; PanelWidth: () => number; PanelHeight: () => number; background: () => string; diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 13cf64558..bd326f917 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -22,7 +22,7 @@ import { Transform } from '../../util/Transform'; import { undoBatch, UndoManager } from '../../util/UndoManager'; import { EditableView } from '../EditableView'; import { TREE_BULLET_WIDTH } from '../global/globalCssVariables.scss'; -import { DocumentView, DocumentViewInternal, DocumentViewProps, StyleProviderFunc } from '../nodes/DocumentView'; +import { DocumentView, DocumentViewInternal, DocumentViewProps, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { RichTextMenu } from '../nodes/formattedText/RichTextMenu'; @@ -44,7 +44,7 @@ export interface TreeViewProps { containerCollection: Doc; renderDepth: number; dropAction: dropActionType; - addDocTab: (doc: Doc, where: string) => boolean; + addDocTab: (doc: Doc, where: OpenWhere) => boolean; panelWidth: () => number; panelHeight: () => number; addDocument: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean; @@ -236,7 +236,7 @@ export class TreeView extends React.Component { const bestAlias = docView.props.Document.author === Doc.CurrentUserEmail && !Doc.IsPrototype(docView.props.Document) ? docView.props.Document : DocListCast(this.props.document.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail); const nextBestAlias = DocListCast(this.props.document.aliases).find(doc => doc.author === Doc.CurrentUserEmail); - this.props.addDocTab(bestAlias ?? nextBestAlias ?? Doc.MakeAlias(this.props.document), 'lightbox'); + this.props.addDocTab(bestAlias ?? nextBestAlias ?? Doc.MakeAlias(this.props.document), OpenWhere.lightbox); } }; @@ -1109,7 +1109,7 @@ export class TreeView extends React.Component { remove: undefined | ((doc: Doc | Doc[]) => boolean), move: DragManager.MoveFunction, dropAction: dropActionType, - addDocTab: (doc: Doc, where: string) => boolean, + addDocTab: (doc: Doc, where: OpenWhere) => boolean, styleProvider: undefined | StyleProviderFunc, screenToLocalXf: () => Transform, isContentActive: (outsideReaction?: boolean) => boolean, diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index 54be6ba0f..7dd9cdb8b 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -82,7 +82,7 @@ interface PivotColumn { filters: string[]; } -export function computerPassLayout(poolData: Map, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) { +export function computePassLayout(poolData: Map, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) { const docMap = new Map(); childPairs.forEach(({ layout, data }, i) => { docMap.set(layout[Id], { @@ -97,7 +97,7 @@ export function computerPassLayout(poolData: Map, pivotDoc: Do return normalizeResults(panelDim, 12, docMap, poolData, viewDefsToJSX, [], 0, []); } -export function computerStarburstLayout(poolData: Map, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) { +export function computeStarburstLayout(poolData: Map, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) { const mustFit = pivotDoc[WidthSym]() !== panelDim[0]; // if a panel size is set that's not the same as the pivot doc's size, then assume this is in a panel for a content fitting view (like a grid) in which case everything must be scaled to stay within the panel const docMap = new Map(); const docSize = mustFit ? panelDim[0] * 0.33 : 75; // assume an icon sized at 75 diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 57cccec4a..8cabf060d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -37,7 +37,7 @@ import { GestureOverlay } from '../../GestureOverlay'; import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, InkingStroke, SetActiveInkColor, SetActiveInkWidth } from '../../InkingStroke'; import { LightboxView } from '../../LightboxView'; import { CollectionFreeFormDocumentView } from '../../nodes/CollectionFreeFormDocumentView'; -import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment, ViewSpecPrefix } from '../../nodes/DocumentView'; +import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, ViewAdjustment, ViewSpecPrefix } from '../../nodes/DocumentView'; import { FieldViewProps } from '../../nodes/FieldView'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { PresBox } from '../../nodes/trails/PresBox'; @@ -47,7 +47,7 @@ import { StyleProp } from '../../StyleProvider'; import { CollectionSubView } from '../CollectionSubView'; import { TreeViewType } from '../CollectionTreeView'; import { TabDocView } from '../TabDocView'; -import { computePivotLayout, computerPassLayout, computerStarburstLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from './CollectionFreeFormLayoutEngines'; +import { computePivotLayout, computePassLayout as computePassLayout, computeStarburstLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from './CollectionFreeFormLayoutEngines'; import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCursors'; import './CollectionFreeFormView.scss'; import { MarqueeView } from './MarqueeView'; @@ -1272,7 +1272,8 @@ export class CollectionFreeFormView extends CollectionSubView { const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine); - const pointerEvents = this.props.isContentActive() === false ? 'none' : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === 'pass' && !this.props.isSelected(true)) ? 'none' : this.props.pointerEvents?.()); + const pointerEvents = + this.props.isContentActive() === false ? 'none' : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === computePassLayout.name && !this.props.isSelected(true)) ? 'none' : this.props.pointerEvents?.()); return pointerEvents; }; getChildDocView(entry: PoolData) { @@ -1328,8 +1329,8 @@ export class CollectionFreeFormView extends CollectionSubView ); } - addDocTab = action((doc: Doc, where: string) => { - if (where === 'inParent') { + addDocTab = action((doc: Doc, where: OpenWhere) => { + if (where === OpenWhere.inParent) { (doc instanceof Doc ? [doc] : doc).forEach(doc => { const pt = this.getTransform().transformPoint(NumCast(doc.x), NumCast(doc.y)); doc.x = pt[0]; @@ -1337,7 +1338,7 @@ export class CollectionFreeFormView extends CollectionSubView(doc as any as Doc[]); return true; } @@ -1457,10 +1458,10 @@ export class CollectionFreeFormView extends CollectionSubView(); // prettier-ignore switch (this.layoutEngine) { - case 'pass': return { newPool, computedElementData: this.doEngineLayout(newPool, computerPassLayout) }; - case 'timeline': return { newPool, computedElementData: this.doEngineLayout(newPool, computeTimelineLayout) }; - case 'pivot': return { newPool, computedElementData: this.doEngineLayout(newPool, computePivotLayout) }; - case 'starburst': return { newPool, computedElementData: this.doEngineLayout(newPool, computerStarburstLayout) }; + case computePassLayout.name : return { newPool, computedElementData: this.doEngineLayout(newPool, computePassLayout) }; + case computeTimelineLayout.name: return { newPool, computedElementData: this.doEngineLayout(newPool, computeTimelineLayout) }; + case computePivotLayout.name: return { newPool, computedElementData: this.doEngineLayout(newPool, computePivotLayout) }; + case computeStarburstLayout.name: return { newPool, computedElementData: this.doEngineLayout(newPool, computeStarburstLayout) }; } return { newPool, computedElementData: this.doFreeformLayout(newPool) }; } @@ -1724,7 +1725,7 @@ export class CollectionFreeFormView extends CollectionSubView ScriptCast(this.Document.onChildClick); onChildDoubleClickHandler = () => ScriptCast(this.Document.onChildDoubleClick); - addDocTab = (doc: Doc, where: string) => { - if (where === 'inPlace' && this.layoutDoc.isInPlaceContainer) { - this.dataDoc[this.props.fieldKey] = new List([doc]); - return true; - } - return this.props.addDocTab(doc, where); - }; focusDocument = (doc: Doc, options: DocFocusOptions) => this.props.focus(this.rootDoc, options); isContentActive = () => this.props.isSelected() || this.props.isContentActive() || this.props.isAnyChildContentActive(); isChildContentActive = () => (((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.isContentActive() ? true : false); @@ -278,7 +271,7 @@ export class CollectionMulticolumnView extends CollectionSubView() { moveDocument={this.props.moveDocument} removeDocument={this.props.removeDocument} whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged} - addDocTab={this.addDocTab} + addDocTab={this.props.addDocTab} pinToPres={this.props.pinToPres} bringToFront={returnFalse} /> diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx index adcd9e1e3..ef75fb159 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx @@ -1,35 +1,36 @@ -import React = require("react"); -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed, observable } from "mobx"; -import { observer } from "mobx-react"; -import { extname } from "path"; -import DatePicker from "react-datepicker"; -import { CellInfo } from "react-table"; -import { DateField } from "../../../../fields/DateField"; -import { Doc, DocListCast, Field, Opt } from "../../../../fields/Doc"; -import { Id } from "../../../../fields/FieldSymbols"; -import { List } from "../../../../fields/List"; -import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField"; -import { ComputedField } from "../../../../fields/ScriptField"; -import { BoolCast, Cast, DateCast, FieldValue, StrCast } from "../../../../fields/Types"; -import { ImageField } from "../../../../fields/URLField"; -import { emptyFunction, Utils } from "../../../../Utils"; -import { Docs } from "../../../documents/Documents"; -import { DocumentType } from "../../../documents/DocumentTypes"; -import { DocumentManager } from "../../../util/DocumentManager"; -import { DragManager } from "../../../util/DragManager"; -import { KeyCodes } from "../../../util/KeyCodes"; -import { CompileScript } from "../../../util/Scripting"; -import { SearchUtil } from "../../../util/SearchUtil"; -import { SnappingManager } from "../../../util/SnappingManager"; -import { undoBatch } from "../../../util/UndoManager"; +import React = require('react'); +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { action, computed, observable } from 'mobx'; +import { observer } from 'mobx-react'; +import { extname } from 'path'; +import DatePicker from 'react-datepicker'; +import { CellInfo } from 'react-table'; +import { DateField } from '../../../../fields/DateField'; +import { Doc, DocListCast, Field, Opt } from '../../../../fields/Doc'; +import { Id } from '../../../../fields/FieldSymbols'; +import { List } from '../../../../fields/List'; +import { SchemaHeaderField } from '../../../../fields/SchemaHeaderField'; +import { ComputedField } from '../../../../fields/ScriptField'; +import { BoolCast, Cast, DateCast, FieldValue, StrCast } from '../../../../fields/Types'; +import { ImageField } from '../../../../fields/URLField'; +import { emptyFunction, Utils } from '../../../../Utils'; +import { Docs } from '../../../documents/Documents'; +import { DocumentType } from '../../../documents/DocumentTypes'; +import { DocumentManager } from '../../../util/DocumentManager'; +import { DragManager } from '../../../util/DragManager'; +import { KeyCodes } from '../../../util/KeyCodes'; +import { CompileScript } from '../../../util/Scripting'; +import { SearchUtil } from '../../../util/SearchUtil'; +import { SnappingManager } from '../../../util/SnappingManager'; +import { undoBatch } from '../../../util/UndoManager'; import '../../../views/DocumentDecorations.scss'; -import { EditableView } from "../../EditableView"; +import { EditableView } from '../../EditableView'; import { MAX_ROW_HEIGHT } from '../../global/globalCssVariables.scss'; -import { DocumentIconContainer } from "../../nodes/DocumentIcon"; -import { OverlayView } from "../../OverlayView"; -import { CollectionView } from "../CollectionView"; -import "./CollectionSchemaView.scss"; +import { DocumentIconContainer } from '../../nodes/DocumentIcon'; +import { OverlayView } from '../../OverlayView'; +import { CollectionView } from '../CollectionView'; +import './CollectionSchemaView.scss'; +import { OpenWhere } from '../../nodes/DocumentView'; // intialize cell properties export interface CellProps { @@ -46,10 +47,9 @@ export interface CellProps { // currently unused renderDepth: number; // called when a button is pressed on the node itself - addDocTab: (document: Doc, where: string) => boolean; + addDocTab: (document: Doc, where: OpenWhere) => boolean; pinToPres: (document: Doc) => void; - moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, - addDocument: (document: Doc | Doc[]) => boolean) => boolean; + moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; isFocused: boolean; changeFocusedCellByIndex: (row: number, col: number) => void; // set whether the cell is in the isEditing mode @@ -67,7 +67,7 @@ export class CollectionSchemaCell extends React.Component { // return a field key that is corrected for whether it COMMENT public static resolvedFieldKey(column: string, rowDoc: Doc) { const fieldKey = column; - if (fieldKey.startsWith("*")) { + if (fieldKey.startsWith('*')) { const rootKey = fieldKey.substring(1); const allKeys = [...Array.from(Object.keys(rowDoc)), ...Array.from(Object.keys(Doc.GetProto(rowDoc)))]; const matchedKeys = allKeys.filter(key => key.includes(rootKey)); @@ -82,33 +82,37 @@ export class CollectionSchemaCell extends React.Component { protected _rowDataDoc = Doc.GetProto(this.props.rowProps.original); // methods for dragging and dropping protected _dropDisposer?: DragManager.DragDropDisposer; - @observable contents: string = ""; + @observable contents: string = ''; - componentDidMount() { document.addEventListener("keydown", this.onKeyDown); } - componentWillUnmount() { document.removeEventListener("keydown", this.onKeyDown); } + componentDidMount() { + document.addEventListener('keydown', this.onKeyDown); + } + componentWillUnmount() { + document.removeEventListener('keydown', this.onKeyDown); + } @action onKeyDown = (e: KeyboardEvent): void => { // If a cell is editable and clicked, hitting enter shoudl allow the user to edit it if (this.props.isFocused && this.props.isEditable && e.keyCode === KeyCodes.ENTER) { - document.removeEventListener("keydown", this.onKeyDown); + document.removeEventListener('keydown', this.onKeyDown); this._isEditing = true; this.props.setIsEditing(true); } - } + }; @action isEditingCallback = (isEditing: boolean): void => { // a general method that takes a boolean that determines whether the cell should be in // is-editing mode // remove the event listener if it's there - document.removeEventListener("keydown", this.onKeyDown); + document.removeEventListener('keydown', this.onKeyDown); // it's not already in is-editing mode, re-add the event listener - isEditing && document.addEventListener("keydown", this.onKeyDown); + isEditing && document.addEventListener('keydown', this.onKeyDown); this._isEditing = isEditing; this.props.setIsEditing(isEditing); this.props.changeFocusedCellByIndex(this.props.row, this.props.col); - } + }; @action onPointerDown = async (e: React.PointerEvent): Promise => { @@ -119,19 +123,19 @@ export class CollectionSchemaCell extends React.Component { this.props.setPreviewDoc(this.props.rowProps.original); let url: string; - if (url = StrCast(this.props.rowProps.row.href)) { + if ((url = StrCast(this.props.rowProps.row.href))) { // opens up the the doc in a new window, blurring the old one try { new URL(url); const temp = window.open(url)!; temp.blur(); window.focus(); - } catch { } + } catch {} } const doc = Cast(this._rowDoc[this.renderFieldKey], Doc, null); doc && this.props.setPreviewDoc(doc); - } + }; @undoBatch applyToDoc = (doc: Doc, row: number, col: number, run: (args?: { [name: string]: any }) => any) => { @@ -142,7 +146,7 @@ export class CollectionSchemaCell extends React.Component { doc[this.renderFieldKey] = res.result; return true; // return whether the change was successful - } + }; private drop = (e: Event, de: DragManager.DropEvent) => { // if the drag has data at its completion @@ -151,41 +155,51 @@ export class CollectionSchemaCell extends React.Component { if (de.complete.docDragData.draggedDocuments.length === 1) { // update the renderFieldKey this._rowDataDoc[this.renderFieldKey] = de.complete.docDragData.draggedDocuments[0]; - } - else { + } else { // create schema document reflecting the new column arrangement - const coll = Docs.Create.SchemaDocument([new SchemaHeaderField("title", "#f1efeb")], de.complete.docDragData.draggedDocuments, {}); + const coll = Docs.Create.SchemaDocument([new SchemaHeaderField('title', '#f1efeb')], de.complete.docDragData.draggedDocuments, {}); this._rowDataDoc[this.renderFieldKey] = coll; } e.stopPropagation(); } - } + }; protected dropRef = (ele: HTMLElement | null) => { // if the drop disposer is not undefined, run its function this._dropDisposer?.(); // if ele is not null, give ele a non-undefined drop disposer ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this))); - } + }; returnHighlights(contents: string, positions?: number[]) { if (positions) { const results = []; StrCast(this.props.Document._searchString); const length = StrCast(this.props.Document._searchString).length; - const color = contents ? "black" : "grey"; + const color = contents ? 'black' : 'grey'; - results.push({contents?.slice(0, positions[0])}); + results.push( + + {contents?.slice(0, positions[0])} + + ); positions.forEach((num, cur) => { - results.push({contents?.slice(num, num + length)}); + results.push( + + {contents?.slice(num, num + length)} + + ); let end = 0; - cur === positions.length - 1 ? end = contents.length : end = positions[cur + 1]; - results.push({contents?.slice(num + length, end)}); - } - ); + cur === positions.length - 1 ? (end = contents.length) : (end = positions[cur + 1]); + results.push( + + {contents?.slice(num + length, end)} + + ); + }); return results; } - return {contents ? contents?.valueOf() : "undefined"}; + return {contents ? contents?.valueOf() : 'undefined'}; } @computed get renderFieldKey() { @@ -199,10 +213,9 @@ export class CollectionSchemaCell extends React.Component { const aliasdoc = await SearchUtil.GetAliasesOfDocument(this._rowDataDoc); const targetContext = aliasdoc.length <= 0 ? undefined : Cast(aliasdoc[0].context, Doc, null); // Jump to the this document - DocumentManager.Instance.jumpToDocument(this._rowDoc, false, emptyFunction, targetContext ? [targetContext] : [], - undefined, undefined, undefined, () => this.props.setPreviewDoc(this._rowDoc)); + DocumentManager.Instance.jumpToDocument(this._rowDoc, false, emptyFunction, targetContext ? [targetContext] : [], undefined, undefined, undefined, () => this.props.setPreviewDoc(this._rowDoc)); } - } + }; renderCellWithType(type: string | undefined) { const dragRef: React.RefObject = React.createRef(); @@ -214,29 +227,29 @@ export class CollectionSchemaCell extends React.Component { const onPointerEnter = (e: React.PointerEvent): void => { // e.buttons === 1 means the left moue pointer is down - if (e.buttons === 1 && SnappingManager.GetIsDragging() && (type === "document" || type === undefined)) { - dragRef.current!.className = "collectionSchemaView-cellContainer doc-drag-over"; + if (e.buttons === 1 && SnappingManager.GetIsDragging() && (type === 'document' || type === undefined)) { + dragRef.current!.className = 'collectionSchemaView-cellContainer doc-drag-over'; } }; const onPointerLeave = (e: React.PointerEvent): void => { // change the class name to indicate that the cell is no longer being dragged - dragRef.current!.className = "collectionSchemaView-cellContainer"; + dragRef.current!.className = 'collectionSchemaView-cellContainer'; }; let contents = Field.toString(field as Field); // display 2 hyphens instead of a blank box for empty cells - contents = contents === "" ? "--" : contents; + contents = contents === '' ? '--' : contents; // classname reflects the tatus of the cell - let className = "collectionSchemaView-cellWrapper"; - if (this._isEditing) className += " editing"; - if (this.props.isFocused && this.props.isEditable) className += " focused"; - if (this.props.isFocused && !this.props.isEditable) className += " inactive"; + let className = 'collectionSchemaView-cellWrapper'; + if (this._isEditing) className += ' editing'; + if (this.props.isFocused && this.props.isEditable) className += ' focused'; + if (this.props.isFocused && !this.props.isEditable) className += ' inactive'; const positions = []; - if (StrCast(this.props.Document._searchString).toLowerCase() !== "") { + if (StrCast(this.props.Document._searchString).toLowerCase() !== '') { // term is ...promise pending... if the field is a Promise, otherwise it is the cell's contents - let term = (field instanceof Promise) ? "...promise pending..." : contents.toLowerCase(); + let term = field instanceof Promise ? '...promise pending...' : contents.toLowerCase(); const search = StrCast(this.props.Document._searchString).toLowerCase(); let start = term.indexOf(search); let tally = 0; @@ -256,56 +269,60 @@ export class CollectionSchemaCell extends React.Component { positions.pop(); } } - const placeholder = type === "number" ? "0" : contents === "" ? "--" : "undefined"; + const placeholder = type === 'number' ? '0' : contents === '' ? '--' : 'undefined'; return ( -
this._isEditing = true)} onPointerEnter={onPointerEnter} onPointerLeave={onPointerLeave}> +
(this._isEditing = true))} + onPointerEnter={onPointerEnter} + onPointerLeave={onPointerLeave}>
-
- {!this.props.Document._searchDoc ? +
+ {!this.props.Document._searchDoc ? ( { const cfield = ComputedField.WithoutComputed(() => FieldValue(field)); const cscript = cfield instanceof ComputedField ? cfield.script.originalScript : undefined; - const cfinalScript = cscript?.split("return")[cscript.split("return").length - 1]; - return cscript ? (cfinalScript?.endsWith(";") ? `:=${cfinalScript?.substring(0, cfinalScript.length - 2)}` : cfinalScript) : - Field.IsField(cfield) ? Field.toScriptString(cfield) : ""; + const cfinalScript = cscript?.split('return')[cscript.split('return').length - 1]; + return cscript ? (cfinalScript?.endsWith(';') ? `:=${cfinalScript?.substring(0, cfinalScript.length - 2)}` : cfinalScript) : Field.IsField(cfield) ? Field.toScriptString(cfield) : ''; }} SetValue={action((value: string) => { // sets what is displayed after the user makes an input let retVal = false; - if (value.startsWith(":=") || value.startsWith("=:=")) { + if (value.startsWith(':=') || value.startsWith('=:=')) { // decides how to compute a value when given either of the above strings - const script = value.substring(value.startsWith("=:=") ? 3 : 2); - retVal = this.props.setComputed(script, value.startsWith(":=") ? this._rowDataDoc : this._rowDoc, this.renderFieldKey, this.props.row, this.props.col); + const script = value.substring(value.startsWith('=:=') ? 3 : 2); + retVal = this.props.setComputed(script, value.startsWith(':=') ? this._rowDataDoc : this._rowDoc, this.renderFieldKey, this.props.row, this.props.col); } else { // check if the input is a number let inputIsNum = true; for (const s of value) { - if (isNaN(parseInt(s)) && !(s === ".") && !(s === ",")) { + if (isNaN(parseInt(s)) && !(s === '.') && !(s === ',')) { inputIsNum = false; } } // check if the input is a boolean - const inputIsBool: boolean = value === "false" || value === "true"; - // what to do in the case - if (!inputIsNum && !inputIsBool && !value.startsWith("=")) { + const inputIsBool: boolean = value === 'false' || value === 'true'; + // what to do in the case + if (!inputIsNum && !inputIsBool && !value.startsWith('=')) { // if it's not a number, it's a string, and should be processed as such - // strips the string of quotes when it is edited to prevent quotes form being added to the text automatically + // strips the string of quotes when it is edited to prevent quotes form being added to the text automatically // after each edit let valueSansQuotes = value; if (this._isEditing) { const vsqLength = valueSansQuotes.length; // get rid of outer quotes - valueSansQuotes = valueSansQuotes.substring(value.startsWith("\"") ? 1 : 0, - valueSansQuotes.charAt(vsqLength - 1) === "\"" ? vsqLength - 1 : vsqLength); + valueSansQuotes = valueSansQuotes.substring(value.startsWith('"') ? 1 : 0, valueSansQuotes.charAt(vsqLength - 1) === '"' ? vsqLength - 1 : vsqLength); } let inputAsString = '"'; // escape any quotes in the string @@ -319,27 +336,27 @@ export class CollectionSchemaCell extends React.Component { // add a closing quote inputAsString += '"'; //two options here: we can strip off outer quotes or we can figure out what's going on with the script - const script = CompileScript(inputAsString, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); + const script = CompileScript(inputAsString, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: 'number', $c: 'number', $: 'any' } }); const changeMade = inputAsString.length !== value.length || inputAsString.length - 2 !== value.length; // change it if a change is made, otherwise, just compile using the old cell conetnts script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); // handle numbers and expressions - } else if (inputIsNum || value.startsWith("=")) { + } else if (inputIsNum || value.startsWith('=')) { //TODO: make accept numbers - const inputscript = value.substring(value.startsWith("=") ? 1 : 0); + const inputscript = value.substring(value.startsWith('=') ? 1 : 0); // if commas are not stripped, the parser only considers the numbers after the last comma - let inputSansCommas = ""; + let inputSansCommas = ''; for (const s of inputscript) { - if (!(s === ",")) { + if (!(s === ',')) { inputSansCommas += s; } } - const script = CompileScript(inputSansCommas, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); + const script = CompileScript(inputSansCommas, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: 'number', $c: 'number', $: 'any' } }); const changeMade = value.length - 2 !== value.length; script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); // handle booleans } else if (inputIsBool) { - const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); + const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: 'number', $c: 'number', $: 'any' } }); const changeMade = value.length - 2 !== value.length; script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); } @@ -352,33 +369,47 @@ export class CollectionSchemaCell extends React.Component { })} OnFillDown={async (value: string) => { // computes all of the value preceded by := - const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); - script.compiled && DocListCast(this.props.Document[this.props.fieldKey]). - forEach((doc, i) => value.startsWith(":=") ? - this.props.setComputed(value.substring(2), Doc.GetProto(doc), this.renderFieldKey, i, this.props.col) : - this.applyToDoc(Doc.GetProto(doc), i, this.props.col, script.run)); + const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: 'number', $c: 'number', $: 'any' } }); + script.compiled && + DocListCast(this.props.Document[this.props.fieldKey]).forEach((doc, i) => + value.startsWith(':=') ? this.props.setComputed(value.substring(2), Doc.GetProto(doc), this.renderFieldKey, i, this.props.col) : this.applyToDoc(Doc.GetProto(doc), i, this.props.col, script.run) + ); }} /> - : + ) : ( this.returnHighlights(contents, positions) - } -
+ )} +
); } - render() { return this.renderCellWithType(undefined); } + render() { + return this.renderCellWithType(undefined); + } } @observer -export class CollectionSchemaNumberCell extends CollectionSchemaCell { render() { return this.renderCellWithType("number"); } } +export class CollectionSchemaNumberCell extends CollectionSchemaCell { + render() { + return this.renderCellWithType('number'); + } +} @observer -export class CollectionSchemaBooleanCell extends CollectionSchemaCell { render() { return this.renderCellWithType("boolean"); } } +export class CollectionSchemaBooleanCell extends CollectionSchemaCell { + render() { + return this.renderCellWithType('boolean'); + } +} @observer -export class CollectionSchemaStringCell extends CollectionSchemaCell { render() { return this.renderCellWithType("string"); } } +export class CollectionSchemaStringCell extends CollectionSchemaCell { + render() { + return this.renderCellWithType('string'); + } +} @observer export class CollectionSchemaDateCell extends CollectionSchemaCell { @@ -396,24 +427,24 @@ export class CollectionSchemaDateCell extends CollectionSchemaCell { // ^ DateCast is always undefined for some reason, but that is what the field should be set to this._rowDoc[this.renderFieldKey] = new DateField(date as Date); //} - } + }; render() { - return !this.props.isFocused ? {this._date ? Field.toString(this._date as Field) : "--"} : - this.handleChange(date)} - onChange={date => this.handleChange(date)} - />; + return !this.props.isFocused ? ( + {this._date ? Field.toString(this._date as Field) : '--'} + ) : ( + this.handleChange(date)} onChange={date => this.handleChange(date)} /> + ); } } @observer export class CollectionSchemaDocCell extends CollectionSchemaCell { - _overlayDisposer?: () => void; - @computed get _doc() { return FieldValue(Cast(this._rowDoc[this.renderFieldKey], Doc)); } + @computed get _doc() { + return FieldValue(Cast(this._rowDoc[this.renderFieldKey], Doc)); + } @action onSetValue = (value: string) => { @@ -422,7 +453,7 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell { const script = CompileScript(value, { addReturn: true, typecheck: true, - transformer: DocumentIconContainer.getTransformer() + transformer: DocumentIconContainer.getTransformer(), }); // compile the script const results = script.compiled && script.run(); @@ -432,44 +463,43 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell { return true; } return false; - } + }; - componentWillUnmount() { this.onBlur(); } + componentWillUnmount() { + this.onBlur(); + } - onBlur = () => { this._overlayDisposer?.(); }; + onBlur = () => { + this._overlayDisposer?.(); + }; onFocus = () => { this.onBlur(); this._overlayDisposer = OverlayView.Instance.addElement(, { x: 0, y: 0 }); - } + }; @action isEditingCallback = (isEditing: boolean): void => { // the isEditingCallback from a general CollectionSchemaCell - document.removeEventListener("keydown", this.onKeyDown); - isEditing && document.addEventListener("keydown", this.onKeyDown); + document.removeEventListener('keydown', this.onKeyDown); + isEditing && document.addEventListener('keydown', this.onKeyDown); this._isEditing = isEditing; this.props.setIsEditing(isEditing); this.props.changeFocusedCellByIndex(this.props.row, this.props.col); - } + }; render() { // if there's a doc, render it - return !this._doc ? this.renderCellWithType("document") : -
-
+ return !this._doc ? ( + this.renderCellWithType('document') + ) : ( +
+
StrCast(this._doc?.title)} SetValue={action((value: string) => { @@ -477,33 +507,36 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell { return true; })} /> -
-
this._doc && this.props.addDocTab(this._doc, "add:right")} className="collectionSchemaView-cellContents-docButton"> +
+
this._doc && this.props.addDocTab(this._doc, OpenWhere.addRight)} className="collectionSchemaView-cellContents-docButton">
-
; +
+ ); } } @observer export class CollectionSchemaImageCell extends CollectionSchemaCell { - choosePath(url: URL) { - if (url.protocol === "data") return url.href; // if the url ises the data protocol, just return the href + if (url.protocol === 'data') return url.href; // if the url ises the data protocol, just return the href if (url.href.indexOf(window.location.origin) === -1) return Utils.CorsProxy(url.href); // otherwise, put it through the cors proxy erver - if (!/\.(png|jpg|jpeg|gif|webp)$/.test(url.href.toLowerCase())) return url.href;//Why is this here — good question + if (!/\.(png|jpg|jpeg|gif|webp)$/.test(url.href.toLowerCase())) return url.href; //Why is this here — good question const ext = extname(url.href); - return url.href.replace(ext, "_o" + ext); + return url.href.replace(ext, '_o' + ext); } render() { const field = Cast(this._rowDoc[this.renderFieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc - const alts = DocListCast(this._rowDoc[this.renderFieldKey + "-alternates"]); // retrieve alternate documents that may be rendered as alternate images - const altpaths = alts.map(doc => Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url).filter(url => url).map(url => this.choosePath(url)); // access the primary layout data of the alternate documents + const alts = DocListCast(this._rowDoc[this.renderFieldKey + '-alternates']); // retrieve alternate documents that may be rendered as alternate images + const altpaths = alts + .map(doc => Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url) + .filter(url => url) + .map(url => this.choosePath(url)); // access the primary layout data of the alternate documents const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths; // If there is a path, follow it; otherwise, follow a link to a default image icon - const url = paths.length ? paths : [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")]; + const url = paths.length ? paths : [Utils.CorsProxy('http://www.cs.brown.edu/~bcz/noImage.png')]; const aspect = Doc.NativeAspect(this._rowDoc); // aspect ratio let width = Math.min(75, this.props.rowProps.width); // get a with that is no smaller than 75px @@ -511,25 +544,28 @@ export class CollectionSchemaImageCell extends CollectionSchemaCell { width = height * aspect; // increase the width of the image if necessary to maintain proportionality const reference = React.createRef(); - return
-
- -
-
; + return ( +
+
+ +
+
+ ); } } - @observer export class CollectionSchemaListCell extends CollectionSchemaCell { _overlayDisposer?: () => void; - @computed get _field() { return this._rowDoc[this.renderFieldKey]; } - @computed get _optionsList() { return this._field as List; } + @computed get _field() { + return this._rowDoc[this.renderFieldKey]; + } + @computed get _optionsList() { + return this._field as List; + } @observable private _opened = false; // whether the list is opened - @observable private _text = "select an item"; + @observable private _text = 'select an item'; @observable private _selectedNum = 0; // the index of the list item selected @action @@ -538,102 +574,109 @@ export class CollectionSchemaListCell extends CollectionSchemaCell { this._optionsList[this._selectedNum] = this._text = value; (this._field as List).splice(this._selectedNum, 1, value); - } + }; @action onSelected = (element: string, index: number) => { // if an item is selected, the private variables should update to reflect this this._text = element; this._selectedNum = index; - } + }; onFocus = () => { this._overlayDisposer?.(); this._overlayDisposer = OverlayView.Instance.addElement(, { x: 0, y: 0 }); - } + }; render() { const link = false; const reference = React.createRef(); - // if the list is not opened, don't display it; otherwise, do. + // if the list is not opened, don't display it; otherwise, do. if (this._optionsList?.length) { - const options = !this._opened ? (null) : + const options = !this._opened ? null : (
{this._optionsList.map((element, index) => { const val = Field.toString(element); - return
this.onSelected(StrCast(element), index)} > - {val} -
; + return ( +
this.onSelected(StrCast(element), index)}> + {val} +
+ ); })} -
; - - const plainText =
{this._text}
; - const textarea =
- this._text} - SetValue={action((value: string) => { - // add special for params - this.onSetValue(value); - return true; - })} - /> -
; +
+ ); + + const plainText =
{this._text}
; + const textarea = ( +
+ this._text} + SetValue={action((value: string) => { + // add special for params + this.onSetValue(value); + return true; + })} + /> +
+ ); //☰ return (
-
{link ? plainText : textarea}
{options} -
+
); } - return this.renderCellWithType("list"); + return this.renderCellWithType('list'); } } - @observer export class CollectionSchemaCheckboxCell extends CollectionSchemaCell { - @computed get _isChecked() { return BoolCast(this._rowDoc[this.renderFieldKey]); } + @computed get _isChecked() { + return BoolCast(this._rowDoc[this.renderFieldKey]); + } render() { const reference = React.createRef(); return (
- this._rowDoc[this.renderFieldKey] = e.target.checked} /> + (this._rowDoc[this.renderFieldKey] = e.target.checked)} />
); } } - @observer export class CollectionSchemaButtons extends CollectionSchemaCell { // the navigation buttons for schema view when it is used for search. render() { - return !this.props.Document._searchDoc || ![DocumentType.PDF, DocumentType.RTF].includes(StrCast(this._rowDoc.type) as DocumentType) ? <> : -
+ return !this.props.Document._searchDoc || ![DocumentType.PDF, DocumentType.RTF].includes(StrCast(this._rowDoc.type) as DocumentType) ? ( + <> + ) : ( +
- -
; +
+ ); } } diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaMovableRow.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaMovableRow.tsx index f872637e5..3cb2df7d3 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaMovableRow.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaMovableRow.tsx @@ -10,6 +10,7 @@ import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; import { undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; +import { OpenWhere } from '../../nodes/DocumentView'; import './CollectionSchemaView.scss'; export interface MovableRowProps { @@ -138,7 +139,7 @@ export class MovableRow extends React.Component
-
this.props.addDocTab(this.props.rowInfo.original, 'add:right')}> +
this.props.addDocTab(this.props.rowInfo.original, OpenWhere.addRight)}>
diff --git a/src/client/views/collections/collectionSchema/SchemaTable.tsx b/src/client/views/collections/collectionSchema/SchemaTable.tsx index fafea5ce3..45ad4f86b 100644 --- a/src/client/views/collections/collectionSchema/SchemaTable.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTable.tsx @@ -23,7 +23,7 @@ import { undoBatch } from '../../../util/UndoManager'; import '../../../views/DocumentDecorations.scss'; import { ContextMenu } from '../../ContextMenu'; import { COLLECTION_BORDER_WIDTH, SCHEMA_DIVIDER_WIDTH } from '../../global/globalCssVariables.scss'; -import { DocumentView } from '../../nodes/DocumentView'; +import { DocumentView, OpenWhere } from '../../nodes/DocumentView'; import { DefaultStyleProvider } from '../../StyleProvider'; import { CollectionView } from '../CollectionView'; import { @@ -86,7 +86,7 @@ export interface SchemaTableProps { ScreenToLocalTransform: () => Transform; active: (outsideReaction: boolean | undefined) => boolean | undefined; onDrop: (e: React.DragEvent, options: DocumentOptions, completed?: (() => void) | undefined) => void; - addDocTab: (document: Doc, where: string) => boolean; + addDocTab: (document: Doc, where: OpenWhere) => boolean; pinToPres: (document: Doc) => void; isSelected: (outsideReaction?: boolean) => boolean; isFocused: (document: Doc, outsideReaction: boolean) => boolean; @@ -625,7 +625,7 @@ export class SchemaTable extends React.Component { }; onOpenClick = () => { - this._showDoc && this.props.addDocTab(this._showDoc, 'add:right'); + this._showDoc && this.props.addDocTab(this._showDoc, OpenWhere.addRight); }; getPreviewTransform = (): Transform => { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 570039550..868822fbf 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -16,7 +16,7 @@ import { CollectionFreeFormView } from '../collections/collectionFreeForm/Collec import { DocComponent } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; import './CollectionFreeFormDocumentView.scss'; -import { DocumentView, DocumentViewProps } from './DocumentView'; +import { DocumentView, DocumentViewProps, OpenWhere } from './DocumentView'; import React = require('react'); export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { @@ -199,7 +199,7 @@ export class CollectionFreeFormDocumentView extends DocComponent string; whenChildContentsActiveChanged: (isActive: boolean) => void; rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected - addDocTab: (doc: Doc, where: string) => boolean; + addDocTab: (doc: Doc, where: OpenWhere) => boolean; filterAddDocument?: (doc: Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example) addDocument?: (doc: Doc | Doc[]) => boolean; removeDocument?: (doc: Doc | Doc[]) => boolean; @@ -474,7 +495,7 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "add:right"), icon: "map-pin", selected: -1 }); + // RadialMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), OpenWhere.addRight), icon: "map-pin", selected: -1 }); const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]); (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) && RadialMenu.Instance.addItem({ @@ -485,7 +506,7 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(this.props.Document, "add:right"), icon: "trash", selected: -1 }); + // RadialMenu.Instance.addItem({ description: "Open in a new tab", event: () => this.props.addDocTab(this.props.Document, OpenWhere.addRight), icon: "trash", selected: -1 }); RadialMenu.Instance.addItem({ description: 'Pin', event: () => this.props.pinToPres(this.props.Document, {}), icon: 'map-pin', selected: -1 }); RadialMenu.Instance.addItem({ description: 'Open', event: () => MobileInterface.Instance.handleClick(this.props.Document), icon: 'trash', selected: -1 }); @@ -586,7 +607,7 @@ export class DocumentViewInternal extends DocComponent (func().result?.select === true ? this.props.select(false) : ''), 'on double click'); } else if (!Doc.IsSystem(this.rootDoc) && !this.rootDoc.isLinkButton) { - UndoManager.RunInBatch(() => LightboxView.AddDocTab(this.rootDoc, 'lightbox', this.props.LayoutTemplate?.(), this.props.addDocTab), 'double tap'); + UndoManager.RunInBatch(() => LightboxView.AddDocTab(this.rootDoc, OpenWhere.lightbox, this.props.LayoutTemplate?.(), this.props.addDocTab), 'double tap'); SelectionManager.DeselectAll(); Doc.UnBrushDoc(this.props.Document); } @@ -857,7 +878,7 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(templateDoc, 'add:right'), icon: 'eye' }); + !Doc.noviceMode && templateDoc && appearanceItems.push({ description: 'Open Template ', event: () => this.props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' }); !Doc.noviceMode && appearanceItems.push({ description: 'Add a Field', @@ -957,8 +978,8 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), 'add:right'), icon: 'layer-group' }); - !Doc.noviceMode && helpItems.push({ description: 'Text Shortcuts Ctrl+/', event: () => this.props.addDocTab(Docs.Create.PdfDocument('/assets/cheat-sheet.pdf', { _width: 300, _height: 300 }), 'add:right'), icon: 'keyboard' }); + helpItems.push({ description: 'Show Metadata', event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), OpenWhere.addRight), icon: 'layer-group' }); + !Doc.noviceMode && helpItems.push({ description: 'Text Shortcuts Ctrl+/', event: () => this.props.addDocTab(Docs.Create.PdfDocument('/assets/cheat-sheet.pdf', { _width: 300, _height: 300 }), OpenWhere.addRight), icon: 'keyboard' }); !Doc.noviceMode && helpItems.push({ description: 'Print Document in Console', event: () => console.log(this.props.Document), icon: 'hand-point-right' }); !Doc.noviceMode && helpItems.push({ description: 'Print DataDoc in Console', event: () => console.log(this.props.Document[DataSym]), icon: 'hand-point-right' }); diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 7d04c4b64..18c5b81ec 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -20,6 +20,7 @@ import { ContextMenuProps } from '../ContextMenuItem'; import e = require('express'); import { FormattedTextBox } from './formattedText/FormattedTextBox'; import { ImageBox } from './ImageBox'; +import { OpenWhere } from './DocumentView'; export type KVPScript = { script: CompiledScript; @@ -259,8 +260,8 @@ export class KeyValueBox extends React.Component { openItems.push({ description: 'Default Perspective', event: () => { - this.props.addDocTab(this.props.Document, 'close'); - this.props.addDocTab(this.fieldDocToLayout, 'add:right'); + this.props.addDocTab(this.props.Document, OpenWhere.close); + this.props.addDocTab(this.fieldDocToLayout, OpenWhere.addRight); }, icon: 'image', }); diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 80def3025..e74ef4a39 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -1,18 +1,19 @@ import { action, observable } from 'mobx'; -import { observer } from "mobx-react"; +import { observer } from 'mobx-react'; import { Doc, Field, Opt } from '../../../fields/Doc'; import { emptyFunction, returnFalse, returnOne, returnZero, returnEmptyFilter, returnEmptyDoclist, emptyPath } from '../../../Utils'; import { Docs } from '../../documents/Documents'; import { Transform } from '../../util/Transform'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; -import { EditableView } from "../EditableView"; +import { EditableView } from '../EditableView'; import { FieldView, FieldViewProps } from './FieldView'; import { KeyValueBox } from './KeyValueBox'; -import "./KeyValueBox.scss"; -import "./KeyValuePair.scss"; -import React = require("react"); +import './KeyValueBox.scss'; +import './KeyValuePair.scss'; +import React = require('react'); import { DefaultStyleProvider } from '../StyleProvider'; +import { OpenWhere } from './DocumentView'; // Represents one row in a key value plane @@ -23,7 +24,7 @@ export interface KeyValuePairProps { keyWidth: number; PanelHeight: () => number; PanelWidth: () => number; - addDocTab: (doc: Doc, where: string) => boolean; + addDocTab: (doc: Doc, where: OpenWhere) => boolean; } @observer export class KeyValuePair extends React.Component { @@ -34,23 +35,23 @@ export class KeyValuePair extends React.Component { @action handleCheck = (e: React.ChangeEvent) => { this.isChecked = e.currentTarget.checked; - } + }; @action uncheck = () => { this.checkbox.current!.checked = false; this.isChecked = false; - } + }; onContextMenu = (e: React.MouseEvent) => { const value = this.props.doc[this.props.keyName]; if (value instanceof Doc) { e.stopPropagation(); e.preventDefault(); - ContextMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(value, { _width: 300, _height: 300 }), "add:right"), icon: "layer-group" }); + ContextMenu.Instance.addItem({ description: 'Open Fields', event: () => this.props.addDocTab(Docs.Create.KVPDocument(value, { _width: 300, _height: 300 }), OpenWhere.addRight), icon: 'layer-group' }); ContextMenu.Instance.displayMenu(e.clientX, e.clientY); } - } + }; render() { const props: FieldViewProps = { @@ -68,7 +69,7 @@ export class KeyValuePair extends React.Component { isSelected: returnFalse, setHeight: returnFalse, select: emptyFunction, - dropAction: "alias", + dropAction: 'alias', bringToFront: emptyFunction, renderDepth: 1, isContentActive: returnFalse, @@ -92,30 +93,30 @@ export class KeyValuePair extends React.Component { doc = doc.proto; } const parenCount = Math.max(0, protoCount - 1); - const keyStyle = protoCount === 0 ? "black" : "blue"; + const keyStyle = protoCount === 0 ? 'black' : 'blue'; - const hover = { transition: "0.3s ease opacity", opacity: this.isPointerOver || this.isChecked ? 1 : 0 }; + const hover = { transition: '0.3s ease opacity', opacity: this.isPointerOver || this.isChecked ? 1 : 0 }; return ( - this.isPointerOver = true)} onPointerLeave={action(() => this.isPointerOver = false)}> + (this.isPointerOver = true))} onPointerLeave={action(() => (this.isPointerOver = false))}>
- - -
{"(".repeat(parenCount)}{props.fieldKey}{")".repeat(parenCount)}
+ +
+ {'('.repeat(parenCount)} + {props.fieldKey} + {')'.repeat(parenCount)} +
@@ -123,13 +124,13 @@ export class KeyValuePair extends React.Component { Field.toKeyValueString(props.Document, props.fieldKey)} - SetValue={(value: string) => - KeyValueBox.SetField(props.Document, props.fieldKey, value)} /> + SetValue={(value: string) => KeyValueBox.SetField(props.Document, props.fieldKey, value)} + />
); } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index d6cf79f87..be9565452 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -17,6 +17,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import './LinkAnchorBox.scss'; import { LinkDocPreview } from './LinkDocPreview'; import React = require('react'); +import { OpenWhere } from './DocumentView'; const higflyout = require('@hig/flyout'); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -88,13 +89,13 @@ export class LinkAnchorBox extends ViewBoxBaseComponent() { }; openLinkDocOnRight = (e: React.MouseEvent) => { - this.props.addDocTab(this.rootDoc, 'add:right'); + this.props.addDocTab(this.rootDoc, OpenWhere.addRight); }; openLinkTargetOnRight = (e: React.MouseEvent) => { const alias = Doc.MakeAlias(Cast(this.layoutDoc[this.fieldKey], Doc, null)); alias._isLinkButton = undefined; alias.layoutKey = 'layout'; - this.props.addDocTab(alias, 'add:right'); + this.props.addDocTab(alias, OpenWhere.addRight); }; @action openLinkEditor = action((e: React.MouseEvent) => { diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index a47577701..135fbca31 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -14,7 +14,7 @@ import { LinkFollower } from '../../util/LinkFollower'; import { LinkManager } from '../../util/LinkManager'; import { Transform } from '../../util/Transform'; import { undoBatch } from '../../util/UndoManager'; -import { DocumentView, DocumentViewSharedProps } from './DocumentView'; +import { DocumentView, DocumentViewSharedProps, OpenWhere } from './DocumentView'; import './LinkDocPreview.scss'; import React = require('react'); import { LinkEditor } from '../linking/LinkEditor'; @@ -156,7 +156,7 @@ export class LinkDocPreview extends React.Component { LinkDocPreview.Clear(); LinkFollower.FollowLink(this._linkDoc, this._linkSrc, this.props.docProps, false); } else if (this.props.hrefs?.length) { - this.props.docProps?.addDocTab(Docs.Create.WebDocument(this.props.hrefs[0], { title: this.props.hrefs[0], _nativeWidth: 850, _width: 200, _height: 400, useCors: true }), 'add:right'); + this.props.docProps?.addDocTab(Docs.Create.WebDocument(this.props.hrefs[0], { title: this.props.hrefs[0], _nativeWidth: 850, _width: 200, _height: 400, useCors: true }), OpenWhere.addRight); } }; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 70ac84fa4..82d5b00f9 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -31,6 +31,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import { RecordingBox } from './RecordingBox'; import './VideoBox.scss'; import { ObjectField } from '../../../fields/ObjectField'; +import { OpenWhere } from './DocumentView'; const path = require('path'); /** @@ -273,7 +274,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() { } showTemplate = (): void => { const dragFactory = Cast(this.layoutDoc.dragFactory, Doc, null); - dragFactory && this.props.addDocTab(dragFactory, 'add:right'); + dragFactory && this.props.addDocTab(dragFactory, OpenWhere.addRight); }; dragAsTemplate = (): void => { this.layoutDoc.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)'); diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index 1e7cb6ea5..63347015b 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -17,6 +17,7 @@ import { Tooltip } from '@material-ui/core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { CollectionViewType } from '../../../documents/DocumentTypes'; import { NodeSelection } from 'prosemirror-state'; +import { OpenWhere } from '../DocumentView'; export class DashFieldView { dom: HTMLDivElement; // container for label and value @@ -227,7 +228,7 @@ export class DashFieldViewInternal extends React.Component c.heading).indexOf(this._fieldKey) === -1 && list.push(new SchemaHeaderField(this._fieldKey, '#f1efeb')); list.map(c => c.heading).indexOf('text') === -1 && list.push(new SchemaHeaderField('text', '#f1efeb')); alias._pivotField = this._fieldKey.startsWith('#') ? '#' : this._fieldKey; - this.props.tbox.props.addDocTab(alias, 'add:right'); + this.props.tbox.props.addDocTab(alias, OpenWhere.addRight); } }; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index fdd61463d..ce4639b76 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -45,7 +45,7 @@ import { LightboxView } from '../../LightboxView'; import { AnchorMenu } from '../../pdf/AnchorMenu'; import { SidebarAnnos } from '../../SidebarAnnos'; import { StyleProp } from '../../StyleProvider'; -import { DocumentViewInternal } from '../DocumentView'; +import { DocumentViewInternal, OpenWhere } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; import { LinkDocPreview } from '../LinkDocPreview'; import { DashDocCommentView } from './DashDocCommentView'; @@ -1428,7 +1428,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { const docView = DocumentManager.Instance.getDocumentView(audiodoc); if (!docView) { - this.props.addDocTab(audiodoc, 'add:bottom'); + this.props.addDocTab(audiodoc, OpenWhere.addBottom); setTimeout(func); } else docView.ComponentView?.playFrom?.(timecode, Cast(anchor.timecodeToHide, 'number', null)); // bcz: would be nice to find the next audio tag in the doc and play until that }; diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts index 3d9bd6add..68b0488a2 100644 --- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts +++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts @@ -9,6 +9,7 @@ import { GetEffectiveAcl } from '../../../../fields/util'; import { Utils } from '../../../../Utils'; import { Docs } from '../../../documents/Documents'; import { SelectionManager } from '../../../util/SelectionManager'; +import { OpenWhere } from '../DocumentView'; import { liftListItem, sinkListItem } from './prosemirrorPatches.js'; const mac = typeof navigator !== 'undefined' ? /Mac/.test(navigator.platform) : false; @@ -135,7 +136,7 @@ export function buildKeymap>(schema: S, props: any, mapKey //Command to create a new Tab with a PDF of all the command shortcuts bind('Mod-/', (state: EditorState, dispatch: (tx: Transaction) => void) => { const newDoc = Docs.Create.PdfDocument(Utils.prepend('/assets/cheat-sheet.pdf'), { _width: 300, _height: 300 }); - props.addDocTab(newDoc, 'add:right'); + props.addDocTab(newDoc, OpenWhere.addRight); }); //Commands to modify BlockType diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index e19b53f50..adfd2fda1 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -23,7 +23,7 @@ import { SelectionManager } from '../../../util/SelectionManager'; import { SettingsManager } from '../../../util/SettingsManager'; import { undoBatch, UndoManager } from '../../../util/UndoManager'; import { CollectionDockingView } from '../../collections/CollectionDockingView'; -import { CollectionFreeFormView, MarqueeViewBounds } from '../../collections/collectionFreeForm'; +import { CollectionFreeFormView, computeTimelineLayout, MarqueeViewBounds } from '../../collections/collectionFreeForm'; import { CollectionView } from '../../collections/CollectionView'; import { TabDocView } from '../../collections/TabDocView'; import { ViewBoxBaseComponent } from '../../DocComponent'; @@ -35,6 +35,7 @@ import { ScriptingBox } from '../ScriptingBox'; import './PresBox.scss'; import { PresEffect, PresMovement, PresStatus } from './PresEnums'; import { map } from 'bluebird'; +import { OpenWhere, OpenWhereMod } from '../DocumentView'; const { Howl } = require('howler'); export interface PinProps { @@ -196,7 +197,7 @@ export class PresBox extends ViewBoxBaseComponent() { ); this.props.setContentView?.(this); this._unmounting = false; - this.rootDoc._forceRenderEngine = 'timeline'; + this.rootDoc._forceRenderEngine = computeTimelineLayout.name; this.layoutDoc.presStatus = PresStatus.Edit; this.layoutDoc._gridGap = 0; this.layoutDoc._yMargin = 0; @@ -563,7 +564,7 @@ export class PresBox extends ViewBoxBaseComponent() { self._eleArray.splice(0, self._eleArray.length, ...eleViewCache); }); const openInTab = (doc: Doc, finished?: () => void) => { - (collectionDocView ?? this).props.addDocTab(doc, ''); + (collectionDocView ?? this).props.addDocTab(doc, OpenWhere.add); this.layoutDoc.presCollection = targetDoc; // this still needs some fixing setTimeout(resetSelection, 500); @@ -725,7 +726,7 @@ export class PresBox extends ViewBoxBaseComponent() { if (DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc)) { this.layoutDoc.presStatus = PresStatus.Edit; Doc.RemoveDocFromList(Doc.MyOverlayDocs, undefined, this.rootDoc); - CollectionDockingView.AddSplit(this.rootDoc, 'right'); + CollectionDockingView.AddSplit(this.rootDoc, OpenWhereMod.right); } else { this.layoutDoc.presStatus = PresStatus.Edit; clearTimeout(this._presTimer); @@ -1760,7 +1761,7 @@ export class PresBox extends ViewBoxBaseComponent() { TabDocView.PinDoc(doc, {}); this.gotoDocument(this.childDocs.length, this.activeItem); } else { - this.props.addDocTab(doc, 'add:right'); + this.props.addDocTab(doc, OpenWhere.addRight); } } }; @@ -2322,7 +2323,7 @@ export class PresBox extends ViewBoxBaseComponent() { static NavigateToDoc(bestTarget: Doc, activeItem: Doc) { const srcContext = Cast(bestTarget.context, Doc, null) ?? Cast(Cast(bestTarget.annotationOn, Doc, null)?.context, Doc, null); const openInTab = (doc: Doc, finished?: () => void) => { - CollectionDockingView.AddSplit(doc, 'right'); + CollectionDockingView.AddSplit(doc, OpenWhereMod.right); finished?.(); }; PresBox.NavigateToTarget(bestTarget, activeItem, openInTab, srcContext); diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 8265de445..2ae597b0b 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -700,7 +700,7 @@ export class MobileInterface extends React.Component { className="docButton" title={Doc.isDocPinned(this._activeDoc) ? 'Unpin from presentation' : 'Pin to presentation'} style={{ backgroundColor: isPinned ? 'black' : 'white', color: isPinned ? 'white' : 'black' }} - onClick={e => TabDocView.PinDoc(this._activeDoc)}> + onClick={e => TabDocView.PinDoc(this._activeDoc, {})}>
); -- cgit v1.2.3-70-g09d2 From 73d3c63658c4bdf3268ea81a02eb96566869b855 Mon Sep 17 00:00:00 2001 From: mehekj Date: Mon, 21 Nov 2022 12:38:37 -0500 Subject: column deletion and new key menu fixes --- .../collectionSchema/CollectionSchemaView.scss | 13 +++- .../collectionSchema/CollectionSchemaView.tsx | 73 +++++++++++++--------- .../collectionSchema/SchemaColumnHeader.tsx | 31 +++++---- .../collections/collectionSchema/SchemaRowBox.tsx | 2 +- 4 files changed, 74 insertions(+), 45 deletions(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss index 99f49eb0e..4fa5d80e2 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss @@ -78,6 +78,15 @@ align-items: flex-start; } + .schema-new-key-options { + margin: 10px; + .schema-key-warning { + color: red; + font-weight: normal; + align-self: center; + } + } + .schema-key-list { width: 100%; max-height: 300px; @@ -85,7 +94,7 @@ } .schema-key-type-option { - margin: 2px 10px; + margin: 2px 0px; input { margin-right: 5px; @@ -93,7 +102,7 @@ } .schema-key-default-val { - margin: 5px 10px; + margin: 5px 0; } .schema-column-menu-button { diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 24008a21d..f7c68c803 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -1,5 +1,5 @@ import React = require('react'); -import { action, computed, observable, ObservableMap, ObservableSet, untracked } from 'mobx'; +import { action, computed, observable, ObservableMap, ObservableSet, trace, untracked } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, DocListCast, StrListCast } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; @@ -66,11 +66,22 @@ export class CollectionSchemaView extends CollectionSubView() { } @computed get storedColumnWidths() { - return Cast( + let widths = Cast( this.layoutDoc.columnWidths, listSpec('number'), this.columnKeys.map(() => (this.props.PanelWidth() - this._rowMenuWidth) / this.columnKeys.length) ); + + const totalWidth = widths.reduce((sum, width) => sum + width, 0); + if (totalWidth !== this.props.PanelWidth() - this._rowMenuWidth) { + widths = widths.map(w => { + const proportion = w / totalWidth; + return proportion * (this.props.PanelWidth() - this._rowMenuWidth); + }); + // this.layoutDoc.columnWidths = new List(widths); + } + + return widths; } @computed get displayColumnWidths() { @@ -84,7 +95,7 @@ export class CollectionSchemaView extends CollectionSubView() { this.addNewKey(newKey, defaultVal); } - let currKeys = this.columnKeys; + let currKeys = [...this.columnKeys]; currKeys[index] = newKey; this.layoutDoc.columnKeys = new List(currKeys); }; @@ -96,7 +107,7 @@ export class CollectionSchemaView extends CollectionSubView() { this.addNewKey(key, defaultVal); } - let currWidths = this.storedColumnWidths; + let currWidths = [...this.storedColumnWidths]; const newColWidth = this.props.PanelWidth() / (currWidths.length + 1); currWidths = currWidths.map(w => { const proportion = w / (this.props.PanelWidth() - this._rowMenuWidth); @@ -105,21 +116,21 @@ export class CollectionSchemaView extends CollectionSubView() { currWidths.splice(index + 1, 0, newColWidth); this.layoutDoc.columnWidths = new List(currWidths); - let currKeys = this.columnKeys; + let currKeys = [...this.columnKeys]; currKeys.splice(index + 1, 0, key); this.layoutDoc.columnKeys = new List(currKeys); }; @action addNewKey = (key: string, defaultVal: any) => { - console.log(defaultVal); this.childDocs.forEach(doc => (doc[key] = defaultVal)); }; @undoBatch @action removeColumn = (index: number) => { - let currWidths = this.storedColumnWidths; + if (this.columnKeys.length === 1) return; + let currWidths = [...this.storedColumnWidths]; const removedColWidth = currWidths[index]; currWidths = currWidths.map(w => { const proportion = w / (this.props.PanelWidth() - this._rowMenuWidth - removedColWidth); @@ -128,9 +139,11 @@ export class CollectionSchemaView extends CollectionSubView() { currWidths.splice(index, 1); this.layoutDoc.columnWidths = new List(currWidths); - let currKeys = this.columnKeys; + let currKeys = [...this.columnKeys]; currKeys.splice(index, 1); this.layoutDoc.columnKeys = new List(currKeys); + console.log([...this.storedColumnWidths]); + console.log([...this.columnKeys]); }; @action @@ -179,7 +192,6 @@ export class CollectionSchemaView extends CollectionSubView() { @undoBatch @action swapColumns = (index1: number, index2: number) => { - console.log(index1, index2); const tempKey = this.columnKeys[index1]; const tempWidth = this.storedColumnWidths[index1]; @@ -194,27 +206,23 @@ export class CollectionSchemaView extends CollectionSubView() { this.layoutDoc.columnWidths = new List(currWidths); }; - @action - dragColumn = (e: any, index: number) => { - console.log(index); - e.stopPropagation(); - e.preventDefault(); - const rect = e.target.getBoundingClientRect(); - if (e.clientX < rect.x) { - console.log('left', e.clientX, rect.x); - if (index < 1) return true; - this.swapColumns(index - 1, index); - return true; - } - if (e.clientX > rect.x + rect.width) { - console.log('right', e.clientX, rect.x + rect.width); - if (index === this.columnKeys.length) return true; - console.log(index); - this.swapColumns(index, index + 1); - return true; - } - return false; - }; + // @action + // dragColumn = (e: any, index: number) => { + // e.stopPropagation(); + // e.preventDefault(); + // const rect = e.target.getBoundingClientRect(); + // if (e.clientX < rect.x) { + // if (index < 1) return true; + // this.swapColumns(index - 1, index); + // return true; + // } + // if (e.clientX > rect.x + rect.width) { + // if (index === this.columnKeys.length) return true; + // this.swapColumns(index, index + 1); + // return true; + // } + // return false; + // }; @action addRowRef = (doc: Doc, ref: HTMLDivElement) => { @@ -405,9 +413,11 @@ export class CollectionSchemaView extends CollectionSubView() { onDrop={this.onExternalDrop.bind(this)}>
+
{this.columnKeys.map((key, index) => { return ( ); })} @@ -425,6 +435,7 @@ export class CollectionSchemaView extends CollectionSubView() { {this.childDocs.map((doc: Doc, index: number) => ( void; removeColumn: (index: number) => void; resizeColumn: (e: any, index: number, left: boolean) => void; - dragColumn: (e: any, index: number) => boolean; + // dragColumn: (e: any, index: number) => boolean; } @observer @@ -24,6 +24,7 @@ export class SchemaColumnHeader extends React.Component @observable _makeNewField: boolean = false; @observable _newFieldType: ColumnType = ColumnType.Number; @observable _newFieldDefault: any = 0; + @observable _newFieldWarning: string = ''; @observable _menuValue: string = ''; @observable _menuOptions: string[] = []; private _makeNewColumn = false; @@ -94,11 +95,17 @@ export class SchemaColumnHeader extends React.Component string
value: {this.fieldDefaultInput}
+
{this._newFieldWarning}
{ - this.setKey(this._menuValue, this._newFieldDefault); - this._makeNewField = false; + if (this.props.possibleKeys.includes(this._menuValue)) { + this._newFieldWarning = 'Field already exists'; + } else if (this._menuValue.length === 0) { + this._newFieldWarning = 'Field cannot be an empty string'; + } else { + this.setKey(this._menuValue, this._newFieldDefault); + } })}> done
@@ -134,7 +141,7 @@ export class SchemaColumnHeader extends React.Component onSearchKeyDown = (e: React.KeyboardEvent) => { switch (e.key) { case 'Enter': - this.setKey(this._menuOptions.length > 0 ? this._menuOptions[0] : this._menuValue); + this.setKey(this._menuOptions.length > 0 && this._menuValue.length > 0 ? this._menuOptions[0] : this._menuValue); break; case 'Escape': this.toggleColumnMenu(); @@ -158,12 +165,12 @@ export class SchemaColumnHeader extends React.Component this._menuOptions = this.props.possibleKeys.filter(value => value.toLowerCase().includes(this._menuValue.toLowerCase())); }; - @action - onPointerDown = (e: React.PointerEvent) => { - e.stopPropagation(); + // @action + // onPointerDown = (e: React.PointerEvent) => { + // e.stopPropagation(); - setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction); - }; + // setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction); + // }; @action toggleColumnMenu = (newCol?: boolean) => { @@ -172,9 +179,11 @@ export class SchemaColumnHeader extends React.Component this._menuVisible = false; } else { this._menuVisible = true; - this._menuValue = this.fieldKey; + this._menuValue = ''; this._menuOptions = this.props.possibleKeys; this._makeNewField = false; + this._newFieldWarning = ''; + this._makeNewField = false; if (newCol) { this._makeNewColumn = true; } @@ -183,7 +192,7 @@ export class SchemaColumnHeader extends React.Component render() { return ( -
+
this.props.resizeColumn(e, this.props.columnIndex, true)}>
{this.fieldKey}
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx index bfce61952..5c1f32565 100644 --- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx +++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx @@ -118,7 +118,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent() {
{this.props.columnKeys.map((key, index) => ( - + ))}
-- cgit v1.2.3-70-g09d2 From 1f5db9cfc594dbf337d752ec94dab5fca7d8b6f7 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 21 Nov 2022 14:50:25 -0500 Subject: working cleaned up version of link editor properties in propertiesView --- src/client/util/DocumentManager.ts | 6 +- src/client/util/LinkFollower.ts | 2 +- src/client/util/SelectionManager.ts | 3 - .../views/PropertiesDocBacklinksSelector.tsx | 5 +- src/client/views/PropertiesView.tsx | 161 ++++++++++----------- .../CollectionFreeFormLinkView.tsx | 1 - .../collectionSchema/CollectionSchemaCells.tsx | 3 +- .../collections/collectionSchema/SchemaTable.tsx | 3 +- src/client/views/linking/LinkEditor.tsx | 22 +-- src/client/views/linking/LinkMenu.tsx | 31 ++-- src/client/views/linking/LinkMenuGroup.tsx | 65 +++++---- src/client/views/linking/LinkMenuItem.scss | 6 +- src/client/views/linking/LinkMenuItem.tsx | 57 ++++---- src/client/views/nodes/LinkDocPreview.tsx | 33 +++-- src/client/views/nodes/LoadingBox.scss | 15 +- src/client/views/nodes/trails/PresBox.tsx | 3 +- 16 files changed, 205 insertions(+), 211 deletions(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 00f6bc40a..7120eeb88 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -5,7 +5,7 @@ import { Cast } from '../../fields/Types'; import { returnFalse } from '../../Utils'; import { DocumentType } from '../documents/DocumentTypes'; import { LightboxView } from '../views/LightboxView'; -import { DocumentView, ViewAdjustment } from '../views/nodes/DocumentView'; +import { DocumentView, OpenWhereMod, ViewAdjustment } from '../views/nodes/DocumentView'; import { LinkAnchorBox } from '../views/nodes/LinkAnchorBox'; import { CollectionDockingView } from '../views/collections/CollectionDockingView'; import { CollectionFreeFormView } from '../views/collections/collectionFreeForm'; @@ -167,7 +167,7 @@ export class DocumentManager { } static addView = (doc: Doc, finished?: () => void) => { - CollectionDockingView.AddSplit(doc, 'right'); + CollectionDockingView.AddSplit(doc, OpenWhereMod.right); finished?.(); }; public jumpToDocument = ( @@ -347,7 +347,7 @@ export function DocFocusOrOpen(doc: Doc, collectionDoc?: Doc) { } else { const context = doc.context !== Doc.MyFilesystem && Cast(doc.context, Doc, null); const showDoc = context || doc; - CollectionDockingView.AddSplit(Doc.BestAlias(showDoc), 'right') && context && setTimeout(() => DocumentManager.Instance.getDocumentView(Doc.GetProto(doc))?.focus(doc, {})); + CollectionDockingView.AddSplit(Doc.BestAlias(showDoc), OpenWhereMod.right) && context && setTimeout(() => DocumentManager.Instance.getDocumentView(Doc.GetProto(doc))?.focus(doc, {})); } } ScriptingGlobals.add(DocFocusOrOpen); diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index 52885e428..5374bf44b 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -122,7 +122,7 @@ export class LinkFollower { allFinished, undefined, undefined, - Cast(target.presZoom, 'number', null) + Cast(sourceDoc.presZoom, 'number', null) ); } } else { diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 1a2dda953..02d672a65 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -16,7 +16,6 @@ export namespace SelectionManager { @action SelectSchemaViewDoc(doc: Opt) { manager.SelectedSchemaDocument = doc; - if (doc?.type === DocumentType.LINK) LinkManager.currentLink = doc; } @action SelectView(docView: DocumentView, ctrlPressed: boolean): void { @@ -34,7 +33,6 @@ export namespace SelectionManager { manager.SelectedViews.clear(); manager.SelectedViews.set(docView, docView.rootDoc); } - if (docView.rootDoc.type === DocumentType.LINK) LinkManager.currentLink = docView.rootDoc; } @action DeselectView(docView: DocumentView): void { @@ -45,7 +43,6 @@ export namespace SelectionManager { } @action DeselectAll(): void { - LinkManager.currentLink = undefined; manager.SelectedSchemaDocument = undefined; Array.from(manager.SelectedViews.keys()).forEach(dv => dv.props.whenChildContentsActiveChanged(false)); manager.SelectedViews.clear(); diff --git a/src/client/views/PropertiesDocBacklinksSelector.tsx b/src/client/views/PropertiesDocBacklinksSelector.tsx index 25ac44078..f7173a593 100644 --- a/src/client/views/PropertiesDocBacklinksSelector.tsx +++ b/src/client/views/PropertiesDocBacklinksSelector.tsx @@ -3,7 +3,6 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast } from '../../fields/Doc'; import { Cast } from '../../fields/Types'; -import { emptyFunction } from '../../Utils'; import { DocumentType } from '../documents/DocumentTypes'; import { LinkManager } from '../util/LinkManager'; import { SelectionManager } from '../util/SelectionManager'; @@ -47,9 +46,9 @@ export class PropertiesDocBacklinksSelector extends React.Component +
{this.props.hideTitle ? null :

Contexts:

} - +
); } diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 076dc8261..ad3f62990 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -1409,7 +1409,7 @@ export class PropertiesView extends React.Component { @undoBatch changeAnimationBehavior = action((behavior: string) => { - const lanch = this.destinationAnchor; + const lanch = this.sourceAnchor; if (lanch) { lanch.presEffect = behavior; } @@ -1417,7 +1417,7 @@ export class PropertiesView extends React.Component { @undoBatch @action updateEffectDirection = (effect: PresEffectDirection) => { - const lanch = this.destinationAnchor; + const lanch = this.sourceAnchor; if (lanch) { lanch.presEffectDirection = effect; } @@ -1425,7 +1425,7 @@ export class PropertiesView extends React.Component { @undoBatch animationDirection = (direction: PresEffectDirection, icon: string, gridColumn: number, gridRow: number, opts: object) => { - const lanch = this.destinationAnchor; + const lanch = this.sourceAnchor; const color = lanch?.presEffectDirection === direction || (direction === PresEffectDirection.Center && !lanch?.presEffectDirection) ? Colors.LIGHT_BLUE : 'black'; return ( {direction}
}> @@ -1451,7 +1451,7 @@ export class PropertiesView extends React.Component { document.getElementById('link_description_input')?.blur(); }; - onDescriptionKey = (e: React.KeyboardEvent) => { + onDescriptionKey = (e: React.KeyboardEvent) => { if (e.key === 'Enter') { this.setDescripValue(this.description); document.getElementById('link_description_input')?.blur(); @@ -1508,29 +1508,21 @@ export class PropertiesView extends React.Component { @computed get editDescription() { return ( - this.handleDescriptionChange(e.currentTarget.value)} className="text" - type="text" /> ); } // Converts seconds to ms and updates presTransition setZoom = (number: String, change?: number) => { - let scale = Number(number) / 100; - if (change) scale += change; - if (scale < 0.01) scale = 0.01; - if (scale > 1) scale = 1; - this.destinationAnchor && (this.destinationAnchor.presZoom = scale); - }; - // Converts seconds to ms and updates presTransition - setZoomSrc = (number: String, change?: number) => { let scale = Number(number) / 100; if (change) scale += change; if (scale < 0.01) scale = 0.01; @@ -1551,11 +1543,11 @@ export class PropertiesView extends React.Component { render() { const isNovice = Doc.noviceMode; - const zoom = Number((NumCast(this.destinationAnchor?.presZoom) * 100).toPrecision(3)); - const zoomSrc = Number((NumCast(this.sourceAnchor?.presZoom) * 100).toPrecision(3)); - const targZoom = this.destinationAnchor?.followLinkZoom; - const srcZooom = this.sourceAnchor?.followLinkZoom; - if (!this.selectedDoc && !this.isPres) { + const zoom = Number((NumCast(this.sourceAnchor?.presZoom, 1) * 100).toPrecision(3)); + const targZoom = this.sourceAnchor?.followLinkZoom; + const selectedDoc = this.selectedDoc; + const indent = 30; + if (!selectedDoc && !this.isPres) { return (
@@ -1564,7 +1556,7 @@ export class PropertiesView extends React.Component {
); } else { - if (this.selectedDoc && !this.isPres) { + if (selectedDoc && !this.isPres) { return (
{ {this.contextsSubMenu} {this.linksSubMenu} - {!this.selectedDoc || !LinkManager.currentLink ? null : ( + {!selectedDoc || !LinkManager.currentLink || !SelectionManager.Views().some(dv => DocListCast(dv.rootDoc.links).includes(LinkManager.currentLink!)) ? null : ( <>
-
-

Link Relationship

+
+

Relationship

{this.editRelationship}
-
+

Description

{this.editDescription}
-
-

Follow Behavior

- this.changeFollowBehavior(e.currentTarget.value)} value={StrCast(selectedDoc.followLinkLocation, 'default')}> - - - - - - - - - {this.selectedDoc.linksToAnnotation ? : null} + + + + + + + + + {selectedDoc.linksToAnnotation ? : null}
-
-

Target Effect

- this.changeAnimationBehavior(e.currentTarget.value)} value={StrCast(this.sourceAnchor?.presEffect, 'default')}> {[PresEffect.None, PresEffect.Zoom, PresEffect.Lightspeed, PresEffect.Fade, PresEffect.Flip, PresEffect.Rotate, PresEffect.Bounce, PresEffect.Roll].map(effect => ( ))} -
+
{this.animationDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})} {this.animationDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})} {this.animationDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})} @@ -1625,20 +1617,27 @@ export class PropertiesView extends React.Component { {this.animationDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })}
- {PresBox.inputter('0.1', '0.1', '10', NumCast(this.destinationAnchor?.presTransition) / 1000, true, (val: string) => - PresBox.SetTransitionTime(val, (timeInMS: number) => this.destinationAnchor && (this.destinationAnchor.presTransition = timeInMS)) + {PresBox.inputter( + '0.1', + '0.1', + '10', + NumCast(this.sourceAnchor?.presTransition) / 1000, + true, + (val: string) => PresBox.SetTransitionTime(val, (timeInMS: number) => this.sourceAnchor && (this.sourceAnchor.presTransition = timeInMS)), + indent )}{' '}
Fast
-
Medium
Slow
{' '}
@@ -1652,39 +1651,35 @@ export class PropertiesView extends React.Component {
+

Show link

+ +
+

Auto-move anchor

-
-

Show link

- -
-
+

Display arrow

-
-

Zoom to target (% screen filled)

-
- +
+

Zoom % screen

+
+
this.setZoom(String(zoom), 0.1))}> @@ -1695,36 +1690,28 @@ export class PropertiesView extends React.Component {
-
- {!targZoom ? null : PresBox.inputter('0', '1', '100', zoom, true, this.setZoom)} -
-

Zoom to source (% screen filled)

-
- -
-
this.setZoomSrc(String(zoomSrc), 0.1))}> - -
-
this.setZoomSrc(String(zoomSrc), -0.1))}> - -
-
-
-
- {!srcZooom ? null : PresBox.inputter('0', '1', '100', zoomSrc, true, this.setZoomSrc)} + {!targZoom ? null : PresBox.inputter('0', '1', '100', zoom, true, this.setZoom, 30)} +
+
0%
+
100%
+
{' '}
)} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index a4131d7c0..b39fcbd48 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -230,7 +230,6 @@ export class CollectionFreeFormLinkView extends React.Component (LinkManager.currentLink = this.props.LinkDocs[0]))); if (!this.renderData) return null; const { a, b, pt1norm, pt2norm, aActive, bActive, textX, textY, pt1, pt2 } = this.renderData; diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx index ef75fb159..a22999f52 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx @@ -31,6 +31,7 @@ import { OverlayView } from '../../OverlayView'; import { CollectionView } from '../CollectionView'; import './CollectionSchemaView.scss'; import { OpenWhere } from '../../nodes/DocumentView'; +import { PinProps } from '../../nodes/trails'; // intialize cell properties export interface CellProps { @@ -48,7 +49,7 @@ export interface CellProps { renderDepth: number; // called when a button is pressed on the node itself addDocTab: (document: Doc, where: OpenWhere) => boolean; - pinToPres: (document: Doc) => void; + pinToPres: (document: Doc, pinProps: PinProps) => void; moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; isFocused: boolean; changeFocusedCellByIndex: (row: number, col: number) => void; diff --git a/src/client/views/collections/collectionSchema/SchemaTable.tsx b/src/client/views/collections/collectionSchema/SchemaTable.tsx index 45ad4f86b..16910cc83 100644 --- a/src/client/views/collections/collectionSchema/SchemaTable.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTable.tsx @@ -24,6 +24,7 @@ import '../../../views/DocumentDecorations.scss'; import { ContextMenu } from '../../ContextMenu'; import { COLLECTION_BORDER_WIDTH, SCHEMA_DIVIDER_WIDTH } from '../../global/globalCssVariables.scss'; import { DocumentView, OpenWhere } from '../../nodes/DocumentView'; +import { PinProps } from '../../nodes/trails'; import { DefaultStyleProvider } from '../../StyleProvider'; import { CollectionView } from '../CollectionView'; import { @@ -87,7 +88,7 @@ export interface SchemaTableProps { active: (outsideReaction: boolean | undefined) => boolean | undefined; onDrop: (e: React.DragEvent, options: DocumentOptions, completed?: (() => void) | undefined) => void; addDocTab: (document: Doc, where: OpenWhere) => boolean; - pinToPres: (document: Doc) => void; + pinToPres: (document: Doc, pinProps: PinProps) => void; isSelected: (outsideReaction?: boolean) => boolean; isFocused: (document: Doc, outsideReaction: boolean) => boolean; setFocused: (document: Doc) => void; diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx index 07c20dae4..01e33708a 100644 --- a/src/client/views/linking/LinkEditor.tsx +++ b/src/client/views/linking/LinkEditor.tsx @@ -252,7 +252,7 @@ export class LinkEditor extends React.Component { get followingDropdown() { return (
-
Follow Behavior:
+
Follow by:
{StrCast(this.props.linkDoc.followLinkLocation, 'default')} @@ -263,28 +263,28 @@ export class LinkEditor extends React.Component { Default
this.changeFollowBehavior('add:left')}> - Always open in new left pane + Always opening in new left pane
this.changeFollowBehavior('add:right')}> - Always open in new right pane + Always opening in new right pane
this.changeFollowBehavior('replace:right')}> - Always replace right tab + Always replacing right tab
this.changeFollowBehavior('replace:left')}> - Always replace left tab + Always replacing left tab
this.changeFollowBehavior('fullScreen')}> - Always open full screen + Always opening full screen
this.changeFollowBehavior('add')}> - Always open in a new tab + Always opening in a new tab
this.changeFollowBehavior('replace')}> - Replace Tab + Replacing Tab
this.changeFollowBehavior('inPlace')}> - In Place + Opening in Place
{this.props.linkDoc.linksToAnnotation ? (
this.changeFollowBehavior('openExternal')}> @@ -320,7 +320,7 @@ export class LinkEditor extends React.Component { get effectDropdown() { return (
-
Transition Effect:
+
Animation:
{StrCast(this.destinationAnchor.presEffect, 'default')} @@ -437,6 +437,8 @@ export class LinkEditor extends React.Component {
void; - clearLinkEditor: () => void; + clearLinkEditor?: () => void; } /** @@ -25,26 +26,24 @@ export class LinkMenu extends React.Component { @observable _editingLink?: Doc; @observable _linkMenuRef = React.createRef(); - @computed get position() { - return this.props.position ?? (dv => ({ x: dv?.left || 0, y: (dv?.bottom || 0) + 15 }))(this.props.docView.getBounds()); - } - - clear = action(() => { - this.props.clearLinkEditor(); - this._editingLink = undefined; - }); + clear = !this.props.clearLinkEditor + ? undefined + : action(() => { + this.props.clearLinkEditor?.(); + this._editingLink = undefined; + }); componentDidMount() { - document.addEventListener('pointerdown', this.onPointerDown, true); + this.props.clearLinkEditor && document.addEventListener('pointerdown', this.onPointerDown, true); } componentWillUnmount() { - document.removeEventListener('pointerdown', this.onPointerDown, true); + this.props.clearLinkEditor && document.removeEventListener('pointerdown', this.onPointerDown, true); } onPointerDown = action((e: PointerEvent) => { LinkDocPreview.Clear(); if (!this._linkMenuRef.current?.contains(e.target as any) && !this._editorRef.current?.contains(e.target as any)) { - this.clear(); + this.clear?.(); } }); @@ -67,13 +66,15 @@ export class LinkMenu extends React.Component { /> )); - return linkItems.length ? linkItems : this.props.position ? [<>] : [

No links have been created yet. Drag the linking button onto another document to create a link.

]; + return linkItems.length ? linkItems : this.props.style ? [<>] : [

No links have been created yet. Drag the linking button onto another document to create a link.

]; }; render() { const sourceDoc = this.props.docView.props.Document; + const style = this.props.style ?? (dv => ({ left: dv?.left || 0, top: this.props.docView.topMost ? undefined : (dv?.bottom || 0) + 15, bottom: this.props.docView.topMost ? 20 : undefined, maxWidth: 200 }))(this.props.docView.getBounds()); + return ( -
+
{this._editingLink ? (
(this._editingLink = undefined))} /> diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx index fa6a2f506..9d2082e21 100644 --- a/src/client/views/linking/LinkMenuGroup.tsx +++ b/src/client/views/linking/LinkMenuGroup.tsx @@ -1,19 +1,19 @@ -import { observer } from "mobx-react"; -import { observable, action } from "mobx"; -import { Doc, StrListCast } from "../../../fields/Doc"; -import { Id } from "../../../fields/FieldSymbols"; -import { Cast } from "../../../fields/Types"; -import { LinkManager } from "../../util/LinkManager"; -import { DocumentView } from "../nodes/DocumentView"; +import { observer } from 'mobx-react'; +import { observable, action } from 'mobx'; +import { Doc, StrListCast } from '../../../fields/Doc'; +import { Id } from '../../../fields/FieldSymbols'; +import { Cast } from '../../../fields/Types'; +import { LinkManager } from '../../util/LinkManager'; +import { DocumentView } from '../nodes/DocumentView'; import './LinkMenu.scss'; -import { LinkMenuItem } from "./LinkMenuItem"; -import React = require("react"); +import { LinkMenuItem } from './LinkMenuItem'; +import React = require('react'); interface LinkMenuGroupProps { sourceDoc: Doc; group: Doc[]; groupType: string; - clearLinkEditor: () => void; + clearLinkEditor?: () => void; showEditor: (linkDoc: Doc) => void; docView: DocumentView; itemHandler?: (doc: Doc) => void; @@ -26,49 +26,52 @@ export class LinkMenuGroup extends React.Component { getBackgroundColor = (): string => { const linkRelationshipList = StrListCast(Doc.UserDoc().linkRelationshipList); const linkColorList = StrListCast(Doc.UserDoc().linkColorList); - let color = "white"; + let color = 'white'; // if this link's relationship property is not default "link", set its color if (linkRelationshipList) { const relationshipIndex = linkRelationshipList.indexOf(this.props.groupType); const RGBcolor: string = linkColorList[relationshipIndex]; if (RGBcolor) { //set opacity to 0.25 by modifiying the rgb string - color = RGBcolor.slice(0, RGBcolor.length - 1) + ", 0.25)"; + color = RGBcolor.slice(0, RGBcolor.length - 1) + ', 0.25)'; } } return color; - } + }; @observable _collapsed = false; render() { const set = new Set(this.props.group); const groupItems = Array.from(set.keys()).map(linkDoc => { - const destination = LinkManager.getOppositeAnchor(linkDoc, this.props.sourceDoc) || + const destination = + LinkManager.getOppositeAnchor(linkDoc, this.props.sourceDoc) || LinkManager.getOppositeAnchor(linkDoc, Cast(linkDoc.anchor2, Doc, null).annotationOn === this.props.sourceDoc ? Cast(linkDoc.anchor2, Doc, null) : Cast(linkDoc.anchor1, Doc, null)); if (destination && this.props.sourceDoc) { - return ; + return ( + + ); } }); return (
-
this._collapsed = !this._collapsed)} style={{ background: this.getBackgroundColor() }}> -

{this.props.groupType}:

+
(this._collapsed = !this._collapsed))} style={{ background: this.getBackgroundColor() }}> +

{this.props.groupType}:

- {this._collapsed ? (null) :
- {groupItems} -
} -
+ {this._collapsed ? null :
{groupItems}
} +
); } -} \ No newline at end of file +} diff --git a/src/client/views/linking/LinkMenuItem.scss b/src/client/views/linking/LinkMenuItem.scss index 2ca97a27d..806a2c381 100644 --- a/src/client/views/linking/LinkMenuItem.scss +++ b/src/client/views/linking/LinkMenuItem.scss @@ -79,7 +79,6 @@ font-size: 9px; line-height: 0.9; margin-left: 20px; - max-width: 125px; height: auto; white-space: break-spaces; } @@ -110,7 +109,7 @@ background-color: rgb(201, 239, 252); .linkMenu-item-buttons { - display: flex; + opacity: 1; } .linkMenu-item-content { @@ -127,7 +126,8 @@ .linkMenu-item-buttons { //@extend: right; position: relative; - display: none; + display: flex; + opacity: 0; .button { width: 20px; diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index c3b5fa997..c3705b0e1 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -12,13 +12,12 @@ import { DocumentManager } from '../../util/DocumentManager'; import { DragManager } from '../../util/DragManager'; import { LinkFollower } from '../../util/LinkFollower'; import { LinkManager } from '../../util/LinkManager'; +import { SettingsManager } from '../../util/SettingsManager'; +import { undoBatch } from '../../util/UndoManager'; import { DocumentView } from '../nodes/DocumentView'; import { LinkDocPreview } from '../nodes/LinkDocPreview'; import './LinkMenuItem.scss'; import React = require('react'); -import { SettingsManager } from '../../util/SettingsManager'; -import { SelectionManager } from '../../util/SelectionManager'; -import { undoBatch } from '../../util/UndoManager'; interface LinkMenuItemProps { groupType: string; @@ -26,7 +25,7 @@ interface LinkMenuItemProps { docView: DocumentView; sourceDoc: Doc; destinationDoc: Doc; - clearLinkEditor: () => void; + clearLinkEditor?: () => void; showEditor: (linkDoc: Doc) => void; menuRef: React.Ref; itemHandler?: (doc: Doc) => void; @@ -71,7 +70,6 @@ export class LinkMenuItem extends React.Component { private _drag = React.createRef(); _editRef = React.createRef(); - _buttonRef = React.createRef(); @observable private _showMore: boolean = false; @action toggleShowMore(e: React.PointerEvent) { @@ -89,7 +87,6 @@ export class LinkMenuItem extends React.Component { } @action onEdit = (e: React.PointerEvent) => { - const sel = SelectionManager.Views(); LinkManager.currentLink = this.props.linkDoc === LinkManager.currentLink ? undefined : this.props.linkDoc; LinkManager.currentLinkAnchor = this.sourceAnchor; setupMoveUpEvents( @@ -119,12 +116,12 @@ export class LinkMenuItem extends React.Component { const eleClone: any = this._drag.current!.cloneNode(true); eleClone.style.transform = `translate(${e.x}px, ${e.y}px)`; StartLinkTargetsDrag(eleClone, this.props.docView, e.x, e.y, this.props.sourceDoc, [this.props.linkDoc]); - this.props.clearLinkEditor(); + this.props.clearLinkEditor?.(); return true; }, emptyFunction, () => { - this.props.clearLinkEditor(); + this.props.clearLinkEditor?.(); if (this.props.itemHandler) { this.props.itemHandler?.(this.props.linkDoc); } else { @@ -167,20 +164,29 @@ export class LinkMenuItem extends React.Component {
- this.props.linkDoc && - LinkDocPreview.SetLinkInfo({ - docProps: this.props.docView.props, - linkSrc: this.props.sourceDoc, - linkDoc: this.props.linkDoc, - showHeader: false, - location: [this._drag.current?.getBoundingClientRect().right ?? 100, this._drag.current?.getBoundingClientRect().top ?? e.clientY], - noPreview: false, - }) - } onPointerDown={this.onLinkButtonDown}> -
+
+ Edit Link
}> +
e.stopPropagation()}> + +
+ +
+
+ this.props.linkDoc && + this.props.clearLinkEditor && + LinkDocPreview.SetLinkInfo({ + docProps: this.props.docView.props, + linkSrc: this.props.sourceDoc, + linkDoc: this.props.linkDoc, + showHeader: false, + location: [this._drag.current?.getBoundingClientRect().right ?? 100, this._drag.current?.getBoundingClientRect().top ?? e.clientY], + noPreview: false, + }) + }> {source ? (

{' '} @@ -198,14 +204,9 @@ export class LinkMenuItem extends React.Component { {!this.props.linkDoc.description ? null :

{StrCast(this.props.linkDoc.description)}

}
-
- Edit Link
}> -
e.stopPropagation()}> - -
- +
Delete Link
}> -
e.stopPropagation()}> +
e.stopPropagation()}>
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index b326865b3..097035661 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -12,12 +12,11 @@ import { DocumentType } from '../../documents/DocumentTypes'; import { DragManager } from '../../util/DragManager'; import { LinkFollower } from '../../util/LinkFollower'; import { LinkManager } from '../../util/LinkManager'; +import { SettingsManager } from '../../util/SettingsManager'; import { Transform } from '../../util/Transform'; -import { undoBatch } from '../../util/UndoManager'; import { DocumentView, DocumentViewSharedProps, OpenWhere } from './DocumentView'; import './LinkDocPreview.scss'; import React = require('react'); -import { LinkEditor } from '../linking/LinkEditor'; interface LinkDocPreviewProps { linkDoc?: Doc; @@ -123,17 +122,21 @@ export class LinkDocPreview extends React.Component { } return undefined; } - @observable _showEditor = false; @action editLink = (e: React.PointerEvent): void => { - LinkManager.currentLink = this.props.linkDoc; setupMoveUpEvents( this, e, returnFalse, emptyFunction, - action(() => (this._showEditor = !this._showEditor)) + action(() => { + LinkManager.currentLink = this._linkDoc === LinkManager.currentLink ? undefined : this._linkDoc; + LinkManager.currentLinkAnchor = this._linkSrc; + if ((SettingsManager.propertiesWidth ?? 0) < 100) { + SettingsManager.propertiesWidth = 250; + } + }) ); }; nextHref = (e: React.PointerEvent) => { @@ -181,22 +184,23 @@ export class LinkDocPreview extends React.Component { @computed get previewHeader() { return !this._linkDoc || !this._markerTargetDoc || !this._targetDoc || !this._linkSrc ? null : (
+
+ Edit Link
} placement="top"> +
+ +
+ +
{StrCast(this._markerTargetDoc.title).length > 16 ? StrCast(this._markerTargetDoc.title).substr(0, 16) + '...' : StrCast(this._markerTargetDoc.title)}

{StrCast(this._linkDoc.description)}

-
+
Next Link
} placement="top">
- - Edit Link
} placement="top"> -
- -
-
); @@ -280,9 +284,8 @@ export class LinkDocPreview extends React.Component { className="linkDocPreview" ref={this._linkDocRef} onPointerDown={this.followLinkPointerDown} - style={{ left: this.props.location[0], top: this.props.location[1], width: this._showEditor ? 'auto' : this.width() + borders, height: this._showEditor ? 'max-content' : this.height() + borders + (this.props.showHeader ? 37 : 0) }}> - {this._showEditor ? null : this.docPreview} - {!this._showEditor || !this._linkSrc || !this._linkDoc ? null : (this._showEditor = !this._showEditor))} />} + style={{ left: this.props.location[0], top: this.props.location[1], width: this.width() + borders, height: this.height() + borders + (this.props.showHeader ? 37 : 0) }}> + {this.docPreview}
); } diff --git a/src/client/views/nodes/LoadingBox.scss b/src/client/views/nodes/LoadingBox.scss index d63ed2575..4c3b8dabe 100644 --- a/src/client/views/nodes/LoadingBox.scss +++ b/src/client/views/nodes/LoadingBox.scss @@ -6,6 +6,13 @@ background-color: #fdfdfd; height: 100%; align-items: center; + .textContainer, + .text { + overflow: hidden; + text-overflow: ellipsis; + max-width: 80%; + text-align: center; + } } .textContainer { @@ -17,14 +24,6 @@ align-content: center; } -.textContainer, -.text { - overflow: hidden; - text-overflow: ellipsis; - max-width: 80%; - text-align: center; -} - .headerText { text-align: center; font-weight: bold; diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 1cb6bc3a2..c04b79a1e 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -1199,7 +1199,7 @@ export class PresBox extends ViewBoxBaseComponent() { _batch: UndoManager.Batch | undefined = undefined; - public static inputter = (min: string, step: string, max: string, value: number, active: boolean, change: (val: string) => void) => { + public static inputter = (min: string, step: string, max: string, value: number, active: boolean, change: (val: string) => void, hmargin?:number) => { let batch: any; return ( () { min={min} max={max} value={value} + style={{marginLeft: hmargin, marginRight:hmargin, width: `calc(100% - ${2*(hmargin??0)}px)`}} className={`toolbar-slider ${active ? '' : 'none'}`} onPointerDown={e => { batch = UndoManager.StartBatch('pres slider'); -- cgit v1.2.3-70-g09d2 From 66184a172006de4d4bf72d9da33858e04d298181 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 1 Dec 2022 10:13:03 -0500 Subject: refactored process of following links / jumping to docs and added following options for zoomTime, etc instead of setting temporary fields on docs. --- src/client/documents/Documents.ts | 8 +- src/client/util/DocumentManager.ts | 98 +++--- .../util/Import & Export/DirectoryImportBox.tsx | 334 +++++++++++---------- src/client/util/LinkFollower.ts | 84 +++--- src/client/util/SharingManager.tsx | 2 +- src/client/views/DocComponent.tsx | 2 +- src/client/views/InkingStroke.tsx | 6 +- src/client/views/MainView.tsx | 2 +- src/client/views/MarqueeAnnotator.tsx | 2 +- src/client/views/PropertiesView.tsx | 28 +- .../views/collections/CollectionNoteTakingView.tsx | 5 +- .../views/collections/CollectionStackingView.tsx | 5 +- src/client/views/collections/TabDocView.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 8 +- .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- .../collectionLinear/CollectionLinearView.tsx | 2 +- .../collectionSchema/CollectionSchemaCells.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 26 +- src/client/views/nodes/ImageBox.tsx | 8 +- src/client/views/nodes/PDFBox.tsx | 13 +- src/client/views/nodes/VideoBox.tsx | 6 +- src/client/views/nodes/WebBox.tsx | 10 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 12 +- src/client/views/nodes/trails/PresBox.tsx | 24 +- src/client/views/pdf/Annotation.tsx | 4 +- src/client/views/pdf/PDFViewer.tsx | 8 +- src/client/views/search/SearchBox.tsx | 2 +- 27 files changed, 354 insertions(+), 353 deletions(-) (limited to 'src/client/views/collections/collectionSchema') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index eed839520..d13d96dd3 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -157,7 +157,7 @@ export class DocumentOptions { _contentBounds?: List; // the (forced) bounds of the document to display. format is: [left, top, right, bottom] _lockedPosition?: boolean; // lock the x,y coordinates of the document so that it can't be dragged _lockedTransform?: boolean; // lock the panx,pany and scale parameters of the document so that it be panned/zoomed - _isPushpin?: boolean; // whether document, when clicked, toggles display of its link target + _followLinkToggle?: boolean; // whether document, when clicked, toggles display of its link target _showTitle?: string; // field name to display in header (:hover is an optional suffix) _showCaption?: string; // which field to display in the caption area. leave empty to have no caption _scrollTop?: number; // scroll location for pdfs @@ -272,7 +272,7 @@ export class DocumentOptions { clipWidth?: number; // percent transition from before to after in comparisonBox dockingConfig?: string; annotationOn?: Doc; - isPushpin?: boolean; + followLinkToggle?: boolean; isGroup?: boolean; // whether a collection should use a grouping UI behavior _removeDropProperties?: List; // list of properties that should be removed from a document when it is dropped. e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document noteType?: string; @@ -1703,7 +1703,7 @@ export namespace DocUtils { } export function LeavePushpin(doc: Doc, annotationField: string) { - if (doc.isPushpin) return undefined; + if (doc.followLinkToggle) return undefined; const context = Cast(doc.context, Doc, null) ?? Cast(doc.annotationOn, Doc, null); const hasContextAnchor = DocListCast(doc.links).some(l => (l.anchor2 === doc && Cast(l.anchor1, Doc, null)?.annotationOn === context) || (l.anchor1 === doc && Cast(l.anchor2, Doc, null)?.annotationOn === context)); if (context && !hasContextAnchor && (context.type === DocumentType.VID || context.type === DocumentType.WEB || context.type === DocumentType.PDF || context.type === DocumentType.IMG)) { @@ -1711,7 +1711,7 @@ export namespace DocUtils { title: 'pushpin', label: '', annotationOn: Cast(doc.annotationOn, Doc, null), - isPushpin: true, + followLinkToggle: true, icon: 'map-pin', x: Cast(doc.x, 'number', null), y: Cast(doc.y, 'number', null), diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 4f02a8202..1b63b615b 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -5,7 +5,7 @@ import { Cast, DocCast } from '../../fields/Types'; import { returnFalse } from '../../Utils'; import { DocumentType } from '../documents/DocumentTypes'; import { LightboxView } from '../views/LightboxView'; -import { DocumentView, OpenWhereMod, ViewAdjustment } from '../views/nodes/DocumentView'; +import { DocFocusOptions, DocumentView, OpenWhereMod, ViewAdjustment } from '../views/nodes/DocumentView'; import { LinkAnchorBox } from '../views/nodes/LinkAnchorBox'; import { CollectionDockingView } from '../views/collections/CollectionDockingView'; import { CollectionFreeFormView } from '../views/collections/collectionFreeForm'; @@ -171,19 +171,13 @@ export class DocumentManager { }; public jumpToDocument = ( targetDoc: Doc, // document to display - willZoom: boolean, // whether to zoom doc to take up most of screen + options: DocFocusOptions, // options for how to navigate to target createViewFunc = DocumentManager.addView, // how to create a view of the doc if it doesn't exist docContext: Doc[], // context to load that should contain the target - linkDoc?: Doc, // link that's being followed - closeContextIfNotFound: boolean = false, // after opening a context where the document should be, this determines whether the context should be closed if the Doc isn't actually there - originatingDoc: Opt = undefined, // doc that initiated the display of the target odoc - finished?: () => void, - originalTarget?: Doc, - noSelect?: boolean, - presZoomScale?: number + finished?: () => void ): void => { - originalTarget = originalTarget ?? targetDoc; - const docView = this.getFirstDocumentView(targetDoc, originatingDoc); + const originalTarget = options.originalTarget ?? targetDoc; + const docView = this.getFirstDocumentView(targetDoc, options.originatingDoc); const annotatedDoc = Cast(targetDoc.annotationOn, Doc, null); const resolvedTarget = targetDoc.type === DocumentType.MARKER ? annotatedDoc ?? docView?.rootDoc ?? targetDoc : docView?.rootDoc ?? targetDoc; // if target is a marker, then focus toggling should apply to the document it's on since the marker itself doesn't have a hidden field var wasHidden = resolvedTarget.hidden; @@ -195,14 +189,14 @@ export class DocumentManager { } const focusAndFinish = (didFocus: boolean) => { const finalTargetDoc = resolvedTarget; - if (originatingDoc?.isPushpin) { + if (options.toggleTarget) { if (!didFocus && !wasHidden) { // don't toggle the hidden state if the doc was already un-hidden as part of this document traversal finalTargetDoc.hidden = !finalTargetDoc.hidden; } } else { finalTargetDoc.hidden && (finalTargetDoc.hidden = undefined); - !noSelect && docView?.select(false); + !options.noSelect && docView?.select(false); } finished?.(); }; @@ -216,9 +210,8 @@ export class DocumentManager { if (annoContainerView.props.Document.layoutKey === 'layout_icon') { annoContainerView.iconify(() => annoContainerView.focus(targetDoc, { + ...options, originalTarget, - willZoom, - scale: presZoomScale, afterFocus: (didFocus: boolean) => new Promise(res => { focusAndFinish(true); @@ -232,13 +225,12 @@ export class DocumentManager { } } if (focusView) { - !noSelect && Doc.linkFollowHighlight(focusView.rootDoc, undefined, targetDoc); //TODO:glr make this a setting in PresBox - if (originatingDoc?.followLinkAudio) DocumentManager.playAudioAnno(focusView.rootDoc); + !options.noSelect && Doc.linkFollowHighlight(focusView.rootDoc, undefined, targetDoc); //TODO:glr make this a setting in PresBox + if (options.playAudio) DocumentManager.playAudioAnno(focusView.rootDoc); const doFocus = (forceDidFocus: boolean) => - focusView.focus(originalTarget ?? targetDoc, { + focusView.focus(originalTarget, { + ...options, originalTarget, - willZoom, - scale: presZoomScale, afterFocus: (didFocus: boolean) => new Promise(res => { focusAndFinish(forceDidFocus || didFocus); @@ -262,13 +254,12 @@ export class DocumentManager { targetDocContextView.rootDoc.hidden = false; // make sure context isn't hidden targetDocContext._viewTransition = 'transform 500ms'; targetDocContextView.props.focus(targetDocContextView.rootDoc, { - willZoom, + ...options, + // originalTarget, // needed? afterFocus: async () => { targetDocContext._viewTransition = undefined; if (targetDocContext.layoutKey === 'layout_icon') { - targetDocContextView.iconify(() => - this.jumpToDocument(resolvedTarget ?? targetDoc, willZoom, createViewFunc, docContext, linkDoc, closeContextIfNotFound, originatingDoc, finished, originalTarget, noSelect, presZoomScale) - ); + targetDocContextView.iconify(() => this.jumpToDocument(resolvedTarget ?? targetDoc, { ...options /* originalTarget - needed?*/ }, createViewFunc, docContext, finished)); } return ViewAdjustment.doNothing; }, @@ -281,56 +272,35 @@ export class DocumentManager { finished?.(); } else { // no timecode means we need to find the context view and focus on our target - const findView = (delay: number) => { - const retryDocView = this.getFirstDocumentView(resolvedTarget); // test again for the target view snce we presumably created the context above by focusing on it - if (retryDocView) { - // we found the target in the context. - Doc.linkFollowHighlight(retryDocView.rootDoc); - retryDocView.focus(targetDoc, { - willZoom, - afterFocus: (didFocus: boolean) => - new Promise(res => { - !noSelect && focusAndFinish(true); - res(ViewAdjustment.doNothing); - }), - }); // focus on the target in the context - } else if (delay > 1000) { - // we didn't find the target, so it must have moved out of the context. Go back to just creating it. - if (closeContextIfNotFound) targetDocContextView.props.removeDocument?.(targetDocContextView.rootDoc); - if (targetDoc.layout) { - // there will no layout for a TEXTANCHOR type document - createViewFunc(Doc.BrushDoc(targetDoc), finished); // create a new view of the target - } - } else { - setTimeout(() => findView(delay + 200), 200); - } - }; - setTimeout(() => findView(0), 0); + const retryDocView = this.getFirstDocumentView(resolvedTarget); // test again for the target view snce we presumably created the context above by focusing on it + if (retryDocView) { + // we found the target in the context. + Doc.linkFollowHighlight(retryDocView.rootDoc); + retryDocView.focus(targetDoc, { + ...options, + // originalTarget -- needed? + afterFocus: (didFocus: boolean) => + new Promise(res => { + !options.noSelect && focusAndFinish(true); + res(ViewAdjustment.doNothing); + }), + }); // focus on the target in the context + } else if (targetDoc.layout) { + // there will no layout for a TEXTANCHOR type document + createViewFunc(Doc.BrushDoc(targetDoc), finished); // create a new view of the target + } } } else { if (docContext.length && docContext[0]?.layoutKey === 'layout_icon') { const docContextView = this.getFirstDocumentView(docContext[0]); if (docContextView) { - return docContextView.iconify(() => - this.jumpToDocument(targetDoc, willZoom, createViewFunc, docContext.slice(1, docContext.length), linkDoc, closeContextIfNotFound, originatingDoc, finished, originalTarget, noSelect, presZoomScale) - ); + return docContextView.iconify(() => this.jumpToDocument(targetDoc, { ...options, originalTarget }, createViewFunc, docContext.slice(1, docContext.length), finished)); } } // there's no context view so we need to create one first and try again when that finishes createViewFunc( targetDocContext, // after creating the context, this calls the finish function that will retry looking for the target - () => - this.jumpToDocument( - targetDoc, - willZoom, - (doc: Doc, finished?: () => void) => doc !== targetDocContext && createViewFunc(doc, finished), - docContext, - linkDoc, - true /* if target not found, get rid of context just created */, - originatingDoc, - finished, - originalTarget - ) + () => this.jumpToDocument(targetDoc, { ...options, originalTarget }, (doc: Doc, finished?: () => void) => doc !== targetDocContext && createViewFunc(doc, finished), docContext, finished) ); } } diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx index 37571ae01..916eee4b7 100644 --- a/src/client/util/Import & Export/DirectoryImportBox.tsx +++ b/src/client/util/Import & Export/DirectoryImportBox.tsx @@ -1,27 +1,27 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { BatchedArray } from "array-batcher"; -import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; -import { observer } from "mobx-react"; -import { extname } from "path"; -import Measure, { ContentRect } from "react-measure"; -import { Doc, DocListCast, DocListCastAsync, Opt } from "../../../fields/Doc"; -import { Id } from "../../../fields/FieldSymbols"; -import { List } from "../../../fields/List"; -import { listSpec } from "../../../fields/Schema"; -import { SchemaHeaderField } from "../../../fields/SchemaHeaderField"; -import { BoolCast, Cast, NumCast } from "../../../fields/Types"; -import { AcceptableMedia, Upload } from "../../../server/SharedMediaTypes"; -import { Utils } from "../../../Utils"; -import { GooglePhotos } from "../../apis/google_docs/GooglePhotosClientUtils"; -import { Docs, DocumentOptions, DocUtils } from "../../documents/Documents"; -import { Networking } from "../../Network"; -import { FieldView, FieldViewProps } from "../../views/nodes/FieldView"; -import { DocumentManager } from "../DocumentManager"; -import "./DirectoryImportBox.scss"; -import ImportMetadataEntry, { keyPlaceholder, valuePlaceholder } from "./ImportMetadataEntry"; -import React = require("react"); +import { BatchedArray } from 'array-batcher'; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; +import { observer } from 'mobx-react'; +import { extname } from 'path'; +import Measure, { ContentRect } from 'react-measure'; +import { Doc, DocListCast, DocListCastAsync, Opt } from '../../../fields/Doc'; +import { Id } from '../../../fields/FieldSymbols'; +import { List } from '../../../fields/List'; +import { listSpec } from '../../../fields/Schema'; +import { SchemaHeaderField } from '../../../fields/SchemaHeaderField'; +import { BoolCast, Cast, NumCast } from '../../../fields/Types'; +import { AcceptableMedia, Upload } from '../../../server/SharedMediaTypes'; +import { Utils } from '../../../Utils'; +import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; +import { Docs, DocumentOptions, DocUtils } from '../../documents/Documents'; +import { Networking } from '../../Network'; +import { FieldView, FieldViewProps } from '../../views/nodes/FieldView'; +import { DocumentManager } from '../DocumentManager'; +import './DirectoryImportBox.scss'; +import ImportMetadataEntry, { keyPlaceholder, valuePlaceholder } from './ImportMetadataEntry'; +import React = require('react'); -const unsupported = ["text/html", "text/plain"]; +const unsupported = ['text/html', 'text/plain']; @observer export class DirectoryImportBox extends React.Component { @@ -29,7 +29,7 @@ export class DirectoryImportBox extends React.Component { @observable private top = 0; @observable private left = 0; private dimensions = 50; - @observable private phase = ""; + @observable private phase = ''; private disposer: Opt; @observable private entries: ImportMetadataEntry[] = []; @@ -40,7 +40,9 @@ export class DirectoryImportBox extends React.Component { @observable private uploading = false; @observable private removeHover = false; - public static LayoutString(fieldKey: string) { return FieldView.LayoutString(DirectoryImportBox, fieldKey); } + public static LayoutString(fieldKey: string) { + return FieldView.LayoutString(DirectoryImportBox, fieldKey); + } constructor(props: FieldViewProps) { super(props); @@ -71,7 +73,7 @@ export class DirectoryImportBox extends React.Component { handleSelection = async (e: React.ChangeEvent) => { runInAction(() => { this.uploading = true; - this.phase = "Initializing download..."; + this.phase = 'Initializing download...'; }); const docs: Doc[] = []; @@ -79,7 +81,7 @@ export class DirectoryImportBox extends React.Component { const files = e.target.files; if (!files || files.length === 0) return; - const directory = (files.item(0) as any).webkitRelativePath.split("/", 1)[0]; + const directory = (files.item(0) as any).webkitRelativePath.split('/', 1)[0]; const validated: File[] = []; for (let i = 0; i < files.length; i++) { @@ -100,7 +102,7 @@ export class DirectoryImportBox extends React.Component { const sizes: number[] = []; const modifiedDates: number[] = []; - runInAction(() => this.phase = `Internal: uploading ${this.quota - this.completed} files to Dash...`); + runInAction(() => (this.phase = `Internal: uploading ${this.quota - this.completed} files to Dash...`)); const batched = BatchedArray.from(validated, { batchSize: 15 }); const uploads = await batched.batchedMapAsync>(async (batch, collector) => { @@ -109,23 +111,28 @@ export class DirectoryImportBox extends React.Component { modifiedDates.push(file.lastModified); }); collector.push(...(await Networking.UploadFilesToServer(batch))); - runInAction(() => this.completed += batch.length); + runInAction(() => (this.completed += batch.length)); }); - await Promise.all(uploads.map(async response => { - const { source: { type }, result } = response; - if (result instanceof Error) { - return; - } - const { accessPaths, exifData } = result; - const path = Utils.prepend(accessPaths.agnostic.client); - const document = type && await DocUtils.DocumentFromType(type, path, { _width: 300 }); - const { data, error } = exifData; - if (document) { - Doc.GetProto(document).exif = error || Doc.Get.FromJson({ data }); - docs.push(document); - } - })); + await Promise.all( + uploads.map(async response => { + const { + source: { type }, + result, + } = response; + if (result instanceof Error) { + return; + } + const { accessPaths, exifData } = result; + const path = Utils.prepend(accessPaths.agnostic.client); + const document = type && (await DocUtils.DocumentFromType(type, path, { _width: 300 })); + const { data, error } = exifData; + if (document) { + Doc.GetProto(document).exif = error || Doc.Get.FromJson({ data }); + docs.push(document); + } + }) + ); for (let i = 0; i < docs.length; i++) { const doc = docs[i]; @@ -146,7 +153,7 @@ export class DirectoryImportBox extends React.Component { _height: 500, _chromeHidden: true, x: NumCast(doc.x), - y: NumCast(doc.y) + offset + y: NumCast(doc.y) + offset, }; const parent = this.props.ContainingCollectionView; if (parent) { @@ -154,14 +161,14 @@ export class DirectoryImportBox extends React.Component { if (docs.length < 50) { importContainer = Docs.Create.MasonryDocument(docs, options); } else { - const headers = [new SchemaHeaderField("title"), new SchemaHeaderField("size")]; + const headers = [new SchemaHeaderField('title'), new SchemaHeaderField('size')]; importContainer = Docs.Create.SchemaDocument(headers, docs, options); } - runInAction(() => this.phase = 'External: uploading files to Google Photos...'); + runInAction(() => (this.phase = 'External: uploading files to Google Photos...')); await GooglePhotos.Export.CollectionToAlbum({ collection: importContainer }); - Doc.AddDocToList(Doc.GetProto(parent.props.Document), "data", importContainer); + Doc.AddDocToList(Doc.GetProto(parent.props.Document), 'data', importContainer); !this.persistent && this.props.removeDocument && this.props.removeDocument(doc); - DocumentManager.Instance.jumpToDocument(importContainer, true, undefined, []); + DocumentManager.Instance.jumpToDocument(importContainer, { willZoom: true }, undefined, []); } runInAction(() => { @@ -169,14 +176,14 @@ export class DirectoryImportBox extends React.Component { this.quota = 1; this.completed = 0; }); - } + }; componentDidMount() { - this.selector.current!.setAttribute("directory", ""); - this.selector.current!.setAttribute("webkitdirectory", ""); + this.selector.current!.setAttribute('directory', ''); + this.selector.current!.setAttribute('webkitdirectory', ''); this.disposer = reaction( () => this.completed, - completed => runInAction(() => this.phase = `Internal: uploading ${this.quota - completed} files to Dash...`) + completed => runInAction(() => (this.phase = `Internal: uploading ${this.quota - completed} files to Dash...`)) ); } @@ -193,7 +200,7 @@ export class DirectoryImportBox extends React.Component { const offset = this.dimensions / 2; this.left = bounds.width / 2 - offset; this.top = bounds.height / 2 - offset; - } + }; @action addMetadataEntry = async () => { @@ -201,8 +208,8 @@ export class DirectoryImportBox extends React.Component { entryDoc.checked = false; entryDoc.key = keyPlaceholder; entryDoc.value = valuePlaceholder; - Doc.AddDocToList(this.props.Document, "data", entryDoc); - } + Doc.AddDocToList(this.props.Document, 'data', entryDoc); + }; @action remove = async (entry: ImportMetadataEntry) => { @@ -217,7 +224,7 @@ export class DirectoryImportBox extends React.Component { } } } - } + }; render() { const dimensions = 50; @@ -228,193 +235,204 @@ export class DirectoryImportBox extends React.Component { const uploading = this.uploading; const showRemoveLabel = this.removeHover; const persistent = this.persistent; - let percent = `${completed / quota * 100}`; - percent = percent.split(".")[0]; - percent = percent.startsWith("100") ? "99" : percent; + let percent = `${(completed / quota) * 100}`; + percent = percent.split('.')[0]; + percent = percent.startsWith('100') ? '99' : percent; const marginOffset = (percent.length === 1 ? 5 : 0) - 1.6; - const message = {this.phase}; - const centerPiece = this.phase.includes("Google Photos") ? - - :
{this.phase}; + const centerPiece = this.phase.includes('Google Photos') ? ( + + ) : ( +
{percent}%
; + color: 'white', + marginLeft: this.left + marginOffset, + }}> + {percent}% +
+ ); return ( - {({ measureRef }) => -
+ {({ measureRef }) => ( +
{message} + position: 'absolute', + display: 'none', + }} + />