diff --git a/src/renderer/src/stories/Button.js b/src/renderer/src/stories/Button.js
index 5a3fc4b35..cab7f0a8a 100644
--- a/src/renderer/src/stories/Button.js
+++ b/src/renderer/src/stories/Button.js
@@ -1,9 +1,11 @@
import { LitElement, html, css } from "lit";
import { styleMap } from "lit/directives/style-map.js";
+import { unsafeHTML } from "lit/directives/unsafe-html.js";
export class Button extends LitElement {
- constructor({ primary, label, color = null, size, onClick, buttonStyles } = {}) {
+ constructor({ icon = null, primary, label, color = null, size, onClick, buttonStyles } = {}) {
super();
+ this.icon = icon;
this.label = label;
this.primary = primary;
this.color = color;
@@ -18,10 +20,6 @@ export class Button extends LitElement {
display: inline-block;
}
- .button-icon {
- margin-right: 10px;
- }
-
.storybook-button {
padding: 10px 15px;
font-family: "Nunito Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
@@ -29,9 +27,22 @@ export class Button extends LitElement {
border: 0;
border-radius: 5px;
cursor: pointer;
- display: inline-block;
line-height: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .button-icon {
+ margin-right: 7px;
}
+
+ svg {
+ margin: 0px !important;
+ width: auto;
+ height: 25px;
+ }
+
.storybook-button--primary {
color: white;
background-color: hsl(190, 60%, 36%);
@@ -89,7 +100,11 @@ export class Button extends LitElement {
)}
@click=${this.onClick}
>
- ${this.icon ? html`${this.icon}` : ""}
+ ${this.icon
+ ? html`${this.icon instanceof HTMLElement ? this.icon : unsafeHTML(this.icon)}`
+ : ""}
${this.label ?? ""}
`;
diff --git a/src/renderer/src/stories/JSONSchemaForm.js b/src/renderer/src/stories/JSONSchemaForm.js
index 1e80b594a..05d5fdda8 100644
--- a/src/renderer/src/stories/JSONSchemaForm.js
+++ b/src/renderer/src/stories/JSONSchemaForm.js
@@ -100,9 +100,9 @@ const componentCSS = `
margin: 15px;
}
-hr {
- margin: 1em 0 1.5em 0;
-}
+ hr {
+ margin: 1em 0 1.5em 0;
+ }
pre {
white-space: pre-wrap; /* Since CSS 2.1 */
@@ -137,14 +137,19 @@ hr {
border-bottom: 1px solid gainsboro;
}
- .guided--text-input-instructions {
- font-size: 13px;
- width: 100%;
- padding-top: 4px;
- color: dimgray !important;
- margin: 0 0 1em;
- line-height: 1.4285em;
-}
+ .guided--text-input-instructions {
+ font-size: 13px;
+ width: 100%;
+ padding-top: 4px;
+ color: dimgray !important;
+ margin: 0 0 1em;
+ line-height: 1.4285em;
+ }
+
+ [disabled] {
+ opacity: 0.5;
+ pointer-events: none;
+ }
`;
document.addEventListener("dragover", (e) => {
@@ -841,45 +846,51 @@ export class JSONSchemaForm extends LitElement {
if (this.mode === "accordion" && hasMany) {
const headerName = header(name);
- this.#nestedForms[name] = new JSONSchemaForm({
- identifier: this.identifier,
- schema: info,
- results: { ...results[name] },
- globals: this.globals?.[name],
-
- states: this.states,
-
- mode: this.mode,
-
- onUpdate: (internalPath, value) => {
- const path = [...localPath, ...internalPath];
- this.updateData(path, value);
- },
-
- required: required[name], // Scoped to the sub-schema
- ignore: this.ignore,
- dialogOptions: this.dialogOptions,
- dialogType: this.dialogType,
- onlyRequired: this.onlyRequired,
- showLevelOverride: this.showLevelOverride,
- deferLoading: this.deferLoading,
- conditionalRequirements: this.conditionalRequirements,
- validateOnChange: (...args) => this.validateOnChange(...args),
- onThrow: (...args) => this.onThrow(...args),
- validateEmptyValues: this.validateEmptyValues,
- onStatusChange: (status) => {
- accordion.setSectionStatus(headerName, status);
- this.checkStatus();
- }, // Forward status changes to the parent form
- onInvalid: (...args) => this.onInvalid(...args),
- onLoaded: () => {
- this.nLoaded++;
- this.checkAllLoaded();
- },
- renderTable: (...args) => this.renderTable(...args),
- onOverride: (...args) => this.onOverride(...args),
- base: [...this.base, ...localPath],
- });
+ // Check properties that will be rendered before creating the accordion
+ const base = [...this.base, ...localPath];
+ const renderable = this.#getRenderable(info, required[name], base);
+
+ if (renderable.length) {
+ this.#nestedForms[name] = new JSONSchemaForm({
+ identifier: this.identifier,
+ schema: info,
+ results: { ...results[name] },
+ globals: this.globals?.[name],
+
+ states: this.states,
+
+ mode: this.mode,
+
+ onUpdate: (internalPath, value) => {
+ const path = [...localPath, ...internalPath];
+ this.updateData(path, value);
+ },
+
+ required: required[name], // Scoped to the sub-schema
+ ignore: this.ignore,
+ dialogOptions: this.dialogOptions,
+ dialogType: this.dialogType,
+ onlyRequired: this.onlyRequired,
+ showLevelOverride: this.showLevelOverride,
+ deferLoading: this.deferLoading,
+ conditionalRequirements: this.conditionalRequirements,
+ validateOnChange: (...args) => this.validateOnChange(...args),
+ onThrow: (...args) => this.onThrow(...args),
+ validateEmptyValues: this.validateEmptyValues,
+ onStatusChange: (status) => {
+ accordion.setSectionStatus(headerName, status);
+ this.checkStatus();
+ }, // Forward status changes to the parent form
+ onInvalid: (...args) => this.onInvalid(...args),
+ onLoaded: () => {
+ this.nLoaded++;
+ this.checkAllLoaded();
+ },
+ renderTable: (...args) => this.renderTable(...args),
+ onOverride: (...args) => this.onOverride(...args),
+ base,
+ });
+ }
if (!this.states[headerName]) this.states[headerName] = {};
this.states[headerName].subtitle = `${
@@ -895,6 +906,8 @@ export class JSONSchemaForm extends LitElement {
accordion.id = name; // assign name to accordion id
+ if (!renderable.length) accordion.setAttribute("disabled", "");
+
return accordion;
}
diff --git a/src/renderer/src/stories/Main.js b/src/renderer/src/stories/Main.js
index 70ed95cee..89e605dad 100644
--- a/src/renderer/src/stories/Main.js
+++ b/src/renderer/src/stories/Main.js
@@ -152,11 +152,11 @@ export class Main extends LitElement {
style="position: sticky; padding: 0px 50px; top: 0; left: 0; background: white; z-index: 1;"
>
-
+
${title}
${unsafeHTML(subtitle)}
-
${controls}
+
${controls}
`
diff --git a/src/renderer/src/stories/assets/global.svg b/src/renderer/src/stories/assets/global.svg
new file mode 100644
index 000000000..c3a0c9a3f
--- /dev/null
+++ b/src/renderer/src/stories/assets/global.svg
@@ -0,0 +1 @@
+
diff --git a/src/renderer/src/stories/pages/guided-mode/data/GuidedMetadata.js b/src/renderer/src/stories/pages/guided-mode/data/GuidedMetadata.js
index 4df29d12f..a67fa149a 100644
--- a/src/renderer/src/stories/pages/guided-mode/data/GuidedMetadata.js
+++ b/src/renderer/src/stories/pages/guided-mode/data/GuidedMetadata.js
@@ -17,6 +17,8 @@ import { createGlobalFormModal } from "../../../forms/GlobalFormModal";
import { Button } from "../../../Button.js";
import { globalSchema } from "../../../../../../../schemas/base-metadata.schema";
+import globalIcon from "../../../assets/global.svg?raw";
+
const propsToIgnore = [
"Ophys", // Always ignore ophys metadata (for now)
"Icephys", // Always ignore icephys metadata (for now)
@@ -51,6 +53,7 @@ export class GuidedMetadataPage extends ManagedPage {
header = {
controls: [
new Button({
+ icon: globalIcon,
label: "Edit Global Metadata",
onClick: () => {
this.#globalModal.form.results = merge(this.info.globalState.project, {});
@@ -92,7 +95,7 @@ export class GuidedMetadataPage extends ManagedPage {
super.connectedCallback();
const modal = (this.#globalModal = createGlobalFormModal.call(this, {
- header: "Edit Global Metadata",
+ header: "Global Metadata",
propsToRemove: [...propsToIgnore],
schema: globalSchema, // Provide HARDCODED global schema for metadata properties (not automatically abstracting across sessions)...
hasInstances: true,
diff --git a/src/renderer/src/stories/pages/guided-mode/data/GuidedSourceData.js b/src/renderer/src/stories/pages/guided-mode/data/GuidedSourceData.js
index cf4d00a3f..70fa3bf03 100644
--- a/src/renderer/src/stories/pages/guided-mode/data/GuidedSourceData.js
+++ b/src/renderer/src/stories/pages/guided-mode/data/GuidedSourceData.js
@@ -12,6 +12,8 @@ import { createGlobalFormModal } from "../../../forms/GlobalFormModal";
import { header } from "../../../forms/utils";
import { Button } from "../../../Button.js";
+import globalIcon from "../../../assets/global.svg?raw";
+
const propsToIgnore = [
"verbose",
"es_key",
@@ -33,7 +35,8 @@ export class GuidedSourceDataPage extends ManagedPage {
header = {
controls: [
new Button({
- label: "Edit Global Metadata",
+ icon: globalIcon,
+ label: "Edit Global Source Data",
onClick: () => {
this.#globalModal.form.results = merge(this.info.globalState.project?.SourceData, {});
this.#globalModal.open = true;
@@ -162,7 +165,7 @@ export class GuidedSourceDataPage extends ManagedPage {
connectedCallback() {
super.connectedCallback();
const modal = (this.#globalModal = createGlobalFormModal.call(this, {
- header: "Edit Global Source Data",
+ header: "Global Source Data",
propsToRemove: [...propsToIgnore, "folder_path", "file_path"],
key: "SourceData",
schema: this.info.globalState.schema.source_data,
diff --git a/src/renderer/src/stories/pages/guided-mode/setup/GuidedSubjects.js b/src/renderer/src/stories/pages/guided-mode/setup/GuidedSubjects.js
index 1dedc3117..36a01d298 100644
--- a/src/renderer/src/stories/pages/guided-mode/setup/GuidedSubjects.js
+++ b/src/renderer/src/stories/pages/guided-mode/setup/GuidedSubjects.js
@@ -11,6 +11,8 @@ import { Button } from "../../../Button.js";
import { createGlobalFormModal } from "../../../forms/GlobalFormModal";
import { header } from "../../../forms/utils";
+import globalIcon from "../../../assets/global.svg?raw";
+
export class GuidedSubjectsPage extends Page {
constructor(...args) {
super(...args);
@@ -20,6 +22,7 @@ export class GuidedSubjectsPage extends Page {
subtitle: "Enter all metadata known about each experiment subject",
controls: [
new Button({
+ icon: globalIcon,
label: "Edit Global Metadata",
onClick: () => {
this.#globalModal.form.results = merge(this.info.globalState.project?.Subject, {});
@@ -88,7 +91,7 @@ export class GuidedSubjectsPage extends Page {
connectedCallback() {
super.connectedCallback();
const modal = (this.#globalModal = createGlobalFormModal.call(this, {
- header: "Edit Global Subject Data",
+ header: "Global Subject Metadata",
key: "Subject",
schema: globalSchema.properties.Subject,
validateOnChange: (key, parent, path) => {