From a2d2737fa4ec1a57f5288ed72eb44a2be4588ee8 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 13 Dec 2019 14:25:35 -0500 Subject: pdf path parsing fix in pdfviewer --- src/client/views/pdf/PDFViewer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 3aa5d1d2c..d16fe2edd 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -125,7 +125,7 @@ export class PDFViewer extends DocAnnotatableComponent this._showWaiting = this._showCover = true); this.props.startupLive && this.setupPdfJsViewer(); -- cgit v1.2.3-70-g09d2 From f49cf16cb4af2851aaa98bb2c6fce81271042fea Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 13 Dec 2019 15:12:04 -0500 Subject: path rosemary server fix --- solr-8.3.1/server/logs/solr_gc.log.0.current | 29 +++++++++++++++++++++++++++- src/client/views/pdf/PDFViewer.tsx | 11 +++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/solr-8.3.1/server/logs/solr_gc.log.0.current b/solr-8.3.1/server/logs/solr_gc.log.0.current index 4b5cdd721..e45ebc49d 100644 --- a/solr-8.3.1/server/logs/solr_gc.log.0.current +++ b/solr-8.3.1/server/logs/solr_gc.log.0.current @@ -295,4 +295,31 @@ Heap after GC invocations=4 (full 0): 2019-12-13T14:20:31.796-0500: 65.642: Total time for which application threads were stopped: 0.0000504 seconds, Stopping threads took: 0.0000174 seconds 2019-12-13T14:20:31.796-0500: 65.642: Total time for which application threads were stopped: 0.0000489 seconds, Stopping threads took: 0.0000240 seconds 2019-12-13T14:20:31.804-0500: 65.649: Total time for which application threads were stopped: 0.0000811 seconds, Stopping threads took: 0.0000239 seconds -2019-12-13T14:20:31.804-0500: 65.649: Total time for which application \ No newline at end of file +2019-12-13T14:20:31.804-0500: 65.649: Total time for which application threads were stopped: 0.0000578 seconds, Stopping threads took: 0.0000174 seconds +2019-12-13T14:20:31.806-0500: 65.651: Total time for which application threads were stopped: 0.0000609 seconds, Stopping threads took: 0.0000206 seconds +2019-12-13T14:20:31.806-0500: 65.651: Total time for which application threads were stopped: 0.0000415 seconds, Stopping threads took: 0.0000167 seconds +2019-12-13T14:20:31.807-0500: 65.652: Total time for which application threads were stopped: 0.0000417 seconds, Stopping threads took: 0.0000152 seconds +2019-12-13T14:20:31.807-0500: 65.652: Total time for which application threads were stopped: 0.0001659 seconds, Stopping threads took: 0.0001210 seconds +2019-12-13T14:20:31.809-0500: 65.655: Total time for which application threads were stopped: 0.0001285 seconds, Stopping threads took: 0.0000161 seconds +2019-12-13T14:20:31.848-0500: 65.694: Total time for which application threads were stopped: 0.0002375 seconds, Stopping threads took: 0.0000963 seconds +2019-12-13T14:20:32.849-0500: 66.694: Total time for which application threads were stopped: 0.0000762 seconds, Stopping threads took: 0.0000226 seconds +2019-12-13T14:20:33.221-0500: 67.066: Total time for which application threads were stopped: 0.0002122 seconds, Stopping threads took: 0.0000344 seconds +2019-12-13T14:20:33.355-0500: 67.200: Total time for which application threads were stopped: 0.0010525 seconds, Stopping threads took: 0.0009766 seconds +2019-12-13T14:20:33.380-0500: 67.226: Total time for which application threads were stopped: 0.0001911 seconds, Stopping threads took: 0.0001312 seconds +2019-12-13T14:20:34.380-0500: 68.226: Total time for which application threads were stopped: 0.0001102 seconds, Stopping threads took: 0.0000259 seconds +2019-12-13T14:21:22.760-0500: 116.604: Total time for which application threads were stopped: 0.0000779 seconds, Stopping threads took: 0.0000232 seconds +2019-12-13T14:21:23.760-0500: 117.604: Total time for which application threads were stopped: 0.0000733 seconds, Stopping threads took: 0.0000271 seconds +2019-12-13T14:21:30.763-0500: 124.606: Total time for which application threads were stopped: 0.0000739 seconds, Stopping threads took: 0.0000263 seconds +2019-12-13T14:21:31.763-0500: 125.606: Total time for which application threads were stopped: 0.0000665 seconds, Stopping threads took: 0.0000222 seconds +2019-12-13T14:22:01.781-0500: 155.623: Total time for which application threads were stopped: 0.0000777 seconds, Stopping threads took: 0.0000250 seconds +2019-12-13T14:22:25.795-0500: 179.636: Total time for which application threads were stopped: 0.0000737 seconds, Stopping threads took: 0.0000255 seconds +2019-12-13T14:22:30.798-0500: 184.639: Total time for which application threads were stopped: 0.0000908 seconds, Stopping threads took: 0.0000229 seconds +2019-12-13T14:23:30.828-0500: 244.667: Total time for which application threads were stopped: 0.0000805 seconds, Stopping threads took: 0.0000293 seconds +2019-12-13T14:24:30.864-0500: 304.700: Total time for which application threads were stopped: 0.0000739 seconds, Stopping threads took: 0.0000250 seconds +2019-12-13T14:25:30.899-0500: 364.733: Total time for which application threads were stopped: 0.0000832 seconds, Stopping threads took: 0.0000266 seconds +2019-12-13T14:27:30.954-0500: 484.784: Total time for which application threads were stopped: 0.0002355 seconds, Stopping threads took: 0.0001565 seconds +2019-12-13T14:28:01.968-0500: 515.796: Total time for which application threads were stopped: 0.0000752 seconds, Stopping threads took: 0.0000252 seconds +2019-12-13T14:28:30.983-0500: 544.810: Total time for which application threads were stopped: 0.0000737 seconds, Stopping threads took: 0.0000252 seconds +2019-12-13T14:29:31.010-0500: 604.836: Total time for which application threads were stopped: 0.0000722 seconds, Stopping threads took: 0.0000242 seconds +2019-12-13T14:30:31.042-0500: 664.865: Total time for which application threads were stopped: 0.0000756 seconds, Stopping threads took: 0.0000251 seconds +2019-12-13T14:31:31.0 \ No newline at end of file diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index a1f710617..4716e9d66 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -30,6 +30,7 @@ import { DocumentDecorations } from "../DocumentDecorations"; import { InkingControl } from "../InkingControl"; import { InkTool } from "../../../new_fields/InkField"; import { TraceMobx } from "../../../new_fields/util"; +import { PdfField } from "../../../new_fields/URLField"; const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer"); const pdfjsLib = require("pdfjs-dist"); @@ -125,6 +126,16 @@ export class PDFViewer extends DocAnnotatableComponent this._showWaiting = this._showCover = true); -- cgit v1.2.3-70-g09d2 From d4f793d73070594086c72cf67a8b2b0a60b2af77 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 13 Dec 2019 15:36:16 -0500 Subject: write to data doc + console logs for pdf fix --- src/client/views/pdf/PDFViewer.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 4716e9d66..253968443 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -126,15 +126,24 @@ export class PDFViewer extends DocAnnotatableComponent Date: Fri, 13 Dec 2019 15:48:13 -0500 Subject: absolute pathname to pdfbox, improved check --- src/client/views/nodes/PDFBox.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 0f5cc0fa9..af996b3d8 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -57,7 +57,7 @@ export class PDFBox extends DocAnnotatableComponent componentDidMount() { const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField); if (pdfUrl instanceof PdfField) { - Pdfjs.getDocument(pdfUrl.url.pathname).promise.then(pdf => runInAction(() => this._pdf = pdf)); + Pdfjs.getDocument(pdfUrl.url.href).promise.then(pdf => runInAction(() => this._pdf = pdf)); } this._selectReactionDisposer = reaction(() => this.props.isSelected(), () => { diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 253968443..41825cda7 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -137,7 +137,7 @@ export class PDFViewer extends DocAnnotatableComponent Date: Fri, 13 Dec 2019 16:49:10 -0500 Subject: server pdf stability improvements --- solr-8.3.1/server/logs/solr.log | 4 + solr-8.3.1/server/logs/solr_gc.log.0.current | 166 ++++++++++++++++++++++++++- src/client/views/pdf/PDFViewer.tsx | 9 +- src/server/ApiManagers/PDFManager.ts | 37 +++--- 4 files changed, 196 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/solr-8.3.1/server/logs/solr.log b/solr-8.3.1/server/logs/solr.log index 25c8bae75..10ed06cb3 100644 --- a/solr-8.3.1/server/logs/solr.log +++ b/solr-8.3.1/server/logs/solr.log @@ -31,3 +31,7 @@ 2019-12-13 19:19:30.793 INFO (main) [ ] o.e.j.s.AbstractConnector Started ServerConnector@8297b3a{HTTP/1.1,[http/1.1, h2c]}{0.0.0.0:8983} 2019-12-13 19:19:30.793 INFO (main) [ ] o.e.j.s.Server Started @4641ms 2019-12-13 19:19:31.371 INFO (qtp1664439369-23) [ ] o.a.s.s.HttpSolrCall [admin] webapp=null path=/admin/info/system params={wt=json} status=0 QTime=51 +2019-12-13 20:58:25.058 INFO (qtp1664439369-19) [ ] o.a.s.s.HttpSolrCall [admin] webapp=null path=/admin/info/system params={wt=json} status=0 QTime=42 +2019-12-13 20:58:36.863 INFO (qtp1664439369-22) [ ] o.a.s.s.HttpSolrCall [admin] webapp=null path=/admin/cores params={indexInfo=false&wt=json&_=1576270716757} status=0 QTime=6 +2019-12-13 20:58:36.894 INFO (qtp1664439369-18) [ ] o.a.s.s.HttpSolrCall [admin] webapp=null path=/admin/info/system params={wt=json&_=1576270716757} status=0 QTime=36 +2019-12-13 20:58:36.921 INFO (qtp1664439369-40) [ ] o.a.s.s.HttpSolrCall [admin] webapp=null path=/admin/info/system params={wt=json&_=1576270716757} status=0 QTime=24 diff --git a/solr-8.3.1/server/logs/solr_gc.log.0.current b/solr-8.3.1/server/logs/solr_gc.log.0.current index e45ebc49d..687372454 100644 --- a/solr-8.3.1/server/logs/solr_gc.log.0.current +++ b/solr-8.3.1/server/logs/solr_gc.log.0.current @@ -322,4 +322,168 @@ Heap after GC invocations=4 (full 0): 2019-12-13T14:28:30.983-0500: 544.810: Total time for which application threads were stopped: 0.0000737 seconds, Stopping threads took: 0.0000252 seconds 2019-12-13T14:29:31.010-0500: 604.836: Total time for which application threads were stopped: 0.0000722 seconds, Stopping threads took: 0.0000242 seconds 2019-12-13T14:30:31.042-0500: 664.865: Total time for which application threads were stopped: 0.0000756 seconds, Stopping threads took: 0.0000251 seconds -2019-12-13T14:31:31.0 \ No newline at end of file +2019-12-13T14:31:31.081-0500: 724.901: Total time for which application threads were stopped: 0.0002465 seconds, Stopping threads took: 0.0001502 seconds +2019-12-13T14:36:31.227-0500: 1025.037: Total time for which application threads were stopped: 0.0000861 seconds, Stopping threads took: 0.0000258 seconds +2019-12-13T14:36:55.239-0500: 1049.048: Total time for which application threads were stopped: 0.0000796 seconds, Stopping threads took: 0.0000297 seconds +2019-12-13T14:37:31.260-0500: 1085.068: Total time for which application threads were stopped: 0.0000800 seconds, Stopping threads took: 0.0000252 seconds +2019-12-13T14:39:31.321-0500: 1205.125: Total time for which application threads were stopped: 0.0000985 seconds, Stopping threads took: 0.0000317 seconds +2019-12-13T14:41:31.380-0500: 1325.180: Total time for which application threads were stopped: 0.0000677 seconds, Stopping threads took: 0.0000185 seconds +2019-12-13T14:42:31.415-0500: 1385.213: Total time for which application threads were stopped: 0.0000780 seconds, Stopping threads took: 0.0000247 seconds +2019-12-13T14:43:31.443-0500: 1445.239: Total time for which application threads were stopped: 0.0000742 seconds, Stopping threads took: 0.0000250 seconds +2019-12-13T14:44:31.467-0500: 1505.261: Total time for which application threads were stopped: 0.0000927 seconds, Stopping threads took: 0.0000250 seconds +2019-12-13T14:45:31.500-0500: 1565.292: Total time for which application threads were stopped: 0.0000861 seconds, Stopping threads took: 0.0000298 seconds +2019-12-13T14:46:31.532-0500: 1625.322: Total time for which application threads were stopped: 0.0000926 seconds, Stopping threads took: 0.0000288 seconds +2019-12-13T14:51:31.682-0500: 1925.463: Total time for which application threads were stopped: 0.0000831 seconds, Stopping threads took: 0.0000269 seconds +2019-12-13T14:52:29.711-0500: 1983.489: Total time for which application threads were stopped: 0.0000811 seconds, Stopping threads took: 0.0000264 seconds +2019-12-13T14:57:30.858-0500: 2284.628: Total time for which application threads were stopped: 0.0000834 seconds, Stopping threads took: 0.0000264 seconds +2019-12-13T15:17:31.465-0500: 3485.201: Total time for which application threads were stopped: 0.0001128 seconds, Stopping threads took: 0.0000462 seconds +2019-12-13T15:19:31.533-0500: 3605.266: Total time for which application threads were stopped: 0.0000927 seconds, Stopping threads took: 0.0000303 seconds +2019-12-13T15:23:31.655-0500: 3845.381: Total time for which application threads were stopped: 0.0000822 seconds, Stopping threads took: 0.0000273 seconds +2019-12-13T15:40:32.169-0500: 4865.871: Total time for which application threads were stopped: 0.0000997 seconds, Stopping threads took: 0.0000339 seconds +2019-12-13T15:41:32.197-0500: 4925.897: Total time for which application threads were stopped: 0.0000729 seconds, Stopping threads took: 0.0000235 seconds +2019-12-13T15:47:32.371-0500: 5286.063: Total time for which application threads were stopped: 0.0001041 seconds, Stopping threads took: 0.0000327 seconds +2019-12-13T15:51:32.487-0500: 5526.174: Total time for which application threads were stopped: 0.0000795 seconds, Stopping threads took: 0.0000253 seconds +2019-12-13T15:55:15.598-0500: 5749.280: Total time for which application threads were stopped: 0.0001565 seconds, Stopping threads took: 0.0000314 seconds +2019-12-13T15:56:32.638-0500: 5826.319: Total time for which application threads were stopped: 0.0000771 seconds, Stopping threads took: 0.0000240 seconds +2019-12-13T15:58:09.684-0500: 5923.363: Total time for which application threads were stopped: 0.0000708 seconds, Stopping threads took: 0.0000216 seconds +2019-12-13T15:58:25.054-0500: 5938.734: Total time for which application threads were stopped: 0.0003699 seconds, Stopping threads took: 0.0000196 seconds +2019-12-13T15:58:25.054-0500: 5938.734: Total time for which application threads were stopped: 0.0000675 seconds, Stopping threads took: 0.0000113 seconds +2019-12-13T15:58:25.054-0500: 5938.734: Total time for which application threads were stopped: 0.0000413 seconds, Stopping threads took: 0.0000101 seconds +2019-12-13T15:58:26.056-0500: 5939.735: Total time for which application threads were stopped: 0.0001509 seconds, Stopping threads took: 0.0000193 seconds +2019-12-13T15:58:35.718-0500: 5949.397: Total time for which application threads were stopped: 0.0001277 seconds, Stopping threads took: 0.0000247 seconds +2019-12-13T15:58:35.719-0500: 5949.398: Total time for which application threads were stopped: 0.0000785 seconds, Stopping threads took: 0.0000151 seconds +2019-12-13T15:58:35.762-0500: 5949.441: Total time for which application threads were stopped: 0.0000840 seconds, Stopping threads took: 0.0000249 seconds +2019-12-13T15:58:35.762-0500: 5949.441: Total time for which application threads were stopped: 0.0000521 seconds, Stopping threads took: 0.0000146 seconds +2019-12-13T15:58:35.762-0500: 5949.441: Total time for which application threads were stopped: 0.0000387 seconds, Stopping threads took: 0.0000131 seconds +2019-12-13T15:58:35.790-0500: 5949.469: Total time for which application threads were stopped: 0.0000792 seconds, Stopping threads took: 0.0000227 seconds +2019-12-13T15:58:35.825-0500: 5949.505: Total time for which application threads were stopped: 0.0018974 seconds, Stopping threads took: 0.0009431 seconds +2019-12-13T15:58:35.845-0500: 5949.524: Total time for which application threads were stopped: 0.0038627 seconds, Stopping threads took: 0.0037713 seconds +2019-12-13T15:58:35.845-0500: 5949.525: Total time for which application threads were stopped: 0.0003415 seconds, Stopping threads took: 0.0002770 seconds +2019-12-13T15:58:35.856-0500: 5949.535: Total time for which application threads were stopped: 0.0001537 seconds, Stopping threads took: 0.0000599 seconds +2019-12-13T15:58:35.856-0500: 5949.535: Total time for which application threads were stopped: 0.0001040 seconds, Stopping threads took: 0.0000346 seconds +2019-12-13T15:58:35.861-0500: 5949.540: Total time for which application threads were stopped: 0.0001447 seconds, Stopping threads took: 0.0000367 seconds +2019-12-13T15:58:35.871-0500: 5949.551: Total time for which application threads were stopped: 0.0001568 seconds, Stopping threads took: 0.0000513 seconds +2019-12-13T15:58:35.876-0500: 5949.555: Total time for which application threads were stopped: 0.0002530 seconds, Stopping threads took: 0.0000532 seconds +2019-12-13T15:58:35.885-0500: 5949.564: Total time for which application threads were stopped: 0.0015837 seconds, Stopping threads took: 0.0014686 seconds +2019-12-13T15:58:35.897-0500: 5949.576: Total time for which application threads were stopped: 0.0001451 seconds, Stopping threads took: 0.0000412 seconds +2019-12-13T15:58:35.897-0500: 5949.577: Total time for which application threads were stopped: 0.0001025 seconds, Stopping threads took: 0.0000230 seconds +2019-12-13T15:58:35.897-0500: 5949.577: Total time for which application threads were stopped: 0.0000632 seconds, Stopping threads took: 0.0000166 seconds +2019-12-13T15:58:35.897-0500: 5949.577: Total time for which application threads were stopped: 0.0000689 seconds, Stopping threads took: 0.0000172 seconds +2019-12-13T15:58:35.897-0500: 5949.577: Total time for which application threads were stopped: 0.0000850 seconds, Stopping threads took: 0.0000176 seconds +2019-12-13T15:58:35.898-0500: 5949.577: Total time for which application threads were stopped: 0.0001922 seconds, Stopping threads took: 0.0001196 seconds +2019-12-13T15:58:35.898-0500: 5949.577: Total time for which application threads were stopped: 0.0000606 seconds, Stopping threads took: 0.0000168 seconds +2019-12-13T15:58:35.898-0500: 5949.577: Total time for which application threads were stopped: 0.0000555 seconds, Stopping threads took: 0.0000159 seconds +2019-12-13T15:58:35.898-0500: 5949.577: Total time for which application threads were stopped: 0.0000564 seconds, Stopping threads took: 0.0000160 seconds +2019-12-13T15:58:35.898-0500: 5949.577: Total time for which application threads were stopped: 0.0000587 seconds, Stopping threads took: 0.0000161 seconds +2019-12-13T15:58:35.927-0500: 5949.607: Total time for which application threads were stopped: 0.0001109 seconds, Stopping threads took: 0.0000534 seconds +2019-12-13T15:58:36.856-0500: 5950.535: Total time for which application threads were stopped: 0.0001815 seconds, Stopping threads took: 0.0000219 seconds +2019-12-13T15:58:37.856-0500: 5951.535: Total time for which application threads were stopped: 0.0000822 seconds, Stopping threads took: 0.0000206 seconds +2019-12-13T15:58:46.860-0500: 5960.539: Total time for which application threads were stopped: 0.0000913 seconds, Stopping threads took: 0.0000300 seconds +2019-12-13T15:58:59.867-0500: 5973.545: Total time for which application threads were stopped: 0.0000974 seconds, Stopping threads took: 0.0000263 seconds +2019-12-13T15:59:31.882-0500: 6005.560: Total time for which application threads were stopped: 0.0001038 seconds, Stopping threads took: 0.0000309 seconds +2019-12-13T16:00:35.912-0500: 6069.588: Total time for which application threads were stopped: 0.0000783 seconds, Stopping threads took: 0.0000223 seconds +2019-12-13T16:02:55.980-0500: 6209.653: Total time for which application threads were stopped: 0.0000870 seconds, Stopping threads took: 0.0000270 seconds +2019-12-13T16:07:01.094-0500: 6454.762: Total time for which application threads were stopped: 0.0001021 seconds, Stopping threads took: 0.0000318 seconds +2019-12-13T16:07:51.119-0500: 6504.786: Total time for which application threads were stopped: 0.0000833 seconds, Stopping threads took: 0.0000264 seconds +2019-12-13T16:09:42.175-0500: 6615.841: Total time for which application threads were stopped: 0.0001578 seconds, Stopping threads took: 0.0001029 seconds +2019-12-13T16:09:47.178-0500: 6620.843: Total time for which application threads were stopped: 0.0000833 seconds, Stopping threads took: 0.0000343 seconds +2019-12-13T16:09:52.181-0500: 6625.847: Total time for which application threads were stopped: 0.0000839 seconds, Stopping threads took: 0.0000264 seconds +2019-12-13T16:09:54.183-0500: 6627.848: Total time for which application threads were stopped: 0.0000903 seconds, Stopping threads took: 0.0000231 seconds +2019-12-13T16:09:55.183-0500: 6628.848: Total time for which application threads were stopped: 0.0000877 seconds, Stopping threads took: 0.0000241 seconds +2019-12-13T16:09:56.184-0500: 6629.849: Total time for which application threads were stopped: 0.0001001 seconds, Stopping threads took: 0.0000234 seconds +2019-12-13T16:10:02.186-0500: 6635.851: Total time for which application threads were stopped: 0.0000840 seconds, Stopping threads took: 0.0000265 seconds +2019-12-13T16:10:04.187-0500: 6637.852: Total time for which application threads were stopped: 0.0001204 seconds, Stopping threads took: 0.0000261 seconds +2019-12-13T16:10:21.197-0500: 6654.861: Total time for which application threads were stopped: 0.0000971 seconds, Stopping threads took: 0.0000267 seconds +2019-12-13T16:10:22.197-0500: 6655.862: Total time for which application threads were stopped: 0.0000808 seconds, Stopping threads took: 0.0000242 seconds +2019-12-13T16:10:23.198-0500: 6656.862: Total time for which application threads were stopped: 0.0000840 seconds, Stopping threads took: 0.0000238 seconds +2019-12-13T16:10:24.198-0500: 6657.863: Total time for which application threads were stopped: 0.0000868 seconds, Stopping threads took: 0.0000266 seconds +2019-12-13T16:10:25.199-0500: 6658.864: Total time for which application threads were stopped: 0.0000835 seconds, Stopping threads took: 0.0000269 seconds +2019-12-13T16:12:13.248-0500: 6766.911: Total time for which application threads were stopped: 0.0001228 seconds, Stopping threads took: 0.0000299 seconds +2019-12-13T16:12:56.273-0500: 6809.935: Total time for which application threads were stopped: 0.0001019 seconds, Stopping threads took: 0.0000298 seconds +2019-12-13T16:13:04.277-0500: 6817.939: Total time for which application threads were stopped: 0.0000859 seconds, Stopping threads took: 0.0000274 seconds +2019-12-13T16:14:31.319-0500: 6904.979: Total time for which application threads were stopped: 0.0001123 seconds, Stopping threads took: 0.0000309 seconds +2019-12-13T16:14:32.319-0500: 6905.979: Total time for which application threads were stopped: 0.0001097 seconds, Stopping threads took: 0.0000280 seconds +2019-12-13T16:16:32.379-0500: 7026.037: Total time for which application threads were stopped: 0.0000783 seconds, Stopping threads took: 0.0000233 seconds +2019-12-13T16:17:31.409-0500: 7085.066: Total time for which application threads were stopped: 0.0000940 seconds, Stopping threads took: 0.0000354 seconds +2019-12-13T16:18:36.447-0500: 7150.103: Total time for which application threads were stopped: 0.0000948 seconds, Stopping threads took: 0.0000364 seconds +2019-12-13T16:19:01.459-0500: 7175.114: Total time for which application threads were stopped: 0.0000938 seconds, Stopping threads took: 0.0000270 seconds +2019-12-13T16:19:31.474-0500: 7205.129: Total time for which application threads were stopped: 0.0000943 seconds, Stopping threads took: 0.0000283 seconds +2019-12-13T16:19:32.474-0500: 7206.129: Total time for which application threads were stopped: 0.0000866 seconds, Stopping threads took: 0.0000244 seconds +2019-12-13T16:21:26.529-0500: 7320.182: Total time for which application threads were stopped: 0.0000850 seconds, Stopping threads took: 0.0000263 seconds +2019-12-13T16:21:32.532-0500: 7326.184: Total time for which application threads were stopped: 0.0000867 seconds, Stopping threads took: 0.0000260 seconds +2019-12-13T16:22:32.557-0500: 7386.209: Total time for which application threads were stopped: 0.0000828 seconds, Stopping threads took: 0.0000258 seconds +2019-12-13T16:23:09.578-0500: 7423.228: Total time for which application threads were stopped: 0.0000867 seconds, Stopping threads took: 0.0000266 seconds +2019-12-13T16:23:12.579-0500: 7426.230: Total time for which application threads were stopped: 0.0000878 seconds, Stopping threads took: 0.0000262 seconds +2019-12-13T16:23:13.579-0500: 7427.230: Total time for which application threads were stopped: 0.0001116 seconds, Stopping threads took: 0.0000279 seconds +2019-12-13T16:23:14.580-0500: 7428.231: Total time for which application threads were stopped: 0.0000861 seconds, Stopping threads took: 0.0000273 seconds +2019-12-13T16:23:18.581-0500: 7432.232: Total time for which application threads were stopped: 0.0000899 seconds, Stopping threads took: 0.0000285 seconds +2019-12-13T16:23:31.589-0500: 7445.240: Total time for which application threads were stopped: 0.0000942 seconds, Stopping threads took: 0.0000286 seconds +2019-12-13T16:23:39.593-0500: 7453.243: Total time for which application threads were stopped: 0.0001319 seconds, Stopping threads took: 0.0000374 seconds +2019-12-13T16:23:41.594-0500: 7455.244: Total time for which application threads were stopped: 0.0000986 seconds, Stopping threads took: 0.0000269 seconds +2019-12-13T16:23:44.596-0500: 7458.246: Total time for which application threads were stopped: 0.0000753 seconds, Stopping threads took: 0.0000196 seconds +2019-12-13T16:23:45.597-0500: 7459.247: Total time for which application threads were stopped: 0.0000923 seconds, Stopping threads took: 0.0000269 seconds +2019-12-13T16:23:50.598-0500: 7464.248: Total time for which application threads were stopped: 0.0000901 seconds, Stopping threads took: 0.0000260 seconds +2019-12-13T16:24:02.603-0500: 7476.253: Total time for which application threads were stopped: 0.0000879 seconds, Stopping threads took: 0.0000266 seconds +2019-12-13T16:24:03.603-0500: 7477.253: Total time for which application threads were stopped: 0.0000809 seconds, Stopping threads took: 0.0000256 seconds +2019-12-13T16:24:05.604-0500: 7479.254: Total time for which application threads were stopped: 0.0000870 seconds, Stopping threads took: 0.0000265 seconds +2019-12-13T16:24:07.605-0500: 7481.255: Total time for which application threads were stopped: 0.0000906 seconds, Stopping threads took: 0.0000275 seconds +2019-12-13T16:24:09.606-0500: 7483.256: Total time for which application threads were stopped: 0.0000833 seconds, Stopping threads took: 0.0000252 seconds +2019-12-13T16:24:10.606-0500: 7484.256: Total time for which application threads were stopped: 0.0000848 seconds, Stopping threads took: 0.0000252 seconds +2019-12-13T16:24:11.606-0500: 7485.256: Total time for which application threads were stopped: 0.0000895 seconds, Stopping threads took: 0.0000260 seconds +2019-12-13T16:24:12.607-0500: 7486.257: Total time for which application threads were stopped: 0.0000837 seconds, Stopping threads took: 0.0000257 seconds +2019-12-13T16:24:14.608-0500: 7488.258: Total time for which application threads were stopped: 0.0000851 seconds, Stopping threads took: 0.0000265 seconds +2019-12-13T16:24:16.609-0500: 7490.259: Total time for which application threads were stopped: 0.0000911 seconds, Stopping threads took: 0.0000254 seconds +2019-12-13T16:24:24.612-0500: 7498.261: Total time for which application threads were stopped: 0.0001183 seconds, Stopping threads took: 0.0000294 seconds +2019-12-13T16:24:25.612-0500: 7499.262: Total time for which application threads were stopped: 0.0002358 seconds, Stopping threads took: 0.0001474 seconds +2019-12-13T16:24:50.625-0500: 7524.274: Total time for which application threads were stopped: 0.0000804 seconds, Stopping threads took: 0.0000241 seconds +2019-12-13T16:30:42.805-0500: 7876.448: Total time for which application threads were stopped: 0.0002015 seconds, Stopping threads took: 0.0000382 seconds +2019-12-13T16:36:07.971-0500: 8201.609: Total time for which application threads were stopped: 0.0001098 seconds, Stopping threads took: 0.0000310 seconds +2019-12-13T16:36:16.975-0500: 8210.612: Total time for which application threads were stopped: 0.0000827 seconds, Stopping threads took: 0.0000270 seconds +2019-12-13T16:36:31.982-0500: 8225.619: Total time for which application threads were stopped: 0.0000675 seconds, Stopping threads took: 0.0000229 seconds +2019-12-13T16:36:32.982-0500: 8226.620: Total time for which application threads were stopped: 0.0000745 seconds, Stopping threads took: 0.0000217 seconds +2019-12-13T16:44:33.635-0500: 8707.266: Total time for which application threads were stopped: 0.0007029 seconds, Stopping threads took: 0.0003845 seconds +2019-12-13T16:44:34.637-0500: 8708.267: Total time for which application threads were stopped: 0.0001147 seconds, Stopping threads took: 0.0000310 seconds +2019-12-13T16:45:15.662-0500: 8749.291: Total time for which application threads were stopped: 0.0001041 seconds, Stopping threads took: 0.0000289 seconds +2019-12-13T16:45:26.667-0500: 8760.296: Total time for which application threads were stopped: 0.0001035 seconds, Stopping threads took: 0.0000324 seconds +{Heap before GC invocations=5 (full 0): + garbage-first heap total 524288K, used 330659K [0x00000000e0000000, 0x00000000e0101000, 0x0000000100000000) + region size 1024K, 307 young (314368K), 4 survivors (4096K) + Metaspace used 32005K, capacity 33082K, committed 33408K, reserved 1079296K + class space used 3875K, capacity 4129K, committed 4224K, reserved 1048576K +2019-12-13T16:45:41.460-0500: 8775.090: [GC pause (G1 Evacuation Pause) (young) +Desired survivor size 20447232 bytes, new threshold 15 (max 15) +- age 1: 394704 bytes, 394704 total +- age 2: 1186424 bytes, 1581128 total +, 0.1129248 secs] + [Parallel Time: 99.7 ms, GC Workers: 8] + [GC Worker Start (ms): Min: 8775094.0, Avg: 8775094.9, Max: 8775095.4, Diff: 1.5] + [Ext Root Scanning (ms): Min: 1.3, Avg: 12.0, Max: 70.9, Diff: 69.6, Sum: 95.9] + [Update RS (ms): Min: 0.0, Avg: 5.9, Max: 14.2, Diff: 14.2, Sum: 47.5] + [Processed Buffers: Min: 0, Avg: 3.6, Max: 10, Diff: 10, Sum: 29] + [Scan RS (ms): Min: 0.0, Avg: 0.0, Max: 0.1, Diff: 0.1, Sum: 0.3] + [Code Root Scanning (ms): Min: 0.0, Avg: 0.9, Max: 2.1, Diff: 2.1, Sum: 6.9] + [Object Copy (ms): Min: 12.1, Avg: 58.2, Max: 74.6, Diff: 62.6, Sum: 465.7] + [Termination (ms): Min: 15.1, Avg: 21.2, Max: 25.9, Diff: 10.8, Sum: 170.0] + [Termination Attempts: Min: 145, Avg: 171.0, Max: 187, Diff: 42, Sum: 1368] + [GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.1, Diff: 0.1, Sum: 0.3] + [GC Worker Total (ms): Min: 97.8, Avg: 98.3, Max: 99.2, Diff: 1.5, Sum: 786.5] + [GC Worker End (ms): Min: 8775193.2, Avg: 8775193.2, Max: 8775193.2, Diff: 0.0] + [Code Root Fixup: 0.4 ms] + [Code Root Purge: 0.8 ms] + [Clear CT: 0.5 ms] + [Other: 11.6 ms] + [Choose CSet: 0.0 ms] + [Ref Proc: 6.1 ms] + [Ref Enq: 0.1 ms] + [Redirty Cards: 0.2 ms] + [Humongous Register: 0.6 ms] + [Humongous Reclaim: 0.0 ms] + [Free CSet: 0.8 ms] + [Eden: 303.0M(303.0M)->0.0B(289.0M) Survivors: 4096.0K->18.0M Heap: 322.9M(512.0M)->33.2M(512.0M)] +Heap after GC invocations=6 (full 0): + garbage-first heap total 524288K, used 34032K [0x00000000e0000000, 0x00000000e0101000, 0x0000000100000000) + region size 1024K, 18 young (18432K), 18 survivors (18432K) + Metaspace used 32005K, capacity 33082K, committed 33408K, reserved 1079296K + class space used 3875K, capacity 4129K, committed 4224K, reserved 1048576K +} + [Times: user=0.20 sys=0.20, real=0.11 secs] diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 41825cda7..450add208 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -136,16 +136,18 @@ export class PDFViewer extends DocAnnotatableComponent this._showWaiting = this._showCover = true); this.props.startupLive && this.setupPdfJsViewer(); @@ -623,7 +625,8 @@ export class PDFViewer extends DocAnnotatableComponent this._coverPath.path = "http://www.cs.brown.edu/~bcz/face.gif")} onLoad={action(() => this._showWaiting = false)} + const resolved = Utils.prepend(this._coverPath.path); + return this._coverPath.path = "http://www.cs.brown.edu/~bcz/face.gif")} onLoad={action(() => this._showWaiting = false)} style={{ position: "absolute", display: "inline-block", top: 0, left: 0, width: `${nativeWidth}px`, height: `${nativeHeight}px` }} />; } diff --git a/src/server/ApiManagers/PDFManager.ts b/src/server/ApiManagers/PDFManager.ts index a190ab0cb..30fadfebd 100644 --- a/src/server/ApiManagers/PDFManager.ts +++ b/src/server/ApiManagers/PDFManager.ts @@ -24,6 +24,14 @@ export default class PDFManager extends ApiManager { } +function dispatchThumbnail(res: express.Response, { width, height }: Pdfjs.PDFPageViewport, thumbnailName: string) { + res.send({ + path: clientPathToFile(Directory.pdf_thumbnails, thumbnailName), + width, + height + }); +} + function getOrCreateThumbnail(thumbnailName: string, res: express.Response) { const noExtension = thumbnailName.substring(0, thumbnailName.length - ".png".length); const pageString = noExtension.split('-')[1]; @@ -33,17 +41,13 @@ function getOrCreateThumbnail(thumbnailName: string, res: express.Response) { exists(path, (exists: boolean) => { if (exists) { const existingThumbnail = createReadStream(path); - imageSize(existingThumbnail, (err: any, { width, height }: any) => { + imageSize(existingThumbnail, (err: any, viewport: any) => { if (err) { console.log(red(`In PDF thumbnail response, unable to determine dimensions of ${thumbnailName}:`)); console.log(err); return; } - res.send({ - path: clientPathToFile(Directory.pdf_thumbnails, thumbnailName), - width, - height - }); + dispatchThumbnail(res, viewport, thumbnailName); }); } else { const offset = thumbnailName.length - pageString.length - 5; @@ -70,19 +74,20 @@ async function CreateThumbnail(file: string, pageNumber: number, res: express.Re await page.render(renderContext).promise; const pngStream = canvas.createPNGStream(); const filenames = path.basename(file).split("."); - const pngFile = serverPathToFile(Directory.pdf_thumbnails, `${filenames[0]}-${pageNumber}.png`); + const thumbnailName = `${filenames[0]}-${pageNumber}.png`; + const pngFile = serverPathToFile(Directory.pdf_thumbnails, thumbnailName); const out = createWriteStream(pngFile); pngStream.pipe(out); - out.on("finish", () => { - res.send({ - path: pngFile, - width: viewport.width, - height: viewport.height + return new Promise((resolve, reject) => { + out.on("finish", () => { + dispatchThumbnail(res, viewport, thumbnailName); + resolve(); + }); + out.on("error", error => { + console.log(red(`In PDF thumbnail creation, encountered the following error when piping ${pngFile}:`)); + console.log(error); + reject(); }); - }); - out.on("error", error => { - console.log(red(`In PDF thumbnail creation, encountered the following error when piping ${pngFile}:`)); - console.log(error); }); } -- cgit v1.2.3-70-g09d2 From 6e6c4f7fd6b36cae11b9dc5089e672f457d5944f Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 13 Dec 2019 17:04:23 -0500 Subject: added re-write check to constructor --- src/client/views/pdf/PDFViewer.tsx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 450add208..648522cd9 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -121,11 +121,8 @@ export class PDFViewer extends DocAnnotatableComponent this._script.run({ this: anno }, console.log, true).result); } - _lastSearch: string = ""; - componentDidMount = async () => { - !this.props.Document.lockedTransform && (this.props.Document.lockedTransform = true); - // change the address to be the file address of the PNG version of each page - // file address of the pdf + constructor(props: any) { + super(props); const backup = "oldPath"; const { url, Document } = this.props; const pathCorrectionTest = /upload\_[a-z0-9]{32}.(.*)/g; @@ -147,6 +144,13 @@ export class PDFViewer extends DocAnnotatableComponent { + !this.props.Document.lockedTransform && (this.props.Document.lockedTransform = true); + // change the address to be the file address of the PNG version of each page + // file address of the pdf const path = Utils.prepend(`/thumbnail${this.props.url.substring("files/pdfs/".length, this.props.url.length - ".pdf".length)}-${(this.Document.curPage || 1)}.png`); this._coverPath = JSON.parse(await rp.get(path)); runInAction(() => this._showWaiting = this._showCover = true); -- cgit v1.2.3-70-g09d2 From c983198f504eabe45e6b4110283b0f53211622b8 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 13 Dec 2019 17:19:31 -0500 Subject: async pdf fixes --- src/server/ApiManagers/PDFManager.ts | 57 ++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/server/ApiManagers/PDFManager.ts b/src/server/ApiManagers/PDFManager.ts index 30fadfebd..7e862631d 100644 --- a/src/server/ApiManagers/PDFManager.ts +++ b/src/server/ApiManagers/PDFManager.ts @@ -1,7 +1,7 @@ import ApiManager, { Registration } from "./ApiManager"; import { Method } from "../RouteManager"; import RouteSubscriber from "../RouteSubscriber"; -import { exists, createReadStream, createWriteStream } from "fs"; +import { existsSync, createReadStream, createWriteStream } from "fs"; import * as Pdfjs from 'pdfjs-dist'; import { createCanvas } from "canvas"; const imageSize = require("probe-image-size"); @@ -24,39 +24,30 @@ export default class PDFManager extends ApiManager { } -function dispatchThumbnail(res: express.Response, { width, height }: Pdfjs.PDFPageViewport, thumbnailName: string) { - res.send({ - path: clientPathToFile(Directory.pdf_thumbnails, thumbnailName), - width, - height - }); -} - -function getOrCreateThumbnail(thumbnailName: string, res: express.Response) { +async function getOrCreateThumbnail(thumbnailName: string, res: express.Response): Promise { const noExtension = thumbnailName.substring(0, thumbnailName.length - ".png".length); const pageString = noExtension.split('-')[1]; const pageNumber = parseInt(pageString); - return new Promise(resolve => { + return new Promise(async resolve => { const path = serverPathToFile(Directory.pdf_thumbnails, thumbnailName); - exists(path, (exists: boolean) => { - if (exists) { - const existingThumbnail = createReadStream(path); - imageSize(existingThumbnail, (err: any, viewport: any) => { - if (err) { - console.log(red(`In PDF thumbnail response, unable to determine dimensions of ${thumbnailName}:`)); - console.log(err); - return; - } - dispatchThumbnail(res, viewport, thumbnailName); - }); - } else { - const offset = thumbnailName.length - pageString.length - 5; - const name = thumbnailName.substring(0, offset) + ".pdf"; - const path = serverPathToFile(Directory.pdfs, name); - CreateThumbnail(path, pageNumber, res); + if (existsSync(path)) { + const existingThumbnail = createReadStream(path); + const { err, viewport } = await new Promise(resolve => { + imageSize(existingThumbnail, (err: any, viewport: any) => resolve({ err, viewport })); + }); + if (err) { + console.log(red(`In PDF thumbnail response, unable to determine dimensions of ${thumbnailName}:`)); + console.log(err); + return; } - resolve(); - }); + dispatchThumbnail(res, viewport, thumbnailName); + } else { + const offset = thumbnailName.length - pageString.length - 5; + const name = thumbnailName.substring(0, offset) + ".pdf"; + const path = serverPathToFile(Directory.pdfs, name); + await CreateThumbnail(path, pageNumber, res); + } + resolve(); }); } @@ -91,6 +82,14 @@ async function CreateThumbnail(file: string, pageNumber: number, res: express.Re }); } +function dispatchThumbnail(res: express.Response, { width, height }: Pdfjs.PDFPageViewport, thumbnailName: string) { + res.send({ + path: clientPathToFile(Directory.pdf_thumbnails, thumbnailName), + width, + height + }); +} + class NodeCanvasFactory { create = (width: number, height: number) => { -- cgit v1.2.3-70-g09d2 From 4a0cd5a75d6f77067ee5d119012c489d73ffb649 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 13 Dec 2019 17:31:21 -0500 Subject: wrong constructor dammit --- src/client/views/nodes/PDFBox.tsx | 27 +++++++++++++++++++++++++-- src/client/views/pdf/PDFViewer.tsx | 25 ------------------------- 2 files changed, 25 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index af996b3d8..9f67f3eab 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -6,8 +6,8 @@ import "pdfjs-dist/web/pdf_viewer.css"; import { Opt, WidthSym, Doc } from "../../../new_fields/Doc"; import { makeInterface } from "../../../new_fields/Schema"; import { ScriptField } from '../../../new_fields/ScriptField'; -import { Cast, NumCast } from "../../../new_fields/Types"; -import { PdfField } from "../../../new_fields/URLField"; +import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; +import { PdfField, URLField } from "../../../new_fields/URLField"; import { Utils } from '../../../Utils'; import { KeyCodes } from '../../northstar/utils/KeyCodes'; import { undoBatch } from '../../util/UndoManager'; @@ -49,6 +49,29 @@ export class PDFBox extends DocAnnotatableComponent constructor(props: any) { super(props); this._initialScale = this.props.ScreenToLocalTransform().Scale; + + const backup = "oldPath"; + const { Document } = this.props; + const { url: { href } } = Cast(Document[this.props.fieldKey], PdfField)!; + const pathCorrectionTest = /upload\_[a-z0-9]{32}.(.*)/g; + const matches = pathCorrectionTest.exec(href); + console.log("\nHere's the { url } being fed into the outer regex:"); + console.log(href); + console.log("And here's the 'properPath' build from the captured filename:\n"); + if (matches !== null) { + const properPath = Utils.prepend(`/files/pdfs/${matches[0]}`); + console.log(properPath); + if (!properPath.includes(href)) { + console.log(`The two (url and proper path) were not equal`); + const proto = Doc.GetProto(Document); + proto[this.props.fieldKey] = new PdfField(properPath); + proto[backup] = href; + } else { + console.log(`The two (url and proper path) were equal`); + } + } else { + console.log("Outer matches was null!"); + } } componentWillUnmount() { diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 648522cd9..e34d353f4 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -121,31 +121,6 @@ export class PDFViewer extends DocAnnotatableComponent this._script.run({ this: anno }, console.log, true).result); } - constructor(props: any) { - super(props); - const backup = "oldPath"; - const { url, Document } = this.props; - const pathCorrectionTest = /upload\_[a-z0-9]{32}.(.*)/g; - const matches = pathCorrectionTest.exec(url); - console.log("\nHere's the { url } being fed into the outer regex:"); - console.log(url); - console.log("And here's the 'properPath' build from the captured filename:\n"); - if (matches !== null) { - const properPath = Utils.prepend(`/files/pdfs/${matches[0]}`); - console.log(properPath); - if (!properPath.includes(url)) { - console.log(`The two (url and proper path) were not equal`); - const proto = Doc.GetProto(Document); - proto[this.props.fieldKey] = new PdfField(properPath); - proto[backup] = url; - } else { - console.log(`The two (url and proper path) were equal`); - } - } else { - console.log("Outer matches was null!"); - } - } - _lastSearch: string = ""; componentDidMount = async () => { !this.props.Document.lockedTransform && (this.props.Document.lockedTransform = true); -- cgit v1.2.3-70-g09d2 From 56e384f2d97d2c399adf21fcf58143773fe3fd53 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 14 Dec 2019 01:51:13 -0500 Subject: fixes to make nativewidth/height more robust for PDFs. fixes for search - filter out extension docs. --- src/client/documents/Documents.ts | 11 ++++--- src/client/util/DragManager.ts | 23 ++++++++------ .../util/Import & Export/DirectoryImportBox.tsx | 7 +---- src/client/util/SearchUtil.ts | 4 +-- src/client/views/DocComponent.tsx | 1 + src/client/views/collections/CollectionSubView.tsx | 4 +-- .../views/collections/ParentDocumentSelector.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 34 ++++++++++++-------- src/client/views/pdf/PDFMenu.tsx | 36 ++-------------------- src/client/views/pdf/PDFViewer.tsx | 4 +-- src/client/views/search/SearchBox.tsx | 5 ++- src/new_fields/Doc.ts | 11 +++++-- 12 files changed, 61 insertions(+), 81 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 7df08c7e6..4ba45ac30 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -112,7 +112,7 @@ export interface DocumentOptions { dropConverter?: ScriptField; // script to run when documents are dropped on this Document. strokeWidth?: number; color?: string; - limitHeight?:number; // maximum height for newly created (eg, from pasting) text documents + limitHeight?: number; // maximum height for newly created (eg, from pasting) text documents // [key: string]: Opt; } @@ -181,7 +181,7 @@ export namespace Docs { }], [DocumentType.PDF, { layout: { view: PDFBox, dataField: data }, - options: { nativeWidth: 1200, curPage: 1 } + options: { curPage: 1 } }], [DocumentType.ICON, { layout: { view: IconBox, dataField: data }, @@ -644,17 +644,20 @@ export namespace Docs { let ctor: ((path: string, options: DocumentOptions) => (Doc | Promise)) | undefined = undefined; if (type.indexOf("image") !== -1) { ctor = Docs.Create.ImageDocument; + if (!options.width) options.width = 300; } if (type.indexOf("video") !== -1) { ctor = Docs.Create.VideoDocument; + if (!options.width) options.width = 600; + if (!options.height) options.height = options.width * 2 / 3; } if (type.indexOf("audio") !== -1) { ctor = Docs.Create.AudioDocument; } if (type.indexOf("pdf") !== -1) { ctor = Docs.Create.PdfDocument; - options.nativeWidth = 927; - options.nativeHeight = 1200; + if (!options.width) options.width = 400; + if (!options.height) options.height = options.width * 1200 / 927; } if (type.indexOf("excel") !== -1) { ctor = Docs.Create.DBDocument; diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 326262895..2631a1e3c 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -18,7 +18,7 @@ import { convertDropDataToButtons } from "./DropConverter"; export type dropActionType = "alias" | "copy" | undefined; export function SetupDrag( _reference: React.RefObject, - docFunc: () => Doc | Promise, + docFunc: () => Doc | Promise | undefined, moveFunc?: DragManager.MoveFunction, dropAction?: dropActionType, treeViewId?: string, @@ -32,13 +32,15 @@ export function SetupDrag( document.removeEventListener("pointermove", onRowMove); document.removeEventListener('pointerup', onRowUp); const doc = await docFunc(); - const dragData = new DragManager.DocumentDragData([doc]); - dragData.dropAction = dropAction; - dragData.moveDocument = moveFunc; - dragData.treeViewId = treeViewId; - dragData.dontHideOnDrop = dontHideOnDrop; - DragManager.StartDocumentDrag([_reference.current!], dragData, e.x, e.y); - dragStarted && dragStarted(); + if (doc) { + const dragData = new DragManager.DocumentDragData([doc]); + dragData.dropAction = dropAction; + dragData.moveDocument = moveFunc; + dragData.treeViewId = treeViewId; + dragData.dontHideOnDrop = dontHideOnDrop; + DragManager.StartDocumentDrag([_reference.current!], dragData, e.x, e.y); + dragStarted && dragStarted(); + } }; const onRowUp = (): void => { document.removeEventListener("pointermove", onRowMove); @@ -49,12 +51,13 @@ export function SetupDrag( e.stopPropagation(); if (e.shiftKey && CollectionDockingView.Instance) { e.persist(); - CollectionDockingView.Instance.StartOtherDrag({ + let dragDoc = await docFunc(); + dragDoc && CollectionDockingView.Instance.StartOtherDrag({ pageX: e.pageX, pageY: e.pageY, preventDefault: emptyFunction, button: 0 - }, [await docFunc()]); + }, [dragDoc]); } else { document.addEventListener("pointermove", onRowMove); document.addEventListener("pointerup", onRowUp); diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx index e6a215b2c..5b5bffd8c 100644 --- a/src/client/util/Import & Export/DirectoryImportBox.tsx +++ b/src/client/util/Import & Export/DirectoryImportBox.tsx @@ -122,12 +122,7 @@ export default class DirectoryImportBox extends React.Component await Promise.all(uploads.map(async ({ name, type, clientAccessPath, exifData }) => { const path = Utils.prepend(clientAccessPath); - const options = { - nativeWidth: 300, - width: 300, - title: name - }; - const document = await Docs.Get.DocumentFromType(type, path, options); + const document = await Docs.Get.DocumentFromType(type, path, { width: 300, title: name }); const { data, error } = exifData; if (document) { Doc.GetProto(document).exif = error || Docs.Get.DocumentHierarchyFromJson(data); diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index 7a9176bec..1fda82880 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -64,7 +64,7 @@ export namespace SearchUtil { const textDocs = newIds.map((id: string) => textDocMap[id]).map(doc => doc as Doc); for (let i = 0; i < textDocs.length; i++) { const testDoc = textDocs[i]; - if (testDoc instanceof Doc && testDoc.type !== DocumentType.KVP && theDocs.findIndex(d => Doc.AreProtosEqual(d, testDoc)) === -1) { + if (testDoc instanceof Doc && testDoc.type !== DocumentType.KVP && testDoc.type !== DocumentType.EXTENSION && theDocs.findIndex(d => Doc.AreProtosEqual(d, testDoc)) === -1) { theDocs.push(Doc.GetProto(testDoc)); theLines.push(newLines[i].map(line => line.replace(query, query.toUpperCase()))); } @@ -74,7 +74,7 @@ export namespace SearchUtil { const docs = ids.map((id: string) => docMap[id]).map(doc => doc as Doc); for (let i = 0; i < ids.length; i++) { const testDoc = docs[i]; - if (testDoc instanceof Doc && testDoc.type !== DocumentType.KVP && (options.allowAliases || theDocs.findIndex(d => Doc.AreProtosEqual(d, testDoc)) === -1)) { + if (testDoc instanceof Doc && testDoc.type !== DocumentType.KVP && testDoc.type !== DocumentType.EXTENSION && (options.allowAliases || theDocs.findIndex(d => Doc.AreProtosEqual(d, testDoc)) === -1)) { theDocs.push(testDoc); theLines.push([]); } diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index c7ddee7ea..7fbad4638 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -59,6 +59,7 @@ export function DocAnnotatableComponent

