From 02ce782c9e9be013c41a27c4b00195ff38de32f7 Mon Sep 17 00:00:00 2001 From: petar-cvit Date: Mon, 2 Jun 2025 18:07:35 +0200 Subject: [PATCH 1/3] support conditional schema --- cyclops-ctrl/internal/mapper/helm.go | 45 +++++++++++++++++++ .../internal/models/helm/helmschema.go | 6 +++ cyclops-ctrl/internal/models/templates.go | 16 +++++++ 3 files changed, 67 insertions(+) diff --git a/cyclops-ctrl/internal/mapper/helm.go b/cyclops-ctrl/internal/mapper/helm.go index 47d8b04a2..2d24575da 100644 --- a/cyclops-ctrl/internal/mapper/helm.go +++ b/cyclops-ctrl/internal/mapper/helm.go @@ -44,6 +44,8 @@ func HelmSchemaToFields(name string, schema helm.Property, defs map[string]helm. fields = append(fields, HelmSchemaToFields(propertyName, property, defs, nil)) } + fields = append(fields, conditionedFields(schema, defs)...) + fields = sortFields(fields, schema.Order) for _, dependency := range dependencies { @@ -238,3 +240,46 @@ func resolvePropertyComposition(schema helm.Property) helm.Property { return schema.AnyOf[0] } + +func conditionedFields(schema helm.Property, defs map[string]helm.Property) []models.Field { + if schema.If == nil { + return []models.Field{} + } + + conditionalFields := make([]models.Field, 0) + + if schema.Then != nil { + for propertyName, property := range schema.Then.Properties { + field := HelmSchemaToFields(propertyName, property, defs, nil) + field.Condition = mapConditions(schema.If, models.Equal) + + conditionalFields = append(conditionalFields, field) + } + } + + if schema.Else != nil { + for propertyName, property := range schema.Else.Properties { + field := HelmSchemaToFields(propertyName, property, defs, nil) + field.Condition = mapConditions(schema.If, models.NotEqual) + + conditionalFields = append(conditionalFields, field) + } + } + + return conditionalFields +} + +func mapConditions(r *helm.Property, operation models.ConditionOperation) []models.Condition { + conditions := make([]models.Condition, 0) + + for propertyName, property := range r.Properties { + conditions = append(conditions, models.Condition{ + Operation: operation, + Property: propertyName, + Const: property.Const, + Enum: property.Enum, + }) + } + + return conditions +} diff --git a/cyclops-ctrl/internal/models/helm/helmschema.go b/cyclops-ctrl/internal/models/helm/helmschema.go index 85ed8dc36..404e5a2b9 100644 --- a/cyclops-ctrl/internal/models/helm/helmschema.go +++ b/cyclops-ctrl/internal/models/helm/helmschema.go @@ -35,6 +35,12 @@ type Property struct { // schema compositions AnyOf []Property `json:"anyOf"` + AllOf []Property `json:"allOf"` + + If *Property `json:"if,omitempty"` + Then *Property `json:"then,omitempty"` + Else *Property `json:"else,omitempty"` + Const *string `json:"const"` } type PropertyType string diff --git a/cyclops-ctrl/internal/models/templates.go b/cyclops-ctrl/internal/models/templates.go index 4d8f02350..5c4f98524 100644 --- a/cyclops-ctrl/internal/models/templates.go +++ b/cyclops-ctrl/internal/models/templates.go @@ -55,4 +55,20 @@ type Field struct { MinLength *int `json:"minLength"` MaxLength *int `json:"maxLength"` Pattern *string `json:"pattern"` + + Condition []Condition `json:"condition"` +} + +type Condition struct { + Operation ConditionOperation `json:"operation"` + Property string `json:"property"` + Const interface{} `json:"const"` + Enum []interface{} `json:"enum"` } + +type ConditionOperation string + +const ( + Equal ConditionOperation = "eq" + NotEqual ConditionOperation = "neq" +) From 3e18ace133fafb6b3ac1ba966d6de094e6796c03 Mon Sep 17 00:00:00 2001 From: petar-cvit Date: Mon, 2 Jun 2025 18:08:06 +0200 Subject: [PATCH 2/3] render sting fields conditionaly --- .../form/fields/string/StringField.tsx | 30 +++++++++++++++---- .../shared/CreateModule/CreateModule.tsx | 3 ++ cyclops-ui/src/utils/conditionalFields.tsx | 29 ++++++++++++++++++ cyclops-ui/src/utils/form.tsx | 1 + 4 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 cyclops-ui/src/utils/conditionalFields.tsx diff --git a/cyclops-ui/src/components/form/fields/string/StringField.tsx b/cyclops-ui/src/components/form/fields/string/StringField.tsx index 34dcf2354..a3c4d9d52 100644 --- a/cyclops-ui/src/components/form/fields/string/StringField.tsx +++ b/cyclops-ui/src/components/form/fields/string/StringField.tsx @@ -1,6 +1,7 @@ -import React from "react"; +import React, { useState } from "react"; import { Form, Input } from "antd"; import { stringInputValidators } from "./validators"; +import { resolveConditions } from "../../../../utils/conditionalFields"; interface Props { field: any; @@ -17,16 +18,32 @@ const StringField = ({ isRequired, isModuleEdit, }: Props) => { - let stringValidationRules = stringInputValidators(field, isRequired); + const [display, setDisplay] = useState(!field.condition); + + const stringValidationRules = stringInputValidators(field, isRequired); + + const shouldUpdate = (prevValues, curValues) => { + if (!field.condition || field.condition.length === 0) { + return false; + } + + let shouldDisplay = resolveConditions(field.condition, curValues); + if (shouldDisplay !== display) { + setDisplay(shouldDisplay); + return true; + } + + return false; + }; return ( {field.display_name} @@ -38,6 +55,7 @@ const StringField = ({ hasFeedback={stringValidationRules.length > 0} validateDebounce={1000} rules={stringValidationRules} + hidden={!display} > diff --git a/cyclops-ui/src/components/shared/CreateModule/CreateModule.tsx b/cyclops-ui/src/components/shared/CreateModule/CreateModule.tsx index bdce440f7..f9c0a5777 100644 --- a/cyclops-ui/src/components/shared/CreateModule/CreateModule.tsx +++ b/cyclops-ui/src/components/shared/CreateModule/CreateModule.tsx @@ -184,6 +184,9 @@ export const CreateModuleComponent = ({ values = findMaps(config.root.properties, values, initialValuesRaw); + setLoadingSubmitCreate(false); + // return + submitModule( moduleName, moduleNamespace, diff --git a/cyclops-ui/src/utils/conditionalFields.tsx b/cyclops-ui/src/utils/conditionalFields.tsx new file mode 100644 index 000000000..c36f4c25c --- /dev/null +++ b/cyclops-ui/src/utils/conditionalFields.tsx @@ -0,0 +1,29 @@ +export function resolveConditions(conditions: any[], values: any): boolean { + for (let condition of conditions) { + if (!resolveCondition(condition, values)) { + return false; + } + } + + return true; +} + +export function resolveCondition(condition: any, values: any): boolean { + const value = values[condition.property]; + + if (condition.operation === "eq") { + console.log( + "should update", + value, + condition.const, + value === condition.const, + ); + return value === condition.const; + } + + if (condition.operation === "neq") { + return value !== condition.const; + } + + return true; +} diff --git a/cyclops-ui/src/utils/form.tsx b/cyclops-ui/src/utils/form.tsx index b3000a38d..2b9795bd3 100644 --- a/cyclops-ui/src/utils/form.tsx +++ b/cyclops-ui/src/utils/form.tsx @@ -1,4 +1,5 @@ import YAML from "yaml"; +import { resolveConditions } from "./conditionalFields"; export function fileExtension(fileExt: string): string { switch (fileExt) { From 226c4ed3416e535f1af666721b0416665d68bbd0 Mon Sep 17 00:00:00 2001 From: petar-cvit Date: Wed, 18 Jun 2025 14:19:52 +0200 Subject: [PATCH 3/3] remove deps --- cyclops-ui/src/utils/form.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/cyclops-ui/src/utils/form.tsx b/cyclops-ui/src/utils/form.tsx index 2b9795bd3..b3000a38d 100644 --- a/cyclops-ui/src/utils/form.tsx +++ b/cyclops-ui/src/utils/form.tsx @@ -1,5 +1,4 @@ import YAML from "yaml"; -import { resolveConditions } from "./conditionalFields"; export function fileExtension(fileExt: string): string { switch (fileExt) {