mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-01-15 06:18:03 -05:00
feat(ui): add node publish denylist
This commit is contained in:
@@ -1809,7 +1809,7 @@
|
||||
"cannotPublish": "Cannot publish workflow",
|
||||
"publishWarnings": "Warnings",
|
||||
"errorWorkflowHasUnsavedChanges": "Workflow has unsaved changes",
|
||||
"errorWorkflowHasBatchOrGeneratorNodes": "Workflow has batch and/or generator nodes",
|
||||
"errorWorkflowHasUnpublishableNodes": "Workflow has batch, generator, or metadata extraction nodes",
|
||||
"errorWorkflowHasInvalidGraph": "Workflow graph invalid (hover Invoke button for details)",
|
||||
"errorWorkflowHasNoOutputNode": "No output node selected",
|
||||
"warningWorkflowHasNoPublishableInputFields": "No publishable input fields selected - published workflow will run with only default values",
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
$isSelectingOutputNode,
|
||||
$outputNodeId,
|
||||
$validationRunData,
|
||||
selectHasUnpublishableNodes,
|
||||
usePublishInputs,
|
||||
} from 'features/nodes/components/sidePanel/workflow/publish';
|
||||
import { useInputFieldTemplateTitleOrThrow } from 'features/nodes/hooks/useInputFieldTemplateTitleOrThrow';
|
||||
@@ -36,7 +37,6 @@ import { useNodeUserTitleOrThrow } from 'features/nodes/hooks/useNodeUserTitleOr
|
||||
import { useOutputFieldNames } from 'features/nodes/hooks/useOutputFieldNames';
|
||||
import { useOutputFieldTemplate } from 'features/nodes/hooks/useOutputFieldTemplate';
|
||||
import { useZoomToNode } from 'features/nodes/hooks/useZoomToNode';
|
||||
import { selectHasBatchOrGeneratorNodes } from 'features/nodes/store/selectors';
|
||||
import { useEnqueueWorkflows } from 'features/queue/hooks/useEnqueueWorkflows';
|
||||
import { $isReadyToEnqueue } from 'features/queue/store/readiness';
|
||||
import { selectAllowPublishWorkflows } from 'features/system/store/configSlice';
|
||||
@@ -201,7 +201,7 @@ const PublishWorkflowButton = memo(() => {
|
||||
const isReadyToDoValidationRun = useStore($isReadyToDoValidationRun);
|
||||
const isReadyToEnqueue = useStore($isReadyToEnqueue);
|
||||
const doesWorkflowHaveUnsavedChanges = useDoesWorkflowHaveUnsavedChanges();
|
||||
const hasBatchOrGeneratorNodes = useAppSelector(selectHasBatchOrGeneratorNodes);
|
||||
const hasUnpublishableNodes = useAppSelector(selectHasUnpublishableNodes);
|
||||
const outputNodeId = useStore($outputNodeId);
|
||||
const isSelectingOutputNode = useStore($isSelectingOutputNode);
|
||||
const inputs = usePublishInputs();
|
||||
@@ -249,7 +249,7 @@ const PublishWorkflowButton = memo(() => {
|
||||
return (
|
||||
<PublishTooltip
|
||||
isWorkflowSaved={!doesWorkflowHaveUnsavedChanges}
|
||||
hasBatchOrGeneratorNodes={hasBatchOrGeneratorNodes}
|
||||
hasUnpublishableNodes={hasUnpublishableNodes}
|
||||
isReadyToEnqueue={isReadyToEnqueue}
|
||||
hasOutputNode={outputNodeId !== null && !isSelectingOutputNode}
|
||||
hasPublishableInputs={inputs.publishable.length > 0}
|
||||
@@ -261,7 +261,7 @@ const PublishWorkflowButton = memo(() => {
|
||||
!allowPublishWorkflows ||
|
||||
!isReadyToEnqueue ||
|
||||
doesWorkflowHaveUnsavedChanges ||
|
||||
hasBatchOrGeneratorNodes ||
|
||||
hasUnpublishableNodes ||
|
||||
!isReadyToDoValidationRun ||
|
||||
!(outputNodeId !== null && !isSelectingOutputNode)
|
||||
}
|
||||
@@ -330,7 +330,7 @@ export const StartPublishFlowButton = memo(() => {
|
||||
const allowPublishWorkflows = useAppSelector(selectAllowPublishWorkflows);
|
||||
const isReadyToEnqueue = useStore($isReadyToEnqueue);
|
||||
const doesWorkflowHaveUnsavedChanges = useDoesWorkflowHaveUnsavedChanges();
|
||||
const hasBatchOrGeneratorNodes = useAppSelector(selectHasBatchOrGeneratorNodes);
|
||||
const hasUnpublishableNodes = useAppSelector(selectHasUnpublishableNodes);
|
||||
const inputs = usePublishInputs();
|
||||
|
||||
const onClick = useCallback(() => {
|
||||
@@ -340,7 +340,7 @@ export const StartPublishFlowButton = memo(() => {
|
||||
return (
|
||||
<PublishTooltip
|
||||
isWorkflowSaved={!doesWorkflowHaveUnsavedChanges}
|
||||
hasBatchOrGeneratorNodes={hasBatchOrGeneratorNodes}
|
||||
hasUnpublishableNodes={hasUnpublishableNodes}
|
||||
isReadyToEnqueue={isReadyToEnqueue}
|
||||
hasOutputNode={true}
|
||||
hasPublishableInputs={inputs.publishable.length > 0}
|
||||
@@ -352,7 +352,7 @@ export const StartPublishFlowButton = memo(() => {
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
isDisabled={
|
||||
!allowPublishWorkflows || !isReadyToEnqueue || doesWorkflowHaveUnsavedChanges || hasBatchOrGeneratorNodes
|
||||
!allowPublishWorkflows || !isReadyToEnqueue || doesWorkflowHaveUnsavedChanges || hasUnpublishableNodes
|
||||
}
|
||||
>
|
||||
{t('workflows.builder.publish')}
|
||||
@@ -366,7 +366,7 @@ StartPublishFlowButton.displayName = 'StartPublishFlowButton';
|
||||
const PublishTooltip = memo(
|
||||
({
|
||||
isWorkflowSaved,
|
||||
hasBatchOrGeneratorNodes,
|
||||
hasUnpublishableNodes,
|
||||
isReadyToEnqueue,
|
||||
hasOutputNode,
|
||||
hasPublishableInputs,
|
||||
@@ -374,7 +374,7 @@ const PublishTooltip = memo(
|
||||
children,
|
||||
}: PropsWithChildren<{
|
||||
isWorkflowSaved: boolean;
|
||||
hasBatchOrGeneratorNodes: boolean;
|
||||
hasUnpublishableNodes: boolean;
|
||||
isReadyToEnqueue: boolean;
|
||||
hasOutputNode: boolean;
|
||||
hasPublishableInputs: boolean;
|
||||
@@ -396,8 +396,8 @@ const PublishTooltip = memo(
|
||||
if (!isWorkflowSaved) {
|
||||
_errors.push(t('workflows.builder.errorWorkflowHasUnsavedChanges'));
|
||||
}
|
||||
if (hasBatchOrGeneratorNodes) {
|
||||
_errors.push(t('workflows.builder.errorWorkflowHasBatchOrGeneratorNodes'));
|
||||
if (hasUnpublishableNodes) {
|
||||
_errors.push(t('workflows.builder.errorWorkflowHasUnpublishableNodes'));
|
||||
}
|
||||
if (!isReadyToEnqueue) {
|
||||
_errors.push(t('workflows.builder.errorWorkflowHasInvalidGraph'));
|
||||
@@ -406,7 +406,7 @@ const PublishTooltip = memo(
|
||||
_errors.push(t('workflows.builder.errorWorkflowHasNoOutputNode'));
|
||||
}
|
||||
return _errors;
|
||||
}, [hasBatchOrGeneratorNodes, hasOutputNode, isReadyToEnqueue, isWorkflowSaved, t]);
|
||||
}, [hasUnpublishableNodes, hasOutputNode, isReadyToEnqueue, isWorkflowSaved, t]);
|
||||
|
||||
if (errors.length === 0 && warnings.length === 0) {
|
||||
return children;
|
||||
|
||||
@@ -4,6 +4,7 @@ import { skipToken } from '@reduxjs/toolkit/query';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { $templates } from 'features/nodes/store/nodesSlice';
|
||||
import {
|
||||
selectNodes,
|
||||
selectNodesSlice,
|
||||
selectWorkflowFormNodeFieldFieldIdentifiersDeduped,
|
||||
selectWorkflowId,
|
||||
@@ -11,7 +12,7 @@ import {
|
||||
import type { Templates } from 'features/nodes/store/types';
|
||||
import type { FieldIdentifier } from 'features/nodes/types/field';
|
||||
import { isBoardFieldType } from 'features/nodes/types/field';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { isBatchNode, isGeneratorNode, isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { atom, computed } from 'nanostores';
|
||||
import { useMemo } from 'react';
|
||||
import { useGetBatchStatusQuery } from 'services/api/endpoints/queue';
|
||||
@@ -108,3 +109,31 @@ export const useIsWorkflowPublished = () => {
|
||||
|
||||
return isPublished;
|
||||
};
|
||||
|
||||
// These nodes are not allowed to be in published workflows because they dynamically generate model identifiers
|
||||
const NODE_TYPE_PUBLISH_DENYLIST = [
|
||||
'metadata_to_model',
|
||||
'metadata_to_sdxl_model',
|
||||
'metadata_to_vae',
|
||||
'metadata_to_lora_collection',
|
||||
'metadata_to_loras',
|
||||
'metadata_to_sdlx_loras',
|
||||
'metadata_to_controlnets',
|
||||
'metadata_to_ip_adapters',
|
||||
'metadata_to_t2i_adapters',
|
||||
];
|
||||
|
||||
export const selectHasUnpublishableNodes = createSelector(selectNodes, (nodes) => {
|
||||
for (const node of nodes) {
|
||||
if (!isInvocationNode(node)) {
|
||||
return true;
|
||||
}
|
||||
if (isBatchNode(node) || isGeneratorNode(node)) {
|
||||
return true;
|
||||
}
|
||||
if (NODE_TYPE_PUBLISH_DENYLIST.includes(node.data.type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user