From c1614abb1eb65ddbba41af99ef8b6232513c24f9 Mon Sep 17 00:00:00 2001 From: Dario Pranjic Date: Wed, 17 Dec 2025 14:59:11 +0100 Subject: [PATCH 1/2] Add disabled reason to flow --- app/graphql/types/flow_type.rb | 8 ++++-- app/graphql/types/input/flow_input_type.rb | 5 +++- app/grpc/flow_handler.rb | 2 +- app/models/flow.rb | 11 ++++++++ .../projects/flows/update_service.rb | 1 + ...51217134754_add_disabled_reasonto_flows.rb | 8 ++++++ db/schema_migrations/20251217134754 | 1 + db/structure.sql | 5 +++- .../projects/flows/update_mutation_spec.rb | 28 +++++++++++++++++++ 9 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 db/migrate/20251217134754_add_disabled_reasonto_flows.rb create mode 100644 db/schema_migrations/20251217134754 diff --git a/app/graphql/types/flow_type.rb b/app/graphql/types/flow_type.rb index daff618a..59623198 100644 --- a/app/graphql/types/flow_type.rb +++ b/app/graphql/types/flow_type.rb @@ -8,6 +8,10 @@ class FlowType < Types::BaseObject field :name, String, null: false, description: 'Name of the flow' + field :disabled_reason, String, + null: true, + description: 'The reason why the flow is disabled, if it is disabled' + field :input_type, Types::DataTypeType, null: true, description: 'The input data type of the flow' @@ -19,7 +23,7 @@ class FlowType < Types::BaseObject method: :flow_settings, description: 'The settings of the flow' field :starting_node_id, Types::GlobalIdType[::NodeFunction], - null: false, + null: true, description: 'The ID of the starting node of the flow' field :type, Types::FlowTypeType, null: false, @@ -38,7 +42,7 @@ class FlowType < Types::BaseObject timestamps def starting_node_id - object.starting_node.to_global_id + object.starting_node&.to_global_id end end end diff --git a/app/graphql/types/input/flow_input_type.rb b/app/graphql/types/input/flow_input_type.rb index 2828cb66..a22f6256 100644 --- a/app/graphql/types/input/flow_input_type.rb +++ b/app/graphql/types/input/flow_input_type.rb @@ -9,7 +9,7 @@ class FlowInputType < Types::BaseInputObject argument :settings, [Types::Input::FlowSettingInputType], required: false, description: 'The settings of the flow' - argument :starting_node_id, Types::GlobalIdType[::NodeFunction], required: true, + argument :starting_node_id, Types::GlobalIdType[::NodeFunction], required: false, description: 'The starting node of the flow' argument :nodes, [Types::Input::NodeFunctionInputType], required: true, @@ -17,6 +17,9 @@ class FlowInputType < Types::BaseInputObject argument :type, Types::GlobalIdType[::FlowType], required: true, description: 'The identifier of the flow type' + + argument :disabled_reason, String, required: false, + description: 'The reason why the flow is disabled, if applicable, if not set the flow is enabled' end end end diff --git a/app/grpc/flow_handler.rb b/app/grpc/flow_handler.rb index 868b57cd..364fb5af 100644 --- a/app/grpc/flow_handler.rb +++ b/app/grpc/flow_handler.rb @@ -10,7 +10,7 @@ class FlowHandler < Tucana::Sagittarius::FlowService::Service def self.update_runtime(runtime) flows = [] runtime.project_assignments.compatible.each do |assignment| - assignment.namespace_project.flows.each do |flow| + assignment.namespace_project.flows.enabled.each do |flow| flows << flow.to_grpc end end diff --git a/app/models/flow.rb b/app/models/flow.rb index d979fb2f..2445dd45 100644 --- a/app/models/flow.rb +++ b/app/models/flow.rb @@ -14,6 +14,17 @@ class Flow < ApplicationRecord allow_blank: false, uniqueness: { case_sensitive: false, scope: :project_id } + validates :disabled_reason, presence: false, + allow_blank: true, + length: { maximum: 100, minimum: 0 } + + scope :enabled, -> { where(disabled_reason: nil) } + scope :disabled, -> { where.not(disabled_reason: nil) } + + def disabled? + disabled_reason.present? + end + def to_grpc Tucana::Shared::ValidationFlow.new( flow_id: id, diff --git a/app/services/namespaces/projects/flows/update_service.rb b/app/services/namespaces/projects/flows/update_service.rb index c731bb08..86e53b91 100644 --- a/app/services/namespaces/projects/flows/update_service.rb +++ b/app/services/namespaces/projects/flows/update_service.rb @@ -51,6 +51,7 @@ def update_flow(t) def update_flow_attributes flow.name = flow_input.name + flow.disabled_reason = flow_input.disabled_reason end def update_settings(t) diff --git a/db/migrate/20251217134754_add_disabled_reasonto_flows.rb b/db/migrate/20251217134754_add_disabled_reasonto_flows.rb new file mode 100644 index 00000000..6b2deaeb --- /dev/null +++ b/db/migrate/20251217134754_add_disabled_reasonto_flows.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class AddDisabledReasontoFlows < Code0::ZeroTrack::Database::Migration[1.0] + def change + add_column :flows, :disabled_reason, :text, null: true, default: nil + add_index :flows, :disabled_reason, length: 100 + end +end diff --git a/db/schema_migrations/20251217134754 b/db/schema_migrations/20251217134754 new file mode 100644 index 00000000..7a3515f7 --- /dev/null +++ b/db/schema_migrations/20251217134754 @@ -0,0 +1 @@ +4b5be2b087ebee13e1319410194a92b64672b7cf3b7b1c9abb7e8bc59d2e94e5 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index aae03fb3..7c8665c4 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -252,7 +252,8 @@ CREATE TABLE flows ( starting_node_id bigint, name text NOT NULL, created_at timestamp with time zone NOT NULL, - updated_at timestamp with time zone NOT NULL + updated_at timestamp with time zone NOT NULL, + disabled_reason text ); CREATE SEQUENCE flows_id_seq @@ -1100,6 +1101,8 @@ CREATE INDEX index_flow_types_on_return_type_id ON flow_types USING btree (retur CREATE UNIQUE INDEX index_flow_types_on_runtime_id_and_identifier ON flow_types USING btree (runtime_id, identifier); +CREATE INDEX index_flows_on_disabled_reason ON flows USING btree (disabled_reason); + CREATE INDEX index_flows_on_flow_type_id ON flows USING btree (flow_type_id); CREATE INDEX index_flows_on_input_type_id ON flows USING btree (input_type_id); diff --git a/spec/requests/graphql/mutation/namespace/projects/flows/update_mutation_spec.rb b/spec/requests/graphql/mutation/namespace/projects/flows/update_mutation_spec.rb index a705f03e..76aa04c0 100644 --- a/spec/requests/graphql/mutation/namespace/projects/flows/update_mutation_spec.rb +++ b/spec/requests/graphql/mutation/namespace/projects/flows/update_mutation_spec.rb @@ -155,6 +155,34 @@ target_type: 'NamespaceProject' ) end + + context 'when flow is disabled' do + let(:input) do + { + flowId: flow.to_global_id.to_s, + flowInput: { + name: generate(:flow_name), + disabledReason: 'Some reason', + type: flow_type.to_global_id.to_s, + startingNodeId: nil, + settings: [], + nodes: [], + }, + } + end + + it 'updates flow as disabled' do + mutate! + + updated_flow_id = graphql_data_at(:namespaces_projects_flows_update, :flow, :id) + expect(updated_flow_id).to be_present + flow = SagittariusSchema.object_from_id(updated_flow_id) + + expect(flow).to be_present + expect(project.flows).to include(flow) + expect(flow.disabled_reason).to eq('Some reason') + end + end end context 'when removing nodes' do From bead5360f0e488aa6621cc4e7c9c583bbd4af83c Mon Sep 17 00:00:00 2001 From: Dario Pranjic Date: Wed, 17 Dec 2025 20:55:13 +0100 Subject: [PATCH 2/2] Compile docs --- app/graphql/types/input/flow_input_type.rb | 5 +++-- docs/graphql/input_object/flowinput.md | 3 ++- docs/graphql/object/flow.md | 3 ++- .../namespaces/projects/flows/create_service_spec.rb | 10 ++++++---- .../namespaces/projects/flows/update_service_spec.rb | 5 +++-- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/app/graphql/types/input/flow_input_type.rb b/app/graphql/types/input/flow_input_type.rb index a22f6256..2201a29d 100644 --- a/app/graphql/types/input/flow_input_type.rb +++ b/app/graphql/types/input/flow_input_type.rb @@ -18,8 +18,9 @@ class FlowInputType < Types::BaseInputObject argument :type, Types::GlobalIdType[::FlowType], required: true, description: 'The identifier of the flow type' - argument :disabled_reason, String, required: false, - description: 'The reason why the flow is disabled, if applicable, if not set the flow is enabled' + argument :disabled_reason, String, + required: false, + description: 'The reason why the flow is disabled, if applicable, if not set the flow is enabled' end end end diff --git a/docs/graphql/input_object/flowinput.md b/docs/graphql/input_object/flowinput.md index 98c8ae41..7838a64e 100644 --- a/docs/graphql/input_object/flowinput.md +++ b/docs/graphql/input_object/flowinput.md @@ -8,8 +8,9 @@ Input type for creating or updating a flow | Name | Type | Description | |------|------|-------------| +| `disabledReason` | [`String`](../scalar/string.md) | The reason why the flow is disabled, if applicable, if not set the flow is enabled | | `name` | [`String!`](../scalar/string.md) | The name of the flow | | `nodes` | [`[NodeFunctionInput!]!`](../input_object/nodefunctioninput.md) | The node functions of the flow | | `settings` | [`[FlowSettingInput!]`](../input_object/flowsettinginput.md) | The settings of the flow | -| `startingNodeId` | [`NodeFunctionID!`](../scalar/nodefunctionid.md) | The starting node of the flow | +| `startingNodeId` | [`NodeFunctionID`](../scalar/nodefunctionid.md) | The starting node of the flow | | `type` | [`FlowTypeID!`](../scalar/flowtypeid.md) | The identifier of the flow type | diff --git a/docs/graphql/object/flow.md b/docs/graphql/object/flow.md index 060e4f43..fff6447d 100644 --- a/docs/graphql/object/flow.md +++ b/docs/graphql/object/flow.md @@ -9,13 +9,14 @@ Represents a flow | Name | Type | Description | |------|------|-------------| | `createdAt` | [`Time!`](../scalar/time.md) | Time when this Flow was created | +| `disabledReason` | [`String`](../scalar/string.md) | The reason why the flow is disabled, if it is disabled | | `id` | [`FlowID!`](../scalar/flowid.md) | Global ID of this Flow | | `inputType` | [`DataType`](../object/datatype.md) | The input data type of the flow | | `name` | [`String!`](../scalar/string.md) | Name of the flow | | `nodes` | [`NodeFunctionConnection!`](../object/nodefunctionconnection.md) | Nodes of the flow | | `returnType` | [`DataType`](../object/datatype.md) | The return data type of the flow | | `settings` | [`FlowSettingConnection!`](../object/flowsettingconnection.md) | The settings of the flow | -| `startingNodeId` | [`NodeFunctionID!`](../scalar/nodefunctionid.md) | The ID of the starting node of the flow | +| `startingNodeId` | [`NodeFunctionID`](../scalar/nodefunctionid.md) | The ID of the starting node of the flow | | `type` | [`FlowType!`](../object/flowtype.md) | The flow type of the flow | | `updatedAt` | [`Time!`](../scalar/time.md) | Time when this Flow was last updated | | `userAbilities` | [`FlowUserAbilities!`](../object/flowuserabilities.md) | Abilities for the current user on this Flow | diff --git a/spec/services/namespaces/projects/flows/create_service_spec.rb b/spec/services/namespaces/projects/flows/create_service_spec.rb index 0f5da28d..d431b66b 100644 --- a/spec/services/namespaces/projects/flows/create_service_spec.rb +++ b/spec/services/namespaces/projects/flows/create_service_spec.rb @@ -12,7 +12,7 @@ let(:namespace_project) { create(:namespace_project, primary_runtime: runtime) } let(:flow_input) do - Struct.new(:settings, :type, :starting_node_id, :nodes, :name).new( + Struct.new(:settings, :type, :starting_node_id, :nodes, :name, :disabled_reason).new( [], create(:flow_type, runtime: runtime).to_global_id, 'gid://sagittarius/NodeFunction/12345', @@ -24,7 +24,8 @@ [] ) ], - generate(:flow_name) + generate(:flow_name), + nil ) end @@ -47,7 +48,7 @@ context 'when starting node is nil' do let(:current_user) { create(:user) } let(:flow_input) do - Struct.new(:settings, :type, :starting_node_id, :nodes, :name).new( + Struct.new(:settings, :type, :starting_node_id, :nodes, :name, :disabled_reason).new( [], create(:flow_type, runtime: runtime).to_global_id, nil, @@ -59,7 +60,8 @@ [] ) ], - generate(:flow_name) + generate(:flow_name), + nil ) end diff --git a/spec/services/namespaces/projects/flows/update_service_spec.rb b/spec/services/namespaces/projects/flows/update_service_spec.rb index e335f232..1dfee1b4 100644 --- a/spec/services/namespaces/projects/flows/update_service_spec.rb +++ b/spec/services/namespaces/projects/flows/update_service_spec.rb @@ -14,7 +14,7 @@ end let(:flow) { create(:flow, project: namespace_project, flow_type: create(:flow_type, runtime: runtime)) } let(:flow_input) do - Struct.new(:settings, :starting_node_id, :nodes, :name).new( + Struct.new(:settings, :starting_node_id, :nodes, :name, :disabled_reason).new( [], starting_node.to_global_id, [ @@ -25,7 +25,8 @@ [] ) ], - "updated #{flow.name}" + "updated #{flow.name}", + nil ) end