From 1c644c6385931cdced66d7ce1adbf8c339bd4050 Mon Sep 17 00:00:00 2001 From: Artemiy Solopov Date: Sun, 2 Nov 2025 01:09:33 +0200 Subject: [PATCH 1/5] Cable config --- config/cable.yml | 21 ++++++++++----------- config/database.yml | 8 ++++++++ 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/config/cable.yml b/config/cable.yml index b9adc5a..e287ba7 100644 --- a/config/cable.yml +++ b/config/cable.yml @@ -1,17 +1,16 @@ -# Async adapter only works within the same process, so for manually triggering cable updates from a console, -# and seeing results in the browser, you must do so from the web console (running inside the dev process), -# not a terminal started via bin/rails console! Add "console" to any action or any ERB template view -# to make the web console appear. -development: - adapter: async - -test: - adapter: test - -production: +sc_default: &sc_default adapter: solid_cable connects_to: database: writing: cable polling_interval: 0.1.seconds message_retention: 1.day + +development: + <<: *sc_default + +test: + adapter: test + +production: + <<: *sc_default diff --git a/config/database.yml b/config/database.yml index f7fadad..51b5bb4 100644 --- a/config/database.yml +++ b/config/database.yml @@ -25,6 +25,10 @@ development: <<: *default database: subtle_storm_development_queue migrations_paths: db/queue_migrate + cable: + <<: *default + database: subtle_storm_development_cable + migrations_paths: db/cable_migrate # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". @@ -37,6 +41,10 @@ test: <<: *default database: subtle_storm_test_queue migrations_paths: db/queue_migrate + cable: + <<: *default + database: subtle_storm_test_cable + migrations_paths: db/cable_migrate # As with config/credentials.yml, you never want to store sensitive information, # like your database password, in your source code. If your source code is From 7839a584644c42d9274c83b0fe718450e45e70a1 Mon Sep 17 00:00:00 2001 From: Artemiy Solopov Date: Mon, 3 Nov 2025 00:38:57 +0200 Subject: [PATCH 2/5] Default task broadcast --- app/models/task.rb | 2 ++ app/views/tasks/_table_row.html.slim | 8 ++++++++ app/views/tasks/index.html.slim | 24 ++++++++---------------- 3 files changed, 18 insertions(+), 16 deletions(-) create mode 100644 app/views/tasks/_table_row.html.slim diff --git a/app/models/task.rb b/app/models/task.rb index 4602a95..467273b 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -10,6 +10,8 @@ class Task < ApplicationRecord has_rich_text :description + broadcasts_to ->(task) { [task.project, :tasks] }, template: 'tasks/_table_row' + def to_param return full_number if association(:project).loaded? diff --git a/app/views/tasks/_table_row.html.slim b/app/views/tasks/_table_row.html.slim new file mode 100644 index 0000000..076f972 --- /dev/null +++ b/app/views/tasks/_table_row.html.slim @@ -0,0 +1,8 @@ +- cache task do + tr id="task_#{task.id}" + td= link_to task.full_number, task_path(task) + td + = task_status_selector task, selector_class: 'small', id: "task_status_selector_#{task.id}", with_form: true + td= task.title + td + = link_to 'Edit', edit_task_path(task) diff --git a/app/views/tasks/index.html.slim b/app/views/tasks/index.html.slim index 4875a90..02e43aa 100644 --- a/app/views/tasks/index.html.slim +++ b/app/views/tasks/index.html.slim @@ -1,20 +1,12 @@ h1= tasks_index_title -.row +section.row = link_to 'New', new_task_path(project: current_project&.code) -- if @tasks.exists? - table.tasks-table - thead - tbody - - @tasks.each do |task| - - cache task do - tr - td= link_to task.full_number, task_path(task) - td - = task_status_selector task, with_form: true - td= task.title - td - = link_to 'Edit', edit_task_path(task) -- else - p No tasks +table.tasks-table + thead + tbody#tasks + = render partial: 'table_row', collection: @tasks, as: :task + +- if current_project + = turbo_stream_from current_project, :tasks From e8bea5dd60631cf0ea27ae3e02f2bbf4cef07259 Mon Sep 17 00:00:00 2001 From: Artemiy Solopov Date: Thu, 13 Nov 2025 00:25:32 +0200 Subject: [PATCH 3/5] Project creation/destruction admin table turbo streams --- app/jobs/projects/post_init_job.rb | 2 ++ app/models/project.rb | 7 ++++++- app/views/projects/_row.html.slim | 1 + app/views/projects/index.html.slim | 9 +++++---- config/environments/development.rb | 2 +- 5 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 app/views/projects/_row.html.slim diff --git a/app/jobs/projects/post_init_job.rb b/app/jobs/projects/post_init_job.rb index 8ab7b32..a01fe32 100644 --- a/app/jobs/projects/post_init_job.rb +++ b/app/jobs/projects/post_init_job.rb @@ -14,6 +14,8 @@ module Projects create_default_task_statuses(project) project.update!(status: :ready) end + + project.broadcast_append_later_to Project, :admin_table, partial: 'projects/row' end private diff --git a/app/models/project.rb b/app/models/project.rb index 4276e4b..f29799c 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -4,7 +4,7 @@ class Project < ApplicationRecord enum :status, %w[preparing ready archived].index_by(&:itself), default: :preparing validates :name, :code, :status, presence: true - validates :code, exclusion: { in: %w[new] }, uniqueness: true, format: { with: /\A[a-z]{2,}\z/ } + validates :code, exclusion: { in: %w[new] }, uniqueness: true, format: { with: /\A[a-z][a-z0-9]{1,}\z/ } has_many :tasks, dependent: :restrict_with_exception has_many :task_statuses, dependent: :destroy @@ -15,6 +15,7 @@ class Project < ApplicationRecord after_commit :schedule_post_init_job, on: :create after_destroy_commit :drop_tasks_number_sequence + after_destroy_commit :broadcast_the_destroy def to_param return unless id @@ -42,4 +43,8 @@ class Project < ApplicationRecord def drop_tasks_number_sequence self.class.connection.execute "DROP SEQUENCE IF EXISTS #{tasks_number_sequence_name}" end + + def broadcast_the_destroy + broadcast_remove_to Project, :admin_table + end end diff --git a/app/views/projects/_row.html.slim b/app/views/projects/_row.html.slim new file mode 100644 index 0000000..5c58d20 --- /dev/null +++ b/app/views/projects/_row.html.slim @@ -0,0 +1 @@ +li id="project_#{project.id}" = link_to project.name, project diff --git a/app/views/projects/index.html.slim b/app/views/projects/index.html.slim index c2f0720..90b7e05 100644 --- a/app/views/projects/index.html.slim +++ b/app/views/projects/index.html.slim @@ -1,7 +1,8 @@ .row = link_to 'New', new_project_path -ul - - @projects.each do |project| - li - = link_to project.name, project +/ TODO: admin view, extract when doing roles stuff +ul#projects + = render collection: @projects, partial: 'row', as: :project + += turbo_stream_from Project, :admin_table diff --git a/config/environments/development.rb b/config/environments/development.rb index 29ec324..696bb16 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -58,7 +58,7 @@ Rails.application.configure do # Replace the default in-process and non-durable queuing backend for Active Job. config.active_job.queue_adapter = :solid_queue config.solid_queue.connects_to = { database: { writing: :queue } } - config.solid_queue.logger = ActiveSupport::Logger.new(STDOUT) + config.solid_queue.logger = ActiveSupport::Logger.new($stdout) # Raises error for missing translations. # config.i18n.raise_on_missing_translations = true From b3ef5157b04affa11496c93b84119a050b0c4cec Mon Sep 17 00:00:00 2001 From: Artemiy Solopov Date: Thu, 27 Nov 2025 00:40:44 +0200 Subject: [PATCH 4/5] fixup! Default task broadcast --- app/views/tasks/_table_row.html.slim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/tasks/_table_row.html.slim b/app/views/tasks/_table_row.html.slim index 076f972..45fa2c3 100644 --- a/app/views/tasks/_table_row.html.slim +++ b/app/views/tasks/_table_row.html.slim @@ -2,7 +2,7 @@ tr id="task_#{task.id}" td= link_to task.full_number, task_path(task) td - = task_status_selector task, selector_class: 'small', id: "task_status_selector_#{task.id}", with_form: true + = task_status_selector task, with_form: true td= task.title td = link_to 'Edit', edit_task_path(task) From 8ddb09b53bdd57f280f7ff70ed42fc5ca5b1b271 Mon Sep 17 00:00:00 2001 From: Artemiy Solopov Date: Thu, 27 Nov 2025 01:23:40 +0200 Subject: [PATCH 5/5] Broadcasting status change --- app/services/tasks/change_status.rb | 16 ++++++++++++++++ app/views/tasks/show.html.slim | 4 +++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/app/services/tasks/change_status.rb b/app/services/tasks/change_status.rb index a15d176..8d925d0 100644 --- a/app/services/tasks/change_status.rb +++ b/app/services/tasks/change_status.rb @@ -9,6 +9,8 @@ module Tasks delegate :model_name, to: Task + after_success :broadcast_status_changes + def perform(task) @task = task @id = task.id @@ -18,5 +20,19 @@ module Tasks @task.status_id = status_id save @task end + + private + + def broadcast_status_changes + view_model_with_form = Tasks::Statuses::SelectorViewModel.new(task, with_form: true) + view_model_no_form = Tasks::Statuses::SelectorViewModel.new(task, with_form: false) + + task.broadcast_replace_to [task, :status, :with_form], + target: view_model_with_form.dom_id, + renderable: view_model_with_form + task.broadcast_replace_to [task, :status, :no_form], + target: view_model_no_form.dom_id, + renderable: view_model_no_form + end end end diff --git a/app/views/tasks/show.html.slim b/app/views/tasks/show.html.slim index 6e2cb75..aaade18 100644 --- a/app/views/tasks/show.html.slim +++ b/app/views/tasks/show.html.slim @@ -3,7 +3,9 @@ div h1= @task.title section.task-show-info - = task_status_selector @task, id: "task_status_selector_#{@task.id}", with_form: true + = task_status_selector @task, with_form: true + = turbo_stream_from @task, :status, :with_form + section= @task.description