From 0a840b4dae451147e591b91cf01795716b61f89f Mon Sep 17 00:00:00 2001 From: Dawid Poliszak Date: Sat, 18 Jan 2025 17:06:45 +0100 Subject: [PATCH] fix (#7457) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix * rebuild backend * revert * resolve processDefinitionData reference issue * remove FE sorting of processDefinitionData * Sort classes on BE --------- Co-authored-by: Ɓukasz Bigorajski --- .../FragmentInputDefinition.tsx | 10 ++++------ .../client/src/reducers/selectors/settings.ts | 11 ++++++++--- .../ui/definition/DefinitionsService.scala | 10 ++++++++-- .../ui/api/DefinitionResourcesSpec.scala | 15 +++++++++++++++ 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/designer/client/src/components/graph/node-modal/fragment-input-definition/FragmentInputDefinition.tsx b/designer/client/src/components/graph/node-modal/fragment-input-definition/FragmentInputDefinition.tsx index c0aa32d74b1..02226d4e2a6 100644 --- a/designer/client/src/components/graph/node-modal/fragment-input-definition/FragmentInputDefinition.tsx +++ b/designer/client/src/components/graph/node-modal/fragment-input-definition/FragmentInputDefinition.tsx @@ -6,7 +6,7 @@ import { getProcessDefinitionData } from "../../../../reducers/selectors/setting import { MapVariableProps } from "../MapVariable"; import { NodeCommonDetailsDefinition } from "../NodeCommonDetailsDefinition"; import { FieldsSelect } from "./FieldsSelect"; -import { find, head, orderBy } from "lodash"; +import { find, head } from "lodash"; import { getDefaultFields } from "./item/utils"; import { FragmentInputParameter } from "./item"; @@ -26,11 +26,9 @@ export function useFragmentInputDefinitionTypeOptions() { [definitionData?.classes], ); - const orderedTypeOptions = useMemo(() => orderBy(typeOptions, (item) => [item.label, item.value], ["asc"]), [typeOptions]); - const defaultTypeOption = useMemo(() => find(typeOptions, { label: "String" }) || head(typeOptions), [typeOptions]); return { - orderedTypeOptions, + typeOptions, defaultTypeOption, }; } @@ -40,7 +38,7 @@ export default function FragmentInputDefinition(props: Props): JSX.Element { const { node, setProperty, isEditMode, showValidation } = passProps; const readOnly = !isEditMode; - const { orderedTypeOptions, defaultTypeOption } = useFragmentInputDefinitionTypeOptions(); + const { typeOptions, defaultTypeOption } = useFragmentInputDefinitionTypeOptions(); const addField = useCallback(() => { addElement("parameters", getDefaultFields(defaultTypeOption.value)); @@ -57,7 +55,7 @@ export default function FragmentInputDefinition(props: Props): JSX.Element { removeField={removeElement} namespace={"parameters"} fields={fields} - options={orderedTypeOptions} + options={typeOptions} showValidation={showValidation} readOnly={readOnly} variableTypes={variableTypes} diff --git a/designer/client/src/reducers/selectors/settings.ts b/designer/client/src/reducers/selectors/settings.ts index 382290a60ea..8177dc4d240 100644 --- a/designer/client/src/reducers/selectors/settings.ts +++ b/designer/client/src/reducers/selectors/settings.ts @@ -1,10 +1,12 @@ -import { createSelector } from "reselect"; +import { createSelector, createSelectorCreator, defaultMemoize } from "reselect"; import { MetricsType } from "../../actions/nk"; import { DynamicTabData } from "../../containers/DynamicTab"; import { ComponentGroup, ProcessDefinitionData } from "../../types"; import { RootState } from "../index"; import { AuthenticationSettings, SettingsState } from "../settings"; -import { uniqBy } from "lodash"; +import { isEqual, uniqBy } from "lodash"; + +const createDeepEqualSelector = createSelectorCreator(defaultMemoize, isEqual); export const getSettings = (state: RootState): SettingsState => state.settings; @@ -17,7 +19,10 @@ export const getSurveySettings = createSelector(getFeatureSettings, (s) => s?.su export const getStickyNotesSettings = createSelector(getFeatureSettings, (s) => s?.stickyNotesSettings); export const getLoggedUser = createSelector(getSettings, (s) => s.loggedUser); export const getLoggedUserId = createSelector(getLoggedUser, (s) => s.id); -export const getProcessDefinitionData = createSelector(getSettings, (s) => s.processDefinitionData || ({} as ProcessDefinitionData)); +export const getProcessDefinitionData = createDeepEqualSelector( + getSettings, + (s) => s.processDefinitionData || ({} as ProcessDefinitionData), +); export const getComponentGroups = createSelector(getProcessDefinitionData, (p) => p.componentGroups || ({} as ComponentGroup[])); export const getCategories = createSelector(getLoggedUser, (u) => u.categories || []); export const getWritableCategories = createSelector(getLoggedUser, getCategories, (user, categories) => diff --git a/designer/server/src/main/scala/pl/touk/nussknacker/ui/definition/DefinitionsService.scala b/designer/server/src/main/scala/pl/touk/nussknacker/ui/definition/DefinitionsService.scala index 92c5d4b8b4b..2f8d59055ab 100644 --- a/designer/server/src/main/scala/pl/touk/nussknacker/ui/definition/DefinitionsService.scala +++ b/designer/server/src/main/scala/pl/touk/nussknacker/ui/definition/DefinitionsService.scala @@ -10,7 +10,7 @@ import pl.touk.nussknacker.engine.definition.component.{ComponentStaticDefinitio import pl.touk.nussknacker.engine.util.Implicits.RichScalaMap import pl.touk.nussknacker.engine.ModelData import pl.touk.nussknacker.engine.api.TemplateEvaluationResult -import pl.touk.nussknacker.engine.api.typed.typing.{Typed, TypingResult} +import pl.touk.nussknacker.engine.api.typed.typing.{Typed, TypedClass, TypingResult} import pl.touk.nussknacker.restmodel.definition._ import pl.touk.nussknacker.ui.definition.DefinitionsService.{ ComponentUiConfigMode, @@ -106,7 +106,13 @@ class DefinitionsService( UIDefinitions( componentGroups = ComponentGroupsPreparer.prepareComponentGroups(components), components = components.map(component => component.component.id -> createUIComponentDefinition(component)).toMap, - classes = modelData.modelDefinitionWithClasses.classDefinitions.all.toList.map(_.clazzName), + classes = modelData.modelDefinitionWithClasses.classDefinitions.all.toList + .map(_.clazzName) + .filter { + case t: TypedClass if t.klass.isArray => false + case _ => true + } + .sortBy(_.display.toLowerCase), scenarioProperties = { if (forFragment) { createUIProperties(FragmentPropertiesConfig.properties ++ fragmentPropertiesConfig, fragmentPropertiesDocsUrl) diff --git a/designer/server/src/test/scala/pl/touk/nussknacker/ui/api/DefinitionResourcesSpec.scala b/designer/server/src/test/scala/pl/touk/nussknacker/ui/api/DefinitionResourcesSpec.scala index e79e236834e..d62d72a92db 100644 --- a/designer/server/src/test/scala/pl/touk/nussknacker/ui/api/DefinitionResourcesSpec.scala +++ b/designer/server/src/test/scala/pl/touk/nussknacker/ui/api/DefinitionResourcesSpec.scala @@ -10,6 +10,7 @@ import org.scalatest.{BeforeAndAfterAll, BeforeAndAfterEach, OptionValues} import pl.touk.nussknacker.engine.api.CirceUtil.RichACursor import pl.touk.nussknacker.engine.api.definition.FixedExpressionValue import pl.touk.nussknacker.engine.api.parameter.{ParameterName, ValueInputWithFixedValuesProvided} +import pl.touk.nussknacker.engine.api.typed.typing.{Typed, TypingResult, Unknown} import pl.touk.nussknacker.engine.api.{FragmentSpecificData, MetaData} import pl.touk.nussknacker.engine.canonicalgraph.canonicalnode.FlatNode import pl.touk.nussknacker.engine.canonicalgraph.{CanonicalProcess, canonicalnode} @@ -103,6 +104,20 @@ class DefinitionResourcesSpec } } + it("should return definition sorted data for allowed classes - skipping array because list should be uses instead") { + getProcessDefinitionData() ~> check { + status shouldBe StatusCodes.OK + + val allowedClasses = responseAs[Json].hcursor.downField("classes").focus.value.asArray.value + val allowedClassesRefClazzNames = allowedClasses.flatMap(_.hcursor.downField("refClazzName").focus.value.asString) + val allowedClassesDisplay = allowedClasses.flatMap(_.hcursor.downField("display").focus.value.asString) + + allowedClassesRefClazzNames should contain("java.util.List") + allowedClassesRefClazzNames should not contain (Array().getClass.getName) + allowedClassesDisplay shouldBe allowedClassesDisplay.sortBy(_.toLowerCase) + } + } + it("should return info about editor based on fragment parameter definition") { val fragmentWithFixedValuesEditor = { CanonicalProcess(