From 5cfed2ecca3c258d99dea508c885310190d47778 Mon Sep 17 00:00:00 2001 From: Garrett Date: Mon, 16 Oct 2023 16:34:52 -0700 Subject: [PATCH 1/4] Add a loose requirement mode --- src/renderer/src/stories/JSONSchemaForm.js | 9 ++++++++- src/renderer/src/stories/pages/FormPage.js | 4 ++-- .../guided-mode/setup/GuidedNewDatasetInfo.js | 15 ++++++--------- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/renderer/src/stories/JSONSchemaForm.js b/src/renderer/src/stories/JSONSchemaForm.js index 195d6cbfb..5d2a639a0 100644 --- a/src/renderer/src/stories/JSONSchemaForm.js +++ b/src/renderer/src/stories/JSONSchemaForm.js @@ -113,6 +113,11 @@ hr { color: #ff0033; } + :host([requirementmode="loose"]) .required label:after { + color: gray; + } + + .required.conditional label:after { color: transparent; } @@ -152,6 +157,7 @@ export class JSONSchemaForm extends LitElement { required: { type: Object, reflect: false }, dialogType: { type: String, reflect: false }, dialogOptions: { type: Object, reflect: false }, + requirementMode: { type: String, reflect: true }, }; } @@ -189,6 +195,7 @@ export class JSONSchemaForm extends LitElement { this.dialogType = props.dialogType; this.deferLoading = props.deferLoading ?? false; + this.requirementMode = props.requirementMode ?? "default"; this.onlyRequired = props.onlyRequired ?? false; this.showLevelOverride = props.showLevelOverride ?? false; @@ -302,7 +309,7 @@ export class JSONSchemaForm extends LitElement { validate = async (resolved) => { // Check if any required inputs are missing const invalidInputs = await this.#validateRequirements(resolved); // get missing required paths - const isValid = !invalidInputs.length; + const isValid = this.requirementMode === 'loose' ? true : !invalidInputs.length; // Print out a detailed error message if any inputs are missing let message = isValid ? "" : `${invalidInputs.length} required inputs are not specified properly.`; diff --git a/src/renderer/src/stories/pages/FormPage.js b/src/renderer/src/stories/pages/FormPage.js index 1cd9ddc28..de82cceab 100644 --- a/src/renderer/src/stories/pages/FormPage.js +++ b/src/renderer/src/stories/pages/FormPage.js @@ -10,12 +10,12 @@ export function schemaToPages(schema, globalStatePath, options, transformationCa .filter(([_, value]) => value.properties) .map(([key, value]) => { const optionsCopy = { ...options }; + if (optionsCopy.required && optionsCopy.required[key]) optionsCopy.required = { [key]: optionsCopy.required[key], }; - // Only bring requirements from the current page - else delete optionsCopy.required; + else delete optionsCopy.required; // Only bring requirements from the current page const page = new GuidedFormPage( transformationCallback({ diff --git a/src/renderer/src/stories/pages/guided-mode/setup/GuidedNewDatasetInfo.js b/src/renderer/src/stories/pages/guided-mode/setup/GuidedNewDatasetInfo.js index 662adc7ff..8a30747cf 100644 --- a/src/renderer/src/stories/pages/guided-mode/setup/GuidedNewDatasetInfo.js +++ b/src/renderer/src/stories/pages/guided-mode/setup/GuidedNewDatasetInfo.js @@ -30,14 +30,11 @@ const changesAcrossSessions = { const projectMetadataSchema = merge(projectGlobalSchema, projectGeneralSchema); Object.entries(baseMetadataSchema.properties).forEach(([globalProp, v]) => { - Object.keys(v.properties) - .filter((prop) => !(changesAcrossSessions[globalProp] ?? []).includes(prop)) - .forEach((prop) => { - const globalNestedProp = - projectMetadataSchema.properties[globalProp] ?? - (projectMetadataSchema.properties[globalProp] = { properties: {} }); - globalNestedProp.properties[prop] = baseMetadataSchema.properties[globalProp].properties[prop]; - }); + const info = projectMetadataSchema.properties[globalProp] = structuredClone(v) + + changesAcrossSessions[globalProp]?.forEach(prop => { + delete info.properties[prop] + }) }); export class GuidedNewDatasetPage extends Page { @@ -111,7 +108,7 @@ export class GuidedNewDatasetPage extends Page { this.state = merge(global.data.output_locations, structuredClone(this.info.globalState.project)); - const pages = schemaToPages.call(this, schema, ["project"], { validateEmptyValues: false }, (info) => { + const pages = schemaToPages.call(this, schema, ["project"], { validateEmptyValues: false , requirementMode: "loose" }, (info) => { info.title = `${info.label} Global Metadata`; return info; }); From 1d3b809670660b78d92cca10f526829e6ebd3dc5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 16 Oct 2023 23:35:32 +0000 Subject: [PATCH 2/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/renderer/src/stories/JSONSchemaForm.js | 4 ++-- .../guided-mode/setup/GuidedNewDatasetInfo.js | 24 ++++++++++++------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/renderer/src/stories/JSONSchemaForm.js b/src/renderer/src/stories/JSONSchemaForm.js index 5d2a639a0..ecc801efd 100644 --- a/src/renderer/src/stories/JSONSchemaForm.js +++ b/src/renderer/src/stories/JSONSchemaForm.js @@ -116,7 +116,7 @@ hr { :host([requirementmode="loose"]) .required label:after { color: gray; } - + .required.conditional label:after { color: transparent; @@ -309,7 +309,7 @@ export class JSONSchemaForm extends LitElement { validate = async (resolved) => { // Check if any required inputs are missing const invalidInputs = await this.#validateRequirements(resolved); // get missing required paths - const isValid = this.requirementMode === 'loose' ? true : !invalidInputs.length; + const isValid = this.requirementMode === "loose" ? true : !invalidInputs.length; // Print out a detailed error message if any inputs are missing let message = isValid ? "" : `${invalidInputs.length} required inputs are not specified properly.`; diff --git a/src/renderer/src/stories/pages/guided-mode/setup/GuidedNewDatasetInfo.js b/src/renderer/src/stories/pages/guided-mode/setup/GuidedNewDatasetInfo.js index 8a30747cf..7e44b9b5a 100644 --- a/src/renderer/src/stories/pages/guided-mode/setup/GuidedNewDatasetInfo.js +++ b/src/renderer/src/stories/pages/guided-mode/setup/GuidedNewDatasetInfo.js @@ -30,11 +30,11 @@ const changesAcrossSessions = { const projectMetadataSchema = merge(projectGlobalSchema, projectGeneralSchema); Object.entries(baseMetadataSchema.properties).forEach(([globalProp, v]) => { - const info = projectMetadataSchema.properties[globalProp] = structuredClone(v) - - changesAcrossSessions[globalProp]?.forEach(prop => { - delete info.properties[prop] - }) + const info = (projectMetadataSchema.properties[globalProp] = structuredClone(v)); + + changesAcrossSessions[globalProp]?.forEach((prop) => { + delete info.properties[prop]; + }); }); export class GuidedNewDatasetPage extends Page { @@ -108,10 +108,16 @@ export class GuidedNewDatasetPage extends Page { this.state = merge(global.data.output_locations, structuredClone(this.info.globalState.project)); - const pages = schemaToPages.call(this, schema, ["project"], { validateEmptyValues: false , requirementMode: "loose" }, (info) => { - info.title = `${info.label} Global Metadata`; - return info; - }); + const pages = schemaToPages.call( + this, + schema, + ["project"], + { validateEmptyValues: false, requirementMode: "loose" }, + (info) => { + info.title = `${info.label} Global Metadata`; + return info; + } + ); pages.forEach((page) => { page.header = { From 6de70d50ffe7d244dc8d9877ff26258552650b62 Mon Sep 17 00:00:00 2001 From: Garrett Date: Tue, 17 Oct 2023 16:18:39 -0700 Subject: [PATCH 3/4] Add explanation --- .../src/stories/pages/guided-mode/GuidedStart.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/renderer/src/stories/pages/guided-mode/GuidedStart.js b/src/renderer/src/stories/pages/guided-mode/GuidedStart.js index 75c8054ff..ceaefb215 100644 --- a/src/renderer/src/stories/pages/guided-mode/GuidedStart.js +++ b/src/renderer/src/stories/pages/guided-mode/GuidedStart.js @@ -65,16 +65,27 @@ export class GuidedStartPage extends Page {

The second section will have you provide your source data files and NWB File metadata on a per-subject basis to populate your files.

+ ${new InspectorListItem({ - message: html`Red boxes are error messages. These will block your conversion progress + message: html`Red boxes are Error messages. These will block your conversion progress until resolved.`, type: "error", })} ${new InspectorListItem({ - message: html`Yellow boxes are warnings. Fixing them will align your NWB files with + message: html`Yellow boxes are Warning messages. Fixing them will align your NWB files with best practices.`, type: "warning", })} + +

+ Throughout the forms found in the GUIDE, asterisks (*) represent required properties. + Attempting to move forward will throw an Error until these properties are filled in. +

+

+ Gray asterisks (*) are sometimes used to represent loose requirements, where missing this property will throw an Error + — though you don't need to specify a value at the current stage. +

+

3. Conversion Preview

In the third section, you will preview your conversion before uploading to DANDI. From 56ccbe287edcfd2aca6fdfdbe6e535e0776c12a0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 17 Oct 2023 23:18:58 +0000 Subject: [PATCH 4/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/renderer/src/stories/pages/guided-mode/GuidedStart.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/renderer/src/stories/pages/guided-mode/GuidedStart.js b/src/renderer/src/stories/pages/guided-mode/GuidedStart.js index ceaefb215..70bb960ab 100644 --- a/src/renderer/src/stories/pages/guided-mode/GuidedStart.js +++ b/src/renderer/src/stories/pages/guided-mode/GuidedStart.js @@ -72,20 +72,20 @@ export class GuidedStartPage extends Page { type: "error", })} ${new InspectorListItem({ - message: html`Yellow boxes are Warning messages. Fixing them will align your NWB files with - best practices.`, + message: html`Yellow boxes are Warning messages. Fixing them will align your NWB + files with best practices.`, type: "warning", })}

- Throughout the forms found in the GUIDE, asterisks (*) represent required properties. + Throughout the forms found in the GUIDE, asterisks (*) represent required properties. Attempting to move forward will throw an Error until these properties are filled in.

Gray asterisks (*) are sometimes used to represent loose requirements, where missing this property will throw an Error — though you don't need to specify a value at the current stage.

- +

3. Conversion Preview

In the third section, you will preview your conversion before uploading to DANDI.