From 518bc10306eb36b50c3f89adf511928aedb307ed Mon Sep 17 00:00:00 2001 From: Cody Baker Date: Fri, 24 May 2024 13:06:23 -0400 Subject: [PATCH] restore frontend changes --- .../src/stories/pages/preview/PreviewPage.js | 96 ++--- .../src/stories/preview/NWBFilePreview.js | 358 ++++++++++-------- .../renderer/src/stories/preview/Neurosift.js | 158 ++++---- 3 files changed, 325 insertions(+), 287 deletions(-) diff --git a/src/electron/renderer/src/stories/pages/preview/PreviewPage.js b/src/electron/renderer/src/stories/pages/preview/PreviewPage.js index a8e6a320a..9c6c79fd0 100644 --- a/src/electron/renderer/src/stories/pages/preview/PreviewPage.js +++ b/src/electron/renderer/src/stories/pages/preview/PreviewPage.js @@ -6,51 +6,59 @@ 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 - } + 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; + }; - updatePath = async (path) => { - if (path) { - const result = await fetch(`${baseUrl}/files/${path}`, { method: "POST" }).then((res) => res.text()); - 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} -
- `; + 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 4bc8b7b71..67345f59b 100644 --- a/src/electron/renderer/src/stories/preview/NWBFilePreview.js +++ b/src/electron/renderer/src/stories/preview/NWBFilePreview.js @@ -1,191 +1,223 @@ import { LitElement, css, html } from "lit"; import { InspectorList } from "./inspector/InspectorList"; -import { Neurosift, getURLFromFilePath } from "./Neurosift"; +import { Neurosift } from "./Neurosift"; import { unsafeHTML } from "lit/directives/unsafe-html.js"; import { run } from "../pages/guided-mode/options/utils"; import { until } from "lit/directives/until.js"; import { InstanceManager } from "../InstanceManager"; import { path } from "../../electron"; 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; - - return isOnline - ? new Neurosift({ url: getURLFromFilePath(this.file, this.project), fullscreen: false }) - : until( - (async () => { - const htmlRep = await run("html", { nwbfile_path: this.file }, { swal: false }); - return unsafeHTML(htmlRep); - })(), - html`Loading HTML representation...` - ); - } + 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), - }; + 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; + }, + {}, + ); - 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...` - )} -
` - : ""} -
`; - } + 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 8def8c8dd..1dbbc04d2 100644 --- a/src/electron/renderer/src/stories/preview/Neurosift.js +++ b/src/electron/renderer/src/stories/preview/Neurosift.js @@ -2,96 +2,94 @@ import { LitElement, css, html } from "lit"; import { Loader } from "../Loader"; import { FullScreenToggle } from "../FullScreenToggle"; -import { baseUrl } from "../../server/globals"; - -export function getURLFromFilePath(file, projectName) { - const regexp = new RegExp(`.+(${projectName}.+)`); - return `${baseUrl}/preview/${file.match(regexp)[1]}`; -} 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);