diff --git a/src/components/graph/SelectionToolbox.vue b/src/components/graph/SelectionToolbox.vue index 641c52cd5..2b0b84248 100644 --- a/src/components/graph/SelectionToolbox.vue +++ b/src/components/graph/SelectionToolbox.vue @@ -27,6 +27,9 @@ icon="pi pi-thumbtack" @click="() => commandStore.execute('Comfy.Canvas.ToggleSelected.Pin')" /> + - canvasStore.selectedItems.some(isLGraphNode) +const selectedNodes = computed(() => + canvasStore.selectedItems.filter(isLGraphNode) ) -const groupSelected = computed(() => - canvasStore.selectedItems.some(isLGraphGroup) +const selectedModelNodes = computed(() => + selectedNodes.value.filter(isModelNode) ) +const selectedGroups = computed(() => + canvasStore.selectedItems.filter(isLGraphGroup) +) +const nodeSelected = computed(() => selectedNodes.value.length > 0) +const groupSelected = computed(() => selectedGroups.value.length > 0) +const modelNodeSelected = computed(() => selectedModelNodes.value.length > 0) const extensionToolboxCommands = computed(() => { const commandIds = new Set( diff --git a/src/components/graph/selectionToolbox/nodeModelsMetadata/ModelForm.vue b/src/components/graph/selectionToolbox/nodeModelsMetadata/ModelForm.vue new file mode 100644 index 000000000..9eed9d535 --- /dev/null +++ b/src/components/graph/selectionToolbox/nodeModelsMetadata/ModelForm.vue @@ -0,0 +1,136 @@ + + + + + + {{ $form.name?.error?.message || $form.directory?.error?.message }} + + + + + + + + + + + {{ $t('nodeMetadata.models.fields.name') }} + + + + + + + + + + + + + {{ $t('nodeMetadata.models.fields.directory') }} + + + + + + + + + + + + + {{ $t('nodeMetadata.models.fields.url') }} + + + + + + {{ $form.url?.error?.message }} + + + + + + + + + + + + + + + diff --git a/src/components/graph/selectionToolbox/nodeModelsMetadata/NodeModelsButton.vue b/src/components/graph/selectionToolbox/nodeModelsMetadata/NodeModelsButton.vue new file mode 100644 index 000000000..a6fe5c594 --- /dev/null +++ b/src/components/graph/selectionToolbox/nodeModelsMetadata/NodeModelsButton.vue @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + diff --git a/src/components/graph/selectionToolbox/nodeModelsMetadata/NodeModelsPopover.vue b/src/components/graph/selectionToolbox/nodeModelsMetadata/NodeModelsPopover.vue new file mode 100644 index 000000000..39aa432a9 --- /dev/null +++ b/src/components/graph/selectionToolbox/nodeModelsMetadata/NodeModelsPopover.vue @@ -0,0 +1,123 @@ + + + + + {{ $t('nodeMetadata.models.title') }} + + + + + + + + + + + + + + + + + diff --git a/src/locales/en/main.json b/src/locales/en/main.json index 77151e26a..484bffd2e 100644 --- a/src/locales/en/main.json +++ b/src/locales/en/main.json @@ -80,6 +80,21 @@ "choose_file_to_upload": "choose file to upload", "capture": "capture" }, + "nodeMetadata": { + "models" : { + "title": "Edit Node Models Metadata", + "save": "Save Models Metadata", + "add": "Add Model", + "remove": "Remove Model", + "modelUpdated": "Model updated", + "modelUpdateFailed": "Invalid model metadata. Node not updated.", + "fields": { + "name": "Name", + "directory": "Directory", + "url": "URL" + } + } + }, "issueReport": { "submitErrorReport": "Submit Error Report (Optional)", "provideEmail": "Give us your email (optional)", @@ -860,4 +875,4 @@ "camera": "Camera", "light": "Light" } -} \ No newline at end of file +} diff --git a/src/schemas/comfyWorkflowSchema.ts b/src/schemas/comfyWorkflowSchema.ts index 2dc440760..a2623d211 100644 --- a/src/schemas/comfyWorkflowSchema.ts +++ b/src/schemas/comfyWorkflowSchema.ts @@ -31,12 +31,12 @@ const zVector2 = z.union([ ]) // Definition of an AI model file used in the workflow. -const zModelFile = z.object({ - name: z.string(), +export const zModelFile = z.object({ + name: z.string().min(1, 'Name cannot be empty'), url: z.string().url(), hash: z.string().optional(), hash_type: z.string().optional(), - directory: z.string() + directory: z.string().min(1, 'Directory cannot be empty') }) const zGraphState = z diff --git a/src/utils/litegraphUtil.ts b/src/utils/litegraphUtil.ts index 66187b4e7..aa1ce0bc1 100644 --- a/src/utils/litegraphUtil.ts +++ b/src/utils/litegraphUtil.ts @@ -47,6 +47,26 @@ export const isLGraphGroup = (item: unknown): item is LGraphGroup => { return item instanceof LGraphGroup } +const modelOutputTypes = new Set([ + 'MODEL', + 'CLIP', + 'VAE', + 'CONTROL_NET', + 'UPSCALE_MODEL', + 'CLIP_VISION', + 'STYLE_MODEL', + 'GLIGEN', + 'HOOKS', + 'UPSCALE_MODEL', + 'PHOTOMAKER', + 'SAM_MODEL' +]) + +export const isModelNode = (node: LGraphNode): boolean => { + if (!node?.outputs?.length) return false + return node.outputs.some((output) => modelOutputTypes.has(`${output.type}`)) +} + /** * Get the color option of all canvas items if they are all the same. * @param items - The items to get the color option of.