From 024aa5eb90a72eb99125895bba2397a4f23886bd Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 18 Oct 2023 14:19:06 +1100 Subject: [PATCH] fix(ui): fix field sorting closes #4934 --- .../hooks/useAnyOrDirectInputFieldNames.ts | 19 +++++++--------- .../hooks/useConnectionInputFieldNames.ts | 22 +++++++++---------- .../nodes/hooks/useOutputFieldNames.ts | 8 +++---- .../nodes/util/getSortedFilteredFieldNames.ts | 20 +++++++++++++++++ 4 files changed, 42 insertions(+), 27 deletions(-) create mode 100644 invokeai/frontend/web/src/features/nodes/util/getSortedFilteredFieldNames.ts diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useAnyOrDirectInputFieldNames.ts b/invokeai/frontend/web/src/features/nodes/hooks/useAnyOrDirectInputFieldNames.ts index 36f2e8a62c..dda2efc156 100644 --- a/invokeai/frontend/web/src/features/nodes/hooks/useAnyOrDirectInputFieldNames.ts +++ b/invokeai/frontend/web/src/features/nodes/hooks/useAnyOrDirectInputFieldNames.ts @@ -9,6 +9,7 @@ import { POLYMORPHIC_TYPES, TYPES_WITH_INPUT_COMPONENTS, } from '../types/constants'; +import { getSortedFilteredFieldNames } from '../util/getSortedFilteredFieldNames'; export const useAnyOrDirectInputFieldNames = (nodeId: string) => { const selector = useMemo( @@ -24,17 +25,13 @@ export const useAnyOrDirectInputFieldNames = (nodeId: string) => { if (!nodeTemplate) { return []; } - return map(nodeTemplate.inputs) - .filter( - (field) => - (['any', 'direct'].includes(field.input) || - POLYMORPHIC_TYPES.includes(field.type)) && - TYPES_WITH_INPUT_COMPONENTS.includes(field.type) - ) - .filter((field) => !field.ui_hidden) - .sort((a, b) => (a.ui_order ?? 0) - (b.ui_order ?? 0)) - .map((field) => field.name) - .filter((fieldName) => fieldName !== 'is_intermediate'); + const fields = map(nodeTemplate.inputs).filter( + (field) => + (['any', 'direct'].includes(field.input) || + POLYMORPHIC_TYPES.includes(field.type)) && + TYPES_WITH_INPUT_COMPONENTS.includes(field.type) + ); + return getSortedFilteredFieldNames(fields); }, defaultSelectorOptions ), diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useConnectionInputFieldNames.ts b/invokeai/frontend/web/src/features/nodes/hooks/useConnectionInputFieldNames.ts index eea874cc87..9fb31df801 100644 --- a/invokeai/frontend/web/src/features/nodes/hooks/useConnectionInputFieldNames.ts +++ b/invokeai/frontend/web/src/features/nodes/hooks/useConnectionInputFieldNames.ts @@ -9,6 +9,7 @@ import { TYPES_WITH_INPUT_COMPONENTS, } from '../types/constants'; import { isInvocationNode } from '../types/types'; +import { getSortedFilteredFieldNames } from '../util/getSortedFilteredFieldNames'; export const useConnectionInputFieldNames = (nodeId: string) => { const selector = useMemo( @@ -24,17 +25,16 @@ export const useConnectionInputFieldNames = (nodeId: string) => { if (!nodeTemplate) { return []; } - return map(nodeTemplate.inputs) - .filter( - (field) => - (field.input === 'connection' && - !POLYMORPHIC_TYPES.includes(field.type)) || - !TYPES_WITH_INPUT_COMPONENTS.includes(field.type) - ) - .filter((field) => !field.ui_hidden) - .sort((a, b) => (a.ui_order ?? 0) - (b.ui_order ?? 0)) - .map((field) => field.name) - .filter((fieldName) => fieldName !== 'is_intermediate'); + + // get the visible fields + const fields = map(nodeTemplate.inputs).filter( + (field) => + (field.input === 'connection' && + !POLYMORPHIC_TYPES.includes(field.type)) || + !TYPES_WITH_INPUT_COMPONENTS.includes(field.type) + ); + + return getSortedFilteredFieldNames(fields); }, defaultSelectorOptions ), diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useOutputFieldNames.ts b/invokeai/frontend/web/src/features/nodes/hooks/useOutputFieldNames.ts index 97956a4889..e0a1e5433e 100644 --- a/invokeai/frontend/web/src/features/nodes/hooks/useOutputFieldNames.ts +++ b/invokeai/frontend/web/src/features/nodes/hooks/useOutputFieldNames.ts @@ -5,6 +5,7 @@ import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import { map } from 'lodash-es'; import { useMemo } from 'react'; import { isInvocationNode } from '../types/types'; +import { getSortedFilteredFieldNames } from '../util/getSortedFilteredFieldNames'; export const useOutputFieldNames = (nodeId: string) => { const selector = useMemo( @@ -20,11 +21,8 @@ export const useOutputFieldNames = (nodeId: string) => { if (!nodeTemplate) { return []; } - return map(nodeTemplate.outputs) - .filter((field) => !field.ui_hidden) - .sort((a, b) => (a.ui_order ?? 0) - (b.ui_order ?? 0)) - .map((field) => field.name) - .filter((fieldName) => fieldName !== 'is_intermediate'); + + return getSortedFilteredFieldNames(map(nodeTemplate.outputs)); }, defaultSelectorOptions ), diff --git a/invokeai/frontend/web/src/features/nodes/util/getSortedFilteredFieldNames.ts b/invokeai/frontend/web/src/features/nodes/util/getSortedFilteredFieldNames.ts new file mode 100644 index 0000000000..b235fe8a07 --- /dev/null +++ b/invokeai/frontend/web/src/features/nodes/util/getSortedFilteredFieldNames.ts @@ -0,0 +1,20 @@ +import { isNil } from 'lodash-es'; +import { InputFieldTemplate, OutputFieldTemplate } from '../types/types'; + +export const getSortedFilteredFieldNames = ( + fields: InputFieldTemplate[] | OutputFieldTemplate[] +): string[] => { + const visibleFields = fields.filter((field) => !field.ui_hidden); + + // we want explicitly ordered fields to be before unordered fields; split the list + const orderedFields = visibleFields + .filter((f) => !isNil(f.ui_order)) + .sort((a, b) => (a.ui_order ?? 0) - (b.ui_order ?? 0)); + const unorderedFields = visibleFields.filter((f) => isNil(f.ui_order)); + + // concat the lists, and return the field names, skipping `is_intermediate` + return orderedFields + .concat(unorderedFields) + .map((f) => f.name) + .filter((fieldName) => fieldName !== 'is_intermediate'); +};