diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index 52bf4ff8f9..8f93f32d90 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -978,6 +978,7 @@ "unsupportedAnyOfLength": "too many union members ({{count}})", "unsupportedMismatchedUnion": "mismatched CollectionOrScalar type with base types {{firstType}} and {{secondType}}", "unableToParseFieldType": "unable to parse field type", + "unableToExtractEnumOptions": "unable to extract enum options", "uNetField": "UNet", "uNetFieldDescription": "UNet submodel.", "unhandledInputProperty": "Unhandled input property", diff --git a/invokeai/frontend/web/src/features/nodes/types/error.ts b/invokeai/frontend/web/src/features/nodes/types/error.ts index e520b7710d..905b487fb0 100644 --- a/invokeai/frontend/web/src/features/nodes/types/error.ts +++ b/invokeai/frontend/web/src/features/nodes/types/error.ts @@ -43,10 +43,10 @@ export class NodeUpdateError extends Error { } /** - * FieldTypeParseError + * FieldParseError * Raised when a field cannot be parsed from a field schema. */ -export class FieldTypeParseError extends Error { +export class FieldParseError extends Error { /** * Create FieldTypeParseError * @param {String} message @@ -56,18 +56,3 @@ export class FieldTypeParseError extends Error { this.name = this.constructor.name; } } - -/** - * UnsupportedFieldTypeError - * Raised when an unsupported field type is parsed. - */ -export class UnsupportedFieldTypeError extends Error { - /** - * Create UnsupportedFieldTypeError - * @param {String} message - */ - constructor(message: string) { - super(message); - this.name = this.constructor.name; - } -} diff --git a/invokeai/frontend/web/src/features/nodes/util/schema/buildFieldInputTemplate.ts b/invokeai/frontend/web/src/features/nodes/util/schema/buildFieldInputTemplate.ts index 94095bbc08..001e1c9cf4 100644 --- a/invokeai/frontend/web/src/features/nodes/util/schema/buildFieldInputTemplate.ts +++ b/invokeai/frontend/web/src/features/nodes/util/schema/buildFieldInputTemplate.ts @@ -23,7 +23,12 @@ import { VAEModelFieldInputTemplate, isStatefulFieldType, } from 'features/nodes/types/field'; -import { InvocationFieldSchema } from 'features/nodes/types/openapi'; +import { + InvocationFieldSchema, + isSchemaObject, +} from 'features/nodes/types/openapi'; +import { t } from 'i18next'; +import { FieldParseError } from 'features/nodes/types/error'; // eslint-disable-next-line @typescript-eslint/no-explicit-any type FieldInputTemplateBuilder = // valid `any`! @@ -321,7 +326,28 @@ const buildImageFieldInputTemplate: FieldInputTemplateBuilder< const buildEnumFieldInputTemplate: FieldInputTemplateBuilder< EnumFieldInputTemplate > = ({ schemaObject, baseField, isCollection, isCollectionOrScalar }) => { - const options = schemaObject.enum ?? []; + let options: EnumFieldInputTemplate['options'] = []; + if (schemaObject.anyOf) { + const filteredAnyOf = schemaObject.anyOf.filter((i) => { + if (isSchemaObject(i)) { + if (i.type === 'null') { + return false; + } + } + return true; + }); + const firstAnyOf = filteredAnyOf[0]; + if (filteredAnyOf.length !== 1 || !isSchemaObject(firstAnyOf)) { + options = []; + } else { + options = firstAnyOf.enum ?? []; + } + } else { + options = schemaObject.enum ?? []; + } + if (options.length === 0) { + throw new FieldParseError(t('nodes.unableToExtractEnumOptions')); + } const template: EnumFieldInputTemplate = { ...baseField, type: { diff --git a/invokeai/frontend/web/src/features/nodes/util/schema/parseFieldType.ts b/invokeai/frontend/web/src/features/nodes/util/schema/parseFieldType.ts index 3b6fadd8a1..4ee4edce1b 100644 --- a/invokeai/frontend/web/src/features/nodes/util/schema/parseFieldType.ts +++ b/invokeai/frontend/web/src/features/nodes/util/schema/parseFieldType.ts @@ -1,10 +1,4 @@ -import { t } from 'i18next'; -import { isArray } from 'lodash-es'; -import { OpenAPIV3_1 } from 'openapi-types'; -import { - FieldTypeParseError, - UnsupportedFieldTypeError, -} from 'features/nodes/types/error'; +import { FieldParseError } from 'features/nodes/types/error'; import { FieldType } from 'features/nodes/types/field'; import { OpenAPIV3_1SchemaOrRef, @@ -14,6 +8,9 @@ import { isRefObject, isSchemaObject, } from 'features/nodes/types/openapi'; +import { t } from 'i18next'; +import { isArray } from 'lodash-es'; +import { OpenAPIV3_1 } from 'openapi-types'; /** * Transforms an invocation output ref object to field type. @@ -70,7 +67,7 @@ export const parseFieldType = ( // This is a single ref type const name = refObjectToSchemaName(allOf[0]); if (!name) { - throw new FieldTypeParseError( + throw new FieldParseError( t('nodes.unableToExtractSchemaNameFromRef') ); } @@ -95,7 +92,7 @@ export const parseFieldType = ( if (isRefObject(filteredAnyOf[0])) { const name = refObjectToSchemaName(filteredAnyOf[0]); if (!name) { - throw new FieldTypeParseError( + throw new FieldParseError( t('nodes.unableToExtractSchemaNameFromRef') ); } @@ -120,7 +117,7 @@ export const parseFieldType = ( if (filteredAnyOf.length !== 2) { // This is a union of more than 2 types, which we don't support - throw new UnsupportedFieldTypeError( + throw new FieldParseError( t('nodes.unsupportedAnyOfLength', { count: filteredAnyOf.length, }) @@ -167,7 +164,7 @@ export const parseFieldType = ( }; } - throw new UnsupportedFieldTypeError( + throw new FieldParseError( t('nodes.unsupportedMismatchedUnion', { firstType, secondType, @@ -186,7 +183,7 @@ export const parseFieldType = ( if (isSchemaObject(schemaObject.items)) { const itemType = schemaObject.items.type; if (!itemType || isArray(itemType)) { - throw new UnsupportedFieldTypeError( + throw new FieldParseError( t('nodes.unsupportedArrayItemType', { type: itemType, }) @@ -196,7 +193,7 @@ export const parseFieldType = ( const name = OPENAPI_TO_FIELD_TYPE_MAP[itemType]; if (!name) { // it's 'null', 'object', or 'array' - skip - throw new UnsupportedFieldTypeError( + throw new FieldParseError( t('nodes.unsupportedArrayItemType', { type: itemType, }) @@ -212,7 +209,7 @@ export const parseFieldType = ( // This is a ref object, extract the type name const name = refObjectToSchemaName(schemaObject.items); if (!name) { - throw new FieldTypeParseError( + throw new FieldParseError( t('nodes.unableToExtractSchemaNameFromRef') ); } @@ -226,7 +223,7 @@ export const parseFieldType = ( const name = OPENAPI_TO_FIELD_TYPE_MAP[schemaObject.type]; if (!name) { // it's 'null', 'object', or 'array' - skip - throw new UnsupportedFieldTypeError( + throw new FieldParseError( t('nodes.unsupportedArrayItemType', { type: schemaObject.type, }) @@ -242,9 +239,7 @@ export const parseFieldType = ( } else if (isRefObject(schemaObject)) { const name = refObjectToSchemaName(schemaObject); if (!name) { - throw new FieldTypeParseError( - t('nodes.unableToExtractSchemaNameFromRef') - ); + throw new FieldParseError(t('nodes.unableToExtractSchemaNameFromRef')); } return { name, @@ -252,5 +247,5 @@ export const parseFieldType = ( isCollectionOrScalar: false, }; } - throw new FieldTypeParseError(t('nodes.unableToParseFieldType')); + throw new FieldParseError(t('nodes.unableToParseFieldType')); }; diff --git a/invokeai/frontend/web/src/features/nodes/util/schema/parseSchema.ts b/invokeai/frontend/web/src/features/nodes/util/schema/parseSchema.ts index b425b11663..c5a7cd9f3d 100644 --- a/invokeai/frontend/web/src/features/nodes/util/schema/parseSchema.ts +++ b/invokeai/frontend/web/src/features/nodes/util/schema/parseSchema.ts @@ -1,12 +1,6 @@ import { logger } from 'app/logging/logger'; import { parseify } from 'common/util/serialize'; -import { t } from 'i18next'; -import { reduce } from 'lodash-es'; -import { OpenAPIV3_1 } from 'openapi-types'; -import { - FieldTypeParseError, - UnsupportedFieldTypeError, -} from 'features/nodes/types/error'; +import { FieldParseError } from 'features/nodes/types/error'; import { FieldInputTemplate, FieldOutputTemplate, @@ -18,6 +12,9 @@ import { isInvocationOutputSchemaObject, isInvocationSchemaObject, } from 'features/nodes/types/openapi'; +import { t } from 'i18next'; +import { reduce } from 'lodash-es'; +import { OpenAPIV3_1 } from 'openapi-types'; import { buildFieldInputTemplate } from './buildFieldInputTemplate'; import { buildFieldOutputTemplate } from './buildFieldOutputTemplate'; import { parseFieldType } from './parseFieldType'; @@ -133,10 +130,7 @@ export const parseSchema = ( inputsAccumulator[propertyName] = fieldInputTemplate; } catch (e) { - if ( - e instanceof FieldTypeParseError || - e instanceof UnsupportedFieldTypeError - ) { + if (e instanceof FieldParseError) { logger('nodes').warn( { node: type, @@ -225,10 +219,7 @@ export const parseSchema = ( outputsAccumulator[propertyName] = fieldOutputTemplate; } catch (e) { - if ( - e instanceof FieldTypeParseError || - e instanceof UnsupportedFieldTypeError - ) { + if (e instanceof FieldParseError) { logger('nodes').warn( { node: type,