Refactored task status into a view model
This commit is contained in:
@@ -76,14 +76,9 @@ form {
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
/* TODO: maybe extract into a separate file */
|
||||||
details.dropdown {
|
details.dropdown {
|
||||||
td & {
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.small {
|
|
||||||
--pico-form-element-spacing-vertical: 0.25em;
|
|
||||||
--pico-form-element-spacing-horizontal: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
|
.tasks-table {
|
||||||
|
.task-status-selector {
|
||||||
|
--pico-form-element-spacing-vertical: 0.25em;
|
||||||
|
--pico-form-element-spacing-horizontal: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.task-status {
|
.task-status {
|
||||||
--color: var(--backlog-color);
|
--color: var(--backlog-color);
|
||||||
--background-color: var(--backlog-bg);
|
--background-color: var(--backlog-bg);
|
||||||
|
|||||||
@@ -9,18 +9,7 @@ module TasksHelper
|
|||||||
'Tasks'
|
'Tasks'
|
||||||
end
|
end
|
||||||
|
|
||||||
# @param status [TaskStatus]
|
def task_status_selector(task, with_form: false)
|
||||||
def task_status_badge(status)
|
render Tasks::Statuses::SelectorViewModel.new(task, with_form:)
|
||||||
# TODO: extract into a component probably
|
|
||||||
|
|
||||||
content_tag(:span, status.name, class: ['badge', 'task-status', status.category.dasherize])
|
|
||||||
end
|
|
||||||
|
|
||||||
def task_status_selector(task, selector_class: '', id: nil, with_form: false)
|
|
||||||
# TODO: extract into a component probably
|
|
||||||
|
|
||||||
raise 'You should pass id if you want the form' if with_form && id.blank?
|
|
||||||
|
|
||||||
render partial: 'tasks/status_selector', locals: { task:, selector_class:, id:, with_form: }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Tasks
|
||||||
|
module Statuses
|
||||||
|
class SelectorViewModel
|
||||||
|
def initialize(task, with_form: false)
|
||||||
|
@task = task
|
||||||
|
@with_form = with_form
|
||||||
|
end
|
||||||
|
|
||||||
|
def dom_id
|
||||||
|
id = @task.persisted? ? @task.id : '_'
|
||||||
|
"task_status_selector_#{id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_in(view_context)
|
||||||
|
view_context.render(
|
||||||
|
partial: 'tasks/status_selector',
|
||||||
|
locals: { task: @task, id: dom_id, with_form: @with_form,
|
||||||
|
project_task_statuses:,
|
||||||
|
task_status_badge: ->(status) { task_status_badge(status, view_context) }}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def project_task_statuses
|
||||||
|
# TODO: refactor because it causes N+1 (task statuses loaded separately)
|
||||||
|
@task.project.task_statuses.default_order
|
||||||
|
end
|
||||||
|
|
||||||
|
def task_status_badge(status, view_context)
|
||||||
|
view_context.content_tag(
|
||||||
|
:span, status.name,
|
||||||
|
class: ['badge', 'task-status', status.category.dasherize]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,2 +1,9 @@
|
|||||||
details.dropdown class=selector_class id=id data-controller="tasks--status-selector"
|
details.dropdown.task-status-selector id=id data-controller="tasks--status-selector"
|
||||||
= render partial: 'status_selector_inner', locals: {selector_id: id, task:, with_form:}
|
summary= task_status_badge[task.status]
|
||||||
|
ul
|
||||||
|
- project_task_statuses.each do |status|
|
||||||
|
li
|
||||||
|
a href="#" data-status-id="#{status.id}" data-action="tasks--status-selector#changeStatus:prevent" = task_status_badge[status]
|
||||||
|
- if with_form
|
||||||
|
= form_with model: Tasks::ChangeStatus.new, url: change_status_task_path(task), method: :patch, data: {'tasks--status-selector-target': 'form', action: 'turbo:submit-end->tasks--status-selector#finalize'} do |f|
|
||||||
|
= f.hidden_field :status_id, data: {'tasks--status-selector-target': 'statusField'}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
summary= task_status_badge task.status
|
|
||||||
ul
|
|
||||||
- task.project.task_statuses.default_order.each do |status|
|
|
||||||
li
|
|
||||||
a href="#" data-status-id="#{status.id}" data-action="tasks--status-selector#changeStatus:prevent" = task_status_badge status
|
|
||||||
- if with_form
|
|
||||||
= form_with model: Tasks::ChangeStatus.new, url: change_status_task_path(task), method: :patch, data: {'tasks--status-selector-target': 'form', action: 'turbo:submit-end->tasks--status-selector#finalize'} do |f|
|
|
||||||
= hidden_field_tag :selector_id, selector_id
|
|
||||||
= f.hidden_field :status_id, data: {'tasks--status-selector-target': 'statusField'}
|
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
- selector_id = params.fetch(:selector_id)
|
- view_model = Tasks::Statuses::SelectorViewModel.new(@task, with_form: true)
|
||||||
= turbo_stream.update selector_id, render(partial: 'status_selector_inner', locals: {selector_id:, task: @task, with_form: true})
|
= turbo_stream.replace view_model.dom_id, render(view_model)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ h1= tasks_index_title
|
|||||||
= link_to 'New', new_task_path(project: current_project&.code)
|
= link_to 'New', new_task_path(project: current_project&.code)
|
||||||
|
|
||||||
- if @tasks.exists?
|
- if @tasks.exists?
|
||||||
table
|
table.tasks-table
|
||||||
thead
|
thead
|
||||||
tbody
|
tbody
|
||||||
- @tasks.each do |task|
|
- @tasks.each do |task|
|
||||||
@@ -12,7 +12,7 @@ h1= tasks_index_title
|
|||||||
tr
|
tr
|
||||||
td= link_to task.full_number, task_path(task)
|
td= link_to task.full_number, task_path(task)
|
||||||
td
|
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= task.title
|
||||||
td
|
td
|
||||||
= link_to 'Edit', edit_task_path(task)
|
= link_to 'Edit', edit_task_path(task)
|
||||||
|
|||||||
Reference in New Issue
Block a user