feat(ui): add graph validation for image collection size

This commit is contained in:
psychedelicious 2024-11-18 16:29:43 -06:00
parent 21ffaab2a2
commit bddccf6d2f
4 changed files with 51 additions and 16 deletions

View File

@ -1015,8 +1015,11 @@
"addingImagesTo": "Adding images to",
"invoke": "Invoke",
"missingFieldTemplate": "Missing field template",
"missingInputForField": "{{nodeLabel}} -> {{fieldLabel}} missing input",
"missingInputForField": "{{nodeLabel}} -> {{fieldLabel}}: missing input",
"missingNodeTemplate": "Missing node template",
"collectionEmpty": "{{nodeLabel}} -> {{fieldLabel}} empty collection",
"collectionTooFewItems": "{{nodeLabel}} -> {{fieldLabel}}: too few items, minimum {{minItems}}",
"collectionTooManyItems": "{{nodeLabel}} -> {{fieldLabel}}: too many items, maximum {{maxItems}}",
"noModelSelected": "No model selected",
"noT5EncoderModelSelected": "No T5 Encoder model selected for FLUX generation",
"noFLUXVAEModelSelected": "No VAE model selected for FLUX generation",

View File

@ -11,6 +11,7 @@ import { $templates } from 'features/nodes/store/nodesSlice';
import { selectNodesSlice } from 'features/nodes/store/selectors';
import type { Templates } from 'features/nodes/store/types';
import { selectWorkflowSettingsSlice } from 'features/nodes/store/workflowSettingsSlice';
import { isImageFieldCollectionInputInstance, isImageFieldCollectionInputTemplate } from 'features/nodes/types/field';
import { isInvocationNode } from 'features/nodes/types/invocation';
import { selectUpscaleSlice } from 'features/parameters/store/upscaleSlice';
import { selectConfigSlice } from 'features/system/store/configSlice';
@ -103,14 +104,45 @@ const createSelector = (arg: {
return;
}
const baseTKeyOptions = {
nodeLabel: node.data.label || nodeTemplate.title,
fieldLabel: field.label || fieldTemplate.title,
};
if (fieldTemplate.required && field.value === undefined && !hasConnection) {
reasons.push({
content: i18n.t('parameters.invoke.missingInputForField', {
nodeLabel: node.data.label || nodeTemplate.title,
fieldLabel: field.label || fieldTemplate.title,
}),
});
reasons.push({ content: i18n.t('parameters.invoke.missingInputForField', baseTKeyOptions) });
return;
} else if (
field.value &&
isImageFieldCollectionInputInstance(field) &&
isImageFieldCollectionInputTemplate(fieldTemplate)
) {
// Image collections may have min or max items to validate
// TODO(psyche): generalize this to other collection types
if (fieldTemplate.minItems !== undefined && fieldTemplate.minItems > 0 && field.value.length === 0) {
reasons.push({ content: i18n.t('parameters.invoke.collectionEmpty', baseTKeyOptions) });
return;
}
if (fieldTemplate.minItems !== undefined && field.value.length < fieldTemplate.minItems) {
reasons.push({
content: i18n.t('parameters.invoke.collectionTooFewItems', {
...baseTKeyOptions,
size: field.value.length,
minItems: fieldTemplate.minItems,
}),
});
return;
}
if (fieldTemplate.maxItems !== undefined && field.value.length > fieldTemplate.maxItems) {
reasons.push({
content: i18n.t('parameters.invoke.collectionTooManyItems', {
...baseTKeyOptions,
size: field.value.length,
maxItems: fieldTemplate.maxItems,
}),
});
return;
}
}
});
});

View File

@ -399,13 +399,13 @@ const zImageFieldCollectionInputTemplate = zFieldInputTemplateBase
type: zImageCollectionFieldType,
originalType: zFieldType.optional(),
default: zImageFieldCollectionValue,
maxLength: z.number().int().gte(0).optional(),
minLength: z.number().int().gte(0).optional(),
maxItems: z.number().int().gte(0).optional(),
minItems: z.number().int().gte(0).optional(),
})
.refine(
(val) => {
if (val.maxLength !== undefined && val.minLength !== undefined) {
return val.maxLength >= val.minLength;
if (val.maxItems !== undefined && val.minItems !== undefined) {
return val.maxItems >= val.minItems;
}
return true;
},

View File

@ -417,15 +417,15 @@ const buildImageFieldCollectionInputTemplate: FieldInputTemplateBuilder<ImageFie
const template: ImageFieldCollectionInputTemplate = {
...baseField,
type: fieldType,
default: schemaObject.default ?? undefined,
default: schemaObject.default ?? (schemaObject.orig_required ? [] : undefined),
};
if (schemaObject.minLength !== undefined) {
template.minLength = schemaObject.minLength;
if (schemaObject.minItems !== undefined) {
template.minItems = schemaObject.minItems;
}
if (schemaObject.maxLength !== undefined) {
template.maxLength = schemaObject.maxLength;
if (schemaObject.maxItems !== undefined) {
template.maxItems = schemaObject.maxItems;
}
return template;