Skip to content

Commit

Permalink
Merge pull request #326 from NeurodataWithoutBorders/preview-inspecto…
Browse files Browse the repository at this point in the history
…r-results

Preview Inspector Results
  • Loading branch information
CodyCBakerPhD authored Aug 25, 2023
2 parents c8daef6 + 096327d commit 3a1acd9
Show file tree
Hide file tree
Showing 19 changed files with 778 additions and 178 deletions.
72 changes: 72 additions & 0 deletions pyflask/apis/neuroconv.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,78 @@ def post(self):
neuroconv_api.abort(500, str(e))


@neuroconv_api.route("/inspect_file")
class InspectNWBFile(Resource):
@neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"})
def post(self):
try:
import json
from nwbinspector import inspect_nwbfile
from nwbinspector.nwbinspector import InspectorOutputJSONEncoder

return json.loads(
json.dumps(
list(
inspect_nwbfile(
ignore=[
"check_description",
"check_data_orientation",
], # TODO: remove when metadata control is exposed
**neuroconv_api.payload,
)
),
cls=InspectorOutputJSONEncoder,
)
)

except Exception as e:
if notBadRequestException(e):
neuroconv_api.abort(500, str(e))


@neuroconv_api.route("/inspect_folder")
class InspectNWBFolder(Resource):
@neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"})
def post(self):
try:
import json
from nwbinspector import inspect_all
from nwbinspector.nwbinspector import InspectorOutputJSONEncoder

messages = list(
inspect_all(
n_jobs=-2, # uses number of CPU - 1
ignore=[
"check_description",
"check_data_orientation",
], # TODO: remove when metadata control is exposed
**neuroconv_api.payload,
)
)

return json.loads(json.dumps(messages, cls=InspectorOutputJSONEncoder))

except Exception as e:
if notBadRequestException(e):
neuroconv_api.abort(500, str(e))


@neuroconv_api.route("/html")
class NWBToHTML(Resource):
@neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"})
def post(self):
try:
from pynwb import NWBHDF5IO

with NWBHDF5IO(neuroconv_api.payload.nwbfile_path, mode="r") as io:
html = io.read()._repr_html_()
return html

except Exception as e:
if notBadRequestException(e):
neuroconv_api.abort(500, str(e))


@neuroconv_api.route("/generate_dataset")
class GenerateDataset(Resource):
@neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"})
Expand Down
2 changes: 1 addition & 1 deletion pyflask/manageNeuroconv/manage_neuroconv.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ def update_conversion_progress(**kwargs):
if not default_output_directory.exists():
os.symlink(resolved_output_directory, default_output_directory)

return str(resolved_output_path)
return dict(file=str(resolved_output_path))


