From 867279b9cc86f19c67d1751db756144f1a1bee8e Mon Sep 17 00:00:00 2001
From: Garrett
Date: Tue, 5 Sep 2023 16:01:00 -0700
Subject: [PATCH 01/12] Create draft of standalone preview page
---
pyflask/app.py | 27 ++++++++-
src/renderer/src/pages.js | 15 +++--
src/renderer/src/stories/assets/inspect.svg | 2 +-
src/renderer/src/stories/assets/preview.svg | 7 +++
.../pages/guided-mode/options/utils.js | 4 +-
.../src/stories/pages/preview/PreviewPage.js | 55 +++++++++++++++++++
src/renderer/src/stories/preview/Neurosift.js | 14 +++--
7 files changed, 113 insertions(+), 11 deletions(-)
create mode 100644 src/renderer/src/stories/assets/preview.svg
create mode 100644 src/renderer/src/stories/pages/preview/PreviewPage.js
diff --git a/pyflask/app.py b/pyflask/app.py
index a87618798..da0205fdf 100644
--- a/pyflask/app.py
+++ b/pyflask/app.py
@@ -2,15 +2,18 @@
import sys
import json
import multiprocessing
+from os.path import sep
from logging import Formatter, DEBUG
from logging.handlers import RotatingFileHandler
from pathlib import Path
+from urllib.parse import unquote
+
# https://stackoverflow.com/questions/32672596/pyinstaller-loads-script-multiple-times#comment103216434_32677108
multiprocessing.freeze_support()
-from flask import Flask, request, send_from_directory
+from flask import Flask, request, send_from_directory, send_file
from flask_cors import CORS
from flask_restx import Api, Resource
@@ -52,6 +55,28 @@
api.add_namespace(neuroconv_api)
api.init_app(app)
+registered = {}
+
+@app.route("/files")
+def get_all_files():
+ return list(registered.keys())
+
+@app.route("/files/", methods=["GET", "POST"])
+def handle_file_request(path):
+
+
+ if request.method == 'GET':
+ if registered[path]:
+ return send_file(f"{sep}{unquote(path)}")
+ else:
+ app.abort(404, 'Resource is not accessible.')
+
+ else:
+ if ('.nwb' in path):
+ registered[path] = True
+ return request.base_url
+ else:
+ app.abort(400, str('Path does not point to an NWB file.'))
@app.route("/conversions/")
def send_conversions(path):
diff --git a/src/renderer/src/pages.js b/src/renderer/src/pages.js
index 09ba41811..d53784f4d 100644
--- a/src/renderer/src/pages.js
+++ b/src/renderer/src/pages.js
@@ -22,11 +22,14 @@ import { TutorialPage } from "./stories/pages/tutorial/Tutorial";
import tutorialIcon from "./stories/assets/exploration.svg?raw";
import uploadIcon from "./stories/assets/dandi.svg?raw";
import inspectIcon from "./stories/assets/inspect.svg?raw";
+import previewIcon from "./stories/assets/preview.svg?raw";
+
import settingsIcon from "./stories/assets/settings.svg?raw";
import { UploadsPage } from "./stories/pages/uploads/UploadsPage";
import { SettingsPage } from "./stories/pages/settings/SettingsPage";
import { InspectPage } from "./stories/pages/inspect/InspectPage";
+import { PreviewPage } from "./stories/pages/preview/PreviewPage";
let dashboard = document.querySelector("nwb-dashboard");
if (!dashboard) dashboard = new Dashboard();
@@ -165,14 +168,18 @@ const pages = {
}),
},
}),
- uploads: new UploadsPage({
- label: "Uploads",
- icon: uploadIcon,
- }),
inspect: new InspectPage({
label: "Inspect",
icon: inspectIcon,
}),
+ preview: new PreviewPage({
+ label: "Preview",
+ icon: previewIcon,
+ }),
+ uploads: new UploadsPage({
+ label: "Uploads",
+ icon: uploadIcon,
+ }),
tutorial: new TutorialPage({
label: "Tutorial",
icon: tutorialIcon,
diff --git a/src/renderer/src/stories/assets/inspect.svg b/src/renderer/src/stories/assets/inspect.svg
index dbbbd8f77..a94da7c42 100644
--- a/src/renderer/src/stories/assets/inspect.svg
+++ b/src/renderer/src/stories/assets/inspect.svg
@@ -4,4 +4,4 @@ height="25"
viewBox="0 -960 960 960"
width="25"
style="margin-right: 30px; margin-bottom: -5px"
->
\ No newline at end of file
+>
\ No newline at end of file
diff --git a/src/renderer/src/stories/assets/preview.svg b/src/renderer/src/stories/assets/preview.svg
new file mode 100644
index 000000000..dbbbd8f77
--- /dev/null
+++ b/src/renderer/src/stories/assets/preview.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/src/renderer/src/stories/pages/guided-mode/options/utils.js b/src/renderer/src/stories/pages/guided-mode/options/utils.js
index 6d1d0020e..20785b4f2 100644
--- a/src/renderer/src/stories/pages/guided-mode/options/utils.js
+++ b/src/renderer/src/stories/pages/guided-mode/options/utils.js
@@ -24,7 +24,9 @@ export const run = async (url, payload, options = {}) => {
const needsSwal = !options.swal && options.swal !== false;
if (needsSwal) openProgressSwal(options).then((swal) => (options.onOpen ? options.onOpen(swal) : undefined));
- const results = await fetch(`${baseUrl}/neuroconv/${url}`, {
+ if (!('base' in options)) options.base = '/neuroconv'
+
+ const results = await fetch(`${baseUrl}${options.base || ''}/${url}`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
diff --git a/src/renderer/src/stories/pages/preview/PreviewPage.js b/src/renderer/src/stories/pages/preview/PreviewPage.js
new file mode 100644
index 000000000..5f2b276c5
--- /dev/null
+++ b/src/renderer/src/stories/pages/preview/PreviewPage.js
@@ -0,0 +1,55 @@
+import { html } from "lit";
+import { Page } from "../Page.js";
+import { onThrow } from "../../../errors";
+import { Button } from "../../Button.js";
+
+import { run } from "../guided-mode/options/utils.js";
+import { JSONSchemaInput } from "../../JSONSchemaInput.js";
+import { Modal } from "../../Modal";
+import { truncateFilePaths } from "../../preview/NWBFilePreview.js";
+import { InspectorList } from "../../preview/inspector/InspectorList.js";
+import { Neurosift } from "../../preview/Neurosift.js";
+import { baseUrl } from "../../../globals.js";
+
+
+export class PreviewPage extends Page {
+ constructor(...args) {
+ super(...args);
+ }
+
+ render() {
+
+ const neurosift = new Neurosift()
+
+ this.input = new JSONSchemaInput({
+ path: ['file_path'],
+ info: {
+ type: 'string',
+ format: 'file'
+ },
+ onUpdate: async (path) => {
+
+ const result = await fetch(`${baseUrl}/files/${path}`, { method: "POST" }).then((res) => res.text());
+
+ if (result) neurosift.url = result
+ },
+ onThrow,
+ });
+
+ return html`
+
+
+
+
NWB File Preview
+
+
Use Neurosift to preview of your NWB file.
+
+
+ ${this.input}
+ ${neurosift}
+
+ `;
+ }
+}
+
+customElements.get("nwbguide-preview-page") || customElements.define("nwbguide-preview-page", PreviewPage);
diff --git a/src/renderer/src/stories/preview/Neurosift.js b/src/renderer/src/stories/preview/Neurosift.js
index 5c8b81d8a..eee813c05 100644
--- a/src/renderer/src/stories/preview/Neurosift.js
+++ b/src/renderer/src/stories/preview/Neurosift.js
@@ -26,7 +26,7 @@ export class Neurosift extends LitElement {
height: 100%;
}
- div {
+ .loader-container {
display: flex;
align-items: center;
justify-content: center;
@@ -49,20 +49,26 @@ export class Neurosift extends LitElement {
`;
}
- constructor({ url }) {
+ static get properties() {
+ return {
+ url: {type: String, reflect: true}
+ }
+ }
+
+ constructor({ url } = {}) {
super();
this.url = url;
}
render() {
- return html` ${new Loader({ message: "Loading Neurosift view..." })}
+ return this.url ? html` ${new Loader({ message: "Loading Neurosift view..." })}
`;
+ >` : ``;
}
}
From b0163228435e3220e648f401334d551627b19585 Mon Sep 17 00:00:00 2001
From: Garrett
Date: Tue, 5 Sep 2023 18:25:55 -0700
Subject: [PATCH 02/12] Support previewing NWB files when selected in native
file explorer
---
package.json | 2 +-
src/renderer/src/electron/index.js | 9 ++-
src/renderer/src/globals.js | 14 ++++
src/renderer/src/progress/index.js | 4 +-
src/renderer/src/progress/update.js | 17 +----
src/renderer/src/stories/Dashboard.js | 4 ++
.../src/stories/pages/inspect/InspectPage.js | 72 ++++++++++---------
.../src/stories/pages/preview/PreviewPage.js | 45 ++++++------
8 files changed, 92 insertions(+), 75 deletions(-)
diff --git a/package.json b/package.json
index bad2cfe3e..59c58571f 100644
--- a/package.json
+++ b/package.json
@@ -56,7 +56,7 @@
{
"ext": "nwb",
"name": "NWB File",
- "role": "Editor"
+ "role": "Viewer"
}
],
"files": [
diff --git a/src/renderer/src/electron/index.js b/src/renderer/src/electron/index.js
index 4f9b30865..537ee2dd3 100644
--- a/src/renderer/src/electron/index.js
+++ b/src/renderer/src/electron/index.js
@@ -1,3 +1,4 @@
+import { updateURLParams } from "../globals.js";
import isElectron from "./check.js";
export { isElectron };
@@ -21,8 +22,12 @@ if (isElectron) {
remote = require("@electron/remote");
app = remote.app;
- electron.ipcRenderer.on("fileOpened", (info, ...args) => {
- console.log("File opened!", ...args);
+ electron.ipcRenderer.on("fileOpened", (info, filepath) => {
+ updateURLParams({ file: filepath })
+ const dashboard = document.querySelector("nwb-dashboard");
+ const activePage = dashboard.getAttribute('activePage')
+ if (activePage === 'preview') dashboard.requestUpdate()
+ else dashboard.setAttribute("activePage", 'preview')
});
["log", "warn", "error"].forEach((method) =>
diff --git a/src/renderer/src/globals.js b/src/renderer/src/globals.js
index b235577dd..1cb3ad5bf 100644
--- a/src/renderer/src/globals.js
+++ b/src/renderer/src/globals.js
@@ -13,3 +13,17 @@ export let runOnLoad = (fn) => {
export const baseUrl = `http://127.0.0.1:${port}`;
export const supportedInterfaces = guideGlobalMetadata.supported_interfaces;
+
+export function updateURLParams(paramsToUpdate) {
+ const params = new URLSearchParams(location.search);
+ for (let key in paramsToUpdate) {
+ const value = paramsToUpdate[key];
+ if (value == undefined) params.delete(key);
+ else params.set(key, value);
+ }
+
+ // Update browser history state
+ const value = `${location.pathname}?${params}`;
+ if (history.state) Object.assign(history.state, paramsToUpdate);
+ window.history.pushState(history.state, null, value);
+}
diff --git a/src/renderer/src/progress/index.js b/src/renderer/src/progress/index.js
index b5c7c2121..a2aa06dfe 100644
--- a/src/renderer/src/progress/index.js
+++ b/src/renderer/src/progress/index.js
@@ -2,9 +2,9 @@ import Swal from "sweetalert2";
import { guidedProgressFilePath, reloadPageToHome, isStorybook, appDirectory } from "../dependencies/simple.js";
import { fs } from "../electron/index.js";
-import { joinPath, runOnLoad } from "../globals.js";
+import { joinPath, runOnLoad, updateURLParams } from "../globals.js";
import { merge } from "../stories/pages/utils.js";
-import { updateAppProgress, updateFile, updateURLParams } from "./update.js";
+import { updateAppProgress, updateFile } from "./update.js";
export * from "./update";
diff --git a/src/renderer/src/progress/update.js b/src/renderer/src/progress/update.js
index 06b422639..5c4f72aea 100644
--- a/src/renderer/src/progress/update.js
+++ b/src/renderer/src/progress/update.js
@@ -1,6 +1,6 @@
import { guidedProgressFilePath } from "../dependencies/simple.js";
import { fs } from "../electron/index.js";
-import { joinPath } from "../globals.js";
+import { joinPath, updateURLParams } from "../globals.js";
import { get } from "./index.js";
export const update = (newDatasetName, previousDatasetName) => {
@@ -23,21 +23,6 @@ export const update = (newDatasetName, previousDatasetName) => {
return "Dataset name updated";
} else throw new Error("No previous dataset name provided");
};
-
-export function updateURLParams(paramsToUpdate) {
- const params = new URLSearchParams(location.search);
- for (let key in paramsToUpdate) {
- const value = paramsToUpdate[key];
- if (value == undefined) params.delete(key);
- else params.set(key, value);
- }
-
- // Update browser history state
- const value = `${location.pathname}?${params}`;
- if (history.state) Object.assign(history.state, paramsToUpdate);
- window.history.pushState(history.state, null, value);
-}
-
export const updateAppProgress = (
pageId,
dataOrProjectName = {},
diff --git a/src/renderer/src/stories/Dashboard.js b/src/renderer/src/stories/Dashboard.js
index 3d3240331..1c6971117 100644
--- a/src/renderer/src/stories/Dashboard.js
+++ b/src/renderer/src/stories/Dashboard.js
@@ -133,6 +133,10 @@ export class Dashboard extends LitElement {
this.#updated();
}
+ requestPageUpdate() {
+ if (this.#active) this.#active.requestUpdate()
+ }
+
createRenderRoot() {
return this;
}
diff --git a/src/renderer/src/stories/pages/inspect/InspectPage.js b/src/renderer/src/stories/pages/inspect/InspectPage.js
index 5645f77f5..aeceb80fc 100644
--- a/src/renderer/src/stories/pages/inspect/InspectPage.js
+++ b/src/renderer/src/stories/pages/inspect/InspectPage.js
@@ -15,44 +15,52 @@ export class InspectPage extends Page {
super(...args);
}
+ showReport = async (value) => {
+ if (!value) {
+ const message = "Please provide a folder to inspect."
+ onThrow(message)
+ throw new Error(message)
+ }
+
+ const items = truncateFilePaths(await run("inspect_folder", { path: value }, { title: "Inspecting your files" }).catch((e) => {
+ this.notify(e.message, "error");
+ throw e;
+ }), value);
+
+ const list = new InspectorList({ items });
+ list.style.padding = "25px";
+
+ const modal = new Modal({
+ header: value
+ })
+ modal.append(list)
+ document.body.append(modal)
+
+ modal.toggle(true)
+ }
+
+ input = new JSONSchemaInput({
+ path: ['folder_path'],
+ info: {
+ type: 'string',
+ format: 'directory'
+ },
+ onThrow,
+ });
+
render() {
const button = new Button({
label: "Inspect Files",
- onClick: async () => {
- const { value } = this.input
- if (!value) {
- const message = "Please provide a folder to inspect."
- onThrow(message)
- throw new Error(message)
- }
-
- const items = truncateFilePaths(await run("inspect_folder", { path: value }, { title: "Inspecting your files" }).catch((e) => {
- this.notify(e.message, "error");
- throw e;
- }), value);
-
- const list = new InspectorList({ items });
- list.style.padding = "25px";
-
- const modal = new Modal({
- header: value
- })
- modal.append(list)
- document.body.append(modal)
-
- modal.toggle(true)
- },
+ onClick: async () => this.showReport(this.input.value),
});
- this.input = new JSONSchemaInput({
- path: ['folder_path'],
- info: {
- type: 'string',
- format: 'directory'
- },
- onThrow,
- });
+ const urlFilePath = new URL(document.location).searchParams.get('file')
+
+ if (urlFilePath) {
+ this.showReport(urlFilePath)
+ this.input.value = urlFilePath
+ }
return html`
diff --git a/src/renderer/src/stories/pages/preview/PreviewPage.js b/src/renderer/src/stories/pages/preview/PreviewPage.js
index 5f2b276c5..5f9d07214 100644
--- a/src/renderer/src/stories/pages/preview/PreviewPage.js
+++ b/src/renderer/src/stories/pages/preview/PreviewPage.js
@@ -1,13 +1,7 @@
import { html } from "lit";
import { Page } from "../Page.js";
import { onThrow } from "../../../errors";
-import { Button } from "../../Button.js";
-
-import { run } from "../guided-mode/options/utils.js";
import { JSONSchemaInput } from "../../JSONSchemaInput.js";
-import { Modal } from "../../Modal";
-import { truncateFilePaths } from "../../preview/NWBFilePreview.js";
-import { InspectorList } from "../../preview/inspector/InspectorList.js";
import { Neurosift } from "../../preview/Neurosift.js";
import { baseUrl } from "../../../globals.js";
@@ -17,24 +11,31 @@ export class PreviewPage extends Page {
super(...args);
}
- render() {
+ updatePath = async (path) => {
+ const result = await fetch(`${baseUrl}/files/${path}`, { method: "POST" }).then((res) => res.text());
+ if (result) this.neurosift.url = result
+ }
- const neurosift = new Neurosift()
+ neurosift = new Neurosift()
+
+ input = new JSONSchemaInput({
+ path: ['file_path'],
+ info: {
+ type: 'string',
+ format: 'file'
+ },
+ onUpdate: this.updatePath,
+ onThrow,
+ });
+
+ render() {
- this.input = new JSONSchemaInput({
- path: ['file_path'],
- info: {
- type: 'string',
- format: 'file'
- },
- onUpdate: async (path) => {
+ const urlFilePath = new URL(document.location).searchParams.get('file')
- const result = await fetch(`${baseUrl}/files/${path}`, { method: "POST" }).then((res) => res.text());
-
- if (result) neurosift.url = result
- },
- onThrow,
- });
+ if (urlFilePath) {
+ this.updatePath(urlFilePath)
+ this.input.value = urlFilePath
+ }
return html`
@@ -46,7 +47,7 @@ export class PreviewPage extends Page {
${this.input}
- ${neurosift}
+ ${this.neurosift}
`;
}
From b9129faab99b8402d00836e01edbf44a2ec63f2c Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Wed, 6 Sep 2023 01:26:46 +0000
Subject: [PATCH 03/12] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
pyflask/app.py | 13 +++---
src/renderer/src/electron/index.js | 8 ++--
src/renderer/src/stories/Dashboard.js | 2 +-
src/renderer/src/stories/assets/inspect.svg | 10 ++---
src/renderer/src/stories/assets/preview.svg | 10 ++---
.../pages/guided-mode/options/utils.js | 4 +-
.../src/stories/pages/inspect/InspectPage.js | 43 ++++++++++---------
.../src/stories/pages/preview/PreviewPage.js | 23 +++++-----
src/renderer/src/stories/preview/Neurosift.js | 24 ++++++-----
.../preview/inspector/InspectorList.js | 10 ++---
10 files changed, 74 insertions(+), 73 deletions(-)
diff --git a/pyflask/app.py b/pyflask/app.py
index da0205fdf..8a978e0d0 100644
--- a/pyflask/app.py
+++ b/pyflask/app.py
@@ -57,26 +57,27 @@
registered = {}
+
@app.route("/files")
def get_all_files():
return list(registered.keys())
+
@app.route("/files/", methods=["GET", "POST"])
def handle_file_request(path):
-
-
- if request.method == 'GET':
+ if request.method == "GET":
if registered[path]:
return send_file(f"{sep}{unquote(path)}")
else:
- app.abort(404, 'Resource is not accessible.')
+ app.abort(404, "Resource is not accessible.")
else:
- if ('.nwb' in path):
+ if ".nwb" in path:
registered[path] = True
return request.base_url
else:
- app.abort(400, str('Path does not point to an NWB file.'))
+ app.abort(400, str("Path does not point to an NWB file."))
+
@app.route("/conversions/")
def send_conversions(path):
diff --git a/src/renderer/src/electron/index.js b/src/renderer/src/electron/index.js
index 537ee2dd3..49545692f 100644
--- a/src/renderer/src/electron/index.js
+++ b/src/renderer/src/electron/index.js
@@ -23,11 +23,11 @@ if (isElectron) {
app = remote.app;
electron.ipcRenderer.on("fileOpened", (info, filepath) => {
- updateURLParams({ file: filepath })
+ updateURLParams({ file: filepath });
const dashboard = document.querySelector("nwb-dashboard");
- const activePage = dashboard.getAttribute('activePage')
- if (activePage === 'preview') dashboard.requestUpdate()
- else dashboard.setAttribute("activePage", 'preview')
+ const activePage = dashboard.getAttribute("activePage");
+ if (activePage === "preview") dashboard.requestUpdate();
+ else dashboard.setAttribute("activePage", "preview");
});
["log", "warn", "error"].forEach((method) =>
diff --git a/src/renderer/src/stories/Dashboard.js b/src/renderer/src/stories/Dashboard.js
index 1c6971117..121391965 100644
--- a/src/renderer/src/stories/Dashboard.js
+++ b/src/renderer/src/stories/Dashboard.js
@@ -134,7 +134,7 @@ export class Dashboard extends LitElement {
}
requestPageUpdate() {
- if (this.#active) this.#active.requestUpdate()
+ if (this.#active) this.#active.requestUpdate();
}
createRenderRoot() {
diff --git a/src/renderer/src/stories/assets/inspect.svg b/src/renderer/src/stories/assets/inspect.svg
index a94da7c42..8b59b651e 100644
--- a/src/renderer/src/stories/assets/inspect.svg
+++ b/src/renderer/src/stories/assets/inspect.svg
@@ -1,7 +1,7 @@
-
\ No newline at end of file
+>
diff --git a/src/renderer/src/stories/assets/preview.svg b/src/renderer/src/stories/assets/preview.svg
index dbbbd8f77..467b1d186 100644
--- a/src/renderer/src/stories/assets/preview.svg
+++ b/src/renderer/src/stories/assets/preview.svg
@@ -1,7 +1,7 @@
-
\ No newline at end of file
+>
diff --git a/src/renderer/src/stories/pages/guided-mode/options/utils.js b/src/renderer/src/stories/pages/guided-mode/options/utils.js
index 20785b4f2..48031dd06 100644
--- a/src/renderer/src/stories/pages/guided-mode/options/utils.js
+++ b/src/renderer/src/stories/pages/guided-mode/options/utils.js
@@ -24,9 +24,9 @@ export const run = async (url, payload, options = {}) => {
const needsSwal = !options.swal && options.swal !== false;
if (needsSwal) openProgressSwal(options).then((swal) => (options.onOpen ? options.onOpen(swal) : undefined));
- if (!('base' in options)) options.base = '/neuroconv'
+ if (!("base" in options)) options.base = "/neuroconv";
- const results = await fetch(`${baseUrl}${options.base || ''}/${url}`, {
+ const results = await fetch(`${baseUrl}${options.base || ""}/${url}`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
diff --git a/src/renderer/src/stories/pages/inspect/InspectPage.js b/src/renderer/src/stories/pages/inspect/InspectPage.js
index aeceb80fc..5b5164a2c 100644
--- a/src/renderer/src/stories/pages/inspect/InspectPage.js
+++ b/src/renderer/src/stories/pages/inspect/InspectPage.js
@@ -9,7 +9,6 @@ import { Modal } from "../../Modal";
import { truncateFilePaths } from "../../preview/NWBFilePreview.js";
import { InspectorList } from "../../preview/inspector/InspectorList.js";
-
export class InspectPage extends Page {
constructor(...args) {
super(...args);
@@ -17,49 +16,51 @@ export class InspectPage extends Page {
showReport = async (value) => {
if (!value) {
- const message = "Please provide a folder to inspect."
- onThrow(message)
- throw new Error(message)
+ const message = "Please provide a folder to inspect.";
+ onThrow(message);
+ throw new Error(message);
}
- const items = truncateFilePaths(await run("inspect_folder", { path: value }, { title: "Inspecting your files" }).catch((e) => {
- this.notify(e.message, "error");
- throw e;
- }), value);
+ const items = truncateFilePaths(
+ await run("inspect_folder", { path: value }, { title: "Inspecting your files" }).catch((e) => {
+ this.notify(e.message, "error");
+ throw e;
+ }),
+ value
+ );
const list = new InspectorList({ items });
list.style.padding = "25px";
const modal = new Modal({
- header: value
- })
- modal.append(list)
- document.body.append(modal)
+ header: value,
+ });
+ modal.append(list);
+ document.body.append(modal);
- modal.toggle(true)
- }
+ modal.toggle(true);
+ };
input = new JSONSchemaInput({
- path: ['folder_path'],
+ path: ["folder_path"],
info: {
- type: 'string',
- format: 'directory'
+ type: "string",
+ format: "directory",
},
onThrow,
});
render() {
-
const button = new Button({
label: "Inspect Files",
onClick: async () => this.showReport(this.input.value),
});
- const urlFilePath = new URL(document.location).searchParams.get('file')
+ const urlFilePath = new URL(document.location).searchParams.get("file");
if (urlFilePath) {
- this.showReport(urlFilePath)
- this.input.value = urlFilePath
+ this.showReport(urlFilePath);
+ this.input.value = urlFilePath;
}
return html`
diff --git a/src/renderer/src/stories/pages/preview/PreviewPage.js b/src/renderer/src/stories/pages/preview/PreviewPage.js
index 5f9d07214..92acdf666 100644
--- a/src/renderer/src/stories/pages/preview/PreviewPage.js
+++ b/src/renderer/src/stories/pages/preview/PreviewPage.js
@@ -5,7 +5,6 @@ import { JSONSchemaInput } from "../../JSONSchemaInput.js";
import { Neurosift } from "../../preview/Neurosift.js";
import { baseUrl } from "../../../globals.js";
-
export class PreviewPage extends Page {
constructor(...args) {
super(...args);
@@ -13,28 +12,27 @@ export class PreviewPage extends Page {
updatePath = async (path) => {
const result = await fetch(`${baseUrl}/files/${path}`, { method: "POST" }).then((res) => res.text());
- if (result) this.neurosift.url = result
- }
+ if (result) this.neurosift.url = result;
+ };
- neurosift = new Neurosift()
+ neurosift = new Neurosift();
input = new JSONSchemaInput({
- path: ['file_path'],
+ path: ["file_path"],
info: {
- type: 'string',
- format: 'file'
+ type: "string",
+ format: "file",
},
onUpdate: this.updatePath,
onThrow,
});
render() {
-
- const urlFilePath = new URL(document.location).searchParams.get('file')
+ const urlFilePath = new URL(document.location).searchParams.get("file");
if (urlFilePath) {
- this.updatePath(urlFilePath)
- this.input.value = urlFilePath
+ this.updatePath(urlFilePath);
+ this.input.value = urlFilePath;
}
return html`
@@ -46,8 +44,7 @@ export class PreviewPage extends Page {
Use Neurosift to preview of your NWB file.
- ${this.input}
- ${this.neurosift}
+ ${this.input} ${this.neurosift}
`;
}
diff --git a/src/renderer/src/stories/preview/Neurosift.js b/src/renderer/src/stories/preview/Neurosift.js
index eee813c05..41cbff439 100644
--- a/src/renderer/src/stories/preview/Neurosift.js
+++ b/src/renderer/src/stories/preview/Neurosift.js
@@ -50,9 +50,9 @@ export class Neurosift extends LitElement {
}
static get properties() {
- return {
- url: {type: String, reflect: true}
- }
+ return {
+ url: { type: String, reflect: true },
+ };
}
constructor({ url } = {}) {
@@ -61,14 +61,16 @@ export class Neurosift extends LitElement {
}
render() {
- return this.url ? html` ${new Loader({ message: "Loading Neurosift view..." })}
- ` : ``;
+ return this.url
+ ? html` ${new Loader({ message: "Loading Neurosift view..." })}
+ `
+ : ``;
}
}
diff --git a/src/renderer/src/stories/preview/inspector/InspectorList.js b/src/renderer/src/stories/preview/inspector/InspectorList.js
index ec5bb3bc0..b4fedb670 100644
--- a/src/renderer/src/stories/preview/inspector/InspectorList.js
+++ b/src/renderer/src/stories/preview/inspector/InspectorList.js
@@ -29,14 +29,15 @@ const aggregateMessages = (items) => {
};
export class InspectorList extends List {
-
static get styles() {
-
- return [super.styles, css`
+ return [
+ super.styles,
+ css`
:host {
display: block;
}
- }`]
+ }`,
+ ];
}
constructor({ items, listStyles }) {
@@ -64,7 +65,6 @@ customElements.get("inspector-list") || customElements.define("inspector-list",
export class InspectorListItem extends LitElement {
static get styles() {
return css`
-
:host {
display: block;
background: gainsboro;
From ee41639327cbb772941c355c9dd54eb0af01e729 Mon Sep 17 00:00:00 2001
From: Garrett
Date: Wed, 13 Sep 2023 07:58:39 -0700
Subject: [PATCH 04/12] Update logo, name, and backend path usage for Windows
---
pyflask/app.py | 2 +-
src/renderer/src/pages.js | 6 ++--
.../src/stories/assets/neurosift-logo.svg | 34 +++++++++++++++++++
.../src/stories/pages/preview/PreviewPage.js | 4 +--
4 files changed, 40 insertions(+), 6 deletions(-)
create mode 100644 src/renderer/src/stories/assets/neurosift-logo.svg
diff --git a/pyflask/app.py b/pyflask/app.py
index 8a978e0d0..890d9bede 100644
--- a/pyflask/app.py
+++ b/pyflask/app.py
@@ -67,7 +67,7 @@ def get_all_files():
def handle_file_request(path):
if request.method == "GET":
if registered[path]:
- return send_file(f"{sep}{unquote(path)}")
+ return send_file(unquote(path))
else:
app.abort(404, "Resource is not accessible.")
diff --git a/src/renderer/src/pages.js b/src/renderer/src/pages.js
index d53784f4d..a02bed0c8 100644
--- a/src/renderer/src/pages.js
+++ b/src/renderer/src/pages.js
@@ -22,7 +22,7 @@ import { TutorialPage } from "./stories/pages/tutorial/Tutorial";
import tutorialIcon from "./stories/assets/exploration.svg?raw";
import uploadIcon from "./stories/assets/dandi.svg?raw";
import inspectIcon from "./stories/assets/inspect.svg?raw";
-import previewIcon from "./stories/assets/preview.svg?raw";
+import neurosiftIcon from "./stories/assets/neurosift-logo.svg?raw";
import settingsIcon from "./stories/assets/settings.svg?raw";
@@ -173,8 +173,8 @@ const pages = {
icon: inspectIcon,
}),
preview: new PreviewPage({
- label: "Preview",
- icon: previewIcon,
+ label: "Neurosift",
+ icon: neurosiftIcon,
}),
uploads: new UploadsPage({
label: "Uploads",
diff --git a/src/renderer/src/stories/assets/neurosift-logo.svg b/src/renderer/src/stories/assets/neurosift-logo.svg
new file mode 100644
index 000000000..94a564956
--- /dev/null
+++ b/src/renderer/src/stories/assets/neurosift-logo.svg
@@ -0,0 +1,34 @@
+
+
+
+
+Created by potrace 1.16, written by Peter Selinger 2001-2019
+
+
+
+
+
+
diff --git a/src/renderer/src/stories/pages/preview/PreviewPage.js b/src/renderer/src/stories/pages/preview/PreviewPage.js
index 92acdf666..e889c48e9 100644
--- a/src/renderer/src/stories/pages/preview/PreviewPage.js
+++ b/src/renderer/src/stories/pages/preview/PreviewPage.js
@@ -39,9 +39,9 @@ export class PreviewPage extends Page {
-
NWB File Preview
+ Neurosift File Visualization
-
Use Neurosift to preview of your NWB file.
+
Explore your NWB file using Neurosift
${this.input} ${this.neurosift}
From eb795ac7cd07ba9f250205563ae7edf7d70e5f21 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Wed, 13 Sep 2023 15:00:48 +0000
Subject: [PATCH 05/12] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
src/renderer/src/stories/assets/neurosift-logo.svg | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/renderer/src/stories/assets/neurosift-logo.svg b/src/renderer/src/stories/assets/neurosift-logo.svg
index 94a564956..460120d59 100644
--- a/src/renderer/src/stories/assets/neurosift-logo.svg
+++ b/src/renderer/src/stories/assets/neurosift-logo.svg
@@ -1,8 +1,8 @@
-
Date: Wed, 13 Sep 2023 08:09:27 -0700
Subject: [PATCH 06/12] Catch windows file-open bug
---
src/renderer/src/electron/index.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/renderer/src/electron/index.js b/src/renderer/src/electron/index.js
index 49545692f..ece0741c1 100644
--- a/src/renderer/src/electron/index.js
+++ b/src/renderer/src/electron/index.js
@@ -23,6 +23,7 @@ if (isElectron) {
app = remote.app;
electron.ipcRenderer.on("fileOpened", (info, filepath) => {
+ if (filepath === '.') return // BUG: Windows throws . when the application is opened (at least dev mode)...
updateURLParams({ file: filepath });
const dashboard = document.querySelector("nwb-dashboard");
const activePage = dashboard.getAttribute("activePage");
From 33b5cd6d8d807527568c581478e025b2242bad75 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Wed, 13 Sep 2023 15:10:26 +0000
Subject: [PATCH 07/12] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
src/renderer/src/electron/index.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/renderer/src/electron/index.js b/src/renderer/src/electron/index.js
index ece0741c1..53f07f615 100644
--- a/src/renderer/src/electron/index.js
+++ b/src/renderer/src/electron/index.js
@@ -23,7 +23,7 @@ if (isElectron) {
app = remote.app;
electron.ipcRenderer.on("fileOpened", (info, filepath) => {
- if (filepath === '.') return // BUG: Windows throws . when the application is opened (at least dev mode)...
+ if (filepath === ".") return; // BUG: Windows throws . when the application is opened (at least dev mode)...
updateURLParams({ file: filepath });
const dashboard = document.querySelector("nwb-dashboard");
const activePage = dashboard.getAttribute("activePage");
From ad0554bb024efb84f4dffb88dd43d27cfdf3b484 Mon Sep 17 00:00:00 2001
From: Garrett Michael Flynn <46533749+GarrettMFlynn@users.noreply.github.com>
Date: Wed, 13 Sep 2023 08:16:48 -0700
Subject: [PATCH 08/12] Fix backend cause of windows issue
---
src/main/main.ts | 10 +++++++---
src/renderer/src/electron/index.js | 1 -
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/src/main/main.ts b/src/main/main.ts
index da68ea02b..39001a2e4 100755
--- a/src/main/main.ts
+++ b/src/main/main.ts
@@ -355,14 +355,18 @@ function initialize() {
else app.on("ready", onAppReady)
}
-function onFileOpened(_, path: string) {
+function isValidFile(filepath: string) {
+ return !fs.existsSync(filepath) && path.extname(filepath) === '.nwb'
+}
+
+function onFileOpened(_, filepath: string) {
restoreWindow() || initialize(); // Ensure the application is properly visible
- onWindowReady((win) => win.webContents.send('fileOpened', path))
+ onWindowReady((win) => win.webContents.send('fileOpened', filepath))
}
if (isWindows && process.argv.length >= 2) {
const openFilePath = process.argv[1];
- if (openFilePath !== "") onFileOpened(null, openFilePath)
+ if (isValidFile(openFilePath)) onFileOpened(null, openFilePath)
}
// Make this app a single instance app.
diff --git a/src/renderer/src/electron/index.js b/src/renderer/src/electron/index.js
index ece0741c1..49545692f 100644
--- a/src/renderer/src/electron/index.js
+++ b/src/renderer/src/electron/index.js
@@ -23,7 +23,6 @@ if (isElectron) {
app = remote.app;
electron.ipcRenderer.on("fileOpened", (info, filepath) => {
- if (filepath === '.') return // BUG: Windows throws . when the application is opened (at least dev mode)...
updateURLParams({ file: filepath });
const dashboard = document.querySelector("nwb-dashboard");
const activePage = dashboard.getAttribute("activePage");
From b6993325ea4035167dc721a52723beee4ffa87c6 Mon Sep 17 00:00:00 2001
From: Garrett
Date: Wed, 13 Sep 2023 08:25:34 -0700
Subject: [PATCH 09/12] Add description to neurosift loader
---
src/renderer/src/stories/JSONSchemaForm.js | 15 +-----------
src/renderer/src/stories/JSONSchemaInput.js | 24 +++++++++++++++++++
src/renderer/src/stories/Loader.ts | 3 ++-
.../src/stories/pages/preview/PreviewPage.js | 1 +
src/renderer/src/stories/preview/Neurosift.js | 2 +-
5 files changed, 29 insertions(+), 16 deletions(-)
diff --git a/src/renderer/src/stories/JSONSchemaForm.js b/src/renderer/src/stories/JSONSchemaForm.js
index f16987160..3fc1d1219 100644
--- a/src/renderer/src/stories/JSONSchemaForm.js
+++ b/src/renderer/src/stories/JSONSchemaForm.js
@@ -2,7 +2,7 @@ import { LitElement, css, html } from "lit";
import { Accordion } from "./Accordion";
import { checkStatus } from "../validation";
-import { capitalize, header } from "./forms/utils";
+import { header } from "./forms/utils";
import { resolve } from "../promises";
import { merge } from "./pages/utils";
import { resolveProperties } from "./pages/guided-mode/data/utils";
@@ -112,14 +112,6 @@ pre {
.required.conditional label:after {
color: transparent;
}
-
-
- .guided--text-input-instructions {
- font-size: 13px;
- width: 100%;
- padding-top: 4px;
- color: dimgray !important;
- }
`;
document.addEventListener("dragover", (e) => {
@@ -422,11 +414,6 @@ export class JSONSchemaForm extends LitElement {
>
${header(name)}
${interactiveInput}
- ${info.description
- ? html`
- ${capitalize(info.description)}${info.description.slice(-1)[0] === "." ? "" : "."}
-
`
- : ""}
diff --git a/src/renderer/src/stories/JSONSchemaInput.js b/src/renderer/src/stories/JSONSchemaInput.js
index 5d13ea390..fe231617c 100644
--- a/src/renderer/src/stories/JSONSchemaInput.js
+++ b/src/renderer/src/stories/JSONSchemaInput.js
@@ -8,6 +8,8 @@ import { Button } from "./Button";
import { List } from "./List";
import { Modal } from "./Modal";
+import { capitalize } from "./forms/utils";
+
const filesystemQueries = ["file", "directory"];
export class JSONSchemaInput extends LitElement {
@@ -69,6 +71,13 @@ export class JSONSchemaInput extends LitElement {
input[type="number"].hideStep {
-moz-appearance: textfield;
}
+
+ .guided--text-input-instructions {
+ font-size: 13px;
+ width: 100%;
+ padding-top: 4px;
+ color: dimgray !important;
+ }
`;
}
@@ -118,6 +127,21 @@ export class JSONSchemaInput extends LitElement {
}
render() {
+
+ const { info } = this;
+
+ const input = this.#render()
+ return html`
+ ${input}
+ ${info.description
+ ? html`
+ ${capitalize(info.description)}${info.description.slice(-1)[0] === "." ? "" : "."}
+
`
+ : ""}
+ `
+ }
+
+ #render() {
const { validateOnChange, info, path: fullPath } = this;
const path = typeof fullPath === "string" ? fullPath.split("-") : [...fullPath];
diff --git a/src/renderer/src/stories/Loader.ts b/src/renderer/src/stories/Loader.ts
index 97e3febf9..ef52cfe30 100644
--- a/src/renderer/src/stories/Loader.ts
+++ b/src/renderer/src/stories/Loader.ts
@@ -1,4 +1,5 @@
import { LitElement, css, html } from "lit";
+import { unsafeHTML } from "lit/directives/unsafe-html.js";
// From https://loading.io/css/
@@ -120,7 +121,7 @@ export class Loader extends LitElement {
return html`
- ${this.message ? html`
${this.message} ` : ''}
+ ${this.message ? html`
${unsafeHTML(this.message)} ` : ''}
`
}
diff --git a/src/renderer/src/stories/pages/preview/PreviewPage.js b/src/renderer/src/stories/pages/preview/PreviewPage.js
index e889c48e9..c07d0c01d 100644
--- a/src/renderer/src/stories/pages/preview/PreviewPage.js
+++ b/src/renderer/src/stories/pages/preview/PreviewPage.js
@@ -22,6 +22,7 @@ export class PreviewPage extends Page {
info: {
type: "string",
format: "file",
+ description: "Please provide a file path that you'd like to visualize using Neurosift. The NWB GUIDE will serve this file and access the appropriate URL automatically."
},
onUpdate: this.updatePath,
onThrow,
diff --git a/src/renderer/src/stories/preview/Neurosift.js b/src/renderer/src/stories/preview/Neurosift.js
index 41cbff439..14dd499ec 100644
--- a/src/renderer/src/stories/preview/Neurosift.js
+++ b/src/renderer/src/stories/preview/Neurosift.js
@@ -62,7 +62,7 @@ export class Neurosift extends LitElement {
render() {
return this.url
- ? html` ${new Loader({ message: "Loading Neurosift view..." })}
+ ? html` ${new Loader({ message: `Loading Neurosift view...${this.url} ` })}
`
: ""}
- `
+ `;
}
#render() {
diff --git a/src/renderer/src/stories/pages/preview/PreviewPage.js b/src/renderer/src/stories/pages/preview/PreviewPage.js
index c07d0c01d..13fea6714 100644
--- a/src/renderer/src/stories/pages/preview/PreviewPage.js
+++ b/src/renderer/src/stories/pages/preview/PreviewPage.js
@@ -22,7 +22,8 @@ export class PreviewPage extends Page {
info: {
type: "string",
format: "file",
- description: "Please provide a file path that you'd like to visualize using Neurosift. The NWB GUIDE will serve this file and access the appropriate URL automatically."
+ description:
+ "Please provide a file path that you'd like to visualize using Neurosift. The NWB GUIDE will serve this file and access the appropriate URL automatically.",
},
onUpdate: this.updatePath,
onThrow,
diff --git a/src/renderer/src/stories/preview/Neurosift.js b/src/renderer/src/stories/preview/Neurosift.js
index 14dd499ec..cc5374af3 100644
--- a/src/renderer/src/stories/preview/Neurosift.js
+++ b/src/renderer/src/stories/preview/Neurosift.js
@@ -62,7 +62,9 @@ export class Neurosift extends LitElement {
render() {
return this.url
- ? html` ${new Loader({ message: `Loading Neurosift view...${this.url} ` })}
+ ? html`
+ ${new Loader({ message: `Loading Neurosift view...${this.url} ` })}
+