diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/util/Import & Export/DirectoryImportBox.tsx | 12 | ||||
-rw-r--r-- | src/client/util/SearchUtil.ts | 23 | ||||
-rw-r--r-- | src/client/util/TooltipTextMenu.tsx | 42 | ||||
-rw-r--r-- | src/client/views/MainView.tsx | 5 | ||||
-rw-r--r-- | src/client/views/collections/ParentDocumentSelector.tsx | 4 | ||||
-rw-r--r-- | src/client/views/globalCssVariables.scss | 13 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 4 | ||||
-rw-r--r-- | src/client/views/pdf/PDFViewer.tsx | 1 | ||||
-rw-r--r-- | src/client/views/pdf/Page.tsx | 4 | ||||
-rw-r--r-- | src/client/views/search/FilterBox.tsx | 4 | ||||
-rw-r--r-- | src/client/views/search/SearchBox.tsx | 11 | ||||
-rw-r--r-- | src/client/views/search/SearchItem.tsx | 4 | ||||
-rw-r--r-- | src/server/Search.ts | 3 | ||||
-rw-r--r-- | src/server/authentication/controllers/user_controller.ts | 25 | ||||
-rw-r--r-- | src/server/authentication/models/user_model.ts | 2 | ||||
-rw-r--r-- | src/server/index.ts | 6 |
16 files changed, 117 insertions, 46 deletions
diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx index a810db0fa..c096e9ceb 100644 --- a/src/client/util/Import & Export/DirectoryImportBox.tsx +++ b/src/client/util/Import & Export/DirectoryImportBox.tsx @@ -8,7 +8,7 @@ import { FieldViewProps, FieldView } from "../../views/nodes/FieldView"; import Measure, { ContentRect } from "react-measure"; import { library } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faArrowUp, faTag, faPlus } from '@fortawesome/free-solid-svg-icons'; +import { faTag, faPlus, faCloudUploadAlt } from '@fortawesome/free-solid-svg-icons'; import { Docs, DocumentOptions } from "../../documents/Documents"; import { observer } from "mobx-react"; import ImportMetadataEntry, { keyPlaceholder, valuePlaceholder } from "./ImportMetadataEntry"; @@ -40,7 +40,7 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps> constructor(props: FieldViewProps) { super(props); - library.add(faArrowUp, faTag, faPlus); + library.add(faTag, faPlus); let doc = this.props.Document; this.editingMetadata = this.editingMetadata || false; this.persistent = this.persistent || false; @@ -237,12 +237,12 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps> }} /> <div style={{ position: "absolute", - left: this.left + 12.6, - top: this.top + 11, + left: this.left + 8, + top: this.top + 10, opacity: uploading ? 0 : 1, transition: "0.4s opacity ease" }}> - <FontAwesomeIcon icon={faArrowUp} color="#FFFFFF" size={"2x"} /> + <FontAwesomeIcon icon={faCloudUploadAlt} color="#FFFFFF" size={"2x"} /> </div> <img style={{ @@ -318,7 +318,7 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps> opacity: uploading ? 0 : 1, transition: "0.4s opacity ease" }} - icon={isEditing ? faArrowUp : faTag} + icon={isEditing ? faCloudUploadAlt : faTag} color="#FFFFFF" size={"1x"} /> diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index 674eeb1a8..806746496 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -14,11 +14,12 @@ export namespace SearchUtil { numFound: number; } - export function Search(query: string, returnDocs: true, start?: number, count?: number): Promise<DocSearchResult>; - export function Search(query: string, returnDocs: false, start?: number, count?: number): Promise<IdSearchResult>; - export async function Search(query: string, returnDocs: boolean, start?: number, rows?: number) { + export function Search(query: string, filterQuery: string | undefined, returnDocs: true, start?: number, count?: number): Promise<DocSearchResult>; + export function Search(query: string, filterQuery: string | undefined, returnDocs: false, start?: number, count?: number): Promise<IdSearchResult>; + export async function Search(query: string, filterQuery: string | undefined, returnDocs: boolean, start?: number, rows?: number) { + query = query || "*"; //If we just have a filter query, search for * as the query const result: IdSearchResult = JSON.parse(await rp.get(DocServer.prepend("/search"), { - qs: { query, start, rows } + qs: { query, filterQuery, start, rows }, })); if (!returnDocs) { return result; @@ -35,31 +36,31 @@ export namespace SearchUtil { const proto = Doc.GetProto(doc); const protoId = proto[Id]; if (returnDocs) { - return (await Search(`proto_i:"${protoId}"`, returnDocs)).docs; + return (await Search("", `proto_i:"${protoId}"`, returnDocs)).docs; } else { - return (await Search(`proto_i:"${protoId}"`, returnDocs)).ids; + return (await Search("", `proto_i:"${protoId}"`, returnDocs)).ids; } // return Search(`{!join from=id to=proto_i}id:${protoId}`, true); } export async function GetViewsOfDocument(doc: Doc): Promise<Doc[]> { - const results = await Search(`proto_i:"${doc[Id]}"`, true); + const results = await Search("", `proto_i:"${doc[Id]}"`, true); return results.docs; } export async function GetContextsOfDocument(doc: Doc): Promise<{ contexts: Doc[], aliasContexts: Doc[] }> { - const docContexts = (await Search(`data_l:"${doc[Id]}"`, true)).docs; + const docContexts = (await Search("", `data_l:"${doc[Id]}"`, true)).docs; const aliases = await GetAliasesOfDocument(doc, false); - const aliasContexts = (await Promise.all(aliases.map(doc => Search(`data_l:"${doc}"`, true)))); + const aliasContexts = (await Promise.all(aliases.map(doc => Search("", `data_l:"${doc}"`, true)))); const contexts = { contexts: docContexts, aliasContexts: [] as Doc[] }; aliasContexts.forEach(result => contexts.aliasContexts.push(...result.docs)); return contexts; } export async function GetContextIdsOfDocument(doc: Doc): Promise<{ contexts: string[], aliasContexts: string[] }> { - const docContexts = (await Search(`data_l:"${doc[Id]}"`, false)).ids; + const docContexts = (await Search("", `data_l:"${doc[Id]}"`, false)).ids; const aliases = await GetAliasesOfDocument(doc, false); - const aliasContexts = (await Promise.all(aliases.map(doc => Search(`data_l:"${doc}"`, false)))); + const aliasContexts = (await Promise.all(aliases.map(doc => Search("", `data_l:"${doc}"`, false)))); const contexts = { contexts: docContexts, aliasContexts: [] as string[] }; aliasContexts.forEach(result => contexts.aliasContexts.push(...result.ids)); return contexts; diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 9ba339285..fe7e0b97f 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -51,6 +51,7 @@ export class TooltipTextMenu { this.tooltip = document.createElement("div"); this.tooltip.className = "tooltipMenu"; + this.dragElement(this.tooltip); // this.createCollapse(); // if (this._collapseBtn) { // this.tooltip.appendChild(this._collapseBtn.render(this.view).dom); @@ -269,6 +270,47 @@ export class TooltipTextMenu { // this.tooltip.appendChild(this.linkEditor); } + dragElement(elmnt: HTMLElement) { + var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0; + if (elmnt) { + // if present, the header is where you move the DIV from: + elmnt.onpointerdown = dragMouseDown; + } + const self = this; + + function dragMouseDown(e: PointerEvent) { + e = e || window.event; + //e.preventDefault(); + // get the mouse cursor position at startup: + pos3 = e.clientX; + pos4 = e.clientY; + document.onpointerup = closeDragElement; + // call a function whenever the cursor moves: + document.onpointermove = elementDrag; + } + + function elementDrag(e: PointerEvent) { + e = e || window.event; + //e.preventDefault(); + // calculate the new cursor position: + pos1 = pos3 - e.clientX; + pos2 = pos4 - e.clientY; + pos3 = e.clientX; + pos4 = e.clientY; + // set the element's new position: + elmnt.style.top = (elmnt.offsetTop - pos2) + "px"; + elmnt.style.left = (elmnt.offsetLeft - pos1) + "px"; + } + + function closeDragElement() { + // stop moving when mouse button is released: + document.onpointerup = null; + document.onpointermove = null; + //self.highlightSearchTerms(self.state, ["hello"]); + //FormattedTextBox.Instance.unhighlightSearchTerms(); + } + } + makeLink = (target: string) => { let node = this.view.state.selection.$from.nodeAfter; let link = this.view.state.schema.mark(this.view.state.schema.marks.link, { href: target }); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 76cc7e6d3..ce7369220 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -1,5 +1,5 @@ import { IconName, library } from '@fortawesome/fontawesome-svg-core'; -import { faArrowDown, faArrowUp, faClone, faCheck, faCommentAlt, faCut, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faPortrait, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faThumbtack, faTree, faUndoAlt, faCat } from '@fortawesome/free-solid-svg-icons'; +import { faArrowDown, faCloudUploadAlt, faArrowUp, faClone, faCheck, faCommentAlt, faCut, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faPortrait, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faThumbtack, faTree, faUndoAlt, faCat } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, configure, observable, runInAction, reaction, trace } from 'mobx'; import { observer } from 'mobx-react'; @@ -130,6 +130,7 @@ export class MainView extends React.Component { library.add(faCheck); library.add(faArrowDown); library.add(faArrowUp); + library.add(faCloudUploadAlt); this.initEventListeners(); this.initAuthenticationRouters(); } @@ -382,7 +383,7 @@ export class MainView extends React.Component { let btns: [React.RefObject<HTMLDivElement>, IconName, string, () => Doc][] = [ [React.createRef<HTMLDivElement>(), "object-group", "Add Collection", addColNode], // [React.createRef<HTMLDivElement>(), "clone", "Add Docking Frame", addDockingNode], - [React.createRef<HTMLDivElement>(), "arrow-up", "Import Directory", addImportCollectionNode], + [React.createRef<HTMLDivElement>(), "cloud-upload-alt", "Import Directory", addImportCollectionNode], ]; if (!ClientUtils.RELEASE) btns.unshift([React.createRef<HTMLDivElement>(), "cat", "Add Cat Image", addImageNode]); diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx index c0f489cd8..a97aa4f36 100644 --- a/src/client/views/collections/ParentDocumentSelector.tsx +++ b/src/client/views/collections/ParentDocumentSelector.tsx @@ -23,9 +23,9 @@ export class SelectorContextMenu extends React.Component<SelectorProps> { async fetchDocuments() { let aliases = (await SearchUtil.GetAliasesOfDocument(this.props.Document)).filter(doc => doc !== this.props.Document); - const { docs } = await SearchUtil.Search(`data_l:"${this.props.Document[Id]}"`, true); + const { docs } = await SearchUtil.Search("", `data_l:"${this.props.Document[Id]}"`, true); const map: Map<Doc, Doc> = new Map; - const allDocs = await Promise.all(aliases.map(doc => SearchUtil.Search(`data_l:"${doc[Id]}"`, true).then(result => result.docs))); + const allDocs = await Promise.all(aliases.map(doc => SearchUtil.Search("", `data_l:"${doc[Id]}"`, true).then(result => result.docs))); allDocs.forEach((docs, index) => docs.forEach(doc => map.set(doc, aliases[index]))); docs.forEach(doc => map.delete(doc)); runInAction(() => { diff --git a/src/client/views/globalCssVariables.scss b/src/client/views/globalCssVariables.scss index fec105516..6dffee586 100644 --- a/src/client/views/globalCssVariables.scss +++ b/src/client/views/globalCssVariables.scss @@ -13,23 +13,26 @@ $darker-alt-accent: rgb(178, 206, 248); $intermediate-color: #9c9396; $dark-color: #121721; // fonts -$sans-serif: "Noto Sans", sans-serif; +$sans-serif: "Noto Sans", +sans-serif; // $sans-serif: "Roboto Slab", sans-serif; -$serif: "Crimson Text", serif; +$serif: "Crimson Text", +serif; // misc values $border-radius: 0.3em; // $search-thumnail-size: 175; - // dragged items -$contextMenu-zindex: 1000; // context menu shows up over everything +// dragged items +$contextMenu-zindex: 100000; // context menu shows up over everything $mainTextInput-zindex: 999; // then text input overlay so that it's context menu will appear over decorations, etc $docDecorations-zindex: 998; // then doc decorations appear over everything else $remoteCursors-zindex: 997; // ... not sure what level the remote cursors should go -- is this right? $COLLECTION_BORDER_WIDTH: 1; $MINIMIZED_ICON_SIZE:25; $MAX_ROW_HEIGHT: 44px; -:export { + +:export { contextMenuZindex: $contextMenu-zindex; COLLECTION_BORDER_WIDTH: $COLLECTION_BORDER_WIDTH; MINIMIZED_ICON_SIZE: $MINIMIZED_ICON_SIZE; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 2c1813482..f7a33466e 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -432,6 +432,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu anno.target = targetDoc; }); } + let pdfDoc = await Cast(annotationDoc.pdfDoc, Doc); + if (pdfDoc) { + DocUtils.MakeLink(annotationDoc, targetDoc, undefined, `Annotation from ${StrCast(pdfDoc.title)}`, "", StrCast(pdfDoc.title)); + } } if (de.data instanceof DragManager.LinkDragData) { let sourceDoc = de.data.linkSourceDocument; diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 01fd1c247..c560e581c 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -278,6 +278,7 @@ export class Viewer extends React.Component<IViewerProps> { if (de.data instanceof DragManager.LinkDragData) { let sourceDoc = de.data.linkSourceDocument; let destDoc = this.makeAnnotationDocument(sourceDoc, 1, "red"); + de.data.droppedDocuments.push(destDoc); let targetAnnotations = DocListCast(this.props.parent.fieldExtensionDoc.annotations); if (targetAnnotations) { targetAnnotations.push(destDoc); diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx index 3d8973414..c9d442fe5 100644 --- a/src/client/views/pdf/Page.tsx +++ b/src/client/views/pdf/Page.tsx @@ -176,6 +176,10 @@ export default class Page extends React.Component<IPageProps> { anno.target = targetDoc; }); } + let pdfDoc = await Cast(annotationDoc.pdfDoc, Doc); + if (pdfDoc) { + DocUtils.MakeLink(annotationDoc, targetDoc, undefined, `Annotation from ${StrCast(pdfDoc.title)}`, "", StrCast(pdfDoc.title)); + } } } }, diff --git a/src/client/views/search/FilterBox.tsx b/src/client/views/search/FilterBox.tsx index 435ca86e3..f11fb008c 100644 --- a/src/client/views/search/FilterBox.tsx +++ b/src/client/views/search/FilterBox.tsx @@ -237,6 +237,10 @@ export class FilterBox extends React.Component { return "+(" + finalColString + ")" + query; } + get filterTypes() { + return this._icons.length === 9 ? undefined : this._icons; + } + @action filterDocsByType(docs: Doc[]) { if (this._icons.length === 9) { diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index dc1d35b1c..3830a6d16 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -67,7 +67,7 @@ export class SearchBox extends React.Component { this._maxSearchIndex = 0; } - enter = (e: React.KeyboardEvent) => { if (e.key === "Enter") { this.submitSearch(); } } + enter = (e: React.KeyboardEvent) => { if (e.key === "Enter") { this.submitSearch(); } }; public static async convertDataUri(imageUri: string, returnedFilename: string) { try { @@ -113,7 +113,12 @@ export class SearchBox extends React.Component { } getAllResults = async (query: string) => { - return SearchUtil.Search(query, true, 0, 10000000); + return SearchUtil.Search(query, this.filterQuery, true, 0, 10000000); + } + + private get filterQuery() { + const types = FilterBox.Instance.filterTypes; + return "proto_i:*" + (types ? ` AND (${types.map(type => `({!join from=id to=proto_i}type_t:"${type}" AND NOT type_t:*) OR type_t:"${type}"`).join(" ")})` : ""); } @@ -124,7 +129,7 @@ export class SearchBox extends React.Component { } this.lockPromise = new Promise(async res => { while (this._results.length <= this._endIndex && (this._numTotalResults === -1 || this._maxSearchIndex < this._numTotalResults)) { - this._curRequest = SearchUtil.Search(query, true, this._maxSearchIndex, 10).then(action((res: SearchUtil.DocSearchResult) => { + this._curRequest = SearchUtil.Search(query, this.filterQuery, true, this._maxSearchIndex, 10).then(action((res: SearchUtil.DocSearchResult) => { // happens at the beginning if (res.numFound !== this._numTotalResults && this._numTotalResults === -1) { diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx index 16ad71d16..e34d101a8 100644 --- a/src/client/views/search/SearchItem.tsx +++ b/src/client/views/search/SearchItem.tsx @@ -51,9 +51,9 @@ export class SelectorContextMenu extends React.Component<SearchItemProps> { async fetchDocuments() { let aliases = (await SearchUtil.GetViewsOfDocument(this.props.doc)).filter(doc => doc !== this.props.doc); - const { docs } = await SearchUtil.Search(`data_l:"${this.props.doc[Id]}"`, true); + const { docs } = await SearchUtil.Search("", `data_l:"${this.props.doc[Id]}"`, true); const map: Map<Doc, Doc> = new Map; - const allDocs = await Promise.all(aliases.map(doc => SearchUtil.Search(`data_l:"${doc[Id]}"`, true).then(result => result.docs))); + const allDocs = await Promise.all(aliases.map(doc => SearchUtil.Search("", `data_l:"${doc[Id]}"`, true).then(result => result.docs))); allDocs.forEach((docs, index) => docs.forEach(doc => map.set(doc, aliases[index]))); docs.forEach(doc => map.delete(doc)); runInAction(() => { diff --git a/src/server/Search.ts b/src/server/Search.ts index 11092c5be..69e327d2d 100644 --- a/src/server/Search.ts +++ b/src/server/Search.ts @@ -30,11 +30,12 @@ export class Search { } } - public async search(query: string, start: number = 0, rows: number = 10) { + public async search(query: string, filterQuery: string = "", start: number = 0, rows: number = 10) { try { const searchResults = JSON.parse(await rp.get(this.url + "dash/select", { qs: { q: query, + fq: filterQuery, fl: "id", start, rows, diff --git a/src/server/authentication/controllers/user_controller.ts b/src/server/authentication/controllers/user_controller.ts index ca4fc171c..fa1cd647d 100644 --- a/src/server/authentication/controllers/user_controller.ts +++ b/src/server/authentication/controllers/user_controller.ts @@ -12,6 +12,9 @@ import * as nodemailer from 'nodemailer'; import c = require("crypto"); import { RouteStore } from "../../RouteStore"; import { Utils } from "../../../Utils"; +import { Schema } from "mongoose"; +import { Opt } from "../../../new_fields/Doc"; +import { MailOptions } from "nodemailer/lib/stream-transport"; /** * GET /signup @@ -45,21 +48,23 @@ export let postSignup = (req: Request, res: Response, next: NextFunction) => { return res.redirect(RouteStore.signup); } - const email = req.body.email; + const email = req.body.email as String; const password = req.body.password; - const user = new User({ - email, + const model = { + email: { type: email, unique: true }, password, userDocumentId: Utils.GenerateGuid() - }); + } as Partial<DashUserModel>; + + const user = new User(model); User.findOne({ email }, (err, existingUser) => { if (err) { return next(err); } if (existingUser) { return res.redirect(RouteStore.login); } - user.save((err) => { + user.save((err: any) => { if (err) { return next(err); } req.logIn(user, (err) => { if (err) { return next(err); } @@ -181,15 +186,15 @@ export let postForgot = function (req: Request, res: Response, next: NextFunctio } }); const mailOptions = { - to: user.email, + to: user.email.type, from: 'brownptcdash@gmail.com', subject: 'Dash Password Reset', text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' + 'Please click on the following link, or paste this into your browser to complete the process:\n\n' + 'http://' + req.headers.host + '/reset/' + token + '\n\n' + 'If you did not request this, please ignore this email and your password will remain unchanged.\n' - }; - smtpTransport.sendMail(mailOptions, function (err) { + } as MailOptions; + smtpTransport.sendMail(mailOptions, function (err: Error | null) { // req.flash('info', 'An e-mail has been sent to ' + user.email + ' with further instructions.'); done(null, err, 'done'); }); @@ -254,12 +259,12 @@ export let postReset = function (req: Request, res: Response) { } }); const mailOptions = { - to: user.email, + to: user.email.type, from: 'brownptcdash@gmail.com', subject: 'Your password has been changed', text: 'Hello,\n\n' + 'This is a confirmation that the password for your account ' + user.email + ' has just been changed.\n' - }; + } as MailOptions; smtpTransport.sendMail(mailOptions, function (err) { done(null, err); }); diff --git a/src/server/authentication/models/user_model.ts b/src/server/authentication/models/user_model.ts index ee85e1c05..fb62de1c8 100644 --- a/src/server/authentication/models/user_model.ts +++ b/src/server/authentication/models/user_model.ts @@ -16,7 +16,7 @@ mongoose.connection.on('disconnected', function () { console.log('connection closed'); }); export type DashUserModel = mongoose.Document & { - email: string, + email: { type: String, unique: true }, password: string, passwordResetToken?: string, passwordResetExpires?: Date, diff --git a/src/server/index.ts b/src/server/index.ts index 58af074aa..06f8358e1 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -58,7 +58,7 @@ clientUtils = `//AUTO-GENERATED FILE: DO NOT EDIT\n${clientUtils.replace('"mode" fs.writeFileSync("./src/client/util/ClientUtils.ts", clientUtils, "utf8"); const mongoUrl = 'mongodb://localhost:27017/Dash'; -mongoose.connect(mongoUrl); +mongoose.connection.readyState === 0 && mongoose.connect(mongoUrl); mongoose.connection.on('connected', () => console.log("connected")); // SESSION MANAGEMENT AND AUTHENTICATION MIDDLEWARE @@ -144,12 +144,12 @@ app.get("/pull", (req, res) => // GETTERS app.get("/search", async (req, res) => { - const { query, start, rows } = req.query; + const { query, filterQuery, start, rows } = req.query; if (query === undefined) { res.send([]); return; } - let results = await Search.Instance.search(query, start, rows); + let results = await Search.Instance.search(query, filterQuery, start, rows); res.send(results); }); |