diff --git a/src/renderer/src/stories/JSONSchemaForm.js b/src/renderer/src/stories/JSONSchemaForm.js index 2c843a674..30a884394 100644 --- a/src/renderer/src/stories/JSONSchemaForm.js +++ b/src/renderer/src/stories/JSONSchemaForm.js @@ -389,46 +389,44 @@ export class JSONSchemaForm extends LitElement { validateSchema = async (resolved, schema, name) => { return await validator - .validate(resolved, schema) - .errors.map((e) => { + .validate(resolved, schema) + .errors.map((e) => { + const propName = e.path.slice(-1)[0] ?? name ?? e.property; + const rowName = e.path.slice(-2)[0]; - const propName = e.path.slice(-1)[0] ?? name ?? e.property; - const rowName = e.path.slice(-2)[0]; + const isRow = typeof rowName === "number"; - const isRow = typeof rowName === "number"; + const resolvedValue = e.path.reduce((acc, token) => acc[token], resolved); - const resolvedValue = e.path.reduce((acc, token) => acc[token], resolved); + // ------------ Exclude Certain Errors ------------ + // Non-Strict Rule + if (schema.strict === false && e.message.includes("is not one of enum values")) return; - // ------------ Exclude Certain Errors ------------ - // Non-Strict Rule - if (schema.strict === false && e.message.includes("is not one of enum values")) return; - - // Allow referring to floats as null (i.e. JSON NaN representation) - if (e.message === "is not of a type(s) number") { - if (resolvedValue === null) return; - } + // Allow referring to floats as null (i.e. JSON NaN representation) + if (e.message === "is not of a type(s) number") { + if (resolvedValue === null) return; + } - return { - type: "error", - message: `${ - typeof propName === "string" - ? `${header(propName)}${isRow ? ` on Row ${rowName}` : ""}` - : `Row ${propName}` - } ${e.message}.`, - }; - }) - .filter((v) => !!v) - } + return { + type: "error", + message: `${ + typeof propName === "string" + ? `${header(propName)}${isRow ? ` on Row ${rowName}` : ""}` + : `Row ${propName}` + } ${e.message}.`, + }; + }) + .filter((v) => !!v); + }; validate = async (resolved = this.resolved) => { - // Validate against the entire JSON Schema const copy = structuredClone(resolved); - delete copy.__disabled + delete copy.__disabled; const result = await this.validateSchema(copy, this.schema); - const resolvedErrors = this.#resolveErrors(result, this.base, resolved) + const resolvedErrors = this.#resolveErrors(result, this.base, resolved); // Check if any required inputs are missing const requiredButNotSpecified = await this.#validateRequirements(resolved); // get missing required paths @@ -444,10 +442,10 @@ export class JSONSchemaForm extends LitElement { } const allErrors = Array.from(flaggedInputs) - .map((el) => { - return Array.from(el.nextElementSibling.children).map((li) => li.message); - }).flat() - + .map((el) => { + return Array.from(el.nextElementSibling.children).map((li) => li.message); + }) + .flat(); const nMissingRequired = allErrors.reduce((acc, curr) => { return (acc += curr.includes(this.#isARequiredPropertyString) ? 1 : 0); @@ -690,8 +688,8 @@ export class JSONSchemaForm extends LitElement { let invalid = []; for (let name in requirements) { - let isRequired = this.#isRequired(name, requirements) - + let isRequired = this.#isRequired(name, requirements); + if (this.#accordions[name]?.disabled) continue; // Skip disabled accordions // // NOTE: Uncomment to block checking requirements inside optional properties @@ -825,7 +823,7 @@ export class JSONSchemaForm extends LitElement { #isARequiredPropertyString = `is a required property`; #resolveErrors = (errors, externalPath, parent) => { - return errors + return errors .map((e) => { // Custom Error Transformations if (this.transformErrors) { @@ -837,7 +835,7 @@ export class JSONSchemaForm extends LitElement { return e; }) .filter((v) => !!v); - } + }; // Assume this is going to return as a Promise—even if the change function isn't returning one triggerValidation = async ( @@ -867,10 +865,7 @@ export class JSONSchemaForm extends LitElement { const skipValidation = !this.validateEmptyValues && value === undefined; const validateArgs = input.pattern || skipValidation ? [] : [value, schema]; - const jsonSchemaErrors = - validateArgs.length === 2 - ? await this.validateSchema(...validateArgs, name) - : []; + const jsonSchemaErrors = validateArgs.length === 2 ? await this.validateSchema(...validateArgs, name) : []; const valid = skipValidation ? true : await this.validateOnChange(name, parent, pathToValidate, value); @@ -958,7 +953,7 @@ export class JSONSchemaForm extends LitElement { if (!isValid && errors.length === 0) errors.push({ type: "error", message: "Invalid value detected" }); - const resolvedErrors = this.#resolveErrors(errors, externalPath, parent) + const resolvedErrors = this.#resolveErrors(errors, externalPath, parent); // Track errors and warnings const updatedWarnings = warnings.map((info) => (onWarning ? onWarning(info) : info)).filter((v) => !!v); @@ -1163,11 +1158,10 @@ export class JSONSchemaForm extends LitElement { const nestedResults = __disabled[name] ?? results[name] ?? this.results[name]; // One or the other will exist—depending on global or local disabling if (renderableInside.length) { - const allIgnore = this.ignore["*"] ?? {}; - const ignore = this.ignore[name] ?? {} - if (ignore["*"]) ignore["*"] = { ...allIgnore, ...ignore["*"] } - else ignore["*"] = allIgnore + const ignore = this.ignore[name] ?? {}; + if (ignore["*"]) ignore["*"] = { ...allIgnore, ...ignore["*"] }; + else ignore["*"] = allIgnore; const ogContext = this; const nested = (this.#nestedForms[name] = new JSONSchemaForm({ 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 b9a01f2dc..f1d4b3251 100644 --- a/src/renderer/src/stories/pages/guided-mode/data/GuidedMetadata.js +++ b/src/renderer/src/stories/pages/guided-mode/data/GuidedMetadata.js @@ -166,7 +166,7 @@ export class GuidedMetadataPage extends ManagedPage { transformErrors: (e, externalPath, parent) => { // JSON Schema Exceptions if (e.message.includes('does not conform to the "date-time" format.')) return false; - if (e.message.includes('not allowed to have the additional property \"Ecephys\".')) return false; // NOTE: Remove after including Ecephys metadata + if (e.message.includes('not allowed to have the additional property "Ecephys".')) return false; // NOTE: Remove after including Ecephys metadata }, conditionalRequirements: [ diff --git a/src/renderer/src/validation/index.js b/src/renderer/src/validation/index.js index 1db670d5a..c539460ef 100644 --- a/src/renderer/src/validation/index.js +++ b/src/renderer/src/validation/index.js @@ -70,13 +70,12 @@ export async function validateOnChange(name, parent, path, value) { }); const res = resolveAll(results, (arr) => { - arr = arr.map((v, i) => { const func = functions[i]; if (typeof func === "function") return v; else return v === null ? undefined : v; - }) - + }); + const flat = arr.flat(); if (flat.find((res) => res?.message)) { return flat