def upload_to_dandi(
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ async function isOffline() {
await Swal.fire({
title: "No Internet Connection",
icon: "warning",
text: "It appears that your computer is not connected to the internet. You may continue, but you will not be able to use features of NWB GUIDE related to uploading data to DANDI.",
text: "You may continue, but certain features (e.g. uploading data to DANDI, viewing data on Neurosift, etc.) will be unavailable.",
heightAuto: false,
backdrop: "rgba(0,0,0, 0.4)",
confirmButtonText: "I understand",
Expand Down Expand Up @@ -87,7 +87,7 @@ async function checkInternetConnection() {
window.addEventListener('online', isOnline);
window.addEventListener('offline', isOffline);

let hasInternet = navigator.onLine
const hasInternet = navigator.onLine
if (hasInternet) isOnline()
else await isOffline()

Expand Down
26 changes: 21 additions & 5 deletions src/renderer/src/stories/InstanceManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,20 @@ export class InstanceManager extends LitElement {
this.instances = props.instances ?? {};
this.header = props.header;
this.instanceType = props.instanceType ?? "Instance";
if (props.renderInstance) this.renderInstance = props.renderInstance;
if (props.onAdded) this.onAdded = props.onAdded;
if (props.onRemoved) this.onRemoved = props.onRemoved;
this.controls = props.controls ?? [];
}

renderInstance = (_, value) => value.content ?? value;
#dynamicInstances = {};

getInstanceContent = ({ id, metadata }) => {
const content = metadata.content ?? metadata;
if (typeof content === "function") {
this.#dynamicInstances[id] = content;
return "";
} else return content;
};

updateState = (id, state) => {
const item = this.#items.find((i) => i.id === id);
Expand Down Expand Up @@ -211,6 +218,8 @@ export class InstanceManager extends LitElement {
el.removeAttribute("selected");
this.shadowRoot.querySelector(`div[data-instance="${instance}"]`).setAttribute("hidden", "");
});

this.#onSelected();
};

#isCategory(value) {
Expand Down Expand Up @@ -258,6 +267,13 @@ export class InstanceManager extends LitElement {
#onSelected = () => {
const selected = this.shadowRoot.querySelector("#selectedName");
selected.innerText = this.#selected;

const dynamic = this.#dynamicInstances[this.#selected];
if (typeof dynamic === "function") {
this.shadowRoot
.querySelector(`div[data-instance="${this.#selected}"]`)
.append((this.#dynamicInstances[this.#selected] = dynamic()));
}
};

#render(toRender = this.instances, path = []) {
Expand Down Expand Up @@ -293,7 +309,7 @@ export class InstanceManager extends LitElement {

const list = html`
${Object.entries(instances).map(([key, info], i) => {
if (info instanceof HTMLElement) info = { content: info };
if (info instanceof HTMLElement || typeof info === "function") info = { content: info };
const listItemInfo = {
id: key,
label: key.split("/").pop(),
Expand Down Expand Up @@ -399,7 +415,7 @@ export class InstanceManager extends LitElement {
</div>
<div id="content">
<div class="controls">
<span id="selectedName">${this.#selected}</span>
<span id="selectedName"></span>
<div>
${this.controls.map((o) => {
return html`<nwb-button
Expand All @@ -422,7 +438,7 @@ export class InstanceManager extends LitElement {
${this.#items.map((item, i) => {
return html`
<div data-instance="${item.id}" ?hidden=${this.#selected !== item.id}>
${this.renderInstance(item.id, item.metadata)}
${this.getInstanceContent(item)}
</div>
`;
})}
Expand Down
34 changes: 5 additions & 29 deletions src/renderer/src/stories/JSONSchemaForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { merge } from "./pages/utils";
import { resolveProperties } from "./pages/guided-mode/data/utils";

import { JSONSchemaInput } from "./JSONSchemaInput";
import { InspectorListItem } from "./preview/inspector/InspectorList";

const componentCSS = `
Expand All @@ -29,30 +30,6 @@ const componentCSS = `
background: rgb(255, 229, 228) !important;
}
.errors {
color: #9d0b0b;
}
.errors > * {
padding: 25px;
background: #f8d7da;
border: 1px solid #f5c2c7;
border-radius: 4px;
margin: 0 0 1em;
}
.warnings {
color: #856404;
}
.warnings > * {
padding: 25px;
background: #fff3cd;
border: 1px solid #ffeeba;
border-radius: 4px;
margin: 0 0 1em;
}
.guided--form-label {
display: block;
width: 100%;
Expand Down Expand Up @@ -277,9 +254,8 @@ export class JSONSchemaForm extends LitElement {
#addMessage = (name, message, type) => {
if (Array.isArray(name)) name = name.join("-"); // Convert array to string
const container = this.shadowRoot.querySelector(`#${name} .${type}`);
const p = document.createElement("p");
p.innerText = message;
container.appendChild(p);
const item = new InspectorListItem(message);
container.appendChild(item);
};

#clearMessages = (fullPath, type) => {
Expand Down Expand Up @@ -625,7 +601,7 @@ export class JSONSchemaForm extends LitElement {
this.checkStatus();

// Show aggregated errors and warnings (if any)
warnings.forEach((info) => this.#addMessage(fullPath, info.message, "warnings"));
warnings.forEach((info) => this.#addMessage(fullPath, info, "warnings"));

const isFunction = typeof valid === "function";

Expand Down Expand Up @@ -658,7 +634,7 @@ export class JSONSchemaForm extends LitElement {
[...path, name]
);

errors.forEach((info) => this.#addMessage(fullPath, info.message, "errors"));
errors.forEach((info) => this.#addMessage(fullPath, info, "errors"));
// element.title = errors.map((info) => info.message).join("\n"); // Set all errors to show on hover

return false;
Expand Down
4 changes: 3 additions & 1 deletion src/renderer/src/stories/List.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ export default {

const Template = (args) => new List(args);

const generateString = () => Math.floor(Math.random() * Date.now()).toString(36);

export const Default = Template.bind({});
Default.args = {
items: [{ value: "test" }],
items: [{ value: "test" }, { value: Array.from({ length: 1000 }).map(generateString).join("") }],
};

export const WithKeys = Template.bind({});
Expand Down
Loading

0 comments on commit 3a1acd9

Please sign in to comment.