From 73842a24ba0b8fe13d6a383bda813c8c8d01ae2f Mon Sep 17 00:00:00 2001 From: Raphael Date: Mon, 4 May 2026 15:44:30 +0200 Subject: [PATCH 1/3] feat: added removed_at field to flow_type_setting migration --- .../20260504131123_add_removed_at_to_flow_type_settings.rb | 7 +++++++ db/schema_migrations/20260504131123 | 1 + db/structure.sql | 3 ++- 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20260504131123_add_removed_at_to_flow_type_settings.rb create mode 100644 db/schema_migrations/20260504131123 diff --git a/db/migrate/20260504131123_add_removed_at_to_flow_type_settings.rb b/db/migrate/20260504131123_add_removed_at_to_flow_type_settings.rb new file mode 100644 index 00000000..cddd2fbe --- /dev/null +++ b/db/migrate/20260504131123_add_removed_at_to_flow_type_settings.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddRemovedAtToFlowTypeSettings < Code0::ZeroTrack::Database::Migration[1.0] + def change + add_column :flow_type_settings, :removed_at, :datetime_with_timezone + end +end diff --git a/db/schema_migrations/20260504131123 b/db/schema_migrations/20260504131123 new file mode 100644 index 00000000..99999a95 --- /dev/null +++ b/db/schema_migrations/20260504131123 @@ -0,0 +1 @@ +230a4eedca49cadd700627c194d5f046f32435cecc60120b63a4e53fc419ef4b \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 19ffd36f..a8856d15 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -240,7 +240,8 @@ CREATE TABLE flow_type_settings ( default_value jsonb, created_at timestamp with time zone NOT NULL, updated_at timestamp with time zone NOT NULL, - "unique" integer DEFAULT 0 NOT NULL + "unique" integer DEFAULT 0 NOT NULL, + removed_at timestamp with time zone ); CREATE SEQUENCE flow_type_settings_id_seq From cde09e6c279d8e09c0cac8ea71a1b47f9a1e5fe3 Mon Sep 17 00:00:00 2001 From: Raphael Date: Mon, 4 May 2026 15:45:03 +0200 Subject: [PATCH 2/3] feat: added removed_at handling to models and serivces --- app/graphql/types/flow_type_setting_type.rb | 1 + app/models/flow_type_setting.rb | 3 +++ .../projects/flows/update_service.rb | 2 +- .../grpc/flow_types/update_service.rb | 26 +++++++++---------- spec/graphql/types/flow_type_setting_spec.rb | 1 + spec/models/flow_type_setting_spec.rb | 15 +++++++++++ .../sagittarius/flow_type_service_spec.rb | 12 +++++++-- 7 files changed, 44 insertions(+), 16 deletions(-) diff --git a/app/graphql/types/flow_type_setting_type.rb b/app/graphql/types/flow_type_setting_type.rb index a0d2704d..68fa8f7f 100644 --- a/app/graphql/types/flow_type_setting_type.rb +++ b/app/graphql/types/flow_type_setting_type.rb @@ -12,6 +12,7 @@ class FlowTypeSettingType < Types::BaseObject field :flow_type, Types::FlowTypeType, null: true, description: 'Flow type of the flow type setting' field :identifier, String, null: false, description: 'Identifier of the flow type setting' field :names, [Types::TranslationType], null: false, description: 'Names of the flow type setting' + field :removed_at, Types::TimeType, null: true, description: 'The timestamp when this setting was soft removed' field :unique, Boolean, null: false, description: 'Unique status of the flow type setting' id_field FlowTypeSetting diff --git a/app/models/flow_type_setting.rb b/app/models/flow_type_setting.rb index 4d3f7076..1afd76dd 100644 --- a/app/models/flow_type_setting.rb +++ b/app/models/flow_type_setting.rb @@ -20,4 +20,7 @@ class FlowTypeSetting < ApplicationRecord has_many :names, -> { by_purpose(:name) }, class_name: 'Translation', as: :owner, inverse_of: :owner has_many :descriptions, -> { by_purpose(:description) }, class_name: 'Translation', as: :owner, inverse_of: :owner + + scope :active, -> { where(removed_at: nil) } + scope :removed, -> { where.not(removed_at: nil) } end diff --git a/app/services/namespaces/projects/flows/update_service.rb b/app/services/namespaces/projects/flows/update_service.rb index 0c1f021c..6b430673 100644 --- a/app/services/namespaces/projects/flows/update_service.rb +++ b/app/services/namespaces/projects/flows/update_service.rb @@ -54,7 +54,7 @@ def update_flow_attributes def update_settings(t) db_settings = flow.flow_settings.first(flow_input.settings.length) - flow_type_settings = flow.flow_type.flow_type_settings + flow_type_settings = flow.flow_type.flow_type_settings.active.order(:id) flow_input.settings.each_with_index do |setting, index| db_settings[index] ||= flow.flow_settings.build diff --git a/app/services/runtimes/grpc/flow_types/update_service.rb b/app/services/runtimes/grpc/flow_types/update_service.rb index f6f01a8b..1cd7c15f 100644 --- a/app/services/runtimes/grpc/flow_types/update_service.rb +++ b/app/services/runtimes/grpc/flow_types/update_service.rb @@ -60,26 +60,26 @@ def update_flowtype(flow_type, t) db_object.version = flow_type.version db_object.definition_source = flow_type.definition_source db_object.display_icon = flow_type.display_icon - db_object.flow_type_settings = update_settings(flow_type.settings, db_object.flow_type_settings) + update_settings(flow_type.settings, db_object.flow_type_settings) link_data_types(db_object, flow_type.linked_data_type_identifiers, t) db_object.save db_object end def update_settings(flow_type_settings, db_setting_relation) - db_settings = db_setting_relation.first(flow_type_settings.length) - flow_type_settings.each_with_index do |setting, index| - db_settings[index] ||= db_setting_relation.build - db_settings[index].identifier = setting.identifier - db_settings[index].unique = setting.unique.to_s.downcase - db_settings[index].default_value = setting.default_value&.to_ruby - db_settings[index].descriptions = update_translations(setting.description, db_settings[index].descriptions) - db_settings[index].names = update_translations(setting.name, db_settings[index].names) - end - - db_setting_relation.excluding(*db_settings).destroy_all + # rubocop:disable Rails/SkipsModelValidations -- when marking settings as removed, we don't care about validations + db_setting_relation.update_all(removed_at: Time.zone.now) + # rubocop:enable Rails/SkipsModelValidations - db_settings + flow_type_settings.map do |setting| + db_setting = db_setting_relation.find_or_initialize_by(identifier: setting.identifier) + db_setting.unique = setting.unique.to_s.downcase + db_setting.default_value = setting.default_value&.to_ruby + db_setting.descriptions = update_translations(setting.description, db_setting.descriptions) + db_setting.names = update_translations(setting.name, db_setting.names) + db_setting.removed_at = nil + db_setting + end end end end diff --git a/spec/graphql/types/flow_type_setting_spec.rb b/spec/graphql/types/flow_type_setting_spec.rb index f6a44eb6..9b986d30 100644 --- a/spec/graphql/types/flow_type_setting_spec.rb +++ b/spec/graphql/types/flow_type_setting_spec.rb @@ -11,6 +11,7 @@ flow_type names descriptions + removed_at id created_at updated_at diff --git a/spec/models/flow_type_setting_spec.rb b/spec/models/flow_type_setting_spec.rb index 0e86123f..50c45b61 100644 --- a/spec/models/flow_type_setting_spec.rb +++ b/spec/models/flow_type_setting_spec.rb @@ -17,4 +17,19 @@ it { is_expected.to allow_values(:none, :project, 'none', 'project').for(:unique) } it { is_expected.not_to allow_value(:unknown, 'unknown', 0).for(:unique) } end + + describe 'scopes' do + let!(:active_setting) { create(:flow_type_setting, removed_at: nil) } + let!(:removed_setting) { create(:flow_type_setting, removed_at: Time.zone.now) } + + it 'returns active settings' do + expect(described_class.active).to include(active_setting) + expect(described_class.active).not_to include(removed_setting) + end + + it 'returns removed settings' do + expect(described_class.removed).to include(removed_setting) + expect(described_class.removed).not_to include(active_setting) + end + end end diff --git a/spec/requests/grpc/sagittarius/flow_type_service_spec.rb b/spec/requests/grpc/sagittarius/flow_type_service_spec.rb index f7474b7b..cc334ec4 100644 --- a/spec/requests/grpc/sagittarius/flow_type_service_spec.rb +++ b/spec/requests/grpc/sagittarius/flow_type_service_spec.rb @@ -152,8 +152,16 @@ flow_type.reload - expect(flow_type.flow_type_settings.size).to eq(1) - expect(flow_type.flow_type_settings.first.identifier).to eq(flow_types.first[:settings].first[:identifier]) + first_setting = flow_type.flow_type_settings.find_by(identifier: 'first_setting') + second_setting = flow_type.flow_type_settings.find_by(identifier: 'second_setting') + other_setting = flow_type.flow_type_settings.find_by(identifier: flow_types.first[:settings].first[:identifier]) + + expect(first_setting).to be_present + expect(second_setting).to be_present + expect(other_setting).to be_present + expect(first_setting.removed_at).to be_present + expect(second_setting.removed_at).to be_present + expect(other_setting.removed_at).to be_nil end end end From ad9646ee229ddc3869c9d0662b28f90ca5d8f056 Mon Sep 17 00:00:00 2001 From: Raphael Date: Mon, 4 May 2026 15:45:24 +0200 Subject: [PATCH 3/3] docs: regenerated docs after removed_at field --- docs/graphql/object/flowtypesetting.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/graphql/object/flowtypesetting.md b/docs/graphql/object/flowtypesetting.md index bb650ecc..94470f83 100644 --- a/docs/graphql/object/flowtypesetting.md +++ b/docs/graphql/object/flowtypesetting.md @@ -15,5 +15,6 @@ Represents a flow type setting | `id` | [`FlowTypeSettingID!`](../scalar/flowtypesettingid.md) | Global ID of this FlowTypeSetting | | `identifier` | [`String!`](../scalar/string.md) | Identifier of the flow type setting | | `names` | [`[Translation!]!`](../object/translation.md) | Names of the flow type setting | +| `removedAt` | [`Time`](../scalar/time.md) | The timestamp when this setting was soft removed | | `unique` | [`Boolean!`](../scalar/boolean.md) | Unique status of the flow type setting | | `updatedAt` | [`Time!`](../scalar/time.md) | Time when this FlowTypeSetting was last updated |