diff --git a/src/electron/renderer/src/stories/pages/preview/PreviewPage.js b/src/electron/renderer/src/stories/pages/preview/PreviewPage.js index 9c6c79fd0..868b279ac 100644 --- a/src/electron/renderer/src/stories/pages/preview/PreviewPage.js +++ b/src/electron/renderer/src/stories/pages/preview/PreviewPage.js @@ -6,59 +6,56 @@ import { Neurosift } from "../../preview/Neurosift.js"; import { baseUrl } from "../../../server/globals"; export class PreviewPage extends Page { - header = { - title: "NWB File Exploration", - subtitle: "Visualize your NWB file using Neurosift.", - }; - - constructor(...args) { - super(...args); - this.style.height = "100%"; // Fix main section - } - - updatePath = async (path) => { - if (path) { - // Enable access to the explicit file path - const result = await fetch(`${baseUrl}/files/${path}`, { - method: "POST", - }).then((res) => res.text()); - - // Set Neurosift to access the returned URL - if (result) this.neurosift.url = result; - } else this.neurosift.url = undefined; - }; - - neurosift = new Neurosift(); - - input = new JSONSchemaInput({ - path: ["file_path"], - schema: { - type: "string", - format: "file", - description: - "Please provide a file path that you'd like to visualize using Neurosift. The GUIDE will serve this file and access the appropriate URL automatically.", - }, - onUpdate: this.updatePath, - onThrow, - }); - - render() { - const urlFilePath = new URL(document.location).searchParams.get("file"); - - if (urlFilePath) { - this.updatePath(urlFilePath); - this.input.value = urlFilePath; + header = { + title: "NWB File Exploration", + subtitle: "Visualize your NWB file using Neurosift.", + }; + + constructor(...args) { + super(...args); + this.style.height = "100%"; // Fix main section } - return html` -
- ${this.input} ${this.neurosift} -
- `; - } + updatePath = async (path) => { + if (path) { + // Enable access to the explicit file path + const result = await fetch(`${baseUrl}/files/${path}`, { + method: "POST", + }).then((res) => res.text()); + + // Set Neurosift to access the returned URL + if (result) this.neurosift.url = result; + } else this.neurosift.url = undefined; + }; + + neurosift = new Neurosift(); + + input = new JSONSchemaInput({ + path: ["file_path"], + schema: { + type: "string", + format: "file", + description: + "Please provide a file path that you'd like to visualize using Neurosift. The GUIDE will serve this file and access the appropriate URL automatically.", + }, + onUpdate: this.updatePath, + onThrow, + }); + + render() { + const urlFilePath = new URL(document.location).searchParams.get("file"); + + if (urlFilePath) { + this.updatePath(urlFilePath); + this.input.value = urlFilePath; + } + + return html` +
+ ${this.input} ${this.neurosift} +
+ `; + } } -customElements.get("nwbguide-preview-page") || - customElements.define("nwbguide-preview-page", PreviewPage); +customElements.get("nwbguide-preview-page") || customElements.define("nwbguide-preview-page", PreviewPage); diff --git a/src/electron/renderer/src/stories/preview/NWBFilePreview.js b/src/electron/renderer/src/stories/preview/NWBFilePreview.js index 67345f59b..9a82e8880 100644 --- a/src/electron/renderer/src/stories/preview/NWBFilePreview.js +++ b/src/electron/renderer/src/stories/preview/NWBFilePreview.js @@ -10,214 +10,194 @@ import { FullScreenToggle } from "../FullScreenToggle"; import { baseUrl } from "../../server/globals"; export function getSharedPath(array) { - array = array.map((str) => str.replace(/\\/g, "/")); // Convert to Mac-style path - const mapped = array.map((str) => str.split("/")); - let shared = mapped.shift(); - mapped.forEach((arr, i) => { - for (let j in arr) { - if (arr[j] !== shared[j]) { - shared = shared.slice(0, j); - break; - } - } - }); + array = array.map((str) => str.replace(/\\/g, "/")); // Convert to Mac-style path + const mapped = array.map((str) => str.split("/")); + let shared = mapped.shift(); + mapped.forEach((arr, i) => { + for (let j in arr) { + if (arr[j] !== shared[j]) { + shared = shared.slice(0, j); + break; + } + } + }); - return shared ? path.normalize(shared.join("/")) : ""; // Convert back to OS-specific path + return shared ? path.normalize(shared.join("/")) : ""; // Convert back to OS-specific path } export function truncateFilePaths(items, basepath) { - return items.map((item) => { - item = { ...item }; - item.file_path = item.file_path - .replace(`${basepath}/`, "") // Mac - .replace(`${basepath}\\`, ""); // Windows - return item; - }); + return items.map((item) => { + item = { ...item }; + item.file_path = item.file_path + .replace(`${basepath}/`, "") // Mac + .replace(`${basepath}\\`, ""); // Windows + return item; + }); } export const removeFilePaths = (items) => { - return items.map((item) => { - const copy = { ...item }; - delete copy.file_path; - return copy; - }); + return items.map((item) => { + const copy = { ...item }; + delete copy.file_path; + return copy; + }); }; class NWBPreviewInstance extends LitElement { - constructor({ file }, project) { - super(); - this.file = file; - this.project = project; - - window.addEventListener("online", () => this.requestUpdate()); - window.addEventListener("offline", () => this.requestUpdate()); - } - - render() { - const isOnline = navigator.onLine; - - if (!isOnline) - return until( - (async () => { - const htmlRep = await run( - "html", - { nwbfile_path: this.file }, - { swal: false }, - ); - return unsafeHTML(htmlRep); - })(), - html`Loading HTML representation...`, - ); - - const neurosift = new Neurosift({ fullscreen: false }); - - // Enable access to the explicit file path - fetch(`${baseUrl}/files/${this.file}`, { method: "POST" }) - .then((res) => res.text()) - .then((result) => { - // Set Neurosift to access the returned URL - if (result) neurosift.url = result; - }); - - return neurosift; - } + constructor({ file }, project) { + super(); + this.file = file; + this.project = project; + + window.addEventListener("online", () => this.requestUpdate()); + window.addEventListener("offline", () => this.requestUpdate()); + } + + render() { + const isOnline = navigator.onLine; + + if (!isOnline) + return until( + (async () => { + const htmlRep = await run("html", { nwbfile_path: this.file }, { swal: false }); + return unsafeHTML(htmlRep); + })(), + html`Loading HTML representation...` + ); + + const neurosift = new Neurosift({ fullscreen: false }); + + // Enable access to the explicit file path + fetch(`${baseUrl}/files/${this.file}`, { method: "POST" }) + .then((res) => res.text()) + .then((result) => { + // Set Neurosift to access the returned URL + if (result) neurosift.url = result; + }); + + return neurosift; + } } -customElements.get("nwb-preview-instance") || - customElements.define("nwb-preview-instance", NWBPreviewInstance); +customElements.get("nwb-preview-instance") || customElements.define("nwb-preview-instance", NWBPreviewInstance); export class NWBFilePreview extends LitElement { - static get styles() { - return css` - :host { - display: block; - width: 100%; - height: 100%; - background: white; - position: relative; - } - - iframe { - width: 100%; - height: 100%; - border: 0; - } - - #inspect { - display: flex; - flex-direction: column; - border-left: 1px solid gray; - box-shadow: -5px 0 5px -5px rgba(0, 0, 0, 0.5); - z-index: 1; - } - `; - } - - constructor({ files = {}, project, inspect = false }) { - super(); - this.project = project; - this.files = files; - this.inspect = inspect; - } - - createInstance = ({ subject, session, info }) => { - return { - subject, - session, - display: () => new NWBPreviewInstance(info, this.project), - }; - }; - - render() { - const fileArr = Object.entries(this.files) - .map(([subject, v]) => - Object.entries(v).map(([session, info]) => { - return { subject, session, info }; - }), - ) - .flat(); - - const onlyFirstFile = fileArr.length <= 1; - - return html` ${new FullScreenToggle({ target: this })} -
-
- ${(() => { - if (onlyFirstFile) - return new NWBPreviewInstance(fileArr[0].info, this.project); - else { - const _instances = fileArr.map(this.createInstance); - - const instances = _instances.reduce( - (acc, { subject, session, display }) => { - if (!acc[`sub-${subject}`]) acc[`sub-${subject}`] = {}; - acc[`sub-${subject}`][`ses-${session}`] = display; - return acc; - }, - {}, - ); - - return new InstanceManager({ instances }); + static get styles() { + return css` + :host { + display: block; + width: 100%; + height: 100%; + background: white; + position: relative; } - })()} -
- ${this.inspect - ? html`
-

- Inspector Report -

- ${until( - (async () => { - const options = {}; // NOTE: Currently options are handled on the Python end until exposed to the user - - const title = "Inspecting your file"; - - const report = onlyFirstFile - ? await run( - "inspect_file", - { nwbfile_path: fileArr[0].info.file, ...options }, - { title }, - ) // Inspect the first file - : await run( - "inspect_folder", - { path, ...options }, - { title: title + "s" }, - ); // Inspect the folder - - const result = onlyFirstFile - ? { - ...report, - messages: removeFilePaths(report.messages), - } - : { - ...report, - messages: truncateFilePaths( - report.messages, - getSharedPath(fileArr.map(({ info }) => info.file)), - ), - }; - - const items = result.messages; - - const list = new InspectorList({ - items: items, - listStyles: { minWidth: "300px", maxWidth: "350px" }, - emptyMessage: "No issues found.", - }); - list.style.padding = "10px"; - return list; - })(), - html`Loading inspector report...`, - )} -
` - : ""} -
`; - } + + iframe { + width: 100%; + height: 100%; + border: 0; + } + + #inspect { + display: flex; + flex-direction: column; + border-left: 1px solid gray; + box-shadow: -5px 0 5px -5px rgba(0, 0, 0, 0.5); + z-index: 1; + } + `; + } + + constructor({ files = {}, project, inspect = false }) { + super(); + this.project = project; + this.files = files; + this.inspect = inspect; + } + + createInstance = ({ subject, session, info }) => { + return { + subject, + session, + display: () => new NWBPreviewInstance(info, this.project), + }; + }; + + render() { + const fileArr = Object.entries(this.files) + .map(([subject, v]) => + Object.entries(v).map(([session, info]) => { + return { subject, session, info }; + }) + ) + .flat(); + + const onlyFirstFile = fileArr.length <= 1; + + return html` ${new FullScreenToggle({ target: this })} +
+
+ ${(() => { + if (onlyFirstFile) return new NWBPreviewInstance(fileArr[0].info, this.project); + else { + const _instances = fileArr.map(this.createInstance); + + const instances = _instances.reduce((acc, { subject, session, display }) => { + if (!acc[`sub-${subject}`]) acc[`sub-${subject}`] = {}; + acc[`sub-${subject}`][`ses-${session}`] = display; + return acc; + }, {}); + + return new InstanceManager({ instances }); + } + })()} +
+ ${this.inspect + ? html`
+

Inspector Report

+ ${until( + (async () => { + const options = {}; // NOTE: Currently options are handled on the Python end until exposed to the user + + const title = "Inspecting your file"; + + const report = onlyFirstFile + ? await run( + "inspect_file", + { nwbfile_path: fileArr[0].info.file, ...options }, + { title } + ) // Inspect the first file + : await run("inspect_folder", { path, ...options }, { title: title + "s" }); // Inspect the folder + + const result = onlyFirstFile + ? { + ...report, + messages: removeFilePaths(report.messages), + } + : { + ...report, + messages: truncateFilePaths( + report.messages, + getSharedPath(fileArr.map(({ info }) => info.file)) + ), + }; + + const items = result.messages; + + const list = new InspectorList({ + items: items, + listStyles: { minWidth: "300px", maxWidth: "350px" }, + emptyMessage: "No issues found.", + }); + list.style.padding = "10px"; + return list; + })(), + html`Loading inspector report...` + )} +
` + : ""} +
`; + } } -customElements.get("nwb-file-preview") || - customElements.define("nwb-file-preview", NWBFilePreview); +customElements.get("nwb-file-preview") || customElements.define("nwb-file-preview", NWBFilePreview); diff --git a/src/electron/renderer/src/stories/preview/Neurosift.js b/src/electron/renderer/src/stories/preview/Neurosift.js index 1dbbc04d2..ecce4cbb9 100644 --- a/src/electron/renderer/src/stories/preview/Neurosift.js +++ b/src/electron/renderer/src/stories/preview/Neurosift.js @@ -4,92 +4,90 @@ import { Loader } from "../Loader"; import { FullScreenToggle } from "../FullScreenToggle"; export class Neurosift extends LitElement { - static get styles() { - return css` - :host { - background: white; - width: 100%; - height: 100%; - display: grid; - grid-template-rows: 100%; - grid-template-columns: 100%; - position: relative; - --loader-color: hsl(200, 80%, 50%); - } + static get styles() { + return css` + :host { + background: white; + width: 100%; + height: 100%; + display: grid; + grid-template-rows: 100%; + grid-template-columns: 100%; + position: relative; + --loader-color: hsl(200, 80%, 50%); + } - iframe, - .loader-container { - width: 100%; - height: 100%; - } + iframe, + .loader-container { + width: 100%; + height: 100%; + } - .loader-container { - display: flex; - align-items: center; - justify-content: center; - position: absolute; - top: 0; - left: 0; - } + .loader-container { + display: flex; + align-items: center; + justify-content: center; + position: absolute; + top: 0; + left: 0; + } - .fullscreen-toggle { - display: flex; - position: absolute; - top: 10px; - right: 10px; - padding: 10px; - color: white; - background-color: gainsboro; - border: 1px solid gray; - border-radius: 10px; - cursor: pointer; - } + .fullscreen-toggle { + display: flex; + position: absolute; + top: 10px; + right: 10px; + padding: 10px; + color: white; + background-color: gainsboro; + border: 1px solid gray; + border-radius: 10px; + cursor: pointer; + } - span { - font-size: 14px; - } + span { + font-size: 14px; + } - small { - padding-left: 10px; - } + small { + padding-left: 10px; + } - iframe { - border: 0; - } - `; - } + iframe { + border: 0; + } + `; + } - static get properties() { - return { - url: { type: String, reflect: true }, - }; - } + static get properties() { + return { + url: { type: String, reflect: true }, + }; + } - constructor({ url, fullscreen = true } = {}) { - super(); - this.url = url; - this.fullscreen = fullscreen; - } + constructor({ url, fullscreen = true } = {}) { + super(); + this.url = url; + this.fullscreen = fullscreen; + } - render() { - return this.url - ? html`
- ${new Loader({ - message: `Loading Neurosift view...
${this.url}`, - })} -
- ${this.fullscreen ? new FullScreenToggle({ target: this }) : ""} - ` - : ``; - } + render() { + return this.url + ? html`
+ ${new Loader({ + message: `Loading Neurosift view...
${this.url}`, + })} +
+ ${this.fullscreen ? new FullScreenToggle({ target: this }) : ""} + ` + : ``; + } } -customElements.get("neurosift-iframe") || - customElements.define("neurosift-iframe", Neurosift); +customElements.get("neurosift-iframe") || customElements.define("neurosift-iframe", Neurosift); diff --git a/src/pyflask/tests/conftest.py b/src/pyflask/tests/conftest.py index 0a19565fa..c585a7124 100644 --- a/src/pyflask/tests/conftest.py +++ b/src/pyflask/tests/conftest.py @@ -3,7 +3,7 @@ def pytest_addoption(parser): - parser.addoption("--target", action="store", help="Run the executable instead of the standard Flask flask_app") + parser.addoption("--target", action="store", help="Run the executable instead of the standard Flask app.") @pytest.fixture(scope="session")