InvokeAI/invokeai/frontend/web/src/common/hooks/useIsReadyToInvoke.ts
mickr777 8c63173b0c
Translation update (#4503)
* Update Translations

* Fix Prettier Issue

* Fix Error in invokebutton.tsx

* More Translations

* few Fixes

* More Translations

* More Translations and lint Fixes

* Update constants.ts

Revert "Update constants.ts"

---------

Co-authored-by: psychedelicious <4822129+psychedelicious@users.noreply.github.com>
2023-09-13 17:31:34 +10:00

124 lines
3.7 KiB
TypeScript

import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { isInvocationNode } from 'features/nodes/types/types';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { forEach, map } from 'lodash-es';
import { getConnectedEdges } from 'reactflow';
import i18n from 'i18next';
const selector = createSelector(
[stateSelector, activeTabNameSelector],
(state, activeTabName) => {
const { generation, system, nodes } = state;
const { initialImage, model } = generation;
const { isProcessing, isConnected } = system;
const reasons: string[] = [];
// Cannot generate if already processing an image
if (isProcessing) {
reasons.push(i18n.t('parameters.invoke.systemBusy'));
}
// Cannot generate if not connected
if (!isConnected) {
reasons.push(i18n.t('parameters.invoke.systemDisconnected'));
}
if (activeTabName === 'img2img' && !initialImage) {
reasons.push(i18n.t('parameters.invoke.noInitialImageSelected'));
}
if (activeTabName === 'nodes') {
if (nodes.shouldValidateGraph) {
if (!nodes.nodes.length) {
reasons.push(i18n.t('parameters.invoke.noNodesInGraph'));
}
nodes.nodes.forEach((node) => {
if (!isInvocationNode(node)) {
return;
}
const nodeTemplate = nodes.nodeTemplates[node.data.type];
if (!nodeTemplate) {
// Node type not found
reasons.push(i18n.t('parameters.invoke.missingNodeTemplate'));
return;
}
const connectedEdges = getConnectedEdges([node], nodes.edges);
forEach(node.data.inputs, (field) => {
const fieldTemplate = nodeTemplate.inputs[field.name];
const hasConnection = connectedEdges.some(
(edge) =>
edge.target === node.id && edge.targetHandle === field.name
);
if (!fieldTemplate) {
reasons.push(i18n.t('parameters.invoke.missingFieldTemplate'));
return;
}
if (
fieldTemplate.required &&
field.value === undefined &&
!hasConnection
) {
reasons.push(
i18n.t('parameters.invoke.missingInputForField', {
nodeLabel: node.data.label || nodeTemplate.title,
fieldLabel: field.label || fieldTemplate.title,
})
);
return;
}
});
});
}
} else {
if (!model) {
reasons.push(i18n.t('parameters.invoke.noModelSelected'));
}
if (state.controlNet.isEnabled) {
map(state.controlNet.controlNets).forEach((controlNet, i) => {
if (!controlNet.isEnabled) {
return;
}
if (!controlNet.model) {
reasons.push(
i18n.t('parameters.invoke.noModelForControlNet', { index: i + 1 })
);
}
if (
!controlNet.controlImage ||
(!controlNet.processedControlImage &&
controlNet.processorType !== 'none')
) {
reasons.push(
i18n.t('parameters.invoke.noControlImageForControlNet', {
index: i + 1,
})
);
}
});
}
}
return { isReady: !reasons.length, isProcessing, reasons };
},
defaultSelectorOptions
);
export const useIsReadyToInvoke = () => {
const { isReady, isProcessing, reasons } = useAppSelector(selector);
return { isReady, isProcessing, reasons };
};