(schema @computed get layoutDoc() { return Doc.Layout(this.props.Document); } @computed get dataDoc() { return (this.props.DataDoc && this.props.Document.isTemplateField ? this.props.DataDoc : Doc.GetProto(this.props.Document)) as Doc; } @computed get extensionDoc() { return Doc.fieldExtensionDoc(this.dataDoc, this.props.fieldKey); } + @computed get extensionDocSync() { return Doc.fieldExtensionDocSync(this.dataDoc, this.props.fieldKey); } @computed get annotationsKey() { return "annotations"; } @action.bound diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 5c7794cc0..062521690 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -262,7 +262,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { .then(result => { const type = result["content-type"]; if (type) { - Docs.Get.DocumentFromType(type, str, { ...options, width: 300, nativeWidth: type.indexOf("video") !== -1 ? 600 : 300 }) + Docs.Get.DocumentFromType(type, str, options) .then(doc => doc && this.props.addDocument(doc)); } }); @@ -281,7 +281,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { const dropFileName = file ? file.name : "-empty-"; promises.push(Networking.PostFormDataToServer("/upload", formData).then(results => { results.map(action(({ clientAccessPath }: any) => { - const full = { ...options, nativeWidth: type.indexOf("video") !== -1 ? 600 : 300, width: 300, title: dropFileName }; + const full = { ...options, width: 300, title: dropFileName }; const pathname = Utils.prepend(clientAccessPath); Docs.Get.DocumentFromType(type, pathname, full).then(doc => { doc && (Doc.GetProto(doc).fileUpload = basename(pathname).replace("upload_", "").replace(/\.[a-z0-9]*$/, "")); diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx index 5208f65c4..31f19d42d 100644 --- a/src/client/views/collections/ParentDocumentSelector.tsx +++ b/src/client/views/collections/ParentDocumentSelector.tsx @@ -81,7 +81,7 @@ export class SelectorContextMenu extends React.Component { @observer export class ParentDocSelector extends React.Component { render() { - let flyout = ( + const flyout = (

diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 9f67f3eab..2f1e1832e 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -3,7 +3,7 @@ import { action, observable, runInAction, reaction, IReactionDisposer, trace, un import { observer } from "mobx-react"; import * as Pdfjs from "pdfjs-dist"; import "pdfjs-dist/web/pdf_viewer.css"; -import { Opt, WidthSym, Doc } from "../../../new_fields/Doc"; +import { Opt, WidthSym, Doc, HeightSym } from "../../../new_fields/Doc"; import { makeInterface } from "../../../new_fields/Schema"; import { ScriptField } from '../../../new_fields/ScriptField'; import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; @@ -49,6 +49,9 @@ export class PDFBox extends DocAnnotatableComponent constructor(props: any) { super(props); this._initialScale = this.props.ScreenToLocalTransform().Scale; + const nw = this.Document.nativeWidth = NumCast(this.extensionDocSync.nativeWidth, NumCast(this.Document.nativeWidth, 927)); + const nh = this.Document.nativeHeight = NumCast(this.extensionDocSync.nativeHeight, NumCast(this.Document.nativeHeight, 1200)); + !this.Document.fitWidth && !this.Document.ignoreAspect && (this.Document.height = this.Document[WidthSym]() * (nh / nw)); const backup = "oldPath"; const { Document } = this.props; @@ -78,10 +81,6 @@ export class PDFBox extends DocAnnotatableComponent this._selectReactionDisposer && this._selectReactionDisposer(); } componentDidMount() { - const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField); - if (pdfUrl instanceof PdfField) { - Pdfjs.getDocument(pdfUrl.url.href).promise.then(pdf => runInAction(() => this._pdf = pdf)); - } this._selectReactionDisposer = reaction(() => this.props.isSelected(), () => { document.removeEventListener("keydown", this.onKeyDown); @@ -90,9 +89,9 @@ export class PDFBox extends DocAnnotatableComponent } loaded = (nw: number, nh: number, np: number) => { - this.dataDoc.numPages = np; - this.Document.nativeWidth = nw * 96 / 72; - this.Document.nativeHeight = nh * 96 / 72; + this.extensionDocSync.numPages = np; + this.extensionDocSync.nativeWidth = this.Document.nativeWidth = nw * 96 / 72; + this.extensionDocSync.nativeHeight = this.Document.nativeHeight = nh * 96 / 72; !this.Document.fitWidth && !this.Document.ignoreAspect && (this.Document.height = this.Document[WidthSym]() * (nh / nw)); } @@ -220,9 +219,9 @@ export class PDFBox extends DocAnnotatableComponent @computed get renderTitleBox() { const classname = "pdfBox" + (this.active() ? "-interactive" : ""); return
{this.props.Document.title} @@ -248,10 +247,19 @@ export class PDFBox extends DocAnnotatableComponent
; } + _pdfjsRequested = false; render() { const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField, null); if (this.props.isSelected() || this.props.Document.scrollY !== undefined) this._everActive = true; - return !pdfUrl || !this._pdf || !this.extensionDoc || (!this._everActive && this.props.ScreenToLocalTransform().Scale > 2.5) ? - this.renderTitleBox : this.renderPdfView; + if (pdfUrl && this.extensionDoc && (this._everActive || (this.extensionDoc.nativeWidth && this.props.ScreenToLocalTransform().Scale < 2.5))) { + if (pdfUrl instanceof PdfField && this._pdf) { + return this.renderPdfView; + } + if (!this._pdfjsRequested) { + this._pdfjsRequested = true; + Pdfjs.getDocument(pdfUrl.url.href).promise.then(pdf => runInAction(() => this._pdf = pdf)); + } + } + return this.renderTitleBox; } } \ No newline at end of file diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx index 38e10e99a..503696ae9 100644 --- a/src/client/views/pdf/PDFMenu.tsx +++ b/src/client/views/pdf/PDFMenu.tsx @@ -12,19 +12,17 @@ export default class PDFMenu extends AntimodeMenu { static Instance: PDFMenu; private _commentCont = React.createRef(); - private _snippetButton: React.RefObject = React.createRef(); @observable private _keyValue: string = ""; @observable private _valueValue: string = ""; @observable private _added: boolean = false; @observable public Highlighting: boolean = false; - @observable public Status: "pdf" | "annotation" | "snippet" | "" = ""; + @observable public Status: "pdf" | "annotation" | "" = ""; public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction; public Highlight: (color: string) => Opt = (color: string) => undefined; public Delete: () => void = unimplementedFunction; - public Snippet: (marquee: { left: number, top: number, width: number, height: number }) => void = unimplementedFunction; public AddTag: (key: string, value: string) => boolean = returnFalse; public PinToPres: () => void = unimplementedFunction; public Marquee: { left: number; top: number; width: number; height: number; } | undefined; @@ -80,34 +78,6 @@ export default class PDFMenu extends AntimodeMenu { this.Delete(); } - snippetStart = (e: React.PointerEvent) => { - document.removeEventListener("pointermove", this.snippetDrag); - document.addEventListener("pointermove", this.snippetDrag); - document.removeEventListener("pointerup", this.snippetEnd); - document.addEventListener("pointerup", this.snippetEnd); - - e.stopPropagation(); - e.preventDefault(); - } - - snippetDrag = (e: PointerEvent) => { - e.stopPropagation(); - e.preventDefault(); - if (!this._dragging) { - this._dragging = true; - - this.Marquee && this.Snippet(this.Marquee); - } - } - - snippetEnd = (e: PointerEvent) => { - this._dragging = false; - document.removeEventListener("pointermove", this.snippetDrag); - document.removeEventListener("pointerup", this.snippetEnd); - e.stopPropagation(); - e.preventDefault(); - } - @action keyChanged = (e: React.ChangeEvent) => { this._keyValue = e.currentTarget.value; @@ -128,14 +98,12 @@ export default class PDFMenu extends AntimodeMenu { } render() { - const buttons = this.Status === "pdf" || this.Status === "snippet" ? + const buttons = this.Status === "pdf" ? [ , , - , ] : [ diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index e34d353f4..1a09991d2 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -417,7 +417,6 @@ export class PDFViewer extends DocAnnotatableComponent v.forEach(a => a.remove())); @@ -515,7 +514,6 @@ export class PDFViewer extends DocAnnotatableComponent { this.Document.height = this.Document[WidthSym]() * this._coverPath.height / this._coverPath.width; - this.Document.nativeHeight = nativeWidth * this._coverPath.height / this._coverPath.width; + this.Document.nativeHeight = (this.Document.nativeWidth || 0) * this._coverPath.height / this._coverPath.width; }).bind(this), 0); } const nativeWidth = (this.Document.nativeWidth || 0); diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index b80c3bb54..2f28ebf76 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -234,8 +234,7 @@ export class SearchBox extends React.Component { y += 300; } } - return Docs.Create.FreeformDocument(docs, { width: 400, height: 400, panX: 175, panY: 175, backgroundColor: "grey", title: `Search Docs: "${this._searchString}"` }); - + return Docs.Create.TreeDocument(docs, { width: 200, height: 400, backgroundColor: "grey", title: `Search Docs: "${this._searchString}"` }); } @action.bound @@ -341,7 +340,7 @@ export class SearchBox extends React.Component { return (
{ e.stopPropagation(); e.preventDefault(); }}>
- + this._searchString ? this.startDragCollection() : undefined)} ref={this.collectionRef} title="Drag Results as Collection"> CreateDocumentExtensionForField(doc, fieldKey), 0); - return extension ? extension : undefined; + const extension = doc[fieldKey + "_ext"]; + if (extension === undefined) { + setTimeout(() => CreateDocumentExtensionForField(doc, fieldKey), 0); + } + return extension ? extension as Doc : undefined; + } + export function fieldExtensionDocSync(doc: Doc, fieldKey: string) { + return (doc[fieldKey + "_ext"] as Doc) || CreateDocumentExtensionForField(doc, fieldKey); } export function CreateDocumentExtensionForField(doc: Doc, fieldKey: string) { -- cgit v1.2.3-70-g09d2 From 2fbd5cdd6eec76d1b0533e325e60a2c53ba62078 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 14 Dec 2019 02:00:36 -0500 Subject: factored out repl into module --- package-lock.json | 71 +++++--- package.json | 2 +- src/server/ChildProcessUtilities/ProcessFactory.ts | 67 -------- src/server/ChildProcessUtilities/daemon/session.ts | 190 --------------------- src/server/ProcessFactory.ts | 44 +++++ src/server/index.ts | 2 +- src/server/session_manager/config.ts | 32 ++++ src/server/session_manager/input_manager.ts | 101 +++++++++++ .../session_crashes_@ 2019-12-11T18:52:10.359Z.log | 1 + .../session_crashes_@ 2019-12-12T00:38:44.803Z.log | 1 + .../session_crashes_@ 2019-12-12T00:42:11.945Z.log | 1 + .../session_manager/logs/current_daemon_pid.log | 1 + .../session_manager/logs/current_server_pid.log | 1 + .../logs/current_session_manager_pid.log | 1 + src/server/session_manager/session_manager.ts | 176 +++++++++++++++++++ 15 files changed, 406 insertions(+), 285 deletions(-) delete mode 100644 src/server/ChildProcessUtilities/ProcessFactory.ts delete mode 100644 src/server/ChildProcessUtilities/daemon/session.ts create mode 100644 src/server/ProcessFactory.ts create mode 100644 src/server/session_manager/config.ts create mode 100644 src/server/session_manager/input_manager.ts create mode 100644 src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-11T18:52:10.359Z.log create mode 100644 src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:38:44.803Z.log create mode 100644 src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:42:11.945Z.log create mode 100644 src/server/session_manager/logs/current_daemon_pid.log create mode 100644 src/server/session_manager/logs/current_server_pid.log create mode 100644 src/server/session_manager/logs/current_session_manager_pid.log create mode 100644 src/server/session_manager/session_manager.ts (limited to 'src') diff --git a/package-lock.json b/package-lock.json index 9591e632d..c7b56b074 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2527,7 +2527,7 @@ }, "browserify-aes": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "requires": { "buffer-xor": "^1.0.3", @@ -2561,7 +2561,7 @@ }, "browserify-rsa": { "version": "4.0.1", - "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "requires": { "bn.js": "^4.1.0", @@ -2598,7 +2598,7 @@ }, "buffer": { "version": "4.9.1", - "resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "dev": true, "requires": { @@ -2762,7 +2762,7 @@ }, "camelcase-keys": { "version": "2.1.0", - "resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "requires": { "camelcase": "^2.0.0", @@ -3529,7 +3529,7 @@ }, "create-hash": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "requires": { "cipher-base": "^1.0.1", @@ -3541,7 +3541,7 @@ }, "create-hmac": { "version": "1.1.7", - "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "requires": { "cipher-base": "^1.0.3", @@ -4084,7 +4084,7 @@ }, "diffie-hellman": { "version": "5.0.3", - "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "requires": { "bn.js": "^4.1.0", @@ -5889,6 +5889,11 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" }, + "get-them-args": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/get-them-args/-/get-them-args-1.3.2.tgz", + "integrity": "sha1-dKILqKSr7OWuGZrQPyvMaP38m6U=" + }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -7013,7 +7018,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "requires": { "kind-of": "^3.0.2" @@ -7062,7 +7067,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "requires": { "kind-of": "^3.0.2" @@ -7773,6 +7778,15 @@ "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.0.3.tgz", "integrity": "sha512-/PpesirAIfaklxUzp4Yb7xBper9MwP6hNRA6BGGUFCgbJ+BM5CKBtsoxinNXkLHAr+GXS1/lSlF2rP7cv5Fl+g==" }, + "kill-port": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/kill-port/-/kill-port-1.6.0.tgz", + "integrity": "sha512-gwHRBZ3OLBcupsOJZlIt2Xvf6QqFH3lfdpGnmonXJnJrqq819UXtItGEU1rCMXHK6sXFlxdpkw8ka56rtWw/eQ==", + "requires": { + "get-them-args": "^1.3.1", + "shell-exec": "^1.0.2" + } + }, "killable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", @@ -7833,7 +7847,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "requires": { "graceful-fs": "^4.1.2", @@ -8147,7 +8161,7 @@ }, "media-typer": { "version": "0.3.0", - "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, "mem": { @@ -8179,7 +8193,7 @@ }, "meow": { "version": "3.7.0", - "resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "requires": { "camelcase-keys": "^2.0.0", @@ -8372,7 +8386,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "requires": { "minimist": "0.0.8" @@ -8713,7 +8727,7 @@ }, "next-tick": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" }, "nice-try": { @@ -8877,7 +8891,7 @@ }, "semver": { "version": "5.3.0", - "resolved": "http://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" }, "tar": { @@ -12480,7 +12494,7 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" }, "os-locale": { @@ -12493,7 +12507,7 @@ }, "os-tmpdir": { "version": "1.0.2", - "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, "osenv": { @@ -12723,7 +12737,7 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-is-inside": { @@ -14043,7 +14057,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -14387,7 +14401,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "requires": { "ret": "~0.1.10" @@ -14652,7 +14666,7 @@ }, "sha.js": { "version": "2.4.11", - "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "requires": { "inherits": "^2.0.1", @@ -14720,6 +14734,11 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" }, + "shell-exec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/shell-exec/-/shell-exec-1.0.2.tgz", + "integrity": "sha512-jyVd+kU2X+mWKMmGhx4fpWbPsjvD53k9ivqetutVW/BQ+WIZoDoP4d8vUMGezV6saZsiNoW2f9GIhg9Dondohg==" + }, "shelljs": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz", @@ -15392,7 +15411,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -15422,7 +15441,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" @@ -15438,7 +15457,7 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" }, "strip-indent": { @@ -16191,7 +16210,7 @@ }, "tty-browserify": { "version": "0.0.0", - "resolved": "http://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", "dev": true }, @@ -17633,7 +17652,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "requires": { "string-width": "^1.0.1", diff --git a/package.json b/package.json index c58f542fc..4b0de5392 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "start-release": "cross-env RELEASE=true NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts", - "session": "npx ts-node ./src/server/ChildProcessUtilities/daemon/session.ts", + "session": "npx ts-node ./src/server/session_manager/session_manager.ts", "start": "cross-env NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts", "debug": "cross-env NODE_OPTIONS=--max_old_space_size=8192 ts-node-dev --inspect -- src/server/index.ts", "build": "cross-env NODE_OPTIONS=--max_old_space_size=8192 webpack --env production", diff --git a/src/server/ChildProcessUtilities/ProcessFactory.ts b/src/server/ChildProcessUtilities/ProcessFactory.ts deleted file mode 100644 index 745b1479a..000000000 --- a/src/server/ChildProcessUtilities/ProcessFactory.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { existsSync, mkdirSync } from "fs"; -import { pathFromRoot, log_execution, fileDescriptorFromStream } from '../ActionUtilities'; -import { red, green } from "colors"; -import rimraf = require("rimraf"); -import { ChildProcess, spawn, StdioOptions } from "child_process"; -import { Stream } from "stream"; -import { resolve } from "path"; - -export namespace ProcessFactory { - - export type Sink = "pipe" | "ipc" | "ignore" | "inherit" | Stream | number | null | undefined; - - export async function createWorker(command: string, args?: readonly string[], stdio?: StdioOptions | "logfile", detached = true): Promise { - if (stdio === "logfile") { - const log_fd = await Logger.create(command, args); - stdio = ["ignore", log_fd, log_fd]; - } - const child = spawn(command, args, { detached, stdio }); - child.unref(); - return child; - } - - export namespace NamedAgents { - - export async function persistenceDaemon() { - await log_execution({ - startMessage: "\ninitializing persistence daemon", - endMessage: ({ result, error }) => { - const success = error === null && result !== undefined; - if (!success) { - console.log(red("failed to initialize the persistance daemon")); - console.log(error); - process.exit(0); - } - return "failsafe daemon process successfully spawned"; - }, - action: () => createWorker('npx', ['ts-node', resolve(__dirname, "./daemon/persistence_daemon.ts")], ["ignore", "inherit", "inherit"]), - color: green - }); - console.log(); - } - } - -} - -export namespace Logger { - - const logPath = pathFromRoot("./logs"); - - export async function initialize() { - if (existsSync(logPath)) { - if (!process.env.SPAWNED) { - await new Promise(resolve => rimraf(logPath, resolve)); - } - } - mkdirSync(logPath); - } - - export async function create(command: string, args?: readonly string[]): Promise { - return fileDescriptorFromStream(generate_log_path(command, args)); - } - - function generate_log_path(command: string, args?: readonly string[]) { - return pathFromRoot(`./logs/${command}-${args?.length}-${new Date().toUTCString()}.log`); - } - -} \ No newline at end of file diff --git a/src/server/ChildProcessUtilities/daemon/session.ts b/src/server/ChildProcessUtilities/daemon/session.ts deleted file mode 100644 index fb2b3551e..000000000 --- a/src/server/ChildProcessUtilities/daemon/session.ts +++ /dev/null @@ -1,190 +0,0 @@ -import * as request from "request-promise"; -import { log_execution, pathFromRoot } from "../../ActionUtilities"; -import { red, yellow, cyan, green, Color } from "colors"; -import * as nodemailer from "nodemailer"; -import { MailOptions } from "nodemailer/lib/json-transport"; -import { writeFileSync, existsSync, mkdirSync } from "fs"; -import { resolve } from 'path'; -import { ChildProcess, exec, execSync } from "child_process"; -import { createInterface } from "readline"; -const killport = require("kill-port"); - -process.on('SIGINT', endPrevious); -const identifier = yellow("__session_manager__:"); - -let manualRestartActive = false; -createInterface(process.stdin, process.stdout).on('line', async line => { - const prompt = line.trim().toLowerCase(); - switch (prompt) { - case "restart": - manualRestartActive = true; - identifiedLog(cyan("Initializing manual restart...")); - await endPrevious(); - break; - case "exit": - identifiedLog(cyan("Initializing session end")); - await endPrevious(); - identifiedLog("Cleanup complete. Exiting session...\n"); - execSync(killAllCommand()); - break; - default: - identifiedLog(red("commands: { exit, restart }")); - return; - } -}); - -const logPath = resolve(__dirname, "./logs"); -const crashPath = resolve(logPath, "./crashes"); -if (!existsSync(logPath)) { - mkdirSync(logPath); -} -if (!existsSync(crashPath)) { - mkdirSync(crashPath); -} - -const crashLogPath = resolve(crashPath, `./session_crashes_${new Date().toISOString()}.log`); -function addLogEntry(message: string, color: Color) { - const formatted = color(`${message} ${timestamp()}.`); - identifiedLog(formatted); - // appendFileSync(crashLogPath, `${formatted}\n`); -} - -function identifiedLog(message?: any, ...optionalParams: any[]) { - console.log(identifier, message, ...optionalParams); -} - -if (!["win32", "darwin"].includes(process.platform)) { - identifiedLog(red("Invalid operating system: this script is supported only on Mac and Windows.")); - process.exit(1); -} - -const latency = 10; -const ports = [1050, 4321]; -const onWindows = process.platform === "win32"; -const LOCATION = "http://localhost"; -const heartbeat = `${LOCATION}:1050/serverHeartbeat`; -const recipient = "samuel_wilkins@brown.edu"; -const { pid } = process; -let restarting = false; -let count = 0; - -function startServerCommand() { - if (onWindows) { - return '"C:\\Program Files\\Git\\git-bash.exe" -c "npm run start-release"'; - } - return `osascript -e 'tell app "Terminal"\ndo script "cd ${pathFromRoot()} && npm run start-release"\nend tell'`; -} - -function killAllCommand() { - if (onWindows) { - return "taskkill /f /im node.exe"; - } - return "killall -9 node"; -} - -identifiedLog("Initializing session..."); - -writeLocalPidLog("session_manager", pid); - -function writeLocalPidLog(filename: string, contents: any) { - const path = `./logs/current_${filename}_pid.log`; - identifiedLog(cyan(`${contents} written to ${path}`)); - writeFileSync(resolve(__dirname, path), `${contents}\n`); -} - -function timestamp() { - return `@ ${new Date().toISOString()}`; -} - -async function endPrevious() { - identifiedLog(yellow("Cleaning up previous connections...")); - current_backup?.kill("SIGTERM"); - await Promise.all(ports.map(port => { - const task = killport(port, 'tcp'); - return task.catch((error: any) => identifiedLog(red(error))); - })); - identifiedLog(yellow("Done. Any failures will be printed in red immediately above.")); -} - -let current_backup: ChildProcess | undefined = undefined; - -async function checkHeartbeat() { - let error: any; - try { - count && !restarting && process.stdout.write(`${identifier} 👂 `); - await request.get(heartbeat); - count && !restarting && console.log('⇠ 💚'); - if (restarting || manualRestartActive) { - addLogEntry(count++ ? "Backup server successfully restarted" : "Server successfully started", green); - restarting = false; - } - } catch (e) { - count && !restarting && console.log("⇠ 💔"); - error = e; - } finally { - if (error) { - if (!restarting || manualRestartActive) { - restarting = true; - if (count && !manualRestartActive) { - console.log(); - addLogEntry("Detected a server crash", red); - identifiedLog(red(error.message)); - await endPrevious(); - await log_execution({ - startMessage: identifier + " Sending crash notification email", - endMessage: ({ error, result }) => { - const success = error === null && result === true; - return identifier + ` ${(success ? `Notification successfully sent to` : `Failed to notify`)} ${recipient} ${timestamp()}`; - }, - action: async () => notify(error || "Hmm, no error to report..."), - color: cyan - }); - identifiedLog(green("Initiating server restart...")); - } - manualRestartActive = false; - current_backup = exec(startServerCommand(), err => identifiedLog(err?.message || count ? "Previous server process exited." : "Spawned initial server.")); - writeLocalPidLog("server", `${(current_backup?.pid ?? -2) + 1} created ${timestamp()}`); - } - } - setTimeout(checkHeartbeat, 1000 * latency); - } -} - -async function startListening() { - identifiedLog(yellow(`After initialization, will poll server heartbeat repeatedly...\n`)); - if (!LOCATION) { - identifiedLog(red("No location specified for session manager. Please include as a command line environment variable or in a .env file.")); - process.exit(0); - } - await checkHeartbeat(); -} - -function emailText(error: any) { - return [ - `Hey ${recipient.split("@")[0]},`, - "You, as a Dash Administrator, are being notified of a server crash event. Here's what we know:", - `Location: ${LOCATION}\nError: ${error}`, - "The server should already be restarting itself, but if you're concerned, use the Remote Desktop Connection to monitor progress." - ].join("\n\n"); -} - -async function notify(error: any) { - const smtpTransport = nodemailer.createTransport({ - service: 'Gmail', - auth: { - user: 'brownptcdash@gmail.com', - pass: 'browngfx1' - } - }); - const mailOptions = { - to: recipient, - from: 'brownptcdash@gmail.com', - subject: 'Dash Server Crash', - text: emailText(error) - } as MailOptions; - return new Promise(resolve => { - smtpTransport.sendMail(mailOptions, (dispatchError: Error | null) => resolve(dispatchError === null)); - }); -} - -startListening(); \ No newline at end of file diff --git a/src/server/ProcessFactory.ts b/src/server/ProcessFactory.ts new file mode 100644 index 000000000..acb8b3a99 --- /dev/null +++ b/src/server/ProcessFactory.ts @@ -0,0 +1,44 @@ +import { existsSync, mkdirSync } from "fs"; +import { pathFromRoot, fileDescriptorFromStream } from './ActionUtilities'; +import rimraf = require("rimraf"); +import { ChildProcess, spawn, StdioOptions } from "child_process"; +import { Stream } from "stream"; + +export namespace ProcessFactory { + + export type Sink = "pipe" | "ipc" | "ignore" | "inherit" | Stream | number | null | undefined; + + export async function createWorker(command: string, args?: readonly string[], stdio?: StdioOptions | "logfile", detached = true): Promise { + if (stdio === "logfile") { + const log_fd = await Logger.create(command, args); + stdio = ["ignore", log_fd, log_fd]; + } + const child = spawn(command, args, { detached, stdio }); + child.unref(); + return child; + } + +} + +export namespace Logger { + + const logPath = pathFromRoot("./logs"); + + export async function initialize() { + if (existsSync(logPath)) { + if (!process.env.SPAWNED) { + await new Promise(resolve => rimraf(logPath, resolve)); + } + } + mkdirSync(logPath); + } + + export async function create(command: string, args?: readonly string[]): Promise { + return fileDescriptorFromStream(generate_log_path(command, args)); + } + + function generate_log_path(command: string, args?: readonly string[]) { + return pathFromRoot(`./logs/${command}-${args?.length}-${new Date().toUTCString()}.log`); + } + +} \ No newline at end of file diff --git a/src/server/index.ts b/src/server/index.ts index bc481e579..2cc35ccec 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -23,7 +23,7 @@ import GeneralGoogleManager from "./ApiManagers/GeneralGoogleManager"; import GooglePhotosManager from "./ApiManagers/GooglePhotosManager"; import { yellow, red } from "colors"; import { disconnect } from "../server/Initialization"; -import { ProcessFactory, Logger } from "./ChildProcessUtilities/ProcessFactory"; +import { ProcessFactory, Logger } from "./ProcessFactory"; export const publicDirectory = path.resolve(__dirname, "public"); export const filesDirectory = path.resolve(publicDirectory, "files"); diff --git a/src/server/session_manager/config.ts b/src/server/session_manager/config.ts new file mode 100644 index 000000000..47d3375e0 --- /dev/null +++ b/src/server/session_manager/config.ts @@ -0,0 +1,32 @@ +import { resolve } from 'path'; +import { yellow } from "colors"; + +export const latency = 10; +export const ports = [1050, 4321]; +export const onWindows = process.platform === "win32"; +export const LOCATION = "http://localhost"; +export const heartbeat = `${LOCATION}:1050/serverHeartbeat`; +export const recipient = "samuel_wilkins@brown.edu"; +export const { pid, platform } = process; + +/** + * Logging + */ +export const identifier = yellow("__session_manager__:"); + +/** + * Paths + */ +export const logPath = resolve(__dirname, "./logs"); +export const crashPath = resolve(logPath, "./crashes"); + +/** + * State + */ +export enum SessionState { + INITIALIZING, + LISTENING, + AUTOMATIC_RESTART, + MANUAL_RESTART, + EXITING +} \ No newline at end of file diff --git a/src/server/session_manager/input_manager.ts b/src/server/session_manager/input_manager.ts new file mode 100644 index 000000000..a95e6baae --- /dev/null +++ b/src/server/session_manager/input_manager.ts @@ -0,0 +1,101 @@ +import { createInterface, Interface } from "readline"; +import { red } from "colors"; + +export interface Configuration { + identifier: string; + onInvalid?: (culprit?: string) => string | string; + isCaseSensitive?: boolean; +} + +export interface Registration { + argPattern: RegExp[]; + action: (parsedArgs: IterableIterator) => any | Promise; +} + +export default class InputManager { + private identifier: string; + private onInvalid: ((culprit?: string) => string) | string; + private isCaseSensitive: boolean; + private commandMap = new Map(); + public interface: Interface; + private busy = false; + private keys: string | undefined; + + constructor({ identifier: prompt, onInvalid, isCaseSensitive }: Configuration) { + this.identifier = prompt; + this.onInvalid = onInvalid || this.usage; + this.isCaseSensitive = isCaseSensitive ?? true; + this.interface = createInterface(process.stdin, process.stdout).on('line', this.considerInput); + } + + private usage = () => { + const resolved = this.keys; + if (resolved) { + return resolved; + } + const members: string[] = []; + const keys = this.commandMap.keys(); + let next: IteratorResult; + while (!(next = keys.next()).done) { + members.push(next.value); + } + return `${this.identifier} commands: { ${members.sort().join(", ")} }`; + } + + public registerCommand = (basename: string, argPattern: RegExp[], action: any | Promise) => { + const existing = this.commandMap.get(basename); + const registration = { argPattern, action }; + if (existing) { + existing.push(registration); + } else { + this.commandMap.set(basename, [registration]); + } + } + + private invalid = (culprit?: string) => { + console.log(red(typeof this.onInvalid === "string" ? this.onInvalid : this.onInvalid(culprit))); + this.busy = false; + } + + private considerInput = async (line: string) => { + if (this.busy) { + console.log(red("Busy")); + return; + } + this.busy = true; + line = line.trim(); + if (this.isCaseSensitive) { + line = line.toLowerCase(); + } + const [command, ...args] = line.split(/\s+/g); + if (!command) { + return this.invalid(); + } + const registered = this.commandMap.get(command); + if (registered) { + const { length } = args; + const candidates = registered.filter(({ argPattern: { length: count } }) => count === length); + for (const { argPattern, action } of candidates) { + const parsed: string[] = []; + let matched = false; + if (length) { + for (let i = 0; i < length; i++) { + let matches: RegExpExecArray | null; + if ((matches = argPattern[i].exec(args[i])) === null) { + break; + } + parsed.push(matches[0]); + } + matched = true; + } + if (!length || matched) { + await action(parsed[Symbol.iterator]()); + this.busy = false; + return; + } + } + } + this.invalid(command); + } + +} \ No newline at end of file diff --git a/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-11T18:52:10.359Z.log b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-11T18:52:10.359Z.log new file mode 100644 index 000000000..4cab8a6a3 --- /dev/null +++ b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-11T18:52:10.359Z.log @@ -0,0 +1 @@ +Detected a server crash @ 2019-12-11T18:52:20.416Z. diff --git a/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:38:44.803Z.log b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:38:44.803Z.log new file mode 100644 index 000000000..3c226445d --- /dev/null +++ b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:38:44.803Z.log @@ -0,0 +1 @@ +Detected a server crash @ 2019-12-12T00:38:54.828Z. diff --git a/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:42:11.945Z.log b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:42:11.945Z.log new file mode 100644 index 000000000..59f14f288 --- /dev/null +++ b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:42:11.945Z.log @@ -0,0 +1 @@ +Detected a server crash @ 2019-12-12T00:42:21.970Z. diff --git a/src/server/session_manager/logs/current_daemon_pid.log b/src/server/session_manager/logs/current_daemon_pid.log new file mode 100644 index 000000000..557e3d7c3 --- /dev/null +++ b/src/server/session_manager/logs/current_daemon_pid.log @@ -0,0 +1 @@ +26860 diff --git a/src/server/session_manager/logs/current_server_pid.log b/src/server/session_manager/logs/current_server_pid.log new file mode 100644 index 000000000..6a2f267b3 --- /dev/null +++ b/src/server/session_manager/logs/current_server_pid.log @@ -0,0 +1 @@ +50888 created @ 2019-12-14T06:59:59.767Z diff --git a/src/server/session_manager/logs/current_session_manager_pid.log b/src/server/session_manager/logs/current_session_manager_pid.log new file mode 100644 index 000000000..ab19403b4 --- /dev/null +++ b/src/server/session_manager/logs/current_session_manager_pid.log @@ -0,0 +1 @@ +50846 diff --git a/src/server/session_manager/session_manager.ts b/src/server/session_manager/session_manager.ts new file mode 100644 index 000000000..6e9b03c79 --- /dev/null +++ b/src/server/session_manager/session_manager.ts @@ -0,0 +1,176 @@ +import * as request from "request-promise"; +import { log_execution, pathFromRoot } from "../ActionUtilities"; +import { red, yellow, cyan, green, Color } from "colors"; +import * as nodemailer from "nodemailer"; +import { MailOptions } from "nodemailer/lib/json-transport"; +import { writeFileSync, existsSync, mkdirSync } from "fs"; +import { resolve } from 'path'; +import { ChildProcess, exec, execSync } from "child_process"; +import InputManager from "./input_manager"; +import { identifier, logPath, crashPath, onWindows, pid, ports, heartbeat, recipient, LOCATION, latency } from "./config"; +const killport = require("kill-port"); + +process.on('SIGINT', endPrevious); + +const { registerCommand } = new InputManager({ identifier }); + +let manualRestartActive = false; +registerCommand("restart", [], async () => { + manualRestartActive = true; + identifiedLog(cyan("Initializing manual restart...")); + await endPrevious(); +}); + +registerCommand("exit", [], async () => { + identifiedLog(cyan("Initializing session end")); + await endPrevious(); + identifiedLog("Cleanup complete. Exiting session...\n"); + execSync(killAllCommand()); +}); + +if (!existsSync(logPath)) { + mkdirSync(logPath); +} +if (!existsSync(crashPath)) { + mkdirSync(crashPath); +} + +const crashLogPath = resolve(crashPath, `./session_crashes_${new Date().toISOString()}.log`); +function addLogEntry(message: string, color: Color) { + const formatted = color(`${message} ${timestamp()}.`); + identifiedLog(formatted); + // appendFileSync(crashLogPath, `${formatted}\n`); +} + +function identifiedLog(message?: any, ...optionalParams: any[]) { + console.log(identifier, message, ...optionalParams); +} + +if (!["win32", "darwin"].includes(process.platform)) { + identifiedLog(red("Invalid operating system: this script is supported only on Mac and Windows.")); + process.exit(1); +} + +let restarting = false; +let count = 0; + +function startServerCommand() { + if (onWindows) { + return '"C:\\Program Files\\Git\\git-bash.exe" -c "npm run start-release"'; + } + return `osascript -e 'tell app "Terminal"\ndo script "cd ${pathFromRoot()} && npm run start-release"\nend tell'`; +} + +function killAllCommand() { + if (onWindows) { + return "taskkill /f /im node.exe"; + } + return "killall -9 node"; +} + +identifiedLog("Initializing session..."); + +writeLocalPidLog("session_manager", pid); + +function writeLocalPidLog(filename: string, contents: any) { + const path = `./logs/current_${filename}_pid.log`; + identifiedLog(cyan(`${contents} written to ${path}`)); + writeFileSync(resolve(__dirname, path), `${contents}\n`); +} + +function timestamp() { + return `@ ${new Date().toISOString()}`; +} + +async function endPrevious() { + identifiedLog(yellow("Cleaning up previous connections...")); + current_backup?.kill("SIGKILL"); + await Promise.all(ports.map(port => { + const task = killport(port, 'tcp'); + return task.catch((error: any) => identifiedLog(red(error))); + })); + identifiedLog(yellow("Done. Any failures will be printed in red immediately above.")); +} + +let current_backup: ChildProcess | undefined = undefined; + +async function checkHeartbeat() { + let error: any; + try { + count && !restarting && process.stdout.write(`${identifier} 👂 `); + await request.get(heartbeat); + count && !restarting && console.log('⇠ 💚'); + if (restarting || manualRestartActive) { + addLogEntry(count++ ? "Backup server successfully restarted" : "Server successfully started", green); + restarting = false; + } + } catch (e) { + count && !restarting && console.log("⇠ 💔"); + error = e; + } finally { + if (error) { + if (!restarting || manualRestartActive) { + restarting = true; + if (count && !manualRestartActive) { + console.log(); + addLogEntry("Detected a server crash", red); + identifiedLog(red(error.message)); + await endPrevious(); + await log_execution({ + startMessage: identifier + " Sending crash notification email", + endMessage: ({ error, result }) => { + const success = error === null && result === true; + return identifier + ` ${(success ? `Notification successfully sent to` : `Failed to notify`)} ${recipient} ${timestamp()}`; + }, + action: async () => notify(error || "Hmm, no error to report..."), + color: cyan + }); + identifiedLog(green("Initiating server restart...")); + } + manualRestartActive = false; + current_backup = exec(startServerCommand(), err => identifiedLog(err?.message || count ? "Previous server process exited." : "Spawned initial server.")); + writeLocalPidLog("server", `${(current_backup?.pid ?? -2) + 1} created ${timestamp()}`); + } + } + setTimeout(checkHeartbeat, 1000 * latency); + } +} + +async function startListening() { + identifiedLog(yellow(`After initialization, will poll server heartbeat repeatedly...\n`)); + if (!LOCATION) { + identifiedLog(red("No location specified for session manager. Please include as a command line environment variable or in a .env file.")); + process.exit(0); + } + await checkHeartbeat(); +} + +function emailText(error: any) { + return [ + `Hey ${recipient.split("@")[0]},`, + "You, as a Dash Administrator, are being notified of a server crash event. Here's what we know:", + `Location: ${LOCATION}\nError: ${error}`, + "The server should already be restarting itself, but if you're concerned, use the Remote Desktop Connection to monitor progress." + ].join("\n\n"); +} + +async function notify(error: any) { + const smtpTransport = nodemailer.createTransport({ + service: 'Gmail', + auth: { + user: 'brownptcdash@gmail.com', + pass: 'browngfx1' + } + }); + const mailOptions = { + to: recipient, + from: 'brownptcdash@gmail.com', + subject: 'Dash Server Crash', + text: emailText(error) + } as MailOptions; + return new Promise(resolve => { + smtpTransport.sendMail(mailOptions, (dispatchError: Error | null) => resolve(dispatchError === null)); + }); +} + +startListening(); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From a1beec1e1ed18ffefc518876fb783b7a14282960 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 14 Dec 2019 03:05:07 -0500 Subject: repaired state logic --- src/server/session_manager/config.ts | 11 ++-- .../session_manager/logs/current_server_pid.log | 2 +- .../logs/current_session_manager_pid.log | 2 +- src/server/session_manager/session_manager.ts | 72 ++++++++++++---------- 4 files changed, 46 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/server/session_manager/config.ts b/src/server/session_manager/config.ts index 47d3375e0..a373b986e 100644 --- a/src/server/session_manager/config.ts +++ b/src/server/session_manager/config.ts @@ -24,9 +24,10 @@ export const crashPath = resolve(logPath, "./crashes"); * State */ export enum SessionState { - INITIALIZING, - LISTENING, - AUTOMATIC_RESTART, - MANUAL_RESTART, - EXITING + STARTING = "STARTING", + INITIALIZED = "INITIALIZED", + LISTENING = "LISTENING", + CRASH_RESTARTING = "CRASH_RESTARTING", + MANUALLY_RESTARTING = "MANUALLY_RESTARTING", + EXITING = "EXITING" } \ No newline at end of file diff --git a/src/server/session_manager/logs/current_server_pid.log b/src/server/session_manager/logs/current_server_pid.log index 6a2f267b3..85fdb7ae0 100644 --- a/src/server/session_manager/logs/current_server_pid.log +++ b/src/server/session_manager/logs/current_server_pid.log @@ -1 +1 @@ -50888 created @ 2019-12-14T06:59:59.767Z +54649 created @ 2019-12-14T08:04:42.391Z diff --git a/src/server/session_manager/logs/current_session_manager_pid.log b/src/server/session_manager/logs/current_session_manager_pid.log index ab19403b4..75c23b35a 100644 --- a/src/server/session_manager/logs/current_session_manager_pid.log +++ b/src/server/session_manager/logs/current_session_manager_pid.log @@ -1 +1 @@ -50846 +54643 diff --git a/src/server/session_manager/session_manager.ts b/src/server/session_manager/session_manager.ts index 6e9b03c79..51aba26a0 100644 --- a/src/server/session_manager/session_manager.ts +++ b/src/server/session_manager/session_manager.ts @@ -7,27 +7,32 @@ import { writeFileSync, existsSync, mkdirSync } from "fs"; import { resolve } from 'path'; import { ChildProcess, exec, execSync } from "child_process"; import InputManager from "./input_manager"; -import { identifier, logPath, crashPath, onWindows, pid, ports, heartbeat, recipient, LOCATION, latency } from "./config"; +import { identifier, logPath, crashPath, onWindows, pid, ports, heartbeat, recipient, LOCATION, latency, SessionState } from "./config"; const killport = require("kill-port"); process.on('SIGINT', endPrevious); +let state: SessionState = SessionState.STARTING; +const is = (...reference: SessionState[]) => reference.includes(state); +const set = (reference: SessionState) => state = reference; const { registerCommand } = new InputManager({ identifier }); -let manualRestartActive = false; registerCommand("restart", [], async () => { - manualRestartActive = true; + set(SessionState.MANUALLY_RESTARTING); identifiedLog(cyan("Initializing manual restart...")); await endPrevious(); }); registerCommand("exit", [], async () => { + set(SessionState.EXITING); identifiedLog(cyan("Initializing session end")); await endPrevious(); identifiedLog("Cleanup complete. Exiting session...\n"); execSync(killAllCommand()); }); +registerCommand("state", [], () => identifiedLog(state)); + if (!existsSync(logPath)) { mkdirSync(logPath); } @@ -51,9 +56,6 @@ if (!["win32", "darwin"].includes(process.platform)) { process.exit(1); } -let restarting = false; -let count = 0; - function startServerCommand() { if (onWindows) { return '"C:\\Program Files\\Git\\git-bash.exe" -c "npm run start-release"'; @@ -95,42 +97,44 @@ async function endPrevious() { let current_backup: ChildProcess | undefined = undefined; async function checkHeartbeat() { + const listening = is(SessionState.LISTENING); let error: any; try { - count && !restarting && process.stdout.write(`${identifier} 👂 `); + listening && process.stdout.write(`${identifier} 👂 `); await request.get(heartbeat); - count && !restarting && console.log('⇠ 💚'); - if (restarting || manualRestartActive) { - addLogEntry(count++ ? "Backup server successfully restarted" : "Server successfully started", green); - restarting = false; + listening && console.log('⇠ 💚'); + if (!listening) { + addLogEntry(is(SessionState.INITIALIZED) ? "Server successfully started" : "Backup server successfully restarted", green); + set(SessionState.LISTENING); } } catch (e) { - count && !restarting && console.log("⇠ 💔"); + listening && console.log("⇠ 💔"); error = e; } finally { - if (error) { - if (!restarting || manualRestartActive) { - restarting = true; - if (count && !manualRestartActive) { - console.log(); - addLogEntry("Detected a server crash", red); - identifiedLog(red(error.message)); - await endPrevious(); - await log_execution({ - startMessage: identifier + " Sending crash notification email", - endMessage: ({ error, result }) => { - const success = error === null && result === true; - return identifier + ` ${(success ? `Notification successfully sent to` : `Failed to notify`)} ${recipient} ${timestamp()}`; - }, - action: async () => notify(error || "Hmm, no error to report..."), - color: cyan - }); - identifiedLog(green("Initiating server restart...")); - } - manualRestartActive = false; - current_backup = exec(startServerCommand(), err => identifiedLog(err?.message || count ? "Previous server process exited." : "Spawned initial server.")); - writeLocalPidLog("server", `${(current_backup?.pid ?? -2) + 1} created ${timestamp()}`); + if (error && !is(SessionState.CRASH_RESTARTING, SessionState.INITIALIZED)) { + if (is(SessionState.STARTING)) { + set(SessionState.INITIALIZED); + } else if (is(SessionState.MANUALLY_RESTARTING)) { + set(SessionState.CRASH_RESTARTING); + } else { + set(SessionState.CRASH_RESTARTING); + console.log(); + addLogEntry("Detected a server crash", red); + identifiedLog(red(error.message)); + await endPrevious(); + await log_execution({ + startMessage: identifier + " Sending crash notification email", + endMessage: ({ error, result }) => { + const success = error === null && result === true; + return identifier + ` ${(success ? `Notification successfully sent to` : `Failed to notify`)} ${recipient} ${timestamp()}`; + }, + action: async () => notify(error || "Hmm, no error to report..."), + color: cyan + }); + identifiedLog(green("Initiating server restart...")); } + current_backup = exec(startServerCommand(), err => identifiedLog(err?.message || is(SessionState.INITIALIZED) ? "Spawned initial server." : "Previous server process exited.")); + writeLocalPidLog("server", `${(current_backup?.pid ?? -2) + 1} created ${timestamp()}`); } setTimeout(checkHeartbeat, 1000 * latency); } -- cgit v1.2.3-70-g09d2 From 1587e3ce712d08b3e6a43dd770c4d586e82f1b23 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 14 Dec 2019 11:24:20 -0500 Subject: constant changes --- src/server/session_manager/config.ts | 5 ++--- src/server/session_manager/session_manager.ts | 22 +++++++--------------- 2 files changed, 9 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/server/session_manager/config.ts b/src/server/session_manager/config.ts index a373b986e..bb84a166d 100644 --- a/src/server/session_manager/config.ts +++ b/src/server/session_manager/config.ts @@ -4,8 +4,7 @@ import { yellow } from "colors"; export const latency = 10; export const ports = [1050, 4321]; export const onWindows = process.platform === "win32"; -export const LOCATION = "http://localhost"; -export const heartbeat = `${LOCATION}:1050/serverHeartbeat`; +export const heartbeat = `http://localhost:1050/serverHeartbeat`; export const recipient = "samuel_wilkins@brown.edu"; export const { pid, platform } = process; @@ -27,7 +26,7 @@ export enum SessionState { STARTING = "STARTING", INITIALIZED = "INITIALIZED", LISTENING = "LISTENING", - CRASH_RESTARTING = "CRASH_RESTARTING", + AUTOMATICALLY_RESTARTING = "CRASH_RESTARTING", MANUALLY_RESTARTING = "MANUALLY_RESTARTING", EXITING = "EXITING" } \ No newline at end of file diff --git a/src/server/session_manager/session_manager.ts b/src/server/session_manager/session_manager.ts index 51aba26a0..97b71403b 100644 --- a/src/server/session_manager/session_manager.ts +++ b/src/server/session_manager/session_manager.ts @@ -7,7 +7,7 @@ import { writeFileSync, existsSync, mkdirSync } from "fs"; import { resolve } from 'path'; import { ChildProcess, exec, execSync } from "child_process"; import InputManager from "./input_manager"; -import { identifier, logPath, crashPath, onWindows, pid, ports, heartbeat, recipient, LOCATION, latency, SessionState } from "./config"; +import { identifier, logPath, crashPath, onWindows, pid, ports, heartbeat, recipient, latency, SessionState } from "./config"; const killport = require("kill-port"); process.on('SIGINT', endPrevious); @@ -111,13 +111,13 @@ async function checkHeartbeat() { listening && console.log("⇠ 💔"); error = e; } finally { - if (error && !is(SessionState.CRASH_RESTARTING, SessionState.INITIALIZED)) { + if (error && !is(SessionState.AUTOMATICALLY_RESTARTING, SessionState.INITIALIZED)) { if (is(SessionState.STARTING)) { set(SessionState.INITIALIZED); } else if (is(SessionState.MANUALLY_RESTARTING)) { - set(SessionState.CRASH_RESTARTING); + set(SessionState.AUTOMATICALLY_RESTARTING); } else { - set(SessionState.CRASH_RESTARTING); + set(SessionState.AUTOMATICALLY_RESTARTING); console.log(); addLogEntry("Detected a server crash", red); identifiedLog(red(error.message)); @@ -140,20 +140,11 @@ async function checkHeartbeat() { } } -async function startListening() { - identifiedLog(yellow(`After initialization, will poll server heartbeat repeatedly...\n`)); - if (!LOCATION) { - identifiedLog(red("No location specified for session manager. Please include as a command line environment variable or in a .env file.")); - process.exit(0); - } - await checkHeartbeat(); -} - function emailText(error: any) { return [ `Hey ${recipient.split("@")[0]},`, "You, as a Dash Administrator, are being notified of a server crash event. Here's what we know:", - `Location: ${LOCATION}\nError: ${error}`, + `Location: ${heartbeat}\nError: ${error}`, "The server should already be restarting itself, but if you're concerned, use the Remote Desktop Connection to monitor progress." ].join("\n\n"); } @@ -177,4 +168,5 @@ async function notify(error: any) { }); } -startListening(); \ No newline at end of file +identifiedLog(yellow(`After initialization, will poll server heartbeat repeatedly...\n`)); +checkHeartbeat(); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 0ed6eea09a91146e0bbd51d52f90c513ba92ed19 Mon Sep 17 00:00:00 2001 From: Sam Wilkins <35748010+samwilkins333@users.noreply.github.com> Date: Sat, 14 Dec 2019 11:47:03 -0500 Subject: Delete session_crashes_@ 2019-12-11T18:52:10.359Z.log --- .../logs/crashes/session_crashes_@ 2019-12-11T18:52:10.359Z.log | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-11T18:52:10.359Z.log (limited to 'src') diff --git a/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-11T18:52:10.359Z.log b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-11T18:52:10.359Z.log deleted file mode 100644 index 4cab8a6a3..000000000 --- a/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-11T18:52:10.359Z.log +++ /dev/null @@ -1 +0,0 @@ -Detected a server crash @ 2019-12-11T18:52:20.416Z. -- cgit v1.2.3-70-g09d2 From bdd6cdb375752531da68477ae136faeb3b2a7813 Mon Sep 17 00:00:00 2001 From: Sam Wilkins <35748010+samwilkins333@users.noreply.github.com> Date: Sat, 14 Dec 2019 11:47:09 -0500 Subject: Delete session_crashes_@ 2019-12-12T00:38:44.803Z.log --- .../logs/crashes/session_crashes_@ 2019-12-12T00:38:44.803Z.log | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:38:44.803Z.log (limited to 'src') diff --git a/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:38:44.803Z.log b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:38:44.803Z.log deleted file mode 100644 index 3c226445d..000000000 --- a/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:38:44.803Z.log +++ /dev/null @@ -1 +0,0 @@ -Detected a server crash @ 2019-12-12T00:38:54.828Z. -- cgit v1.2.3-70-g09d2 From 6d74e1870fcbcd0fa873ce308709f1f3741de538 Mon Sep 17 00:00:00 2001 From: Sam Wilkins <35748010+samwilkins333@users.noreply.github.com> Date: Sat, 14 Dec 2019 11:47:16 -0500 Subject: Delete session_crashes_@ 2019-12-12T00:42:11.945Z.log --- .../logs/crashes/session_crashes_@ 2019-12-12T00:42:11.945Z.log | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:42:11.945Z.log (limited to 'src') diff --git a/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:42:11.945Z.log b/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:42:11.945Z.log deleted file mode 100644 index 59f14f288..000000000 --- a/src/server/session_manager/logs/crashes/session_crashes_@ 2019-12-12T00:42:11.945Z.log +++ /dev/null @@ -1 +0,0 @@ -Detected a server crash @ 2019-12-12T00:42:21.970Z. -- cgit v1.2.3-70-g09d2 From b913591895e18fad58a5a12ad3beb522073c4b04 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 14 Dec 2019 11:50:38 -0500 Subject: test --- src/server/session_manager/session_manager.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/server/session_manager/session_manager.ts b/src/server/session_manager/session_manager.ts index 97b71403b..9fe4b1ab8 100644 --- a/src/server/session_manager/session_manager.ts +++ b/src/server/session_manager/session_manager.ts @@ -40,11 +40,10 @@ if (!existsSync(crashPath)) { mkdirSync(crashPath); } -const crashLogPath = resolve(crashPath, `./session_crashes_${new Date().toISOString()}.log`); function addLogEntry(message: string, color: Color) { const formatted = color(`${message} ${timestamp()}.`); identifiedLog(formatted); - // appendFileSync(crashLogPath, `${formatted}\n`); + // appendFileSync(resolve(crashPath, `./session_crashes_${new Date().toISOString()}.log`), `${formatted}\n`); } function identifiedLog(message?: any, ...optionalParams: any[]) { -- cgit v1.2.3-70-g09d2 From e959463fcc494eb6a3e92809cbeb27024169c8f0 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 14 Dec 2019 12:02:36 -0500 Subject: updating --- src/server/session_manager/config.ts | 3 ++- src/server/session_manager/session_manager.ts | 12 +++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/server/session_manager/config.ts b/src/server/session_manager/config.ts index bb84a166d..ebbd999c6 100644 --- a/src/server/session_manager/config.ts +++ b/src/server/session_manager/config.ts @@ -28,5 +28,6 @@ export enum SessionState { LISTENING = "LISTENING", AUTOMATICALLY_RESTARTING = "CRASH_RESTARTING", MANUALLY_RESTARTING = "MANUALLY_RESTARTING", - EXITING = "EXITING" + EXITING = "EXITING", + UPDATING = "UPDATING" } \ No newline at end of file diff --git a/src/server/session_manager/session_manager.ts b/src/server/session_manager/session_manager.ts index 9fe4b1ab8..b620c8502 100644 --- a/src/server/session_manager/session_manager.ts +++ b/src/server/session_manager/session_manager.ts @@ -31,6 +31,16 @@ registerCommand("exit", [], async () => { execSync(killAllCommand()); }); +registerCommand("update", [], async () => { + set(SessionState.UPDATING); + await new Promise(resolve => { + exec("git pull && npm install", () => { + resolve(); + }); + }); + set(SessionState.MANUALLY_RESTARTING); +}); + registerCommand("state", [], () => identifiedLog(state)); if (!existsSync(logPath)) { @@ -110,7 +120,7 @@ async function checkHeartbeat() { listening && console.log("⇠ 💔"); error = e; } finally { - if (error && !is(SessionState.AUTOMATICALLY_RESTARTING, SessionState.INITIALIZED)) { + if (error && !is(SessionState.AUTOMATICALLY_RESTARTING, SessionState.INITIALIZED, SessionState.UPDATING)) { if (is(SessionState.STARTING)) { set(SessionState.INITIALIZED); } else if (is(SessionState.MANUALLY_RESTARTING)) { -- cgit v1.2.3-70-g09d2 From 559a709a4901ccb1932d8d2845a199d91093153c Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 14 Dec 2019 12:05:00 -0500 Subject: log during update --- src/server/session_manager/session_manager.ts | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/server/session_manager/session_manager.ts b/src/server/session_manager/session_manager.ts index b620c8502..37b32d621 100644 --- a/src/server/session_manager/session_manager.ts +++ b/src/server/session_manager/session_manager.ts @@ -33,12 +33,15 @@ registerCommand("exit", [], async () => { registerCommand("update", [], async () => { set(SessionState.UPDATING); + identifiedLog(cyan("Initializing server update from version control...")); + await endPrevious(); await new Promise(resolve => { exec("git pull && npm install", () => { resolve(); }); }); set(SessionState.MANUALLY_RESTARTING); + identifiedLog("Update complete. Initializing manual restart...\n"); }); registerCommand("state", [], () => identifiedLog(state)); -- cgit v1.2.3-70-g09d2 From b9ca80873fdfb3c0e2b48ee715e9cbc4ff968aba Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 14 Dec 2019 12:09:05 -0500 Subject: update --- src/server/session_manager/session_manager.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/session_manager/session_manager.ts b/src/server/session_manager/session_manager.ts index 37b32d621..d5ef94dc7 100644 --- a/src/server/session_manager/session_manager.ts +++ b/src/server/session_manager/session_manager.ts @@ -36,7 +36,10 @@ registerCommand("update", [], async () => { identifiedLog(cyan("Initializing server update from version control...")); await endPrevious(); await new Promise(resolve => { - exec("git pull && npm install", () => { + exec(updateCommand(), error => { + if (error) { + identifiedLog(red(error.message)); + } resolve(); }); }); @@ -68,6 +71,13 @@ if (!["win32", "darwin"].includes(process.platform)) { process.exit(1); } +function updateCommand() { + if (onWindows) { + return '"C:\\Program Files\\Git\\git-bash.exe" -c "git pull && npm install"'; + } + return `osascript -e 'tell app "Terminal"\ndo script "cd ${pathFromRoot()} && git pull && npm install"\nend tell'`; +} + function startServerCommand() { if (onWindows) { return '"C:\\Program Files\\Git\\git-bash.exe" -c "npm run start-release"'; -- cgit v1.2.3-70-g09d2 From e38cf2b6186378eb85ba49eda481233b220ccb7b Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 14 Dec 2019 12:15:27 -0500 Subject: draft update protocl --- src/server/session_manager/session_manager.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/server/session_manager/session_manager.ts b/src/server/session_manager/session_manager.ts index d5ef94dc7..35cc833f2 100644 --- a/src/server/session_manager/session_manager.ts +++ b/src/server/session_manager/session_manager.ts @@ -23,13 +23,15 @@ registerCommand("restart", [], async () => { await endPrevious(); }); -registerCommand("exit", [], async () => { +registerCommand("exit", [], exit); + +async function exit() { set(SessionState.EXITING); identifiedLog(cyan("Initializing session end")); await endPrevious(); identifiedLog("Cleanup complete. Exiting session...\n"); execSync(killAllCommand()); -}); +} registerCommand("update", [], async () => { set(SessionState.UPDATING); @@ -43,8 +45,7 @@ registerCommand("update", [], async () => { resolve(); }); }); - set(SessionState.MANUALLY_RESTARTING); - identifiedLog("Update complete. Initializing manual restart...\n"); + await exit(); }); registerCommand("state", [], () => identifiedLog(state)); -- cgit v1.2.3-70-g09d2 From d7bc3d445fdf0ffc86812da27cf07e51bfbfe9c5 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 14 Dec 2019 12:38:31 -0500 Subject: factored out commands --- src/server/session_manager/session_manager.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/server/session_manager/session_manager.ts b/src/server/session_manager/session_manager.ts index 35cc833f2..92f1eaa05 100644 --- a/src/server/session_manager/session_manager.ts +++ b/src/server/session_manager/session_manager.ts @@ -72,18 +72,23 @@ if (!["win32", "darwin"].includes(process.platform)) { process.exit(1); } +const windowsPrepend = (command: string) => `"C:\\Program Files\\Git\\git-bash.exe" -c "${command}"`; +const macPrepend = (command: string) => `osascript -e 'tell app "Terminal"\ndo script "cd ${pathFromRoot()} && ${command}"\nend tell'`; + function updateCommand() { + const command = "git pull && npm install"; if (onWindows) { - return '"C:\\Program Files\\Git\\git-bash.exe" -c "git pull && npm install"'; + return windowsPrepend(command); } - return `osascript -e 'tell app "Terminal"\ndo script "cd ${pathFromRoot()} && git pull && npm install"\nend tell'`; + return macPrepend(command); } function startServerCommand() { + const command = "npm run start-release"; if (onWindows) { - return '"C:\\Program Files\\Git\\git-bash.exe" -c "npm run start-release"'; + return windowsPrepend(command); } - return `osascript -e 'tell app "Terminal"\ndo script "cd ${pathFromRoot()} && npm run start-release"\nend tell'`; + return macPrepend(command); } function killAllCommand() { -- cgit v1.2.3-70-g09d2 From 50940d2f1680aabbadcf9dd6e5455b7c7517115a Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 14 Dec 2019 12:39:20 -0500 Subject: newline --- src/server/session_manager/session_manager.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/server/session_manager/session_manager.ts b/src/server/session_manager/session_manager.ts index 92f1eaa05..d8b2f6e74 100644 --- a/src/server/session_manager/session_manager.ts +++ b/src/server/session_manager/session_manager.ts @@ -136,7 +136,7 @@ async function checkHeartbeat() { set(SessionState.LISTENING); } } catch (e) { - listening && console.log("⇠ 💔"); + listening && console.log("⇠ 💔\n"); error = e; } finally { if (error && !is(SessionState.AUTOMATICALLY_RESTARTING, SessionState.INITIALIZED, SessionState.UPDATING)) { @@ -146,7 +146,6 @@ async function checkHeartbeat() { set(SessionState.AUTOMATICALLY_RESTARTING); } else { set(SessionState.AUTOMATICALLY_RESTARTING); - console.log(); addLogEntry("Detected a server crash", red); identifiedLog(red(error.message)); await endPrevious(); -- cgit v1.2.3-70-g09d2 From 7edce1af91621b7724e4763a5afabb4ab86d183c Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 14 Dec 2019 21:49:09 -0500 Subject: make %@ portal hyperlink creation create a link as well. --- src/client/util/RichTextRules.ts | 5 +++-- src/client/views/nodes/DocumentView.tsx | 6 ------ src/client/views/nodes/FormattedTextBox.tsx | 1 + 3 files changed, 4 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts index 364c85165..f5dd459fc 100644 --- a/src/client/util/RichTextRules.ts +++ b/src/client/util/RichTextRules.ts @@ -85,8 +85,9 @@ export const inpRules = { const value = state.doc.textBetween(start, end); if (value) { DocServer.GetRefField(value).then(docx => { - const doc = ((docx instanceof Doc) && docx) || Docs.Create.FreeformDocument([], { title: value, width: 500, height: 500 }, value); - DocUtils.Publish(doc, value, returnFalse, returnFalse); + const target = ((docx instanceof Doc) && docx) || Docs.Create.FreeformDocument([], { title: value, width: 500, height: 500 }, value); + DocUtils.Publish(target, value, returnFalse, returnFalse); + DocUtils.MakeLink({ doc: (schema as any).Document }, { doc: target }, "portal link", ""); }); const link = state.schema.marks.link.create({ href: Utils.prepend("/doc/" + value), location: "onRight", title: value }); return state.tr.addMark(start, end, link); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index b096d68fc..9f651a498 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -434,12 +434,6 @@ export class DocumentView extends DocComponent(Docu onClicks.push({ description: this.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" }); onClicks.push({ description: this.Document.isButton || this.Document.onClick ? "Remove Click Behavior" : "Follow Link", event: this.makeBtnClicked, icon: "concierge-bell" }); onClicks.push({ description: "Edit onClick Script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", obj.x, obj.y) }); - onClicks.push({ - description: "Edit onClick Foreach Doc Script", icon: "edit", event: (obj: any) => { - this.props.Document.collectionContext = this.props.ContainingCollectionDoc; - ScriptBox.EditButtonScript("Foreach Collection Doc (d) => ", this.props.Document, "onClick", obj.x, obj.y, "docList(this.collectionContext.data).map(d => {", "});\n"); - } - }); !existingOnClick && cm.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" }); const funcs: ContextMenuProps[] = []; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index a298fd6af..e40c00e54 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -822,6 +822,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & clipboardTextSerializer: this.clipboardTextSerializer, handlePaste: this.handlePaste, }); + (this._editorView.state.schema as any).Document = this.props.Document; if (startup && this._editorView) { Doc.GetProto(doc).documentText = undefined; this._editorView.dispatch(this._editorView.state.tr.insertText(startup)); -- cgit v1.2.3-70-g09d2 From 877a6f481a06e2454ff9d8eabe43acb0e58a2676 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 15 Dec 2019 10:38:23 -0500 Subject: writing selectedDocs to user doc to allow selection to be part of scripting --- src/client/util/DragManager.ts | 2 +- src/client/util/SelectionManager.ts | 3 +++ src/client/views/nodes/FormattedTextBox.tsx | 2 +- src/client/views/nodes/KeyValueBox.tsx | 3 ++- src/new_fields/Doc.ts | 12 +++++++++--- 5 files changed, 16 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 2631a1e3c..df2f5fe3c 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -51,7 +51,7 @@ export function SetupDrag( e.stopPropagation(); if (e.shiftKey && CollectionDockingView.Instance) { e.persist(); - let dragDoc = await docFunc(); + const dragDoc = await docFunc(); dragDoc && CollectionDockingView.Instance.StartOtherDrag({ pageX: e.pageX, pageY: e.pageY, diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index e01216e0f..d9283de35 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -2,6 +2,8 @@ import { observable, action, runInAction, ObservableMap } from "mobx"; import { Doc } from "../../new_fields/Doc"; import { DocumentView } from "../views/nodes/DocumentView"; import { computedFn } from "mobx-utils"; +import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils"; +import { List } from "../../new_fields/List"; export namespace SelectionManager { @@ -27,6 +29,7 @@ export namespace SelectionManager { manager.SelectedDocuments.clear(); manager.SelectedDocuments.set(docView, true); } + Doc.UserDoc().SelectedDocs = new List(SelectionManager.SelectedDocuments().map(dv => dv.props.Document)); } @action DeselectDoc(docView: DocumentView): void { diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index e40c00e54..3efbd434e 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -822,7 +822,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & clipboardTextSerializer: this.clipboardTextSerializer, handlePaste: this.handlePaste, }); - (this._editorView.state.schema as any).Document = this.props.Document; + this._editorView.state.schema.Document = this.props.Document; if (startup && this._editorView) { Doc.GetProto(doc).documentText = undefined; this._editorView.dispatch(this._editorView.state.tr.insertText(startup)); diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 322d639dc..07d6d6f5e 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -57,7 +57,8 @@ export class KeyValueBox extends React.Component { value = eq ? value.substr(1) : value; const dubEq = value.startsWith(":=") ? "computed" : value.startsWith(";=") ? "script" : false; value = dubEq ? value.substr(2) : value; - const options: ScriptOptions = { addReturn: true, params: { this: "Doc" } }; + const editable = value.includes("selectedDocs"); // bcz: Argh TODO - need a UI mechanism for letting user know that a function can't be run read-only. e.g., selectedDocs() wants to cache its old value so it can't be run read-only + const options: ScriptOptions = { addReturn: true, params: { this: "Doc" }, editable: editable }; if (dubEq) options.typecheck = false; const script = CompileScript(value, options); if (!script.compiled) { diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index aa33d4c8b..a22b289bb 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -1,4 +1,4 @@ -import { observable, ObservableMap, runInAction, action } from "mobx"; +import { observable, ObservableMap, runInAction, action, untracked } from "mobx"; import { alias, map, serializable } from "serializr"; import { DocServer } from "../client/DocServer"; import { DocumentType } from "../client/documents/DocumentTypes"; @@ -474,7 +474,7 @@ export namespace Doc { return extension ? extension as Doc : undefined; } export function fieldExtensionDocSync(doc: Doc, fieldKey: string) { - return (doc[fieldKey + "_ext"] as Doc) || CreateDocumentExtensionForField(doc, fieldKey); + return (doc[fieldKey + "_ext"] as Doc) || CreateDocumentExtensionForField(doc, fieldKey); } export function CreateDocumentExtensionForField(doc: Doc, fieldKey: string) { @@ -753,4 +753,10 @@ Scripting.addGlobal(function aliasDocs(field: any) { return new List(field. Scripting.addGlobal(function docList(field: any) { return DocListCast(field); }); Scripting.addGlobal(function sameDocs(doc1: any, doc2: any) { return Doc.AreProtosEqual(doc1, doc2); }); Scripting.addGlobal(function undo() { return UndoManager.Undo(); }); -Scripting.addGlobal(function redo() { return UndoManager.Redo(); }); \ No newline at end of file +Scripting.addGlobal(function redo() { return UndoManager.Redo(); }); +Scripting.addGlobal(function selectedDocs(container: Doc, excludeCollections: boolean) { + let docs = DocListCast(Doc.UserDoc().SelectedDocs).filter(d => (!excludeCollections || !Cast(d.data, listSpec(Doc), null)) && d.type !== DocumentType.KVP && !Doc.AreProtosEqual(d, container)); + if (docs.length) untracked(() => container && (container.cachedSelection = new List(docs))); + else docs = untracked(() => DocListCast(container.cachedSelection)); + return new List(docs); +}); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 6683517a69f4806d026e7af85069f18b1f0a9d1f Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 15 Dec 2019 12:44:20 -0500 Subject: added _last_ for computedScripts to access last value of script --- src/client/util/RichTextSchema.tsx | 6 +++++- src/client/views/nodes/KeyValueBox.tsx | 3 +-- src/new_fields/Doc.ts | 5 ++--- src/new_fields/ScriptField.ts | 3 ++- 4 files changed, 10 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 543f45731..7a048ed0d 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -741,7 +741,11 @@ export class DashDocView { self._dashDoc = dashDoc; dashDoc.hideSidebar = true; if (node.attrs.width !== dashDoc.width + "px" || node.attrs.height !== dashDoc.height + "px") { - view.dispatch(view.state.tr.setNodeMarkup(getPos(), null, { ...node.attrs, width: dashDoc.width + "px", height: dashDoc.height + "px" })); + try { // bcz: an exception will be thrown if two aliases are open at the same time when a doc view comment is made + view.dispatch(view.state.tr.setNodeMarkup(getPos(), null, { ...node.attrs, width: dashDoc.width + "px", height: dashDoc.height + "px" })); + } catch (e) { + console.log(e); + } } this._reactionDisposer && this._reactionDisposer(); this._reactionDisposer = reaction(() => dashDoc[HeightSym]() + dashDoc[WidthSym](), () => { diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 07d6d6f5e..234a6a9d3 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -57,8 +57,7 @@ export class KeyValueBox extends React.Component { value = eq ? value.substr(1) : value; const dubEq = value.startsWith(":=") ? "computed" : value.startsWith(";=") ? "script" : false; value = dubEq ? value.substr(2) : value; - const editable = value.includes("selectedDocs"); // bcz: Argh TODO - need a UI mechanism for letting user know that a function can't be run read-only. e.g., selectedDocs() wants to cache its old value so it can't be run read-only - const options: ScriptOptions = { addReturn: true, params: { this: "Doc" }, editable: editable }; + const options: ScriptOptions = { addReturn: true, params: { this: "Doc", _last_: "any" }, editable: false }; if (dubEq) options.typecheck = false; const script = CompileScript(value, options); if (!script.compiled) { diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index a22b289bb..171f3fd2d 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -754,9 +754,8 @@ Scripting.addGlobal(function docList(field: any) { return DocListCast(field); }) Scripting.addGlobal(function sameDocs(doc1: any, doc2: any) { return Doc.AreProtosEqual(doc1, doc2); }); Scripting.addGlobal(function undo() { return UndoManager.Undo(); }); Scripting.addGlobal(function redo() { return UndoManager.Redo(); }); -Scripting.addGlobal(function selectedDocs(container: Doc, excludeCollections: boolean) { +Scripting.addGlobal(function selectedDocs(container: Doc, excludeCollections: boolean, prevValue: any) { let docs = DocListCast(Doc.UserDoc().SelectedDocs).filter(d => (!excludeCollections || !Cast(d.data, listSpec(Doc), null)) && d.type !== DocumentType.KVP && !Doc.AreProtosEqual(d, container)); - if (docs.length) untracked(() => container && (container.cachedSelection = new List(docs))); - else docs = untracked(() => DocListCast(container.cachedSelection)); + if (!docs.length) return prevValue; return new List(docs); }); \ No newline at end of file diff --git a/src/new_fields/ScriptField.ts b/src/new_fields/ScriptField.ts index 6b2723663..0cadb60ed 100644 --- a/src/new_fields/ScriptField.ts +++ b/src/new_fields/ScriptField.ts @@ -124,8 +124,9 @@ export class ScriptField extends ObjectField { @scriptingGlobal @Deserializable("computed", deserializeScript) export class ComputedField extends ScriptField { + _lastComputedResult: any; //TODO maybe add an observable cache based on what is passed in for doc, considering there shouldn't really be that many possible values for doc - value = computedFn((doc: Doc) => this.script.run({ this: doc }, console.log).result); + value = computedFn((doc: Doc) => this._lastComputedResult = this.script.run({ this: doc, _last_: this._lastComputedResult }, console.log).result); public static MakeScript(script: string, params: object = {}, ) { const compiled = ScriptField.CompileScript(script, params, false); return compiled.compiled ? new ComputedField(compiled) : undefined; -- cgit v1.2.3-70-g09d2 From 2bb5667b10a8c402f8ec75c632ca3fdabe642419 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 15 Dec 2019 18:25:03 -0500 Subject: added LOD detail switching for collection free form views --- .../collectionFreeForm/CollectionFreeFormView.scss | 2 ++ .../collectionFreeForm/CollectionFreeFormView.tsx | 21 ++++++++++++++------- src/new_fields/documentSchemas.ts | 4 +++- 3 files changed, 19 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index 070d4aa65..f8a9e49d8 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -52,6 +52,8 @@ left: 0; width: 100%; height: 100%; + align-items: center; + display: flex; } // selection border...? diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 89c1df598..9bb6fa97e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -882,6 +882,19 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { eles.push(); return eles; } + @computed get placeholder() { + return
+ {this.props.Document.title}>
; + } + @computed get marqueeView() { + return + + {this.children} + + ; + } render() { TraceMobx(); // update the actual dimensions of the collection so that they can inquired (e.g., by a minimap) @@ -895,13 +908,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
- - - {this.children} - - + {!BoolCast(this.Document.LODdisable) && this.props.renderDepth > 0 && this.Document[WidthSym]() * this.Document[HeightSym]() / this.props.ScreenToLocalTransform().Scale < NumCast(this.Document.LODarea, 100000) ? this.placeholder : this.marqueeView}
; } diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts index 5c2ba6111..21e69fbed 100644 --- a/src/new_fields/documentSchemas.ts +++ b/src/new_fields/documentSchemas.ts @@ -48,7 +48,9 @@ export const documentSchema = createSchema({ animateToDimensions: listSpec("number"), // layout information about the target rectangle a document is animating towards scrollToLinkID: "string", // id of link being traversed. allows this doc to scroll/highlight/etc its link anchor. scrollToLinkID should be set to undefined by this doc after it sets up its scroll,etc. strokeWidth: "number", - fontSize: "string" + fontSize: "string", + LODarea: "number", // area (width*height) where CollectionFreeFormViews switch from a label to rendering contents + LODdisable: "boolean", // whether to disbale LOD switching for CollectionFreeFormViews }); export const positionSchema = createSchema({ -- cgit v1.2.3-70-g09d2 From 55823d0cc300f5cdd90ee34013bfdee93b5709e6 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 15 Dec 2019 20:11:58 -0500 Subject: added a DocumentBox as a contentfitting container for another document. added a menu item for showing selected document. --- src/client/documents/DocumentTypes.ts | 3 +- src/client/documents/Documents.ts | 9 ++++ .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../views/nodes/ContentFittingDocumentView.tsx | 6 +-- src/client/views/nodes/DocumentBox.scss | 6 +++ src/client/views/nodes/DocumentBox.tsx | 55 ++++++++++++++++++++++ src/client/views/nodes/DocumentContentsView.tsx | 3 +- src/client/views/nodes/ImageBox.tsx | 1 - src/new_fields/ScriptField.ts | 2 +- .../authentication/models/current_user_utils.ts | 1 + 10 files changed, 80 insertions(+), 8 deletions(-) create mode 100644 src/client/views/nodes/DocumentBox.scss create mode 100644 src/client/views/nodes/DocumentBox.tsx (limited to 'src') diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts index f6dd0c346..8f96b2fa6 100644 --- a/src/client/documents/DocumentTypes.ts +++ b/src/client/documents/DocumentTypes.ts @@ -25,5 +25,6 @@ export enum DocumentType { COLOR = "color", DOCULINK = "doculink", PDFANNO = "pdfanno", - INK = "ink" + INK = "ink", + DOCUMENT = "document" } \ No newline at end of file diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 4ba45ac30..50c51ace1 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -48,6 +48,7 @@ import { PresElementBox } from "../views/presentationview/PresElementBox"; import { QueryBox } from "../views/nodes/QueryBox"; import { ColorBox } from "../views/nodes/ColorBox"; import { DocuLinkBox } from "../views/nodes/DocuLinkBox"; +import { DocumentBox } from "../views/nodes/DocumentBox"; import { InkingStroke } from "../views/InkingStroke"; import { InkField } from "../../new_fields/InkField"; const requestImageSize = require('../util/request-image-size'); @@ -171,6 +172,10 @@ export namespace Docs { layout: { view: KeyValueBox, dataField: data }, options: { height: 150 } }], + [DocumentType.DOCUMENT, { + layout: { view: DocumentBox, dataField: data }, + options: { height: 250 } + }], [DocumentType.VID, { layout: { view: VideoBox, dataField: data }, options: { currentTimecode: 0 }, @@ -482,6 +487,10 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.KVP), document, { title: document.title + ".kvp", ...options }); } + export function DocumentDocument(document?: Doc, options: DocumentOptions = {}) { + return InstanceFromProto(Prototypes.get(DocumentType.DOCUMENT), document, { title: document ? document.title + "" : "container", ...options }); + } + export function FreeformDocument(documents: Array, options: DocumentOptions, id?: string) { return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, viewType: CollectionViewType.Freeform }, id); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 9bb6fa97e..0b18e9f25 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -908,7 +908,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
- {!BoolCast(this.Document.LODdisable) && this.props.renderDepth > 0 && this.Document[WidthSym]() * this.Document[HeightSym]() / this.props.ScreenToLocalTransform().Scale < NumCast(this.Document.LODarea, 100000) ? this.placeholder : this.marqueeView} + {!BoolCast(this.Document.LODdisable) && !this.props.isAnnotationOverlay && this.props.renderDepth > 0 && this.Document[WidthSym]() * this.Document[HeightSym]() / this.props.ScreenToLocalTransform().Scale < NumCast(this.Document.LODarea, 100000) ? this.placeholder : this.marqueeView}
; } diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx index 5e3306a11..2565fd932 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.tsx +++ b/src/client/views/nodes/ContentFittingDocumentView.tsx @@ -31,9 +31,9 @@ interface ContentFittingDocumentViewProps { CollectionDoc?: Doc; onClick?: ScriptField; getTransform: () => Transform; - addDocument: (document: Doc) => boolean; - moveDocument: (document: Doc, target: Doc | undefined, addDoc: ((doc: Doc) => boolean)) => boolean; - removeDocument: (document: Doc) => boolean; + addDocument?: (document: Doc) => boolean; + moveDocument?: (document: Doc, target: Doc | undefined, addDoc: ((doc: Doc) => boolean)) => boolean; + removeDocument?: (document: Doc) => boolean; active: (outsideReaction: boolean) => boolean; whenActiveChanged: (isActive: boolean) => void; addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean; diff --git a/src/client/views/nodes/DocumentBox.scss b/src/client/views/nodes/DocumentBox.scss new file mode 100644 index 000000000..6a2f98166 --- /dev/null +++ b/src/client/views/nodes/DocumentBox.scss @@ -0,0 +1,6 @@ +.documentBox-container { + width: 100%; + height: 100%; + pointer-events: all; + background: gray; +} \ No newline at end of file diff --git a/src/client/views/nodes/DocumentBox.tsx b/src/client/views/nodes/DocumentBox.tsx new file mode 100644 index 000000000..2f2cba485 --- /dev/null +++ b/src/client/views/nodes/DocumentBox.tsx @@ -0,0 +1,55 @@ +import { observer } from "mobx-react"; +import { Doc } from "../../../new_fields/Doc"; +import { documentSchema } from "../../../new_fields/documentSchemas"; +import { makeInterface } from "../../../new_fields/Schema"; +import { ComputedField } from "../../../new_fields/ScriptField"; +import { emptyFunction, emptyPath } from "../../../Utils"; +import { ContextMenu } from "../ContextMenu"; +import { ContextMenuProps } from "../ContextMenuItem"; +import { DocComponent } from "../DocComponent"; +import { ContentFittingDocumentView } from "./ContentFittingDocumentView"; +import "./DocumentBox.scss"; +import { FieldView, FieldViewProps } from "./FieldView"; +import React = require("react"); + +type DocBoxSchema = makeInterface<[typeof documentSchema]>; +const DocBoxDocument = makeInterface(documentSchema); + +@observer +export class DocumentBox extends DocComponent(DocBoxDocument) { + public static LayoutString(fieldKey: string) { return FieldView.LayoutString(DocumentBox, fieldKey); } + + + specificContextMenu = (e: React.MouseEvent): void => { + const funcs: ContextMenuProps[] = []; + funcs.push({ description: "Auto Show Selected", event: () => Doc.GetProto(this.props.Document).data = ComputedField.MakeFunction("selectedDocs(this,true,_last_)?.[0]"), icon: "expand-arrows-alt" }); + + ContextMenu.Instance.addItem({ description: "DocumentBox Funcs...", subitems: funcs, icon: "asterisk" }); + } + render() { + const containedDoc = this.props.Document[this.props.fieldKey] as Doc; + return
+ {!containedDoc ? (null) : } +
; + } +} diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 1bbc82119..8f6bfc8e1 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -14,6 +14,7 @@ import { LinkFollowBox } from "../linking/LinkFollowBox"; import { YoutubeBox } from "./../../apis/youtube/YoutubeBox"; import { AudioBox } from "./AudioBox"; import { ButtonBox } from "./ButtonBox"; +import { DocumentBox } from "./DocumentBox"; import { DocumentViewProps } from "./DocumentView"; import "./DocumentView.scss"; import { FontIconBox } from "./FontIconBox"; @@ -102,7 +103,7 @@ export class DocumentContentsView extends React.Component Date: Sun, 15 Dec 2019 20:31:34 -0500 Subject: from last --- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 0b18e9f25..fc507bf5e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -908,7 +908,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
- {!BoolCast(this.Document.LODdisable) && !this.props.isAnnotationOverlay && this.props.renderDepth > 0 && this.Document[WidthSym]() * this.Document[HeightSym]() / this.props.ScreenToLocalTransform().Scale < NumCast(this.Document.LODarea, 100000) ? this.placeholder : this.marqueeView} + {!BoolCast(this.Document.LODdisable) && !this.props.isAnnotationOverlay && this.props.renderDepth > 0 && this.Document[WidthSym]() * this.Document[HeightSym]() / this.props.ScreenToLocalTransform().Scale / this.props.ScreenToLocalTransform().Scale < NumCast(this.Document.LODarea, 100000) ? this.placeholder : this.marqueeView}
; } -- cgit v1.2.3-70-g09d2 From 15333069562d265a8bc8e5d1d3ec1bfc564d8796 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 15 Dec 2019 21:47:34 -0500 Subject: fixed auto show seleted function --- src/client/views/nodes/DocumentBox.tsx | 2 +- src/new_fields/Doc.ts | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/DocumentBox.tsx b/src/client/views/nodes/DocumentBox.tsx index 2f2cba485..b9a97b42d 100644 --- a/src/client/views/nodes/DocumentBox.tsx +++ b/src/client/views/nodes/DocumentBox.tsx @@ -22,7 +22,7 @@ export class DocumentBox extends DocComponent(DocB specificContextMenu = (e: React.MouseEvent): void => { const funcs: ContextMenuProps[] = []; - funcs.push({ description: "Auto Show Selected", event: () => Doc.GetProto(this.props.Document).data = ComputedField.MakeFunction("selectedDocs(this,true,_last_)?.[0]"), icon: "expand-arrows-alt" }); + funcs.push({ description: "Auto Show Selected", event: () => Doc.GetProto(this.props.Document).data = ComputedField.MakeFunction("selectedDocs(this,true,[_last_])?.[0]"), icon: "expand-arrows-alt" }); ContextMenu.Instance.addItem({ description: "DocumentBox Funcs...", subitems: funcs, icon: "asterisk" }); } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 171f3fd2d..c3a6a1658 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -756,6 +756,5 @@ Scripting.addGlobal(function undo() { return UndoManager.Undo(); }); Scripting.addGlobal(function redo() { return UndoManager.Redo(); }); Scripting.addGlobal(function selectedDocs(container: Doc, excludeCollections: boolean, prevValue: any) { let docs = DocListCast(Doc.UserDoc().SelectedDocs).filter(d => (!excludeCollections || !Cast(d.data, listSpec(Doc), null)) && d.type !== DocumentType.KVP && !Doc.AreProtosEqual(d, container)); - if (!docs.length) return prevValue; - return new List(docs); + return docs.length ? new List(docs) : prevValue; }); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 01aca20caca1f8736fd7035b8cda35e7c415aa2b Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 16 Dec 2019 00:38:59 -0500 Subject: added onclick option for selecting first link target. changed contentFittingDocView to center vertically as well as horizontally --- src/client/util/SelectionManager.ts | 5 ++++- src/client/views/nodes/ContentFittingDocumentView.scss | 5 +++-- src/client/views/nodes/ContentFittingDocumentView.tsx | 18 +++++++++++------- src/client/views/nodes/DocumentView.tsx | 15 +++++++++++++++ src/new_fields/Doc.ts | 4 +++- 5 files changed, 36 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index d9283de35..cb7a69295 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -2,8 +2,8 @@ import { observable, action, runInAction, ObservableMap } from "mobx"; import { Doc } from "../../new_fields/Doc"; import { DocumentView } from "../views/nodes/DocumentView"; import { computedFn } from "mobx-utils"; -import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils"; import { List } from "../../new_fields/List"; +import { Scripting } from "./Scripting"; export namespace SelectionManager { @@ -81,3 +81,6 @@ export namespace SelectionManager { return Array.from(manager.SelectedDocuments.keys()); } } + +Scripting.addGlobal(function selectDoc(doc: any) { Doc.UserDoc().SelectedDocs = new List([doc]); }); + diff --git a/src/client/views/nodes/ContentFittingDocumentView.scss b/src/client/views/nodes/ContentFittingDocumentView.scss index 796e67269..2801af441 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.scss +++ b/src/client/views/nodes/ContentFittingDocumentView.scss @@ -2,10 +2,11 @@ .contentFittingDocumentView { position: relative; - height: auto !important; + display: flex; + align-items: center; .contentFittingDocumentView-previewDoc { - position: absolute; + position: relative; display: inline; } diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx index 2565fd932..e15790c9d 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.tsx +++ b/src/client/views/nodes/ContentFittingDocumentView.tsx @@ -47,8 +47,8 @@ interface ContentFittingDocumentViewProps { export class ContentFittingDocumentView extends React.Component{ public get displayName() { return "DocumentView(" + this.props.Document?.title + ")"; } // this makes mobx trace() statements more descriptive private get layoutDoc() { return this.props.Document && Doc.Layout(this.props.Document); } - private get nativeWidth() { return NumCast(this.layoutDoc!.nativeWidth, this.props.PanelWidth()); } - private get nativeHeight() { return NumCast(this.layoutDoc!.nativeHeight, this.props.PanelHeight()); } + private get nativeWidth() { return NumCast(this.layoutDoc?.nativeWidth, this.props.PanelWidth()); } + private get nativeHeight() { return NumCast(this.layoutDoc?.nativeHeight, this.props.PanelHeight()); } private contentScaling = () => { const wscale = this.props.PanelWidth() / (this.nativeWidth ? this.nativeWidth : this.props.PanelWidth()); if (wscale * this.nativeHeight > this.props.PanelHeight()) { @@ -73,21 +73,25 @@ export class ContentFittingDocumentView extends React.Component this.nativeWidth && (!this.props.Document || !this.props.Document.fitWidth) ? this.nativeWidth * this.contentScaling() : this.props.PanelWidth(); private PanelHeight = () => this.nativeHeight && (!this.props.Document || !this.props.Document.fitWidth) ? this.nativeHeight * this.contentScaling() : this.props.PanelHeight(); - private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, 0).scale(1 / this.contentScaling()); + private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, -this.centeringYOffset).scale(1 / this.contentScaling()); private get centeringOffset() { return this.nativeWidth && (!this.props.Document || !this.props.Document.fitWidth) ? (this.props.PanelWidth() - this.nativeWidth * this.contentScaling()) / 2 : 0; } + private get centeringYOffset() { return Math.abs(this.centeringOffset) < 0.001 ? (this.props.PanelHeight() - this.nativeHeight * this.contentScaling()) / 2 : 0; } - @computed get borderRounding() { return StrCast(this.props.Document!.borderRounding); } + @computed get borderRounding() { return StrCast(this.props.Document?.borderRounding); } render() { TraceMobx(); - return (
+ return (
0.001 ? "auto" : this.props.PanelWidth(), + height: Math.abs(this.centeringOffset) > 0.0001 ? "auto" : this.props.PanelHeight() + }}> {!this.props.Document || !this.props.PanelWidth ? (null) : (
0.001 ? `${100 * this.nativeHeight / this.nativeWidth * this.props.PanelWidth() / this.props.PanelHeight()}%` : this.props.PanelHeight(), + width: Math.abs(this.centeringOffset) > 0.001 ? `${100 * (this.props.PanelWidth() - this.centeringOffset * 2) / this.props.PanelWidth()}%` : this.props.PanelWidth() }}> (Docu this.onClickHandler.script.run({ this: this.Document.isTemplateField && this.props.DataDoc ? this.props.DataDoc : this.props.Document }, console.log); } else if (this.Document.type === DocumentType.BUTTON) { ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", e.clientX, e.clientY); + } else if (this.props.Document.isButton === "Selector") { // this should be moved to an OnClick script + this.Document.links?.[0] instanceof Doc && (Doc.UserDoc().SelectedDocs = new List([Doc.LinkOtherAnchor(this.Document.links[0]!, this.props.Document)])); } else if (this.Document.isButton) { SelectionManager.SelectDoc(this, e.ctrlKey); // don't think this should happen if a button action is actually triggered. this.buttonClick(e.altKey, e.ctrlKey); @@ -315,6 +318,17 @@ export class DocumentView extends DocComponent(Docu } } + @undoBatch + makeSelBtnClicked = (): void => { + if (this.Document.isButton || this.Document.onClick || this.Document.ignoreClick) { + this.Document.isButton = false; + this.Document.ignoreClick = false; + this.Document.onClick = undefined; + } else { + this.props.Document.isButton = "Selector"; + } + } + @undoBatch @action drop = async (e: Event, de: DragManager.DropEvent) => { @@ -433,6 +447,7 @@ export class DocumentView extends DocComponent(Docu onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript("toggleDetail(this)"), icon: "window-restore" }); onClicks.push({ description: this.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" }); onClicks.push({ description: this.Document.isButton || this.Document.onClick ? "Remove Click Behavior" : "Follow Link", event: this.makeBtnClicked, icon: "concierge-bell" }); + onClicks.push({ description: this.props.Document.isButton ? "Remove Select Link Behavior" : "Select Link", event: this.makeSelBtnClicked, icon: "concierge-bell" }); onClicks.push({ description: "Edit onClick Script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", obj.x, obj.y) }); !existingOnClick && cm.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" }); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index c3a6a1658..b8f11c8c8 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -687,7 +687,9 @@ export namespace Doc { } + export function LinkOtherAnchor(linkDoc: Doc, anchorDoc: Doc) { return Doc.AreProtosEqual(anchorDoc, Cast(linkDoc.anchor1, Doc) as Doc) ? Cast(linkDoc.anchor2, Doc) as Doc : Cast(linkDoc.anchor1, Doc) as Doc; } export function LinkEndpoint(linkDoc: Doc, anchorDoc: Doc) { return Doc.AreProtosEqual(anchorDoc, Cast(linkDoc.anchor1, Doc) as Doc) ? "layoutKey1" : "layoutKey2"; } + export function linkFollowUnhighlight() { Doc.UnhighlightAll(); document.removeEventListener("pointerdown", linkFollowUnhighlight); @@ -755,6 +757,6 @@ Scripting.addGlobal(function sameDocs(doc1: any, doc2: any) { return Doc.AreProt Scripting.addGlobal(function undo() { return UndoManager.Undo(); }); Scripting.addGlobal(function redo() { return UndoManager.Redo(); }); Scripting.addGlobal(function selectedDocs(container: Doc, excludeCollections: boolean, prevValue: any) { - let docs = DocListCast(Doc.UserDoc().SelectedDocs).filter(d => (!excludeCollections || !Cast(d.data, listSpec(Doc), null)) && d.type !== DocumentType.KVP && !Doc.AreProtosEqual(d, container)); + const docs = DocListCast(Doc.UserDoc().SelectedDocs).filter(d => !Doc.AreProtosEqual(d, container) && (!excludeCollections || !Cast(d.data, listSpec(Doc), null)) && d.type !== DocumentType.KVP); return docs.length ? new List(docs) : prevValue; }); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 001cea83f6c57914e0e76a75a94f3e06e542a419 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 16 Dec 2019 01:01:09 -0500 Subject: from last --- src/client/views/nodes/DocumentView.tsx | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 59e68fc4c..18885f272 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -44,6 +44,7 @@ import { InkingControl } from '../InkingControl'; import { InkTool } from '../../../new_fields/InkField'; import { TraceMobx } from '../../../new_fields/util'; import { List } from '../../../new_fields/List'; +import { FormattedTextBoxComment } from './FormattedTextBoxComment'; library.add(fa.faEdit, fa.faTrash, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faCompressArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faAlignCenter, fa.faCaretSquareRight, fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faLink, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, fa.faLock, fa.faLaptopCode, fa.faMale, @@ -172,6 +173,7 @@ export class DocumentView extends DocComponent(Docu } else if (this.Document.type === DocumentType.BUTTON) { ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", e.clientX, e.clientY); } else if (this.props.Document.isButton === "Selector") { // this should be moved to an OnClick script + FormattedTextBoxComment.Hide(); this.Document.links?.[0] instanceof Doc && (Doc.UserDoc().SelectedDocs = new List([Doc.LinkOtherAnchor(this.Document.links[0]!, this.props.Document)])); } else if (this.Document.isButton) { SelectionManager.SelectDoc(this, e.ctrlKey); // don't think this should happen if a button action is actually triggered. -- cgit v1.2.3-70-g09d2