From 1dcf0433a1320e55f42104845e978e8a2b10a9c9 Mon Sep 17 00:00:00 2001 From: Niklas van Schrick Date: Mon, 3 Nov 2025 19:00:00 +0100 Subject: [PATCH 1/2] First start of the flow update mutation --- .../namespaces/projects/flows/update.rb | 42 +++++++ .../projects/flows/update_service.rb | 113 ++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 app/graphql/mutations/namespaces/projects/flows/update.rb create mode 100644 app/services/namespaces/projects/flows/update_service.rb diff --git a/app/graphql/mutations/namespaces/projects/flows/update.rb b/app/graphql/mutations/namespaces/projects/flows/update.rb new file mode 100644 index 00000000..291086a8 --- /dev/null +++ b/app/graphql/mutations/namespaces/projects/flows/update.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module Mutations + module Namespaces + module Projects + module Flows + class Update < BaseMutation + description 'Update an existing flow.' + + field :flow, Types::FlowType, null: true, description: 'The updated flow.' + + argument :flow_id, Types::GlobalIdType[Flow], + required: true, description: 'The ID of the flow to update' + + argument :flow_input, Types::Input::FlowInputType, description: 'The updated flow', required: true + + def resolve(flow_id:, flow_input:, **_params) + flow = SagittariusSchema.object_from_id(flow_id) + + return error('Invalid flow id') if flow.nil? + + flow_type = SagittariusSchema.object_from_id(flow.type) + return error('Invalid flow type id') if flow_type.nil? + + ::Namespaces::Projects::Flows::UpdateService.new( + current_authentication, + flow, + flow_input + ).execute.to_mutation_response(success_key: :flow) + end + + def error(message) + { + flow: nil, + errors: [create_message_error(message)], + } + end + end + end + end + end +end diff --git a/app/services/namespaces/projects/flows/update_service.rb b/app/services/namespaces/projects/flows/update_service.rb new file mode 100644 index 00000000..7ef18186 --- /dev/null +++ b/app/services/namespaces/projects/flows/update_service.rb @@ -0,0 +1,113 @@ +# frozen_string_literal: true + +module Namespaces + module Projects + module Flows + class UpdateService + include Sagittarius::Database::Transactional + + attr_reader :current_authentication, :flow, :flow_input + + def initialize(current_authentication, flow, flow_input) + @current_authentication = current_authentication + @flow = flow + @flow_input = flow_input + end + + def execute + unless Ability.allowed?(current_authentication, :update_flow, flow) + return ServiceResponse.error(message: 'Missing permission', payload: :missing_permission) + end + + transactional do |t| + update_settings(t) + update_nodes(t) + + validate_flow(t) + + create_audit_event + + ServiceResponse.success(message: 'Flow updated', payload: flow) + end + end + + private + + def update_settings(t) + flow_input.settings.each do |setting| + flow_setting = flow.flow_settings.find_or_initialize_by(flow_setting_id: setting.flow_setting_id) + flow_setting.object = setting.object + + next if flow_setting.valid? + + t.rollback_and_return! ServiceResponse.error( + message: 'Invalid flow settings', + payload: flow_setting.errors + ) + end + + flow.flow_settings.where.not(flow_setting_id: flow_input.settings.map(&:flow_setting_id)).destroy_all + end + + def update_nodes(t) + all_nodes = flow.collect_node_functions + + current_node_input = flow_input.starting_node + + node_index = 0 + until current_node_input.nil? + current_node = all_nodes[node_index] + + update_node(t, current_node, current_node_input) + + current_node_input = current_node_input.next_node + node_index += 1 + end + end + + def update_node(t, current_node, current_node_input) + + end + + def update_node_parameters(t, current_node, current_node_input) + current_node_input.parameters.each do |parameter| + node_parameter = current_node.parameters.find_or_initialize_by(runtime_parameter_definition_id: parameter.runtime_parameter_definition_id) + node_parameter.value = parameter.value + + next if node_parameter.valid? + + t.rollback_and_return! ServiceResponse.error( + message: 'Invalid node parameter', + payload: node_parameter.errors + ) + end + + current_node.node_parameters.where.not(runtime_parameter_id: current_node_input.parameters.map(&:runtime_parameter_definition_id)).destroy_all + end + + def validate_flow(t) + res = Validation::ValidationService.new(current_authentication, flow).execute + + return unless res.error? + + t.rollback_and_return! ServiceResponse.error( + message: 'Flow validation failed', + payload: res.payload + ) + end + + def create_audit_event + AuditService.audit( + :flow_updated, + author_id: current_authentication.user.id, + entity: flow, + target: flow.project, + details: { + **flow_input.attributes.except('created_at', 'updated_at'), + } + ) + end + end + end + end +end From 3079a98264f66c2e9eb1696053bfa84f663a5f4e Mon Sep 17 00:00:00 2001 From: Niklas van Schrick Date: Sun, 9 Nov 2025 02:01:03 +0100 Subject: [PATCH 2/2] More progress on flow update --- .../projects/flows/update_service.rb | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/app/services/namespaces/projects/flows/update_service.rb b/app/services/namespaces/projects/flows/update_service.rb index 7ef18186..f81adf54 100644 --- a/app/services/namespaces/projects/flows/update_service.rb +++ b/app/services/namespaces/projects/flows/update_service.rb @@ -59,6 +59,7 @@ def update_nodes(t) current_node = all_nodes[node_index] update_node(t, current_node, current_node_input) + update_node_parameters(t, current_node, current_node_input) current_node_input = current_node_input.next_node node_index += 1 @@ -70,19 +71,36 @@ def update_node(t, current_node, current_node_input) end def update_node_parameters(t, current_node, current_node_input) - current_node_input.parameters.each do |parameter| - node_parameter = current_node.parameters.find_or_initialize_by(runtime_parameter_definition_id: parameter.runtime_parameter_definition_id) - node_parameter.value = parameter.value - - next if node_parameter.valid? + db_parameters = current_node.node_parameters.first(current_node_input.parameters.count) + current_node_input.parameters.each_with_index do |parameter, index| + db_parameters[index] ||= NodeParameter.new + db_parameters[index].runtime_parameter_definition_id = parameter.runtime_parameter_definition_id.model_id + if parameter.value.function_value + db_parameters[index].function_value = SagittariusSchema.object_from_id(parameter.value.function_value.runtime_function_id) + db_parameters[index].literal_value = nil + db_parameters[index].reference_value = nil + elsif parameter.value.literal_value + db_parameters[index].literal_value = parameter.value.literal_value + db_parameters[index].function_value = nil + db_parameters[index].reference_value = nil + else + db_parameters[index].reference_value = ReferenceValue.create( + reference_value_id: parameter.value.reference_value.reference_value_id, + data_type_identifier: get_data_type_identifier(identifier) + ) + db_parameters[index].literal_value = nil + db_parameters[index].function_value = nil + end + + next if db_parameters[index].valid? t.rollback_and_return! ServiceResponse.error( message: 'Invalid node parameter', - payload: node_parameter.errors + payload: db_parameters[index].errors ) end - current_node.node_parameters.where.not(runtime_parameter_id: current_node_input.parameters.map(&:runtime_parameter_definition_id)).destroy_all + current_node.node_parameters = db_parameters end def validate_flow(t)