Workflow default status and computing positions
This commit is contained in:
@@ -17,7 +17,7 @@ module ProjectAdmin
|
||||
end
|
||||
|
||||
@form = ProjectAdmin::Workflows::Statuses::BatchUpdate.new(form_params)
|
||||
if @form.call(@workflow)
|
||||
if @form.perform(@workflow)
|
||||
redirect_to(action: :edit_transitions)
|
||||
else
|
||||
render :edit
|
||||
@@ -29,13 +29,14 @@ module ProjectAdmin
|
||||
end
|
||||
|
||||
def batch_update_transitions
|
||||
form_params = params.expect(workflow: { task_statuses_attributes: [[:id, { next_status_ids: [] }]] })
|
||||
form_params = params.expect(workflow: [:default_status_id,
|
||||
{ task_statuses_attributes: [[:id, { next_status_ids: [] }]] }])
|
||||
if form_params[:task_statuses_attributes].respond_to?(:keys)
|
||||
form_params[:task_statuses_attributes] = form_params[:task_statuses_attributes].values
|
||||
end
|
||||
|
||||
@form = ProjectAdmin::Workflows::Statuses::UpdateTransitions.new(form_params)
|
||||
if @form.call(@workflow)
|
||||
if @form.perform(@workflow)
|
||||
redirect_to project_admin_workflow_path(@project, @workflow)
|
||||
else
|
||||
render :edit_transitions
|
||||
|
||||
@@ -13,7 +13,7 @@ class TasksController < ApplicationController
|
||||
Task.all
|
||||
end
|
||||
|
||||
@tasks = @tasks.includes(:status, :project, workflow: :task_statuses)
|
||||
@tasks = @tasks.includes(:project, workflow: %i[task_statuses default_status], status: :next_statuses)
|
||||
end
|
||||
|
||||
def show; end
|
||||
@@ -21,7 +21,8 @@ class TasksController < ApplicationController
|
||||
def new
|
||||
@project = self.current_project = fetch_project || Project.order(:name).first
|
||||
@workflow = fetch_workflow || @project.workflows.first
|
||||
@form = Tasks::Create.new(project_id: @project.id, workflow_id: @workflow.id)
|
||||
@form = Tasks::Create.new(project_id: @project.id, workflow_id: @workflow.id,
|
||||
status_id: @workflow.default_status&.id)
|
||||
end
|
||||
|
||||
def create
|
||||
|
||||
@@ -6,7 +6,18 @@ class Workflow < ApplicationRecord
|
||||
has_many :tasks, dependent: :restrict_with_exception
|
||||
has_many :task_statuses, dependent: :restrict_with_error
|
||||
accepts_nested_attributes_for :task_statuses, allow_destroy: true
|
||||
belongs_to :default_status, class_name: 'TaskStatus', optional: true
|
||||
|
||||
enum :icon, { task: 'task', warning: 'warning' }, default: 'task', scopes: false
|
||||
enum :color, { blue: 'blue', gray: 'gray', lime: 'lime', red: 'red', teal: 'teal' }, default: 'gray', scopes: false
|
||||
|
||||
validate :should_own_default_status
|
||||
|
||||
private
|
||||
|
||||
def should_own_default_status
|
||||
return if default_status.nil?
|
||||
|
||||
errors.add(:default_status, 'Should own default status') unless default_status.id.in?(task_status_ids)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -40,7 +40,7 @@ module ProjectAdmin
|
||||
@task_statuses = Array(attributes).map { |e| TaskStatus.new(e) }
|
||||
end
|
||||
|
||||
def call(workflow)
|
||||
def perform(workflow)
|
||||
@workflow = workflow
|
||||
|
||||
@workflow.assign_attributes(task_statuses_attributes: task_statuses.map(&:to_model_attributes))
|
||||
|
||||
@@ -12,20 +12,50 @@ module ProjectAdmin
|
||||
attribute :next_status_ids
|
||||
end
|
||||
|
||||
attr_accessor :task_statuses
|
||||
attr_accessor :workflow, :task_statuses
|
||||
|
||||
attribute :default_status_id, :integer
|
||||
|
||||
def self.from_model(workflow)
|
||||
new(task_statuses_attributes: workflow.task_statuses
|
||||
.includes(:next_statuses)
|
||||
.map { |ts| { id: ts.id, next_status_ids: ts.next_status_ids } })
|
||||
new(
|
||||
workflow:,
|
||||
task_statuses_attributes: workflow.task_statuses
|
||||
.includes(:next_statuses)
|
||||
.map { |ts| { id: ts.id, next_status_ids: ts.next_status_ids } },
|
||||
default_status_id: workflow.default_status_id
|
||||
)
|
||||
end
|
||||
|
||||
def task_statuses_attributes=(attributes)
|
||||
@task_statuses = Array(attributes).map { |e| TaskStatus.new(e) }
|
||||
end
|
||||
|
||||
def call(workflow)
|
||||
workflow.update(task_statuses_attributes: task_statuses.map(&:attributes))
|
||||
def perform(workflow)
|
||||
@workflow = workflow
|
||||
workflow.assign_attributes(default_status_id:, task_statuses_attributes: task_statuses.map(&:attributes))
|
||||
save workflow
|
||||
end
|
||||
|
||||
after_success do
|
||||
if @workflow.default_status.nil?
|
||||
@workflow.task_statuses.update!(position: 0)
|
||||
return
|
||||
end
|
||||
|
||||
@workflow.transaction do
|
||||
@workflow.default_status.update!(position: 0)
|
||||
seen_status_ids = Set[@workflow.default_status.id]
|
||||
statuses_to_process = [@workflow.default_status]
|
||||
|
||||
until statuses_to_process.empty?
|
||||
status = statuses_to_process.pop
|
||||
|
||||
next_statuses = status.next_statuses.where.not(id: seen_status_ids)
|
||||
next_statuses.update(position: status.position + 1)
|
||||
statuses_to_process.concat(next_statuses.to_a)
|
||||
seen_status_ids.merge(next_statuses.map(&:id))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -40,7 +40,11 @@ module Tasks
|
||||
private
|
||||
|
||||
def workflow_task_statuses
|
||||
@task.workflow.task_statuses.sort_by { |e| [e.position, e.name] }
|
||||
return @task.workflow.task_statuses.sort_by { |e| [e.position, e.name] } if @task.status.next_statuses.empty?
|
||||
|
||||
@task.status.next_statuses.sort_by { |e| [e.position, e.name] }.tap do |statuses|
|
||||
statuses.prepend(@task.status)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,5 +9,5 @@ h1
|
||||
h2 Statuses
|
||||
|
||||
ul
|
||||
- @workflow.task_statuses.each do |status|
|
||||
- @workflow.task_statuses.default_order.each do |status|
|
||||
li= task_status_badge(status)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
= f.fields_for :task_statuses do |tsf|
|
||||
section
|
||||
div= task_status_badge tsf.object
|
||||
div= f.radio_button :default_status_id, tsf.object.id
|
||||
div= tsf.collection_checkboxes :next_status_ids, @workflow.task_statuses - [tsf.object], :id, :name
|
||||
|
||||
.submit
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddDefaultStatusToWorkflows < ActiveRecord::Migration[8.1]
|
||||
def change
|
||||
add_reference :workflows, :default_status, foreign_key: { to_table: :task_statuses }
|
||||
end
|
||||
end
|
||||
Generated
+4
-1
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[8.1].define(version: 2026_04_25_112121) do
|
||||
ActiveRecord::Schema[8.1].define(version: 2026_04_25_123859) do
|
||||
create_table "action_text_rich_texts", charset: "utf8mb4", collation: "utf8mb4_uca1400_ai_ci", force: :cascade do |t|
|
||||
t.text "body", size: :long
|
||||
t.datetime "created_at", null: false
|
||||
@@ -114,10 +114,12 @@ ActiveRecord::Schema[8.1].define(version: 2026_04_25_112121) do
|
||||
create_table "workflows", charset: "utf8mb4", collation: "utf8mb4_uca1400_ai_ci", force: :cascade do |t|
|
||||
t.string "color", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.bigint "default_status_id"
|
||||
t.string "icon", null: false
|
||||
t.string "name", null: false
|
||||
t.bigint "project_id", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["default_status_id"], name: "index_workflows_on_default_status_id"
|
||||
t.index ["project_id", "name"], name: "index_workflows_on_project_id_and_name", unique: true
|
||||
t.index ["project_id"], name: "index_workflows_on_project_id"
|
||||
end
|
||||
@@ -130,4 +132,5 @@ ActiveRecord::Schema[8.1].define(version: 2026_04_25_112121) do
|
||||
add_foreign_key "tasks", "projects"
|
||||
add_foreign_key "tasks", "task_statuses", column: "status_id"
|
||||
add_foreign_key "workflows", "projects"
|
||||
add_foreign_key "workflows", "task_statuses", column: "default_status_id"
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user