From 8eb432d8456a39eb26c0fb4aba628e15e31899d0 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 16 Jul 2019 12:12:24 -0400 Subject: Uploaded image audio to server --- src/client/views/nodes/ImageBox.tsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 73ae8955d..0014633ca 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -22,6 +22,7 @@ import "./ImageBox.scss"; import React = require("react"); import { RouteStore } from '../../../server/RouteStore'; import { Docs } from '../../documents/Documents'; +import { DocServer } from '../../DocServer'; var requestImageSize = require('../../util/request-image-size'); var path = require('path'); @@ -157,8 +158,15 @@ export class ImageBox extends DocComponent(ImageD }).then(function (stream) { gumStream = stream; recorder = new MediaRecorder(stream); - recorder.ondataavailable = function (e: any) { - var url = URL.createObjectURL(e.data); + recorder.ondataavailable = async function (e: any) { + const formData = new FormData(); + formData.append("file", e.data); + const res = await fetch(DocServer.prepend(RouteStore.upload), { + method: 'POST', + body: formData + }); + const files = await res.json(); + const url = DocServer.prepend(files[0]); // upload to server with known URL let audioDoc = Docs.Create.AudioDocument(url, { title: "audio test", x: NumCast(self.props.Document.x), y: NumCast(self.props.Document.y), width: 200, height: 32 }); audioDoc.embed = true; @@ -174,7 +182,7 @@ export class ImageBox extends DocComponent(ImageD recorder.stop(); gumStream.getAudioTracks()[0].stop(); - }, 1000); + }, 5000); }); } -- cgit v1.2.3-70-g09d2 From b10e8e0c22bdc27e39c365cae1a1592bc714b547 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Tue, 16 Jul 2019 12:23:10 -0400 Subject: linter --- src/client/views/nodes/VideoBox.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 3ade3396e..972e6875d 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -157,8 +157,8 @@ export class VideoBox extends DocComponent(VideoD let iframe = e.target; let onYoutubePlayerStateChange = (event: any) => runInAction(() => { console.log("Event " + event.data); - if (event.data == YT.PlayerState.PLAYING && !this.Playing) this.Play(false); - if (event.data == YT.PlayerState.PAUSED && this.Playing) this.Pause(false); + if (event.data === YT.PlayerState.PLAYING && !this.Playing) this.Play(false); + if (event.data === YT.PlayerState.PAUSED && this.Playing) this.Pause(false); }); let onYoutubePlayerReady = (event: any) => { console.log("READY!"); @@ -169,7 +169,7 @@ export class VideoBox extends DocComponent(VideoD let interactive = InkingControl.Instance.selectedTool === InkTool.None && this.props.isSelected() && !DocumentDecorations.Instance.Interacting; iframe.style.pointerEvents = interactive ? "all" : "none"; }, { fireImmediately: true }); - } + }; this._youtubePlayer = new YT.Player(`${this.youtubeVideoId + this._youtubeIframeId}-player`, { events: { 'onReady': onYoutubePlayerReady, -- cgit v1.2.3-70-g09d2 From adc70137f01072271672be1b4bf1b823b1b28060 Mon Sep 17 00:00:00 2001 From: Mohammad Amoush Date: Tue, 16 Jul 2019 13:31:55 -0400 Subject: reverted user controller email format --- src/server/authentication/controllers/user_controller.ts | 6 +++--- src/server/authentication/models/user_model.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/server/authentication/controllers/user_controller.ts b/src/server/authentication/controllers/user_controller.ts index fa1cd647d..0e431f1e6 100644 --- a/src/server/authentication/controllers/user_controller.ts +++ b/src/server/authentication/controllers/user_controller.ts @@ -52,7 +52,7 @@ export let postSignup = (req: Request, res: Response, next: NextFunction) => { const password = req.body.password; const model = { - email: { type: email, unique: true }, + email, password, userDocumentId: Utils.GenerateGuid() } as Partial; @@ -186,7 +186,7 @@ export let postForgot = function (req: Request, res: Response, next: NextFunctio } }); const mailOptions = { - to: user.email.type, + to: user.email, 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' + @@ -259,7 +259,7 @@ export let postReset = function (req: Request, res: Response) { } }); const mailOptions = { - to: user.email.type, + to: user.email, from: 'brownptcdash@gmail.com', subject: 'Your password has been changed', text: 'Hello,\n\n' + diff --git a/src/server/authentication/models/user_model.ts b/src/server/authentication/models/user_model.ts index fb62de1c8..45fbf23b1 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: { type: String, unique: true }, + email: String, password: string, passwordResetToken?: string, passwordResetExpires?: Date, @@ -42,7 +42,7 @@ export type AuthToken = { }; const userSchema = new mongoose.Schema({ - email: { type: String, unique: true }, + email: String, password: String, passwordResetToken: String, passwordResetExpires: Date, -- cgit v1.2.3-70-g09d2 From 7f6666500f157c5884377d714137426cf05e7569 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 16 Jul 2019 13:40:20 -0400 Subject: Changed search to display extension documents as the extended documents --- src/client/documents/Documents.ts | 2 +- src/client/views/InkingControl.tsx | 4 ++-- src/client/views/collections/CollectionVideoView.tsx | 2 +- src/client/views/search/SearchBox.tsx | 13 ++++++++----- 4 files changed, 12 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 177810444..5bbfe1c49 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -235,7 +235,7 @@ export namespace Docs { let title = prototypeId.toUpperCase().replace(upper, `_${upper}`); // synthesize the default options, the type and title from computed values and // whatever options pertain to this specific prototype - let options = { title: title, type: type, ...defaultOptions, ...(template.options || {}) }; + let options = { title: title, type: type, baseProto: true, ...defaultOptions, ...(template.options || {}) }; let primary = layout.view.LayoutString(); let collectionView = layout.collectionView; if (collectionView) { diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index 1910e409b..c7f7bdb66 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -1,5 +1,5 @@ import { observable, action, computed, runInAction } from "mobx"; -import { ColorState } from 'react-color'; +import { ColorResult } from 'react-color'; import React = require("react"); import { observer } from "mobx-react"; import "./InkingControl.scss"; @@ -41,7 +41,7 @@ export class InkingControl extends React.Component { } @undoBatch - switchColor = action((color: ColorState): void => { + switchColor = action((color: ColorResult): void => { this._selectedColor = color.hex + (color.rgb.a !== undefined ? this.decimalToHexString(Math.round(color.rgb.a * 255)) : "ff"); if (InkingControl.Instance.selectedTool === InkTool.None) { if (MainOverlayTextBox.Instance.SetColor(color.hex)) return; diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index faf507496..096e7e9d1 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -88,7 +88,7 @@ export class CollectionVideoView extends React.Component { canvas.width = 640; canvas.height = 640 * NumCast(this.props.Document.nativeHeight) / NumCast(this.props.Document.nativeWidth); var ctx = canvas.getContext('2d');//draw image to canvas. scale to target dimensions - this._videoBox!.player && ctx && ctx.drawImage(this._videoBox!.player!, 0, 0, canvas.width, canvas.height); + this._videoBox!.player && ctx && ctx.drawImage(this._videoBox!.player, 0, 0, canvas.width, canvas.height); //convert to desired file format var dataUrl = canvas.toDataURL('image/png'); // can also use 'image/png' diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index ec778b346..dc76d1ff4 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -6,7 +6,7 @@ import "./FilterBox.scss"; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { SetupDrag } from '../../util/DragManager'; import { Docs } from '../../documents/Documents'; -import { NumCast } from '../../../new_fields/Types'; +import { NumCast, Cast } from '../../../new_fields/Types'; import { Doc } from '../../../new_fields/Doc'; import { SearchItem } from './SearchItem'; import { DocServer } from '../../DocServer'; @@ -118,7 +118,7 @@ export class SearchBox extends React.Component { 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(" ")})` : ""); + return "NOT baseProto_b:true" + (types ? ` AND (${types.map(type => `({!join from=id to=proto_i}type_t:"${type}" AND NOT type_t:*) OR type_t:"${type}"`).join(" ")})` : ""); } @@ -129,15 +129,18 @@ 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, this.filterQuery, true, this._maxSearchIndex, 10).then(action((res: SearchUtil.DocSearchResult) => { + this._curRequest = SearchUtil.Search(query, this.filterQuery, true, this._maxSearchIndex, 10).then(action(async (res: SearchUtil.DocSearchResult) => { // happens at the beginning if (res.numFound !== this._numTotalResults && this._numTotalResults === -1) { this._numTotalResults = res.numFound; } - let filteredDocs = FilterBox.Instance.filterDocsByType(res.docs); - this._results.push(...filteredDocs); + const docs = await Promise.all(res.docs.map(doc => Cast(doc.extendsDoc, Doc, doc as any))); + let filteredDocs = FilterBox.Instance.filterDocsByType(docs); + runInAction(() => { + this._results.push(...filteredDocs); + }); this._curRequest = undefined; })); -- cgit v1.2.3-70-g09d2 From 520fbe435330c8e426e2d504585ba1559300eadb Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Tue, 16 Jul 2019 14:18:42 -0400 Subject: fixed login redirection bug --- src/server/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/index.ts b/src/server/index.ts index 06f8358e1..2cca7a35b 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -110,7 +110,7 @@ function addSecureRoute(method: Method, if (req.user) { handler(req.user, res, req); } else { - req.session!.target = `http://localhost:${port}${req.originalUrl}`; + req.session!.target = `${req.headers.host}${req.originalUrl}`; onRejection(res, req); } }; -- cgit v1.2.3-70-g09d2 From 967638b84c15f35bbfb1c464ac8e22916a1a2bc7 Mon Sep 17 00:00:00 2001 From: monikahedman Date: Tue, 16 Jul 2019 14:31:20 -0400 Subject: changes --- src/client/views/search/FilterBox.tsx | 3 +++ src/client/views/search/SearchBox.scss | 4 ++-- src/client/views/search/SearchBox.tsx | 15 +++++++-------- 3 files changed, 12 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/client/views/search/FilterBox.tsx b/src/client/views/search/FilterBox.tsx index f11fb008c..757665bcf 100644 --- a/src/client/views/search/FilterBox.tsx +++ b/src/client/views/search/FilterBox.tsx @@ -87,6 +87,9 @@ export class FilterBox extends React.Component { } }); + + let el = acc[i] as HTMLElement; + el.click(); } }); } diff --git a/src/client/views/search/SearchBox.scss b/src/client/views/search/SearchBox.scss index 324ba3063..109b88ac9 100644 --- a/src/client/views/search/SearchBox.scss +++ b/src/client/views/search/SearchBox.scss @@ -41,11 +41,10 @@ } .searchBox-results { - margin-right: 142px; + margin-right: 136px; top: 300px; display: flex; flex-direction: column; - margin-right: 72px; max-height: 560px; overflow: hidden; overflow-y: auto; @@ -60,5 +59,6 @@ text-transform: uppercase; text-align: left; font-weight: bold; + margin-left: 28px; } } \ No newline at end of file diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 3830a6d16..661c9c10b 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -22,6 +22,7 @@ export class SearchBox extends React.Component { @observable private _searchString: string = ""; @observable private _resultsOpen: boolean = false; + @observable private _searchbarOpen: boolean = false; @observable private _results: Doc[] = []; @observable private _openNoResults: boolean = false; @observable private _visibleElements: JSX.Element[] = []; @@ -107,6 +108,7 @@ export class SearchBox extends React.Component { runInAction(() => { this._resultsOpen = true; + this._searchbarOpen = true; this._openNoResults = true; this.resultsScrolled(); }); @@ -198,6 +200,7 @@ export class SearchBox extends React.Component { this._openNoResults = false; FilterBox.Instance.closeFilter(); this._resultsOpen = true; + this._searchbarOpen = true; FilterBox.Instance._pointerTime = e.timeStamp; } @@ -205,6 +208,7 @@ export class SearchBox extends React.Component { closeSearch = () => { FilterBox.Instance.closeFilter(); this.closeResults(); + this._searchbarOpen = false; } @action.bound @@ -281,15 +285,10 @@ export class SearchBox extends React.Component { } @computed - get resFull() { - console.log(this._numTotalResults) - return this._numTotalResults <= 8; - } + get resFull() { return this._numTotalResults <= 8; } @computed - get resultHeight() { - return this._numTotalResults * 70; - } + get resultHeight() { return this._numTotalResults * 70; } render() { return ( @@ -300,7 +299,7 @@ export class SearchBox extends React.Component { + style={{ width: this._searchbarOpen ? "500px" : "100px" }} /> -- cgit v1.2.3-70-g09d2 From c6b933c6e89d5f438c434e8676cce9a6a577edbc Mon Sep 17 00:00:00 2001 From: monikahedman Date: Tue, 16 Jul 2019 14:35:35 -0400 Subject: checkbox --- src/client/views/search/FieldFilters.tsx | 2 +- src/client/views/search/FilterBox.tsx | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/client/views/search/FieldFilters.tsx b/src/client/views/search/FieldFilters.tsx index 648aac20a..7a33282d2 100644 --- a/src/client/views/search/FieldFilters.tsx +++ b/src/client/views/search/FieldFilters.tsx @@ -34,7 +34,7 @@ export class FieldFilters extends React.Component {
- +
); } diff --git a/src/client/views/search/FilterBox.tsx b/src/client/views/search/FilterBox.tsx index 757665bcf..f28b074a7 100644 --- a/src/client/views/search/FilterBox.tsx +++ b/src/client/views/search/FilterBox.tsx @@ -40,7 +40,7 @@ export class FilterBox extends React.Component { @observable private _icons: string[] = this._allIcons; @observable private _titleFieldStatus: boolean = true; @observable private _authorFieldStatus: boolean = true; - @observable private _dataFieldStatus: boolean = true; + @observable public _deletedDocsStatus: boolean = false; @observable private _collectionStatus = false; @observable private _collectionSelfStatus = true; @observable private _collectionParentStatus = true; @@ -164,13 +164,13 @@ export class FilterBox extends React.Component { if (this._authorFieldStatus) { finalQuery = finalQuery + this.basicFieldFilters(query, Keys.AUTHOR); } - if (this._dataFieldStatus) { + if (this._deletedDocsStatus) { finalQuery = finalQuery + this.basicFieldFilters(query, Keys.DATA); } return finalQuery; } - get fieldFiltersApplied() { return !(this._dataFieldStatus && this._authorFieldStatus && this._titleFieldStatus); } + get fieldFiltersApplied() { return !(this._deletedDocsStatus && this._authorFieldStatus && this._titleFieldStatus); } //TODO: basically all of this //gets all of the collections of all the docviews that are selected @@ -308,7 +308,7 @@ export class FilterBox extends React.Component { updateAuthorStatus(newStat: boolean) { this._authorFieldStatus = newStat; } @action.bound - updateDataStatus(newStat: boolean) { this._dataFieldStatus = newStat; } + updateDataStatus(newStat: boolean) { this._deletedDocsStatus = newStat; } @action.bound updateCollectionStatus(newStat: boolean) { this._collectionStatus = newStat; } @@ -324,7 +324,7 @@ export class FilterBox extends React.Component { getParentCollectionStatus() { return this._collectionParentStatus; } getTitleStatus() { return this._titleFieldStatus; } getAuthorStatus() { return this._authorFieldStatus; } - getDataStatus() { return this._dataFieldStatus; } + getDataStatus() { return this._deletedDocsStatus; } // Useful queries: // Delegates of a document: {!join from=id to=proto_i}id:{protoId} @@ -376,7 +376,7 @@ export class FilterBox extends React.Component {
-- cgit v1.2.3-70-g09d2 From 1b5bf295d951858a9d54e95e2ada4882f1a39f40 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 16 Jul 2019 14:41:18 -0400 Subject: Added start of deleted documents to search --- solr/conf/schema.xml | 1 + src/client/views/search/SearchBox.tsx | 3 +- src/server/GarbageCollector.ts | 87 +++++++++++++++++++++-------------- 3 files changed, 55 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/solr/conf/schema.xml b/solr/conf/schema.xml index 8610786af..7a21794cb 100644 --- a/solr/conf/schema.xml +++ b/solr/conf/schema.xml @@ -44,6 +44,7 @@ + diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index dc76d1ff4..733e93a62 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -118,7 +118,8 @@ export class SearchBox extends React.Component { private get filterQuery() { const types = FilterBox.Instance.filterTypes; - return "NOT baseProto_b:true" + (types ? ` AND (${types.map(type => `({!join from=id to=proto_i}type_t:"${type}" AND NOT type_t:*) OR type_t:"${type}"`).join(" ")})` : ""); + const includeDeleted = false; + return "NOT baseProto_b:true" + (includeDeleted ? "" : " AND NOT deleted:true") + (types ? ` AND (${types.map(type => `({!join from=id to=proto_i}type_t:"${type}" AND NOT type_t:*) OR type_t:"${type}"`).join(" ")})` : ""); } diff --git a/src/server/GarbageCollector.ts b/src/server/GarbageCollector.ts index 59682e51e..ea5388004 100644 --- a/src/server/GarbageCollector.ts +++ b/src/server/GarbageCollector.ts @@ -59,7 +59,9 @@ function addDoc(doc: any, ids: string[], files: { [name: string]: string[] }) { } } -async function GarbageCollect() { +async function GarbageCollect(full: boolean = true) { + console.log("start GC"); + const start = Date.now(); // await new Promise(res => setTimeout(res, 3000)); const cursor = await Database.Instance.query({}, { userDocumentId: 1 }, 'users'); const users = await cursor.toArray(); @@ -68,7 +70,7 @@ async function GarbageCollect() { const files: { [name: string]: string[] } = {}; while (ids.length) { - const count = Math.min(ids.length, 100); + const count = Math.min(ids.length, 1000); const index = ids.length - count; const fetchIds = ids.splice(index, count).filter(id => !visited.has(id)); if (!fetchIds.length) { @@ -91,43 +93,58 @@ async function GarbageCollect() { cursor.close(); - const toDeleteCursor = await Database.Instance.query({ _id: { $nin: Array.from(visited) } }, { _id: 1 }); + const notToDelete = Array.from(visited); + const toDeleteCursor = await Database.Instance.query({ _id: { $nin: notToDelete } }, { _id: 1 }); const toDelete: string[] = (await toDeleteCursor.toArray()).map(doc => doc._id); toDeleteCursor.close(); - let i = 0; - let deleted = 0; - while (i < toDelete.length) { - const count = Math.min(toDelete.length, 5000); - const toDeleteDocs = toDelete.slice(i, i + count); - i += count; - const result = await Database.Instance.delete({ _id: { $in: toDeleteDocs } }, "newDocuments"); - deleted += result.deletedCount || 0; - } - // const result = await Database.Instance.delete({ _id: { $in: toDelete } }, "newDocuments"); - console.log(`${deleted} documents deleted`); + if (!full) { + await Database.Instance.updateMany({ _id: { $nin: notToDelete } }, { $set: { "deleted": true } }); + await Database.Instance.updateMany({ _id: { $in: notToDelete } }, { $unset: { "deleted": true } }); + console.log(await Search.Instance.updateDocuments( + notToDelete.map(id => ({ + id, deleted: { set: null } + })) + .concat(toDelete.map(id => ({ + id, deleted: { set: true } + }))))); + console.log("Done with partial GC"); + console.log(`Took ${(Date.now() - start) / 1000} seconds`); + } else { + let i = 0; + let deleted = 0; + while (i < toDelete.length) { + const count = Math.min(toDelete.length, 5000); + const toDeleteDocs = toDelete.slice(i, i + count); + i += count; + const result = await Database.Instance.delete({ _id: { $in: toDeleteDocs } }, "newDocuments"); + deleted += result.deletedCount || 0; + } + // const result = await Database.Instance.delete({ _id: { $in: toDelete } }, "newDocuments"); + console.log(`${deleted} documents deleted`); - await Search.Instance.deleteDocuments(toDelete); - console.log("Cleared search documents"); + await Search.Instance.deleteDocuments(toDelete); + console.log("Cleared search documents"); - const folder = "./src/server/public/files/"; - fs.readdir(folder, (_, fileList) => { - const filesToDelete = fileList.filter(file => { - const ext = path.extname(file); - let base = path.basename(file, ext); - const existsInDb = (base in files || (base = base.substring(0, base.length - 2)) in files) && files[base].includes(ext); - return file !== ".gitignore" && !existsInDb; - }); - console.log(`Deleting ${filesToDelete.length} files`); - filesToDelete.forEach(file => { - console.log(`Deleting file ${file}`); - try { - fs.unlinkSync(folder + file); - } catch { - console.warn(`Couldn't delete file ${file}`); - } + const folder = "./src/server/public/files/"; + fs.readdir(folder, (_, fileList) => { + const filesToDelete = fileList.filter(file => { + const ext = path.extname(file); + let base = path.basename(file, ext); + const existsInDb = (base in files || (base = base.substring(0, base.length - 2)) in files) && files[base].includes(ext); + return file !== ".gitignore" && !existsInDb; + }); + console.log(`Deleting ${filesToDelete.length} files`); + filesToDelete.forEach(file => { + console.log(`Deleting file ${file}`); + try { + fs.unlinkSync(folder + file); + } catch { + console.warn(`Couldn't delete file ${file}`); + } + }); + console.log(`Deleted ${filesToDelete.length} files`); }); - console.log(`Deleted ${filesToDelete.length} files`); - }); + } } -GarbageCollect(); +GarbageCollect(false); -- cgit v1.2.3-70-g09d2 From 189bb0ffd14fb0b8db0edbe813efe19f143a30fd Mon Sep 17 00:00:00 2001 From: monikahedman Date: Tue, 16 Jul 2019 14:46:44 -0400 Subject: shes fixed --- src/client/views/search/SearchBox.tsx | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 661c9c10b..0b2d792e0 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -94,6 +94,7 @@ export class SearchBox extends React.Component { this._results = []; this._isSearch = []; this._visibleElements = []; + FilterBox.Instance.closeFilter(); //if there is no query there should be no result if (query === "") { -- cgit v1.2.3-70-g09d2 From ecbae6521dde8e7e973b8d5f4e826746ea21a665 Mon Sep 17 00:00:00 2001 From: monikahedman Date: Tue, 16 Jul 2019 14:48:48 -0400 Subject: fixed AGAIN --- src/client/views/search/FilterBox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/search/FilterBox.tsx b/src/client/views/search/FilterBox.tsx index f28b074a7..706d1eb7f 100644 --- a/src/client/views/search/FilterBox.tsx +++ b/src/client/views/search/FilterBox.tsx @@ -170,7 +170,7 @@ export class FilterBox extends React.Component { return finalQuery; } - get fieldFiltersApplied() { return !(this._deletedDocsStatus && this._authorFieldStatus && this._titleFieldStatus); } + get fieldFiltersApplied() { return !(this._authorFieldStatus && this._titleFieldStatus); } //TODO: basically all of this //gets all of the collections of all the docviews that are selected -- cgit v1.2.3-70-g09d2 From bef7fc20fecf4056a4f8ff47ff593b2df5e329af Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 16 Jul 2019 14:53:25 -0400 Subject: cleaned up and conquered video boxes. --- src/client/views/SearchBox.tsx | 45 +++--------- src/client/views/collections/CollectionSubView.tsx | 4 +- .../views/collections/CollectionVideoView.tsx | 65 ++---------------- src/client/views/nodes/VideoBox.tsx | 79 ++++++++++++++++++---- 4 files changed, 86 insertions(+), 107 deletions(-) (limited to 'src') diff --git a/src/client/views/SearchBox.tsx b/src/client/views/SearchBox.tsx index 6995e3c7d..8fb43021a 100644 --- a/src/client/views/SearchBox.tsx +++ b/src/client/views/SearchBox.tsx @@ -1,27 +1,18 @@ -import * as React from 'react'; -import { observer } from 'mobx-react'; -import { observable, action, runInAction } from 'mobx'; -import { Utils } from '../../Utils'; -import { MessageStore } from '../../server/Message'; -import "./SearchBox.scss"; -import { faSearch, faObjectGroup } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { library } from '@fortawesome/fontawesome-svg-core'; -// const app = express(); -// import * as express from 'express'; -import { Search } from '../../server/Search'; +import { faObjectGroup, faSearch } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { action, observable, runInAction } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; import * as rp from 'request-promise'; -import { SearchItem } from './search/SearchItem'; -import { isString } from 'util'; -import { constant } from 'async'; -import { DocServer } from '../DocServer'; import { Doc } from '../../new_fields/Doc'; import { Id } from '../../new_fields/FieldSymbols'; -import { DocumentManager } from '../util/DocumentManager'; -import { SetupDrag } from '../util/DragManager'; -import { Docs } from '../documents/Documents'; -import { RouteStore } from '../../server/RouteStore'; import { NumCast } from '../../new_fields/Types'; +import { DocServer } from '../DocServer'; +import { Docs } from '../documents/Documents'; +import { SetupDrag } from '../util/DragManager'; +import { SearchItem } from './search/SearchItem'; +import "./SearchBox.scss"; library.add(faSearch); library.add(faObjectGroup); @@ -72,22 +63,6 @@ export class SearchBox extends React.Component { } return docs; } - public static async convertDataUri(imageUri: string, returnedFilename: string) { - try { - let posting = DocServer.prepend(RouteStore.dataUriToImage); - const returnedUri = await rp.post(posting, { - body: { - uri: imageUri, - name: returnedFilename - }, - json: true, - }); - return returnedUri; - - } catch (e) { - console.log(e); - } - } @action handleClickFilter = (e: Event): void => { diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 71f1908f0..8e8d5708b 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -179,8 +179,8 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { } } if (text && text.indexOf("www.youtube.com/watch") !== -1) { - const url = text.replace("youtube.com/watch?v=", "youtube.com/embed/");// + "?enablejsapi=1"; - this.props.addDocument(Docs.Create.VideoDocument(url, { ...options, width: 400, height: 315 })); + const url = text.replace("youtube.com/watch?v=", "youtube.com/embed/"); + this.props.addDocument(Docs.Create.VideoDocument(url, { ...options, title: url, width: 400, height: 315 })); return; } diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 096e7e9d1..d7d5773ba 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -1,20 +1,12 @@ -import { action, observable, trace } from "mobx"; -import * as htmlToImage from "html-to-image"; +import { action } from "mobx"; import { observer } from "mobx-react"; -import { ContextMenu } from "../ContextMenu"; -import { CollectionViewType, CollectionBaseView, CollectionRenderProps } from "./CollectionBaseView"; -import React = require("react"); -import "./CollectionVideoView.scss"; -import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; +import { NumCast } from "../../../new_fields/Types"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; -import { emptyFunction, Utils } from "../../../Utils"; -import { Id } from "../../../new_fields/FieldSymbols"; import { VideoBox } from "../nodes/VideoBox"; -import { NumCast, Cast, StrCast } from "../../../new_fields/Types"; -import { VideoField } from "../../../new_fields/URLField"; -import { SearchBox } from "../search/SearchBox"; -import { DocServer } from "../../DocServer"; -import { Docs, DocUtils } from "../../documents/Documents"; +import { CollectionBaseView, CollectionRenderProps, CollectionViewType } from "./CollectionBaseView"; +import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; +import "./CollectionVideoView.scss"; +import React = require("react"); @observer @@ -68,49 +60,6 @@ export class CollectionVideoView extends React.Component { this.props.Document.curPage = 0; } } - - onContextMenu = (e: React.MouseEvent): void => { - if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - } - - let field = Cast(this.props.Document[this.props.fieldKey], VideoField); - if (field) { - let url = field.url.href; - ContextMenu.Instance.addItem({ - description: "Copy path", event: () => { Utils.CopyText(url); }, icon: "expand-arrows-alt" - }); - } - let width = NumCast(this.props.Document.width); - let height = NumCast(this.props.Document.height); - ContextMenu.Instance.addItem({ - description: "Take Snapshot", event: async () => { - var canvas = document.createElement('canvas'); - canvas.width = 640; - canvas.height = 640 * NumCast(this.props.Document.nativeHeight) / NumCast(this.props.Document.nativeWidth); - var ctx = canvas.getContext('2d');//draw image to canvas. scale to target dimensions - this._videoBox!.player && ctx && ctx.drawImage(this._videoBox!.player, 0, 0, canvas.width, canvas.height); - - //convert to desired file format - var dataUrl = canvas.toDataURL('image/png'); // can also use 'image/png' - // if you want to preview the captured image, - - let filename = encodeURIComponent("snapshot" + this.props.Document.title + "_" + this.props.Document.curPage).replace(/\./g, ""); - SearchBox.convertDataUri(dataUrl, filename).then(returnedFilename => { - if (returnedFilename) { - let url = DocServer.prepend(returnedFilename); - let imageSummary = Docs.Create.ImageDocument(url, { - x: NumCast(this.props.Document.x) + width, y: NumCast(this.props.Document.y), - width: 150, height: height / width * 150, title: "--snapshot" + NumCast(this.props.Document.curPage) + " image-" - }); - this.props.addDocument && this.props.addDocument(imageSummary, false); - DocUtils.MakeLink(imageSummary, this.props.Document); - } - }); - }, - icon: "expand-arrows-alt" - }); - } - setVideoBox = (videoBox: VideoBox) => { this._videoBox = videoBox; }; private subView = (_type: CollectionViewType, renderProps: CollectionRenderProps) => { @@ -123,7 +72,7 @@ export class CollectionVideoView extends React.Component { render() { return ( - + {this.subView} ); } diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 972e6875d..9806b10b5 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -1,19 +1,24 @@ import React = require("react"); -import { action, IReactionDisposer, observable, reaction, trace, computed, runInAction, untracked } from "mobx"; +import { action, computed, IReactionDisposer, observable, reaction, runInAction, untracked } from "mobx"; import { observer } from "mobx-react"; +import * as rp from 'request-promise'; +import { InkTool } from "../../../new_fields/InkField"; import { makeInterface } from "../../../new_fields/Schema"; import { Cast, FieldValue, NumCast } from "../../../new_fields/Types"; import { VideoField } from "../../../new_fields/URLField"; +import { RouteStore } from "../../../server/RouteStore"; +import { Utils } from "../../../Utils"; +import { DocServer } from "../../DocServer"; +import { Docs, DocUtils } from "../../documents/Documents"; import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from "../ContextMenuItem"; import { DocComponent } from "../DocComponent"; +import { DocumentDecorations } from "../DocumentDecorations"; import { InkingControl } from "../InkingControl"; import { positionSchema } from "./DocumentView"; import { FieldView, FieldViewProps } from './FieldView'; import { pageSchema } from "./ImageBox"; import "./VideoBox.scss"; -import { InkTool } from "../../../new_fields/InkField"; -import { DocumentDecorations } from "../DocumentDecorations"; type VideoDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>; const VideoDocument = makeInterface(positionSchema, pageSchema); @@ -52,21 +57,17 @@ export class VideoBox extends DocComponent(VideoD @action public Play = (update: boolean = true) => { this.Playing = true; update && this.player && this.player.play(); - console.log("PLAYING = " + update); update && this._youtubePlayer && this._youtubePlayer.playVideo(); !this._playTimer && (this._playTimer = setInterval(this.updateTimecode, 500)); this.updateTimecode(); } @action public Seek(time: number) { - console.log("Seeking " + time); - //if (this._youtubePlayer && this._youtubePlayer.getPlayerState() === 5) return; this._youtubePlayer && this._youtubePlayer.seekTo(Math.round(time), true); } @action public Pause = (update: boolean = true) => { this.Playing = false; - console.log("PAUSING = " + update); update && this.player && this.player.pause(); update && this._youtubePlayer && this._youtubePlayer.pauseVideo(); this._playTimer && clearInterval(this._playTimer); @@ -119,13 +120,62 @@ export class VideoBox extends DocComponent(VideoD } } + public static async convertDataUri(imageUri: string, returnedFilename: string) { + try { + let posting = DocServer.prepend(RouteStore.dataUriToImage); + const returnedUri = await rp.post(posting, { + body: { + uri: imageUri, + name: returnedFilename + }, + json: true, + }); + return returnedUri; + + } catch (e) { + console.log(e); + } + } specificContextMenu = (e: React.MouseEvent): void => { let field = Cast(this.Document[this.props.fieldKey], VideoField); if (field) { + let url = field.url.href; let subitems: ContextMenuProps[] = []; + subitems.push({ description: "Copy path", event: () => { Utils.CopyText(url); }, icon: "expand-arrows-alt" }); subitems.push({ description: "Toggle Show Controls", event: action(() => VideoBox._showControls = !VideoBox._showControls), icon: "expand-arrows-alt" }); - subitems.push({ description: "GOTO 3", event: action(() => this.Seek(3)), icon: "expand-arrows-alt" }); - subitems.push({ description: "PLAY", event: action(() => this.Play()), icon: "expand-arrows-alt" }); + let width = NumCast(this.props.Document.width); + let height = NumCast(this.props.Document.height); + subitems.push({ + description: "Take Snapshot", event: async () => { + var canvas = document.createElement('canvas'); + canvas.width = 640; + canvas.height = 640 * NumCast(this.props.Document.nativeHeight) / NumCast(this.props.Document.nativeWidth); + var ctx = canvas.getContext('2d');//draw image to canvas. scale to target dimensions + if (ctx) { + ctx.rect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = "blue"; + ctx.fill(); + this._videoRef && ctx.drawImage(this._videoRef, 0, 0, canvas.width, canvas.height); + } + + //convert to desired file format + var dataUrl = canvas.toDataURL('image/png'); // can also use 'image/png' + // if you want to preview the captured image, + let filename = encodeURIComponent("snapshot" + this.props.Document.title + "_" + this.props.Document.curPage).replace(/\./g, ""); + VideoBox.convertDataUri(dataUrl, filename).then(returnedFilename => { + if (returnedFilename) { + let url = DocServer.prepend(returnedFilename); + let imageSummary = Docs.Create.ImageDocument(url, { + x: NumCast(this.props.Document.x) + width, y: NumCast(this.props.Document.y), + width: 150, height: height / width * 150, title: "--snapshot" + NumCast(this.props.Document.curPage) + " image-" + }); + this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.addDocument && this.props.ContainingCollectionView.props.addDocument(imageSummary, false); + DocUtils.MakeLink(imageSummary, this.props.Document); + } + }); + }, + icon: "expand-arrows-alt" + }); ContextMenu.Instance.addItem({ description: "Video Funcs...", subitems: subitems }); } } @@ -155,13 +205,18 @@ export class VideoBox extends DocComponent(VideoD else this._youtubeContentCreated = false; let iframe = e.target; + let started = true; let onYoutubePlayerStateChange = (event: any) => runInAction(() => { - console.log("Event " + event.data); + if (started && event.data === YT.PlayerState.PLAYING) { + started = false; + this._youtubePlayer.unMute(); + this.Pause(); + return; + } if (event.data === YT.PlayerState.PLAYING && !this.Playing) this.Play(false); if (event.data === YT.PlayerState.PAUSED && this.Playing) this.Pause(false); }); let onYoutubePlayerReady = (event: any) => { - console.log("READY!"); this._reactionDisposer && this._reactionDisposer(); this._youtubeReactionDisposer && this._youtubeReactionDisposer(); this._reactionDisposer = reaction(() => this.props.Document.curPage, () => !this.Playing && this.Seek(this.Document.curPage || 0)); @@ -186,7 +241,7 @@ export class VideoBox extends DocComponent(VideoD let start = untracked(() => Math.round(NumCast(this.props.Document.curPage))); return ; } -- cgit v1.2.3-70-g09d2 From 6353522fbd8dc961b9c172b15d33af842fdab323 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 16 Jul 2019 17:03:41 -0400 Subject: Added deduplication of results --- src/client/views/search/SearchBox.tsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 04db26aca..cb4aef961 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -24,6 +24,7 @@ export class SearchBox extends React.Component { @observable private _resultsOpen: boolean = false; @observable private _searchbarOpen: boolean = false; @observable private _results: Doc[] = []; + private _resultsSet = new Set(); @observable private _openNoResults: boolean = false; @observable private _visibleElements: JSX.Element[] = []; @@ -61,6 +62,7 @@ export class SearchBox extends React.Component { this._openNoResults = false; this._results = []; + this._resultsSet.clear(); this._visibleElements = []; this._numTotalResults = -1; this._endIndex = -1; @@ -92,6 +94,7 @@ export class SearchBox extends React.Component { let query = this._searchString; query = FilterBox.Instance.getFinalQuery(query); this._results = []; + this._resultsSet.clear(); this._isSearch = []; this._visibleElements = []; @@ -120,7 +123,7 @@ export class SearchBox extends React.Component { private get filterQuery() { const types = FilterBox.Instance.filterTypes; - const includeDeleted = false; + const includeDeleted = FilterBox.Instance.getDataStatus(); return "NOT baseProto_b:true" + (includeDeleted ? "" : " AND NOT deleted:true") + (types ? ` AND (${types.map(type => `({!join from=id to=proto_i}type_t:"${type}" AND NOT type_t:*) OR type_t:"${type}"`).join(" ")})` : ""); } @@ -142,7 +145,13 @@ export class SearchBox extends React.Component { const docs = await Promise.all(res.docs.map(doc => Cast(doc.extendsDoc, Doc, doc as any))); let filteredDocs = FilterBox.Instance.filterDocsByType(docs); runInAction(() => { - this._results.push(...filteredDocs); + // this._results.push(...filteredDocs); + filteredDocs.forEach(doc => { + if (!this._resultsSet.has(doc)) { + this._results.push(doc); + this._resultsSet.add(doc); + } + }); }); this._curRequest = undefined; @@ -219,6 +228,7 @@ export class SearchBox extends React.Component { closeResults() { this._resultsOpen = false; this._results = []; + this._resultsSet.clear(); this._visibleElements = []; this._numTotalResults = -1; this._endIndex = -1; -- cgit v1.2.3-70-g09d2