aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/views/Main.scss35
-rw-r--r--src/client/views/Main.tsx7
-rw-r--r--src/client/views/SearchBox.scss63
-rw-r--r--src/client/views/SearchBox.tsx89
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx11
-rw-r--r--src/fields/Document.ts15
-rw-r--r--src/server/Search.ts38
-rw-r--r--src/server/database.ts12
-rw-r--r--src/server/index.ts19
9 files changed, 258 insertions, 31 deletions
diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss
index 89fdf595a..fbc7c8ef3 100644
--- a/src/client/views/Main.scss
+++ b/src/client/views/Main.scss
@@ -1,5 +1,6 @@
@import "globalCssVariables";
@import "nodeModuleOverrides";
+
html,
body {
width: 100%;
@@ -7,9 +8,9 @@ body {
overflow: auto;
font-family: $sans-serif;
margin: 0;
- position:absolute;
+ position: absolute;
top: 0;
- left:0;
+ left: 0;
}
div {
@@ -46,7 +47,7 @@ h1 {
}
.jsx-parser {
- width:100%;
+ width: 100%;
pointer-events: none;
border-radius: inherit;
}
@@ -120,6 +121,7 @@ button:hover {
position: absolute;
bottom: 62px;
left: 24px;
+
.toolbar-button {
display: block;
margin-bottom: 10px;
@@ -131,6 +133,7 @@ button:hover {
position: absolute;
bottom: 24px;
left: 24px;
+
label {
background: $dark-color;
color: $light-color;
@@ -143,44 +146,53 @@ button:hover {
cursor: pointer;
transition: transform 0.2s;
}
+
label p {
padding-left: 10.5px;
padding-top: 3px;
}
+
label:hover {
background: $main-accent;
transform: scale(1.15);
}
+
input {
display: none;
}
+
input:not(:checked)~#add-options-content {
display: none;
}
+
input:checked~label {
transform: rotate(45deg);
transition: transform 0.5s;
cursor: pointer;
}
}
+
#root {
overflow: visible;
}
+
#main-div {
- width:100%;
- height:100%;
- position:absolute;
+ width: 100%;
+ height: 100%;
+ position: absolute;
top: 0;
- left:0;
+ left: 0;
overflow: scroll;
}
+
#mainContent-div {
- width:100%;
- height:100%;
- position:absolute;
+ width: 100%;
+ height: 100%;
+ position: absolute;
top: 0;
- left:0;
+ left: 0;
}
+
#add-options-content {
display: table;
opacity: 1;
@@ -195,6 +207,7 @@ button:hover {
ul#add-options-list {
list-style: none;
padding: 0;
+
li {
display: inline-block;
padding: 0;
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 129079271..f32e92aac 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -38,9 +38,9 @@ import "./Main.scss";
import { MainOverlayTextBox } from './MainOverlayTextBox';
import { DocumentView } from './nodes/DocumentView';
import { PreviewCursor } from './PreviewCursor';
+import { SearchBox } from './SearchBox';
import { SelectionManager } from '../util/SelectionManager';
-
@observer
export class Main extends React.Component {
public static Instance: Main;
@@ -270,7 +270,10 @@ export class Main extends React.Component {
</div >,
<div className="main-buttonDiv" key="workspaces" style={{ top: '34px', left: '2px', position: 'absolute' }} ref={workspacesRef}>
<button onClick={toggleWorkspaces}>Workspaces</button></div>,
- <div className="main-buttonDiv" key="logout" style={{ top: '34px', right: '1px', position: 'absolute' }} ref={logoutRef}>
+
+ <div className="main-searchDiv" key="search" style={{ top: '34px', right: '1px', position: 'absolute' }} ref={workspacesRef}> <SearchBox /> </div>,
+
+ <div className="main-buttonDiv" key="logout" style={{ bottom: '34px', right: '1px', position: 'absolute' }} ref={logoutRef}>
<button onClick={() => request.get(ServerUtils.prepend(RouteStore.logout), emptyFunction)}>Log Out</button></div>
];
}
diff --git a/src/client/views/SearchBox.scss b/src/client/views/SearchBox.scss
new file mode 100644
index 000000000..92363e681
--- /dev/null
+++ b/src/client/views/SearchBox.scss
@@ -0,0 +1,63 @@
+@import "globalCssVariables";
+
+.searchBox {
+ height: 32px;
+ //display: flex;
+ //padding: 4px;
+ -webkit-transition: width 0.4s ease-in-out;
+ transition: width 0.4s ease-in-out;
+ align-items: center;
+
+ .submit-search {
+ text-align: right;
+ color: $dark-color;
+ -webkit-transition: right 0.4s;
+ transition: right 0.4s;
+ }
+
+ .submit-search:hover {
+ color: $main-accent;
+ transform: scale(1.05);
+ cursor: pointer;
+ }
+
+ input[type=text] {
+ width: 130px;
+ -webkit-transition: width 0.4s;
+ transition: width 0.4s;
+ position: absolute;
+ right: 100px;
+ }
+
+ input[type=text]:focus {
+ width: 500px;
+ outline: 3px solid lightblue;
+ }
+
+ .filter-button {
+ position: absolute;
+ right: 30px;
+ }
+}
+
+.filter-form {
+ background: $dark-color;
+ height: 400px;
+ width: 400px;
+ position: relative;
+ right: 1px;
+ color: $light-color;
+ padding: 10px;
+ flex-direction: column;
+}
+
+#header {
+ text-transform: uppercase;
+ letter-spacing: 2px;
+ font-size: 100%;
+ height: 40px;
+}
+
+#option {
+ height: 20px;
+} \ No newline at end of file
diff --git a/src/client/views/SearchBox.tsx b/src/client/views/SearchBox.tsx
new file mode 100644
index 000000000..7f388719d
--- /dev/null
+++ b/src/client/views/SearchBox.tsx
@@ -0,0 +1,89 @@
+import * as React from 'react';
+import { observer } from 'mobx-react';
+import { observable, action } from 'mobx';
+import { Utils } from '../../Utils';
+import { MessageStore } from '../../server/Message';
+import { Server } from '../Server';
+import "./SearchBox.scss";
+import { faSearch } from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { library } from '@fortawesome/fontawesome-svg-core';
+import { actionFieldDecorator } from 'mobx/lib/internal';
+
+library.add(faSearch);
+
+@observer
+export class SearchBox extends React.Component {
+ @observable
+ searchString: string = "";
+
+ @observable private _open: boolean = false;
+
+ @action.bound
+ onChange(e: React.ChangeEvent<HTMLInputElement>) {
+ this.searchString = e.target.value;
+
+ }
+
+ submitSearch = () => {
+ Utils.EmitCallback(Server.Socket, MessageStore.SearchFor, this.searchString, (results: string[]) => {
+ for (const result of results) {
+ console.log(result);
+ Utils.GetQueryVariable()
+ }
+ });
+ }
+
+ @action
+ handleClick = (e: Event): void => {
+ var className = (e.target as any).className;
+ var id = (e.target as any).id;
+ console.log(id);
+ //let imgPrev = document.getElementById("img_preview");
+ console.log(className);
+ if (className !== "filter-button" && className !== "filter-form") {
+ console.log("false");
+ this._open = false;
+ }
+
+ }
+
+ componentWillMount() {
+ document.addEventListener('mousedown', this.handleClick, false);
+ }
+
+ componentWillUnmount() {
+ document.removeEventListener('mousedown', this.handleClick, false);
+ }
+
+ @action
+ toggleDisplay = () => {
+ this._open = !this._open;
+ }
+
+ render() {
+ return (
+ <div id="outer">
+ <div className="searchBox" id="outer">
+ {/* <input value={this.searchString} onChange={this.onChange} />
+ <button onClick={this.submitSearch} /> */}
+
+ <input value={this.searchString} onChange={this.onChange} type="text" placeholder="Search.." className="search" />
+ {/* {this._items.filter(prop => prop.description.toLowerCase().indexOf(this._searchString.toLowerCase()) !== -1).
+ map(prop => <ContextMenuItem {...prop} key={prop.description} />)} */}
+
+ <button className="filter-button" onClick={this.toggleDisplay}> Filter </button>
+ <div className="submit-search" ><FontAwesomeIcon style={{ height: "100%" }} icon="search" size="lg" /></div>
+ </div>
+ <div className="filter-form" id="filter" style={this._open ? { display: "flex" } : { display: "none" }}>
+ <div className="filter-form" id="header">Filter Search Results</div>
+ <div className="filter-form" id="option">
+ filter by collection, key, type of node
+ </div>
+
+ </div>
+ </div>
+
+ );
+ }
+} \ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 1a953006a..8647ded8a 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -47,13 +47,10 @@ export class CollectionFreeFormView extends CollectionSubView {
this._selectOnLoaded = newBox.Id;// track the new text box so we can give it a prop that tells it to focus itself when it's displayed
this.addDocument(newBox, false);
}
- @action
- private addDocument = (newBox: Document, allowDuplicates: boolean) => {
- this.props.addDocument(newBox, false);
- this.bringToFront(newBox);
- return true;
- }
- private selectDocuments = (docs: Document[]) => {
+
+ public addDocument = (newBox: Document, allowDuplicates: boolean) => this.props.addDocument(this.bringToFront(newBox), false);
+
+ public selectDocuments = (docs: Document[]) => {
SelectionManager.DeselectAll;
docs.map(doc => DocumentManager.Instance.getDocumentView(doc)).filter(dv => dv).map(dv =>
SelectionManager.SelectDoc(dv!, true));
diff --git a/src/fields/Document.ts b/src/fields/Document.ts
index 55ac731dd..339f370cc 100644
--- a/src/fields/Document.ts
+++ b/src/fields/Document.ts
@@ -29,15 +29,14 @@ export class Document extends Field {
}
static FromJson(data: any, id: string, save: boolean): Document {
let doc = new Document(id, save);
- let fields = data as [string, string][];
- fields.forEach(pair => doc._proxies.set(pair[0], pair[1]));
+ let fields = data as { key: string, field: string }[];
+ fields.forEach(pair => doc._proxies.set(pair.key, pair.field));
return doc;
}
- UpdateFromServer(data: [string, string][]) {
- for (const key in data) {
- const element = data[key];
- this._proxies.set(element[0], element[1]);
+ UpdateFromServer(data: { key: string, field: string }[]) {
+ for (const kv of data) {
+ this._proxies.set(kv.key, kv.field);
}
}
@@ -448,9 +447,9 @@ export class Document extends Field {
}
ToJson() {
- let fields: [string, string][] = [];
+ let fields: { key: string, field: string }[] = [];
this._proxies.forEach((field, key) =>
- field && fields.push([key, field]));
+ field && fields.push({ key, field }));
return {
type: Types.Document,
diff --git a/src/server/Search.ts b/src/server/Search.ts
new file mode 100644
index 000000000..7d8602346
--- /dev/null
+++ b/src/server/Search.ts
@@ -0,0 +1,38 @@
+import * as rp from 'request-promise';
+import { Database } from './database';
+
+export class Search {
+ public static Instance = new Search();
+ private url = 'http://localhost:8983/solr/';
+
+ public updateDocument(document: any): rp.RequestPromise {
+ return rp.post(this.url + "dash/update/json/docs", {
+ headers: { 'content-type': 'application/json' },
+ body: JSON.stringify(document)
+ });
+ }
+
+ public async search(query: string) {
+ const searchResults = JSON.parse(await rp.get(this.url + "dash/select", {
+ qs: {
+ q: query
+ }
+ }));
+ const fields = searchResults.response.docs;
+ const ids = fields.map((field: any) => field.id);
+ const docs = await Database.Instance.searchQuery(ids);
+ const docIds = docs.map((doc: any) => doc._id);
+ return docIds;
+ }
+
+ public async clear() {
+ return rp.post(this.url + "dash/update", {
+ body: {
+ delete: {
+ query: "*:*"
+ }
+ },
+ json: true
+ });
+ }
+} \ No newline at end of file
diff --git a/src/server/database.ts b/src/server/database.ts
index 5457e4dd5..d5905c7b3 100644
--- a/src/server/database.ts
+++ b/src/server/database.ts
@@ -72,6 +72,18 @@ export class Database {
});
}
+ public searchQuery(ids: string[], collectionName = Database.DocumentsCollection): Promise<any> {
+ return new Promise<any>(resolve => {
+ this.db && this.db.collection(collectionName).find({ "data.field": { "$in": ids } }).toArray((err, docs) => {
+ if (err) {
+ console.log(err.message);
+ console.log(err.errmsg);
+ }
+ resolve(docs);
+ });
+ });
+ }
+
public print() {
console.log("db says hi!");
}
diff --git a/src/server/index.ts b/src/server/index.ts
index 70a7d266c..cb4268a2d 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -11,6 +11,7 @@ import { ObservableMap } from 'mobx';
import * as passport from 'passport';
import * as path from 'path';
import * as request from 'request';
+import * as rp from 'request-promise';
import * as io from 'socket.io';
import { Socket } from 'socket.io';
import * as webpack from 'webpack';
@@ -22,7 +23,7 @@ import { getForgot, getLogin, getLogout, getReset, getSignup, postForgot, postLo
import { DashUserModel } from './authentication/models/user_model';
import { Client } from './Client';
import { Database } from './database';
-import { MessageStore, Transferable } from "./Message";
+import { MessageStore, Transferable, Types } from "./Message";
import { RouteStore } from './RouteStore';
const app = express();
const config = require('../../webpack.config');
@@ -32,6 +33,7 @@ const serverPort = 4321;
import expressFlash = require('express-flash');
import flash = require('connect-flash');
import c = require("crypto");
+import { Search } from './Search';
const MongoStore = require('connect-mongo')(session);
const mongoose = require('mongoose');
@@ -120,6 +122,12 @@ app.get("/pull", (req, res) =>
// GETTERS
+app.get("/search", async (req, res) => {
+ let query = req.query.query || "hello";
+ let results = await Search.Instance.search(query);
+ res.send(results);
+});
+
// anyone attempting to navigate to localhost at this port will
// first have to login
addSecureRoute(
@@ -234,14 +242,16 @@ server.on("connection", function (socket: Socket) {
Utils.AddServerHandler(socket, MessageStore.DeleteAll, deleteFields);
});
-function deleteFields() {
- return Database.Instance.deleteAll();
+async function deleteFields() {
+ await Database.Instance.deleteAll();
+ await Search.Instance.clear();
}
async function deleteAll() {
await Database.Instance.deleteAll();
await Database.Instance.deleteAll('sessions');
await Database.Instance.deleteAll('users');
+ await Search.Instance.clear();
}
function barReceived(guid: String) {
@@ -260,6 +270,9 @@ function getFields([ids, callback]: [string[], (result: Transferable[]) => void]
function setField(socket: Socket, newValue: Transferable) {
Database.Instance.update(newValue.id, newValue, () =>
socket.broadcast.emit(MessageStore.SetField.Message, newValue));
+ if (newValue.type === Types.Text) {
+ Search.Instance.updateDocument({ id: newValue.id, data: (newValue as any).data });
+ }
}
server.listen(serverPort);