From e9f8804a68327c64e1ade13081cab0b3b6c0ce21 Mon Sep 17 00:00:00 2001 From: bobzel Date: Sat, 15 Aug 2020 16:02:22 -0400 Subject: fixes for search -- need to rethink how to get a sortable string field (removed _s suffix for now). --- src/server/Search.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src/server') diff --git a/src/server/Search.ts b/src/server/Search.ts index decd1f5b1..3869867cd 100644 --- a/src/server/Search.ts +++ b/src/server/Search.ts @@ -7,11 +7,10 @@ export namespace Search { export async function updateDocument(document: any) { try { - const res = await rp.post(pathTo("update"), { + return await rp.post(pathTo("update"), { headers: { 'content-type': 'application/json' }, body: JSON.stringify([document]) }); - return res; } catch (e) { // console.warn("Search error: " + e + document); } @@ -19,11 +18,10 @@ export namespace Search { export async function updateDocuments(documents: any[]) { try { - const res = await rp.post(pathTo("update"), { + return await rp.post(pathTo("update"), { headers: { 'content-type': 'application/json' }, body: JSON.stringify(documents) }); - return res; } catch (e) { // console.warn("Search error: ", e, documents); } -- cgit v1.2.3-70-g09d2 From 0f50185738a1bef1e5f015b269ae022c60eba8e6 Mon Sep 17 00:00:00 2001 From: bobzel Date: Sat, 15 Aug 2020 20:38:39 -0400 Subject: cleaned up console.logs. fixed updating lastModified for SOLR --- src/client/views/collections/CollectionSchemaCells.tsx | 9 --------- src/client/views/collections/CollectionSchemaView.tsx | 1 - src/client/views/nodes/formattedText/DashDocView.tsx | 4 ++-- src/server/websocket.ts | 3 +++ 4 files changed, 5 insertions(+), 12 deletions(-) (limited to 'src/server') diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx index 81b63cbcd..003a1e9ff 100644 --- a/src/client/views/collections/CollectionSchemaCells.tsx +++ b/src/client/views/collections/CollectionSchemaCells.tsx @@ -69,16 +69,9 @@ export class CollectionSchemaCell extends React.Component { protected _document = this.props.rowProps.original; protected _dropDisposer?: DragManager.DragDropDisposer; - async componentWillMount() { - - } - async componentDidMount() { document.addEventListener("keydown", this.onKeyDown); - console.log("mounted"); - console.log(this.type); if (this.type === "context") { - console.log("mounted2"); const doc = Doc.GetProto(this.props.rowProps.original); const aliasdoc = await SearchUtil.GetAliasesOfDocument(doc); if (aliasdoc.length > 0) { @@ -425,14 +418,12 @@ export class CollectionSchemaCell extends React.Component { /> : this.returnHighlights(() => { - console.log(props.fieldKey); const dateCheck: Date | undefined = this.props.rowProps.original[this.props.rowProps.column.id as string] instanceof DateField ? DateCast(this.props.rowProps.original[this.props.rowProps.column.id as string]).date : undefined; if (dateCheck !== undefined) { cfield = dateCheck.toLocaleString(); } if (props.fieldKey === "context") { cfield = this.contents; - console.log("this should work"); } if (props.fieldKey === "*lastModified") { if (FieldValue(props.Document["data-lastModified"]) !== undefined) { diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 9c64178a8..6f8fb53ec 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -523,7 +523,6 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { @action onTablePointerDown = (e: React.PointerEvent): void => { - console.log("TB ptr " + e.screenX + " " + e.screenY); this.setFocused(this.props.Document); if (e.button === 0 && !e.altKey && !e.ctrlKey && !e.metaKey && this.props.isSelected(true)) { e.stopPropagation(); diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx index 212da3f3d..145ee8c2e 100644 --- a/src/client/views/nodes/formattedText/DashDocView.tsx +++ b/src/client/views/nodes/formattedText/DashDocView.tsx @@ -114,7 +114,7 @@ export class DashDocView extends React.Component { } /*endregion*/ - componentWillMount = () => { + componentWillUnmount = () => { this._reactionDisposer?.(); } @@ -254,7 +254,7 @@ export class DashDocView extends React.Component { whenActiveChanged={returnFalse} bringToFront={emptyFunction} dontRegisterView={false} - docFilters={this.props.tbox?.props.docFilters||returnEmptyFilter} + docFilters={this.props.tbox?.props.docFilters || returnEmptyFilter} ContainingCollectionView={this._textBox.props.ContainingCollectionView} ContainingCollectionDoc={this._textBox.props.ContainingCollectionDoc} ContentScaling={this.contentScaling} diff --git a/src/server/websocket.ts b/src/server/websocket.ts index ec351c283..b33e76c0b 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -290,6 +290,9 @@ export namespace WebSocket { if (term !== undefined) { const { suffix, value } = term; update[key + suffix] = { set: value }; + if (key.endsWith('lastModified')) { + update["lastModified" + suffix] = value; + } } } if (dynfield) { -- cgit v1.2.3-70-g09d2 From 561a8d0bd130ea5c1fd68a4dd2344f0333d388cc Mon Sep 17 00:00:00 2001 From: bobzel Date: Sun, 30 Aug 2020 13:10:54 -0400 Subject: fixed importBox upload to give feedback, share code. fixed stacking autoHeight to happen immediately. fixed images to not need to request image information. changed doc decorations to change image native width. changed alert() when dropping on impermissibale doc. fixed allow dropping over images,etc. changed default image nativeSize to 900 --- src/client/documents/Documents.ts | 23 +++++---- src/client/util/CurrentUserUtils.ts | 1 - src/client/views/DocumentDecorations.tsx | 6 +-- src/client/views/MainView.tsx | 56 +++++----------------- .../views/collections/CollectionStackingView.tsx | 9 ++++ src/client/views/collections/CollectionSubView.tsx | 3 +- src/client/views/collections/TabDocView.tsx | 4 +- .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- src/client/views/globalCssVariables.scss | 2 + src/client/views/globalCssVariables.scss.d.ts | 1 + src/client/views/nodes/DocumentView.tsx | 7 ++- src/client/views/nodes/ImageBox.tsx | 49 +++++++++++-------- src/mobile/ImageUpload.tsx | 8 ++-- src/server/ApiManagers/UploadManager.ts | 2 +- 14 files changed, 84 insertions(+), 89 deletions(-) (limited to 'src/server') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 262086735..9a24a8052 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1,5 +1,5 @@ -import { runInAction, action } from "mobx"; -import { extname, basename } from "path"; +import { runInAction } from "mobx"; +import { basename, extname } from "path"; import { DateField } from "../../fields/DateField"; import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym } from "../../fields/Doc"; import { HtmlField } from "../../fields/HtmlField"; @@ -12,21 +12,22 @@ import { ComputedField, ScriptField } from "../../fields/ScriptField"; import { Cast, NumCast, StrCast } from "../../fields/Types"; import { AudioField, ImageField, PdfField, VideoField, WebField, YoutubeField } from "../../fields/URLField"; import { MessageStore } from "../../server/Message"; +import { Upload } from "../../server/SharedMediaTypes"; import { OmitKeys, Utils } from "../../Utils"; import { YoutubeBox } from "../apis/youtube/YoutubeBox"; import { DocServer } from "../DocServer"; +import { Networking } from "../Network"; import { DocumentManager } from "../util/DocumentManager"; import { dropActionType } from "../util/DragManager"; import { DirectoryImportBox } from "../util/Import & Export/DirectoryImportBox"; import { LinkManager } from "../util/LinkManager"; import { Scripting } from "../util/Scripting"; -import { UndoManager, undoBatch } from "../util/UndoManager"; -import { DocumentType } from "./DocumentTypes"; -import { SearchBox } from "../views/search/SearchBox"; +import { undoBatch, UndoManager } from "../util/UndoManager"; import { CollectionDockingView } from "../views/collections/CollectionDockingView"; import { CollectionView, CollectionViewType } from "../views/collections/CollectionView"; import { ContextMenu } from "../views/ContextMenu"; import { ContextMenuProps } from "../views/ContextMenuItem"; +import { DFLT_IMAGE_NATIVE_DIM } from "../views/globalCssVariables.scss"; import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, InkingStroke } from "../views/InkingStroke"; import { AudioBox } from "../views/nodes/AudioBox"; import { ColorBox } from "../views/nodes/ColorBox"; @@ -46,11 +47,12 @@ import { SliderBox } from "../views/nodes/SliderBox"; import { VideoBox } from "../views/nodes/VideoBox"; import { WebBox } from "../views/nodes/WebBox"; import { PresElementBox } from "../views/presentationview/PresElementBox"; +import { SearchBox } from "../views/search/SearchBox"; import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo"; -import { Networking } from "../Network"; -import { Upload } from "../../server/SharedMediaTypes"; +import { DocumentType } from "./DocumentTypes"; const path = require('path'); +const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace("px", "")); export interface DocumentOptions { system?: boolean; _autoHeight?: boolean; @@ -146,6 +148,7 @@ export interface DocumentOptions { borderRounding?: string; boxShadow?: string; dontRegisterChildViews?: boolean; + dontRegisterView?: boolean; lookupField?: ScriptField; // script that returns the value of a field. This script is passed the rootDoc, layoutDoc, field, and container of the document. see PresBox. "onDoubleClick-rawScript"?: string; // onDoubleClick script in raw text form "onChildDoubleClick-rawScript"?: string; // onChildDoubleClick script in raw text form @@ -1210,8 +1213,10 @@ export namespace DocUtils { proto.text = result.rawText; proto.fileUpload = basename(pathname).replace("upload_", "").replace(/\.[a-z0-9]*$/, ""); if (Upload.isImageInformation(result)) { - proto["data-nativeWidth"] = (result.nativeWidth > result.nativeHeight) ? 400 * result.nativeWidth / result.nativeHeight : 400; - proto["data-nativeHeight"] = (result.nativeWidth > result.nativeHeight) ? 400 : 400 / (result.nativeWidth / result.nativeHeight); + const maxNativeDim = Math.min(Math.max(result.nativeHeight, result.nativeWidth), defaultNativeImageDim); + proto["data-nativeOrientation"] = result.exifData?.data?.image?.Orientation; + proto["data-nativeWidth"] = (result.nativeWidth < result.nativeHeight) ? maxNativeDim * result.nativeWidth / result.nativeHeight : maxNativeDim; + proto["data-nativeHeight"] = (result.nativeWidth < result.nativeHeight) ? maxNativeDim : maxNativeDim / (result.nativeWidth / result.nativeHeight); proto.contentSize = result.contentSize; } generatedDocuments.push(doc); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 260552879..b9dd18a36 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -864,7 +864,6 @@ export class CurrentUserUtils { } } - static setupClickEditorTemplates(doc: Doc) { if (doc["clickFuncs-child"] === undefined) { // to use this function, select it from the context menu of a collection. then edit the onChildClick script. Add two Doc variables: 'target' and 'thisContainer', then assign 'target' to some target collection. After that, clicking on any document in the initial collection will open it in the target diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 6db5186ba..de87b8aa5 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -475,10 +475,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> doc[DataSym][fieldKey + "-nativeHeight"] = doc._nativeHeight = nheight = doc._height || 0; } const anno = Cast(doc.annotationOn, Doc, null); - if (e.ctrlKey && anno) { + if (e.ctrlKey && (anno || doc.type === DocumentType.IMG)) { dW !== 0 && runInAction(() => { - const dataDoc = anno[DataSym]; - const annoFieldKey = Doc.LayoutFieldKey(anno); + const dataDoc = (anno ?? doc)[DataSym]; + const annoFieldKey = Doc.LayoutFieldKey(anno ?? doc); const nw = NumCast(dataDoc[annoFieldKey + "-nativeWidth"]); const nh = NumCast(dataDoc[annoFieldKey + "-nativeHeight"]); dataDoc[annoFieldKey + "-nativeWidth"] = nw + (dW > 0 ? 10 : -10); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 07ba7e805..338d9544e 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -9,7 +9,7 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; import Measure from 'react-measure'; import * as rp from 'request-promise'; -import { Doc, DocListCast, Field, Opt } from '../../fields/Doc'; +import { Doc, DocListCast, Field, Opt, DocListCastAsync } from '../../fields/Doc'; import { List } from '../../fields/List'; import { PrefetchProxy } from '../../fields/Proxy'; import { listSpec } from '../../fields/Schema'; @@ -18,7 +18,7 @@ import { TraceMobx } from '../../fields/util'; import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, simulateMouseClick, Utils } from '../../Utils'; import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { DocServer } from '../DocServer'; -import { Docs } from '../documents/Documents'; +import { Docs, DocUtils } from '../documents/Documents'; import { DocumentType } from '../documents/DocumentTypes'; import { Networking } from '../Network'; import { CurrentUserUtils } from '../util/CurrentUserUtils'; @@ -63,6 +63,8 @@ import { PDFMenu } from './pdf/PDFMenu'; import { PreviewCursor } from './PreviewCursor'; import { PropertiesView } from './PropertiesView'; import { SearchBox } from './search/SearchBox'; +import { CollectionSubView, CollectionSubViewLoader } from './collections/CollectionSubView'; +import ReactLoading from 'react-loading'; @observer export class MainView extends React.Component { @@ -847,8 +849,6 @@ export class MainView extends React.Component { } importDocument = () => { - const sidebar = Cast(Doc.UserDoc().myImportDocs, Doc, null); - const sidebarDocView = DocumentManager.Instance.getDocumentView(sidebar); const input = document.createElement("input"); input.type = "file"; input.multiple = true; @@ -864,55 +864,21 @@ export class MainView extends React.Component { const json = await response.json(); if (json !== "error") { const doc = await DocServer.GetRefField(json); - if (doc instanceof Doc && sidebarDocView) { - sidebarDocView.props.addDocument?.(doc); + if (doc instanceof Doc) { setTimeout(() => { SearchUtil.Search(`{!join from=id to=proto_i}id:link*`, true, {}).then(docs => { docs.docs.forEach(d => LinkManager.Instance.addLink(d)); }); }, 2000); // need to give solr some time to update so that this query will find any link docs we've added. - } } } else if (input.files && input.files.length !== 0) { - const files = input.files || []; - Array.from(files).forEach(async file => { - const res = await Networking.UploadFilesToServer(file); - res.map(async ({ result }) => { - const name = file.name; - if (result instanceof Error) { - return; - } - const path = Utils.prepend(result.accessPaths.agnostic.client); - let doc: Doc; - // Case 1: File is a video - if (file.type.includes("video")) { - doc = Docs.Create.VideoDocument(path, { _height: 100, title: name }); - // Case 2: File is a PDF document - } else if (file.type === "application/pdf") { - doc = Docs.Create.PdfDocument(path, { _height: 100, _fitWidth: true, title: name }); - // Case 3: File is an image - } else if (file.type.includes("image")) { - doc = Docs.Create.ImageDocument(path, { _height: 100, title: name }); - // Case 4: File is an audio document - } else { - doc = Docs.Create.AudioDocument(path, { title: name }); - } - const res = await rp.get(Utils.prepend("/getUserDocumentId")); - if (!res) { - throw new Error("No user id returned"); - } - const field = await DocServer.GetRefField(res); - let pending: Opt; - if (field instanceof Doc) { - pending = sidebar; - } - if (pending) { - const data = await Cast(pending.data, listSpec(Doc)); - if (data) data.push(doc); - else pending.data = new List([doc]); - } - }); + const importDocs = Cast(Doc.UserDoc().myImportDocs, Doc, null); + const disposer = OverlayView.Instance.addElement(, { x: 300, y: 200 }); + + DocListCastAsync(importDocs.data).then(async list => { + list?.push(... await DocUtils.uploadFilesToDocs(Array.from(input.files || []), {})); + disposer(); }); } else { console.log("No file selected"); diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 5386d617c..04c464b73 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -38,6 +38,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) _masonryGridRef: HTMLDivElement | null = null; _draggerRef = React.createRef(); _pivotFieldDisposer?: IReactionDisposer; + _autoHeightDisposer?: IReactionDisposer; _docXfs: any[] = []; _columnStart: number = 0; @observable _heightMap = new Map(); @@ -148,10 +149,12 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) () => this.pivotField, () => this.layoutDoc._columnHeaders = new List() ); + this._autoHeightDisposer = reaction(() => this.layoutDoc._autoHeight, this.forceAutoHeight); } componentWillUnmount() { super.componentWillUnmount(); this._pivotFieldDisposer?.(); + this._autoHeightDisposer?.(); } @action @@ -384,6 +387,11 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) return this.props.ScreenToLocalTransform().translate(offset[0], offset[1] + offsety); } + forceAutoHeight = () => { + const doc = this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc; + Doc.Layout(doc)._height = this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0); + } + sectionMasonry = (heading: SchemaHeaderField | undefined, docList: Doc[], first: boolean) => { const key = this.pivotField; let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined; @@ -450,6 +458,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) const subItems: ContextMenuProps[] = []; subItems.push({ description: `${this.layoutDoc._columnsFill ? "Variable Size" : "Autosize"} Column`, event: () => this.layoutDoc._columnsFill = !this.layoutDoc._columnsFill, icon: "plus" }); subItems.push({ description: `${this.layoutDoc._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" }); + subItems.push({ description: "Clear All", event: () => this.dataDoc.data = new List([]), icon: "times" }); ContextMenu.Instance.addItem({ description: "Options...", subitems: subItems, icon: "eye" }); } } diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index cb3f486bb..7820e2fa3 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -228,7 +228,8 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.props.Document); added = docDragData.moveDocument(movedDocs, this.props.Document, canAdd ? this.addDocument : returnFalse); } else added = res; - e.stopPropagation(); + added && e.stopPropagation(); + return added; } else { ScriptCast(this.props.Document.dropConverter)?.script.run({ dragData: docDragData }); added = this.addDocument(docDragData.droppedDocuments); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 5acf825f1..fb3de3b68 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -217,8 +217,8 @@ export class TabDocView extends React.Component { } ScreenToLocalTransform = () => { - if (this._mainCont && this._mainCont.children) { - const { translateX, translateY } = Utils.GetScreenTransform(this._mainCont.children[0].firstChild as HTMLElement); + if (this._mainCont?.children) { + const { translateX, translateY } = Utils.GetScreenTransform(this._mainCont.children[0]?.firstChild as HTMLElement); const scale = Utils.GetScreenTransform(this._mainCont).scale; return CollectionDockingView.Instance?.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(1 / this.contentScaling() / scale); } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 1aa30fc02..f928e3fb8 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -783,7 +783,7 @@ export class MarqueeView extends React.Component e.preventDefault()} onScroll={(e) => e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0} onClick={this.onClick} onPointerDown={this.onPointerDown}> {this._visible ? this.marqueeDiv : null} diff --git a/src/client/views/globalCssVariables.scss b/src/client/views/globalCssVariables.scss index 7eb07ff55..70a7946ba 100644 --- a/src/client/views/globalCssVariables.scss +++ b/src/client/views/globalCssVariables.scss @@ -36,6 +36,7 @@ $remoteCursors-zindex: 997; // ... not sure what level the remote cursors should $COLLECTION_BORDER_WIDTH: 1; $MINIMIZED_ICON_SIZE:25; $MAX_ROW_HEIGHT: 44px; +$DFLT_IMAGE_NATIVE_DIM: 900px; :export { contextMenuZindex: $contextMenu-zindex; @@ -45,4 +46,5 @@ $MAX_ROW_HEIGHT: 44px; SEARCH_THUMBNAIL_SIZE: $search-thumnail-size; ANTIMODEMENU_HEIGHT: $antimodemenu-height; SEARCH_PANEL_HEIGHT: $searchpanel-height; + DFLT_IMAGE_NATIVE_DIM: $DFLT_IMAGE_NATIVE_DIM; } \ No newline at end of file diff --git a/src/client/views/globalCssVariables.scss.d.ts b/src/client/views/globalCssVariables.scss.d.ts index fd1f60f13..531b38d68 100644 --- a/src/client/views/globalCssVariables.scss.d.ts +++ b/src/client/views/globalCssVariables.scss.d.ts @@ -7,6 +7,7 @@ interface IGlobalScss { SEARCH_THUMBNAIL_SIZE: string; ANTIMODEMENU_HEIGHT: string; SEARCH_PANEL_HEIGHT: string; + DFLT_IMAGE_NATIVE_DIM: string; } declare const globalCssVariables: IGlobalScss; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index f4eb71145..8c8562267 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -198,7 +198,7 @@ export class DocumentView extends DocComponent(Docu this._mainCont.current && (this._multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this))); // this._mainCont.current && (this.holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this))); - if (!this.props.dontRegisterView) { + if (!BoolCast(this.rootDoc.dontRegisterView, this.props.dontRegisterView)) { DocumentManager.Instance.DocumentViews.push(this); } } @@ -627,7 +627,10 @@ export class DocumentView extends DocComponent(Docu @undoBatch @action drop = async (e: Event, de: DragManager.DropEvent) => { if (this.props.Document === CurrentUserUtils.ActiveDashboard) { - alert("linking to document tabs not yet supported. Drop link on document content."); + if ((e.target as any)?.closest?.("*.lm_content")) { + alert("You can't perform this move most likely because you don't have permission to modify the destination."); + } + else alert("linking to document tabs not yet supported. Drop link on document content."); return; } const makeLink = action((linkDoc: Doc) => { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 6cce5fb87..688bac725 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, observable, runInAction } from 'mobx'; +import { action, computed, observable, runInAction, reaction, IReactionDisposer } from 'mobx'; import { observer } from "mobx-react"; import { DataSym, Doc, DocListCast, HeightSym, WidthSym } from '../../../fields/Doc'; import { documentSchema } from '../../../fields/documentSchemas'; @@ -26,7 +26,6 @@ import { FaceRectangles } from './FaceRectangles'; import { FieldView, FieldViewProps } from './FieldView'; import "./ImageBox.scss"; import React = require("react"); -const requestImageSize = require('../../util/request-image-size'); const path = require('path'); const { Howl } = require('howler'); @@ -63,6 +62,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent = React.createRef(); private _dropDisposer?: DragManager.DragDropDisposer; + private _pathDisposer?: IReactionDisposer; @observable private _audioState = 0; @observable static _showControls: boolean; @observable uploadIcon = uploadIcons.idle; @@ -72,6 +72,15 @@ export class ImageBox extends ViewBoxAnnotatableComponent this.paths.length && this.resize(this.paths[0]), + () => true, + { fireImmediately: true }); + } + componentWillUnmount() { + this._pathDisposer?.(); + } + @undoBatch @action drop = (e: Event, de: DragManager.DropEvent) => { @@ -242,29 +251,29 @@ export class ImageBox extends ViewBoxAnnotatableComponent { const basePath = imgPath.replace(/_[oms]./, ""); + const curPath = this.dataDoc[this.fieldKey + "-path"]; const cachedNativeSize = { - width: basePath === this.dataDoc[this.fieldKey + "-path"] ? NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]) : 0, - height: basePath === this.dataDoc[this.fieldKey + "-path"] ? NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]) : 0, + width: basePath === curPath || !curPath ? NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]) : 0, + height: basePath === curPath || !curPath ? NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]) : 0, }; const docAspect = this.layoutDoc[HeightSym]() / this.layoutDoc[WidthSym](); const cachedAspect = cachedNativeSize.height / cachedNativeSize.width; if (!cachedNativeSize.width || !cachedNativeSize.height || Math.abs(NumCast(this.layoutDoc._width) / NumCast(this.layoutDoc._height) - cachedNativeSize.width / cachedNativeSize.height) > 0.05) { if (!this.layoutDoc.isTemplateDoc || this.dataDoc !== this.layoutDoc) { - requestImageSize(imgPath).then(action((inquiredSize: any) => { - const rotation = NumCast(this.dataDoc[this.fieldKey + "-rotation"]) % 180; - const rotatedNativeSize = { width: inquiredSize.width, height: inquiredSize.height }; - if (inquiredSize.orientation === 6 || rotation === 90 || rotation === 270) { - rotatedNativeSize.width = inquiredSize.height; - rotatedNativeSize.height = inquiredSize.width; - } - const rotatedAspect = rotatedNativeSize.height / rotatedNativeSize.width; - if (this.layoutDoc[WidthSym]() && (!cachedNativeSize.width || !cachedNativeSize.height || Math.abs(1 - docAspect / rotatedAspect) > 0.1)) { - this.layoutDoc._height = this.layoutDoc[WidthSym]() * rotatedAspect; - this.dataDoc[this.fieldKey + "-nativeWidth"] = this.layoutDoc._nativeWidth = this.layoutDoc._width; - this.dataDoc[this.fieldKey + "-nativeHeight"] = this.layoutDoc._nativeHeight = this.layoutDoc._height; - this.dataDoc[this.fieldKey + "-path"] = basePath; - } - })).catch(console.log); + const rotation = NumCast(this.dataDoc[this.fieldKey + "-rotation"]) % 180; + const orientation = NumCast(this.dataDoc[this.fieldKey + "-nativeOrientation"]); + if (orientation === 6 || rotation === 90 || rotation === 270) { + this.layoutDoc._nativeWidth = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]); + this.layoutDoc._nativeHeight = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]); + } else { + this.layoutDoc._nativeWidth = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]); + this.layoutDoc._nativeHeight = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]); + } + const rotatedAspect = NumCast(this.layoutDoc._nativeHeight) / NumCast(this.layoutDoc._nativeWidth); + if (this.layoutDoc[WidthSym]() && (!cachedNativeSize.width || !cachedNativeSize.height || Math.abs(1 - docAspect / rotatedAspect) > 0.1)) { + this.layoutDoc._height = this.layoutDoc[WidthSym]() * rotatedAspect; + this.dataDoc[this.fieldKey + "-path"] = basePath; + } } else if (Math.abs(1 - docAspect / cachedAspect) > 0.1) { this.layoutDoc._width = this.layoutDoc[WidthSym]() || cachedNativeSize.width; this.layoutDoc._height = this.layoutDoc[WidthSym]() * cachedAspect; @@ -385,8 +394,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent(); +const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace("px", "")); @observer export class Uploader extends React.Component { @@ -52,13 +54,13 @@ export class Uploader extends React.Component { let doc = null; // Case 1: File is a video if (file.type === "video/mp4") { - doc = Docs.Create.VideoDocument(path, { _nativeWidth: 400, _width: 400, title: name }); + doc = Docs.Create.VideoDocument(path, { _nativeWidth: defaultNativeImageDim, _width: 400, title: name }); // Case 2: File is a PDF document } else if (file.type === "application/pdf") { - doc = Docs.Create.PdfDocument(path, { _nativeWidth: 400, _width: 400, _fitWidth: true, title: name }); + doc = Docs.Create.PdfDocument(path, { _nativeWidth: defaultNativeImageDim, _width: 400, _fitWidth: true, title: name }); // Case 3: File is another document type (most likely Image) } else { - doc = Docs.Create.ImageDocument(path, { _nativeWidth: 400, _width: 400, title: name }); + doc = Docs.Create.ImageDocument(path, { _nativeWidth: defaultNativeImageDim, _width: 400, title: name }); } this.setOpacity(4, "1"); // Slab 4 const res = await rp.get(Utils.prepend("/getUserDocumentId")); diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts index e088cd2c4..76f5afe16 100644 --- a/src/server/ApiManagers/UploadManager.ts +++ b/src/server/ApiManagers/UploadManager.ts @@ -55,7 +55,7 @@ export default class UploadManager extends ApiManager { const results: Upload.FileResponse[] = []; for (const key in files) { const result = await DashUploadUtils.upload(files[key]); - result && results.push(result); + result && !(result.result instanceof Error) && results.push(result); } _success(res, results); resolve(); -- cgit v1.2.3-70-g09d2 From 4ab5484797ccc39a4e7924135f92259c2b15d88f Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 1 Sep 2020 23:15:55 -0400 Subject: trying new solr schema that splits words on whitespace. fixed context menu clicking in schema/search view. --- solr-8.3.1/server/solr/dash/conf/characters.txt | 3 +++ solr-8.3.1/server/solr/dash/conf/schema.xml | 24 +++++++++++++--------- src/client/util/SearchUtil.ts | 4 ++-- src/client/views/MainView.tsx | 4 +++- src/client/views/PropertiesView.tsx | 15 +++++++++++--- .../CollectionSchemaMovableTableHOC.tsx | 1 + src/client/views/search/SearchBox.tsx | 2 +- src/server/ApiManagers/SearchManager.ts | 2 +- src/server/Search.ts | 5 ++--- 9 files changed, 39 insertions(+), 21 deletions(-) create mode 100644 solr-8.3.1/server/solr/dash/conf/characters.txt (limited to 'src/server') diff --git a/solr-8.3.1/server/solr/dash/conf/characters.txt b/solr-8.3.1/server/solr/dash/conf/characters.txt new file mode 100644 index 000000000..3a4c81bc8 --- /dev/null +++ b/solr-8.3.1/server/solr/dash/conf/characters.txt @@ -0,0 +1,3 @@ +\# => ALPHA +@ => ALPHA +\u0023 => ALPHA \ No newline at end of file diff --git a/solr-8.3.1/server/solr/dash/conf/schema.xml b/solr-8.3.1/server/solr/dash/conf/schema.xml index 74c4b494c..11078caeb 100644 --- a/solr-8.3.1/server/solr/dash/conf/schema.xml +++ b/solr-8.3.1/server/solr/dash/conf/schema.xml @@ -5,19 +5,23 @@ - + - - - - - + + + + + + + - - - - + + + + + + diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index b34acce27..b09eff849 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -23,7 +23,7 @@ export namespace SearchUtil { } export interface SearchParams { - hl?: boolean; + hl?: string; "hl.fl"?: string; start?: number; rows?: number; @@ -39,7 +39,7 @@ export namespace SearchUtil { export async function Search(query: string, returnDocs: boolean, options: SearchParams = {}) { query = query || "*"; //If we just have a filter query, search for * as the query const rpquery = Utils.prepend("/dashsearch"); - let replacedQuery = query.replace(/type_t:([^ )])/g, (substring, arg) => `{!join from=id to=proto_i}type_t:${arg}`); + let replacedQuery = query.replace(/type_t:([^ )])/g, (substring, arg) => `{!join from=id to=proto_i}*:* AND ${arg}`); if (options.onlyAliases) { const header = query.match(/_[atnb]?:/) ? replacedQuery : "DEFAULT:" + replacedQuery; replacedQuery = `{!join from=id to=proto_i}${header}`; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 7dddd1669..6db518f1e 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -55,6 +55,7 @@ import { PDFMenu } from './pdf/PDFMenu'; import { PreviewCursor } from './PreviewCursor'; import { PropertiesView } from './PropertiesView'; import { SearchBox } from './search/SearchBox'; +import { TraceMobx } from '../../fields/util'; const _global = (window /* browser */ || global /* node */) as any; @observer @@ -152,7 +153,7 @@ export class MainView extends React.Component { const targets = document.elementsFromPoint(e.x, e.y); if (targets.length) { const targClass = targets[0].className.toString(); - if (SearchBox.Instance._searchbarOpen) { + if (SearchBox.Instance._searchbarOpen || SearchBox.Instance.open) { const check = targets.some((thing) => (thing.className === "collectionSchemaView-searchContainer" || (thing as any)?.dataset.icon === "filter" || thing.className === "collectionSchema-header-menuOptions")); @@ -520,6 +521,7 @@ export class MainView extends React.Component { } @computed get search() { + TraceMobx(); return
{ const docs = SelectionManager.SelectedDocuments().length < 2 ? [this.dataDoc] : SelectionManager.SelectedDocuments().map(dv => dv.dataDoc); docs.forEach(doc => Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key))); const rows: JSX.Element[] = []; - const noviceReqFields = ["author", "creationDate"]; + const noviceReqFields = ["author", "creationDate", "tags"]; const noviceLayoutFields = ["_curPage"]; const noviceKeys = [...Array.from(Object.keys(ids)).filter(key => key[0] === "#" || key.indexOf("lastModified") !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith("ACL"))), ...noviceReqFields, ...noviceLayoutFields]; @@ -234,11 +234,20 @@ export class PropertiesView extends React.Component { docs.forEach(doc => { if (value.indexOf(":") !== -1) { const newVal = value[0].toUpperCase() + value.substring(1, value.length); - KeyValueBox.SetField(doc, newVal.substring(0, newVal.indexOf(":")), newVal.substring(newVal.indexOf(":") + 1, newVal.length), true); + const splits = newVal.split(":"); + KeyValueBox.SetField(doc, splits[0], splits[1], true); + const tags = StrCast(doc.tags, ":"); + if (tags.includes(`${splits[0]}:`) && splits[1] === "undefined") { + KeyValueBox.SetField(doc, "tags", `"${tags.replace(splits[0] + ":", "")}"`, true); + } return true; } else if (value[0] === "#") { const newVal = value + `:'${value}'`; - KeyValueBox.SetField(doc, newVal.substring(0, newVal.indexOf(":")), newVal.substring(newVal.indexOf(":") + 1, newVal.length), true); + KeyValueBox.SetField(doc, value, `'${value}'`, true); + const tags = StrCast(doc.tags, ":"); + if (!tags.includes(`#${value}:`)) { + KeyValueBox.SetField(doc, "tags", `"${tags + value + ':'}"`, true); + } return true; } }); diff --git a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx index 383a9312f..881246bd4 100644 --- a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx +++ b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx @@ -201,6 +201,7 @@ export class MovableRow extends React.Component { } onRowContextMenu = (e: React.MouseEvent): void => { + e.preventDefault(); 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" }); } diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index e6fd64a3c..3d564f073 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -286,7 +286,7 @@ export class SearchBox extends ViewBoxBaseComponent { while (this._results.length <= this._endIndex && (this._numTotalResults === -1 || this._maxSearchIndex < this._numTotalResults)) { - this._curRequest = SearchUtil.Search(query, true, { onlyAliases: true, allowAliases: true, /*sort: this.primarySort,*/ fq: this.filterQuery, start: 0, rows: this._numResultsPerPage, hl: true, "hl.fl": "*", }).then(action(async (res: SearchUtil.DocSearchResult) => { + this._curRequest = SearchUtil.Search(query, true, { onlyAliases: true, allowAliases: true, /*sort: this.primarySort,*/ fq: this.filterQuery, start: 0, rows: this._numResultsPerPage, hl: "on", "hl.fl": "*", }).then(action(async (res: SearchUtil.DocSearchResult) => { // happens at the beginning this.realTotalResults = res.numFound <= 0 ? 0 : res.numFound; if (res.numFound !== this._numTotalResults && this._numTotalResults === -1) { diff --git a/src/server/ApiManagers/SearchManager.ts b/src/server/ApiManagers/SearchManager.ts index a5aaab63e..a52430ee8 100644 --- a/src/server/ApiManagers/SearchManager.ts +++ b/src/server/ApiManagers/SearchManager.ts @@ -62,7 +62,7 @@ export class SearchManager extends ApiManager { subscription: "/dashsearch", secureHandler: async ({ req, res }) => { const solrQuery: any = {}; - ["q", "fq", "start", "rows", "sort", "hl", "hl.fl"].forEach(key => solrQuery[key] = req.query[key]); + ["q", "fq", "start", "rows", "sort", "hl.maxAnalyzedChars", "hl", "hl.fl"].forEach(key => solrQuery[key] = req.query[key]); if (solrQuery.q === undefined) { res.send([]); return; diff --git a/src/server/Search.ts b/src/server/Search.ts index 3869867cd..68f61deb2 100644 --- a/src/server/Search.ts +++ b/src/server/Search.ts @@ -29,9 +29,8 @@ export namespace Search { export async function search(query: any) { try { - const searchResults = JSON.parse(await rp.get(pathTo("select"), { - qs: query - })); + const output = await rp.get(pathTo("select"), { qs: query }); + const searchResults = JSON.parse(output); const { docs, numFound } = searchResults.response; const ids = docs.map((field: any) => field.id); return { ids, numFound, highlighting: searchResults.highlighting }; -- cgit v1.2.3-70-g09d2