mirror of
https://github.com/opf/openproject.git
synced 2026-06-13 19:20:00 +00:00
[64823] Improve usability of Workflow tables (#20581)
* Split workflow tables into multiple tabs Co-authored-by: Behrokh Satarnejad <b.satarnejad@openproject.com> * make header and first column sticky in work flow tables * calculate the height of the table * Update the tabs individually * calculate the height of the table * Add tests for separated Workflow update process * add a new style sheet for the workflows page and handle vertical and horizontal scroll in it * set a class for page header in workflows page * set page header class for other pages like summary and copy as well * make header and first column sticky in summary page * make the button sticky while scrolling horizontally * redirect to the current tab in update method --------- Co-authored-by: Behrokh Satarnejad <b.satarnejad@openproject.com>
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
<%#-- copyright
|
||||
OpenProject is an open source project management software.
|
||||
Copyright (C) the OpenProject GmbH
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License version 3.
|
||||
|
||||
OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
Copyright (C) 2010-2013 the ChiliProject Team
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
See COPYRIGHT and LICENSE files for more details.
|
||||
|
||||
++#%>
|
||||
|
||||
<%=
|
||||
render Primer::OpenProject::PageHeader.new(classes: "workflows-page-header") do |header|
|
||||
header.with_title { title }
|
||||
header.with_breadcrumbs(breadcrumb_items)
|
||||
|
||||
header.with_action_button(
|
||||
tag: :a,
|
||||
mobile_icon: :copy,
|
||||
mobile_label: t(:button_copy),
|
||||
size: :medium,
|
||||
href: copy_workflows_path,
|
||||
aria: { label: I18n.t(:button_copy) },
|
||||
title: I18n.t(:button_copy)
|
||||
) do |button|
|
||||
button.with_leading_visual_icon(icon: :copy)
|
||||
t(:button_copy)
|
||||
end
|
||||
|
||||
header.with_action_button(
|
||||
tag: :a,
|
||||
mobile_icon: :info,
|
||||
mobile_label: t(:label_workflow_summary),
|
||||
size: :medium,
|
||||
href: workflows_path,
|
||||
aria: { label: I18n.t(:label_workflow_summary) },
|
||||
title: I18n.t(:label_workflow_summary)
|
||||
) do |button|
|
||||
button.with_leading_visual_icon(icon: :info)
|
||||
t(:label_workflow_summary)
|
||||
end
|
||||
|
||||
helpers.render_tab_header_nav(header, @tabs)
|
||||
end
|
||||
%>
|
||||
@@ -0,0 +1,51 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# -- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
# ++
|
||||
|
||||
module Workflows
|
||||
class EditPageHeaderComponent < ApplicationComponent
|
||||
include OpPrimer::ComponentHelpers
|
||||
include ApplicationHelper
|
||||
|
||||
def initialize(tabs:)
|
||||
super
|
||||
@tabs = tabs
|
||||
end
|
||||
|
||||
def breadcrumb_items
|
||||
[{ href: admin_index_path, text: t("label_administration") },
|
||||
{ href: admin_settings_work_packages_general_path, text: t(:label_work_package_plural) },
|
||||
title]
|
||||
end
|
||||
|
||||
def title
|
||||
Workflow.model_name.human
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -28,7 +28,7 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
++#%>
|
||||
|
||||
<%=
|
||||
render Primer::OpenProject::PageHeader.new do |header|
|
||||
render Primer::OpenProject::PageHeader.new(classes: "workflows-page-header") do |header|
|
||||
header.with_title { title }
|
||||
header.with_breadcrumbs(breadcrumb_items)
|
||||
|
||||
|
||||
@@ -39,15 +39,10 @@ module Workflows
|
||||
end
|
||||
|
||||
def breadcrumb_items
|
||||
base_items = [{ href: admin_index_path, text: t("label_administration") },
|
||||
{ href: admin_settings_work_packages_general_path, text: t(:label_work_package_plural) },
|
||||
title]
|
||||
|
||||
if @state == :edit
|
||||
base_items
|
||||
else
|
||||
base_items.insert(2, { href: edit_workflows_path, text: t(:label_workflow) })
|
||||
end
|
||||
[{ href: admin_index_path, text: t("label_administration") },
|
||||
{ href: admin_settings_work_packages_general_path, text: t(:label_work_package_plural) },
|
||||
{ href: edit_workflows_path, text: t(:label_workflow) },
|
||||
title]
|
||||
end
|
||||
|
||||
def title
|
||||
@@ -56,8 +51,6 @@ module Workflows
|
||||
t(:label_workflow_summary)
|
||||
when :copy
|
||||
t(:label_workflow_copy)
|
||||
when :edit
|
||||
Workflow.model_name.human
|
||||
else
|
||||
t(:label_workflow_plural)
|
||||
end
|
||||
|
||||
@@ -57,13 +57,14 @@ class WorkflowsController < ApplicationController
|
||||
end
|
||||
|
||||
def update
|
||||
tab = params[:tab] || "always"
|
||||
call = Workflows::BulkUpdateService
|
||||
.new(role: @role, type: @type)
|
||||
.new(role: @role, type: @type, tab:)
|
||||
.call(permitted_status_params)
|
||||
|
||||
if call.success?
|
||||
flash[:notice] = I18n.t(:notice_successful_update)
|
||||
redirect_to action: "edit", role_id: @role, type_id: @type
|
||||
redirect_to action: "edit", role_id: @role, type_id: @type, tab:
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
module WorkflowHelper
|
||||
def workflow_tabs
|
||||
[
|
||||
{
|
||||
name: "always",
|
||||
partial: "workflows/form",
|
||||
path: edit_workflows_path({ tab: :always }.merge(params.permit(:role_id, :type_id, :used_statuses_only))),
|
||||
label: I18n.t(:"admin.workflows.tabs.default_transitions")
|
||||
},
|
||||
{
|
||||
name: "author",
|
||||
partial: "workflows/form",
|
||||
path: edit_workflows_path({ tab: :author }.merge(params.permit(:role_id, :type_id, :used_statuses_only))),
|
||||
label: I18n.t(:"admin.workflows.tabs.user_author")
|
||||
},
|
||||
{
|
||||
name: "assignee",
|
||||
partial: "workflows/form",
|
||||
path: edit_workflows_path({ tab: :assignee }.merge(params.permit(:role_id, :type_id, :used_statuses_only))),
|
||||
label: I18n.t(:"admin.workflows.tabs.user_assignee")
|
||||
}
|
||||
]
|
||||
end
|
||||
end
|
||||
@@ -29,9 +29,10 @@
|
||||
#++
|
||||
|
||||
class Workflows::BulkUpdateService < BaseServices::Update
|
||||
def initialize(role:, type:)
|
||||
def initialize(role:, type:, tab:)
|
||||
@role = role
|
||||
@type = type
|
||||
@tab = tab
|
||||
end
|
||||
|
||||
def call(status_transitions)
|
||||
@@ -64,8 +65,8 @@ class Workflows::BulkUpdateService < BaseServices::Update
|
||||
role:,
|
||||
old_status: status_map[status_id.to_i],
|
||||
new_status: status_map[new_status_id.to_i],
|
||||
author: options_include(options, "author"),
|
||||
assignee: options_include(options, "assignee"))
|
||||
author: author?,
|
||||
assignee: assignee?)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -73,7 +74,13 @@ class Workflows::BulkUpdateService < BaseServices::Update
|
||||
end
|
||||
|
||||
def delete_current
|
||||
Workflow.where(role_id: role.id, type_id: type.id).delete_all
|
||||
if author?
|
||||
Workflow.where(role_id: role.id, type_id: type.id, author: true).delete_all
|
||||
elsif assignee?
|
||||
Workflow.where(role_id: role.id, type_id: type.id, assignee: true).delete_all
|
||||
else
|
||||
Workflow.where(role_id: role.id, type_id: type.id, assignee: false, author: false).delete_all
|
||||
end
|
||||
end
|
||||
|
||||
def bulk_insert(workflows)
|
||||
@@ -89,7 +96,11 @@ class Workflows::BulkUpdateService < BaseServices::Update
|
||||
@status_map ||= Status.all.group_by(&:id).transform_values(&:first)
|
||||
end
|
||||
|
||||
def options_include(options, string)
|
||||
options.is_a?(Array) && options.include?(string) && !options.include?("always")
|
||||
def author?
|
||||
@tab == "author"
|
||||
end
|
||||
|
||||
def assignee?
|
||||
@tab == "assignee"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -26,10 +26,22 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
See COPYRIGHT and LICENSE files for more details.
|
||||
|
||||
++#%>
|
||||
|
||||
<% name = tab[:name] %>
|
||||
<% workflows = @workflows[name] %>
|
||||
|
||||
<%=
|
||||
if name == "assignee"
|
||||
render(Primer::OpenProject::Heading.new(tag: :h3, my: 3)) { t(:label_additional_workflow_transitions_for_assignee) }
|
||||
elsif name == "author"
|
||||
render(Primer::OpenProject::Heading.new(tag: :h3, my: 3)) { t(:label_additional_workflow_transitions_for_author) }
|
||||
end
|
||||
%>
|
||||
|
||||
<div id="workflow_form_<%= name %>" class="generic-table--container">
|
||||
<div class="generic-table--results-container">
|
||||
<table class="generic-table workflow-table transitions-<%= name %>">
|
||||
<thead>
|
||||
<thead class="-sticky">
|
||||
<tr>
|
||||
<th></th>
|
||||
<th colspan="<%= @statuses.length %>">
|
||||
@@ -39,7 +51,7 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
<%= t(:label_new_statuses_allowed) %>
|
||||
</span>
|
||||
<span class="workflow-table--check-all">
|
||||
(<%= check_all_links "workflow_form_" + name %>)
|
||||
(<%= check_all_links "workflow_form_#{name}" %>)
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -28,9 +28,11 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
++#%>
|
||||
<% html_title t(:label_administration), t(:label_workflow_plural) -%>
|
||||
|
||||
<%= render Workflows::PageHeaderComponent.new(state: :edit) %>
|
||||
<%= render Workflows::EditPageHeaderComponent.new(tabs: workflow_tabs) %>
|
||||
|
||||
<%= styled_form_tag({}, method: "get") do %>
|
||||
<%= hidden_field_tag "tab", params[:tab] || "always" %>
|
||||
|
||||
<fieldset class="simple-filters--container">
|
||||
<legend><%= t(:text_workflow_edit) %></legend>
|
||||
<ul class="simple-filters--filters">
|
||||
@@ -57,31 +59,32 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
</li>
|
||||
</ul>
|
||||
<li class="simple-filters--controls">
|
||||
<%= submit_tag t(:button_edit), name: nil, accesskey: accesskey(:edit), class: "button -small -primary" %>
|
||||
<%= render(
|
||||
Primer::Beta::Button.new(
|
||||
scheme: :primary,
|
||||
type: :submit,
|
||||
name: nil,
|
||||
accesskey: accesskey(:edit),
|
||||
size: :small
|
||||
)
|
||||
) { t(:button_edit) } %>
|
||||
</li>
|
||||
</ul>
|
||||
</fieldset>
|
||||
<% end %>
|
||||
|
||||
<% if @type && @role && @statuses.any? %>
|
||||
<%= form_tag({ action: :update }, id: "workflow_form", method: :patch) do %>
|
||||
<%= hidden_field_tag "type_id", @type.id %>
|
||||
<%= hidden_field_tag "role_id", @role.id %>
|
||||
<%= hidden_field_tag "tab", params[:tab] || "always" %>
|
||||
|
||||
<%= render partial: "form",
|
||||
locals: { name: "always", workflows: @workflows["always"] } %>
|
||||
<%= render_tabs workflow_tabs %>
|
||||
|
||||
<%= augmented_collapsible_section initiallyExpanded: @workflows["author"].present?,
|
||||
title: t(:label_additional_workflow_transitions_for_author) do %>
|
||||
<%= render partial: "form", locals: { name: "author", workflows: @workflows["author"] } %>
|
||||
<% end %>
|
||||
|
||||
<%= augmented_collapsible_section initiallyExpanded: @workflows["assignee"].present?,
|
||||
title: t(:label_additional_workflow_transitions_for_assignee) do %>
|
||||
<%= render partial: "form", locals: { name: "assignee", workflows: @workflows["assignee"] } %>
|
||||
<% end %>
|
||||
|
||||
<%= styled_button_tag t(:button_save), class: "-primary -with-icon icon-checkmark" %>
|
||||
<%=
|
||||
render Primer::Beta::Button.new(scheme: :primary, type: :submit, id: "work-flow-save-button") do
|
||||
t(:button_save)
|
||||
end
|
||||
%>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% html_title(Workflow.model_name.human) -%>
|
||||
|
||||
@@ -31,10 +31,10 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
<%= render Workflows::PageHeaderComponent.new(state: :show) %>
|
||||
|
||||
<% if @workflow_counts.any? %>
|
||||
<div class="autoscroll">
|
||||
|
||||
<div class="generic-table--container">
|
||||
<div class="generic-table--results-container">
|
||||
<table class="generic-table" data-controller="table-highlighting">
|
||||
<table class="generic-table workflow-table" data-controller="table-highlighting" id="workflow_summary">
|
||||
<colgroup>
|
||||
<col data-highlight="false">
|
||||
<col>
|
||||
@@ -44,7 +44,7 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
<col>
|
||||
<col data-highlight="false">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<thead class="-sticky">
|
||||
<tr>
|
||||
<th><div class="generic-table--empty-header"></div></th>
|
||||
<% @workflow_counts.first.last.each do |role, count| %>
|
||||
@@ -74,7 +74,7 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% else %>
|
||||
<%= no_results_box %>
|
||||
<% end %>
|
||||
|
||||
@@ -171,6 +171,11 @@ en:
|
||||
expired: "Expired on %{date}"
|
||||
revoked: "Revoked on %{date}"
|
||||
title: "Access token table"
|
||||
workflows:
|
||||
tabs:
|
||||
default_transitions: "Default transitions"
|
||||
user_author: "User is author"
|
||||
user_assignee: "User is assignee"
|
||||
|
||||
authentication:
|
||||
login_and_registration: "Login and registration"
|
||||
|
||||
@@ -84,3 +84,4 @@
|
||||
@import user-content/index
|
||||
@import bim/index
|
||||
@import reporting/index
|
||||
@import "work_packages/workflows"
|
||||
|
||||
@@ -55,52 +55,6 @@ table
|
||||
font-style: normal
|
||||
font-weight: var(--base-text-weight-bold)
|
||||
background-color: #EEEEEE
|
||||
|
||||
#workflow_form
|
||||
.generic-table--results-container
|
||||
position: relative
|
||||
|
||||
.workflow-table.generic-table
|
||||
// Let space for the turned header
|
||||
margin-left: 30px
|
||||
width: calc(100% - 30px)
|
||||
|
||||
.workflow-table--current-status
|
||||
font-weight: var(--base-text-weight-bold)
|
||||
text-transform: uppercase
|
||||
font-size: 0.875rem
|
||||
|
||||
tbody
|
||||
span.workflow-table--turned-header
|
||||
white-space: nowrap
|
||||
transform: rotate(270deg)
|
||||
position: absolute
|
||||
top: 235px
|
||||
left: 0px
|
||||
transform-origin: 0 0
|
||||
text-transform: uppercase
|
||||
font-weight: var(--base-text-weight-bold)
|
||||
max-width: 220px
|
||||
@include text-shortener
|
||||
|
||||
thead
|
||||
th
|
||||
padding: 0 6px
|
||||
.workflow-table--header
|
||||
text-align: right
|
||||
display: flex
|
||||
span
|
||||
flex-basis: 50%
|
||||
.workflow-table--check-all
|
||||
font-size: 12px
|
||||
font-style: italic
|
||||
text-transform: none
|
||||
a:hover
|
||||
text-decoration: underline
|
||||
|
||||
.generic-table--sort-header-outer:hover
|
||||
background: none
|
||||
|
||||
tr
|
||||
div.expander
|
||||
cursor: pointer
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
.controller-workflows
|
||||
#content-body
|
||||
display: grid
|
||||
grid-area: auto
|
||||
padding-top: 0
|
||||
overflow-x: scroll
|
||||
|
||||
.workflows-page-header
|
||||
padding-top: 1rem
|
||||
|
||||
#workflow_form
|
||||
.generic-table--results-container
|
||||
position: relative
|
||||
overflow: visible
|
||||
|
||||
.generic-table--container
|
||||
overflow: visible
|
||||
|
||||
.workflow-table.generic-table
|
||||
// Let space for the turned header
|
||||
margin-left: 30px
|
||||
width: calc(100% - 30px)
|
||||
|
||||
.workflow-table--current-status
|
||||
font-weight: var(--base-text-weight-bold)
|
||||
text-transform: uppercase
|
||||
font-size: 0.875rem
|
||||
|
||||
td:first-child:not(:has(.workflow-table--turned-header)),
|
||||
th:first-child
|
||||
position: sticky
|
||||
left: -1rem
|
||||
background: var(--body-background)
|
||||
z-index: 2
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.08)
|
||||
padding-top: 16px
|
||||
|
||||
th:first-child
|
||||
z-index: 3
|
||||
|
||||
tbody
|
||||
span.workflow-table--turned-header
|
||||
white-space: nowrap
|
||||
transform: rotate(270deg)
|
||||
position: absolute
|
||||
top: 235px
|
||||
left: 0px
|
||||
transform-origin: 0 0
|
||||
text-transform: uppercase
|
||||
font-weight: var(--base-text-weight-bold)
|
||||
max-width: 220px
|
||||
@include text-shortener
|
||||
|
||||
thead
|
||||
th
|
||||
padding: 0 6px
|
||||
.workflow-table--header
|
||||
text-align: right
|
||||
display: flex
|
||||
span
|
||||
flex-basis: 50%
|
||||
.workflow-table--check-all
|
||||
font-size: 12px
|
||||
font-style: italic
|
||||
text-transform: none
|
||||
a:hover
|
||||
text-decoration: underline
|
||||
|
||||
.generic-table--sort-header-outer:hover
|
||||
background: none
|
||||
|
||||
#workflow_summary
|
||||
td:first-child:not(:has(.workflow-table--turned-header)),
|
||||
th:first-child
|
||||
position: sticky
|
||||
left: -1rem
|
||||
background: var(--body-background)
|
||||
z-index: 2
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.08)
|
||||
|
||||
th:first-child
|
||||
z-index: 3
|
||||
|
||||
#work-flow-save-button
|
||||
position: sticky
|
||||
left: 0
|
||||
@@ -253,8 +253,8 @@ RSpec.describe WorkflowsController do
|
||||
|
||||
allow(Workflows::BulkUpdateService)
|
||||
.to receive(:new)
|
||||
.with(role:, type:)
|
||||
.and_return(service)
|
||||
.with(role: role, type: type, tab: "always")
|
||||
.and_return(service)
|
||||
|
||||
service
|
||||
end
|
||||
@@ -279,7 +279,7 @@ RSpec.describe WorkflowsController do
|
||||
|
||||
it "redirects to edit" do
|
||||
expect(response)
|
||||
.to redirect_to edit_workflows_path(role_id: role.id, type_id: type.id)
|
||||
.to redirect_to edit_workflows_path(role_id: role.id, type_id: type.id, tab: "always")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -77,6 +77,98 @@ RSpec.describe "Workflow edit" do
|
||||
.to have_field "status_#{statuses[2].id}_#{statuses[0].id}_", checked: false
|
||||
expect(page)
|
||||
.to have_field "status_#{statuses[2].id}_#{statuses[1].id}_", checked: false
|
||||
|
||||
expect(Workflow.where(type_id: type.id, role_id: role.id).count).to be 2
|
||||
|
||||
w = Workflow.where(role_id: role.id, type_id: type.id, old_status_id: statuses[0].id, new_status_id: statuses[1].id).first
|
||||
assert !w.author
|
||||
assert !w.assignee
|
||||
|
||||
w = Workflow.where(role_id: role.id, type_id: type.id, old_status_id: statuses[1].id, new_status_id: statuses[2].id).first
|
||||
assert !w.author
|
||||
assert !w.assignee
|
||||
end
|
||||
end
|
||||
|
||||
it "allows editing the workflow when the user is author" do
|
||||
click_link "User is author"
|
||||
click_button "Edit"
|
||||
|
||||
within "#workflow_form_author" do
|
||||
check "status_#{statuses[2].id}_#{statuses[1].id}_"
|
||||
end
|
||||
|
||||
click_button "Save"
|
||||
|
||||
expect_flash(message: "Successful update.")
|
||||
|
||||
within "#workflow_form_author" do
|
||||
expect(page)
|
||||
.to have_field "status_#{statuses[2].id}_#{statuses[1].id}_", checked: true
|
||||
|
||||
expect(page)
|
||||
.to have_field "status_#{statuses[0].id}_#{statuses[1].id}_", checked: false
|
||||
expect(page)
|
||||
.to have_field "status_#{statuses[1].id}_#{statuses[2].id}_", checked: false
|
||||
expect(page)
|
||||
.to have_field "status_#{statuses[0].id}_#{statuses[2].id}_", checked: false
|
||||
expect(page)
|
||||
.to have_field "status_#{statuses[1].id}_#{statuses[0].id}_", checked: false
|
||||
expect(page)
|
||||
.to have_field "status_#{statuses[2].id}_#{statuses[0].id}_", checked: false
|
||||
|
||||
expect(Workflow.where(type_id: type.id, role_id: role.id).count).to be 2
|
||||
|
||||
# the newly added Workflow
|
||||
w = Workflow.where(role_id: role.id, type_id: type.id, old_status_id: statuses[2].id, new_status_id: statuses[1].id).first
|
||||
assert w.author
|
||||
assert !w.assignee
|
||||
|
||||
# The already existing Workflow
|
||||
w = Workflow.where(role_id: role.id, type_id: type.id, old_status_id: statuses[0].id, new_status_id: statuses[1].id).first
|
||||
assert !w.author
|
||||
assert !w.assignee
|
||||
end
|
||||
end
|
||||
|
||||
it "allows editing the workflow when the user is assignee" do
|
||||
click_link "User is assignee"
|
||||
click_button "Edit"
|
||||
|
||||
within "#workflow_form_assignee" do
|
||||
check "status_#{statuses[2].id}_#{statuses[0].id}_"
|
||||
end
|
||||
|
||||
click_button "Save"
|
||||
|
||||
expect_flash(message: "Successful update.")
|
||||
|
||||
within "#workflow_form_assignee" do
|
||||
expect(page)
|
||||
.to have_field "status_#{statuses[2].id}_#{statuses[0].id}_", checked: true
|
||||
|
||||
expect(page)
|
||||
.to have_field "status_#{statuses[0].id}_#{statuses[1].id}_", checked: false
|
||||
expect(page)
|
||||
.to have_field "status_#{statuses[1].id}_#{statuses[2].id}_", checked: false
|
||||
expect(page)
|
||||
.to have_field "status_#{statuses[0].id}_#{statuses[2].id}_", checked: false
|
||||
expect(page)
|
||||
.to have_field "status_#{statuses[1].id}_#{statuses[0].id}_", checked: false
|
||||
expect(page)
|
||||
.to have_field "status_#{statuses[2].id}_#{statuses[1].id}_", checked: false
|
||||
|
||||
expect(Workflow.where(type_id: type.id, role_id: role.id).count).to be 2
|
||||
|
||||
# the newly added Workflow
|
||||
w = Workflow.where(role_id: role.id, type_id: type.id, old_status_id: statuses[2].id, new_status_id: statuses[0].id).first
|
||||
assert !w.author
|
||||
assert w.assignee
|
||||
|
||||
# The already existing Workflow
|
||||
w = Workflow.where(role_id: role.id, type_id: type.id, old_status_id: statuses[0].id, new_status_id: statuses[1].id).first
|
||||
assert !w.author
|
||||
assert !w.assignee
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -54,7 +54,7 @@ RSpec.describe Workflows::BulkUpdateService, "integration", type: :model do
|
||||
end
|
||||
|
||||
let(:instance) do
|
||||
described_class.new(role:, type:)
|
||||
described_class.new(role:, type:, tab:)
|
||||
end
|
||||
|
||||
describe "#call" do
|
||||
@@ -64,6 +64,7 @@ RSpec.describe Workflows::BulkUpdateService, "integration", type: :model do
|
||||
end
|
||||
|
||||
context "with status transitions for everybody" do
|
||||
let(:tab) { "always" }
|
||||
let(:params) do
|
||||
{
|
||||
status4.id => { status5.id => ["always"] },
|
||||
@@ -88,11 +89,11 @@ RSpec.describe Workflows::BulkUpdateService, "integration", type: :model do
|
||||
end
|
||||
end
|
||||
|
||||
context "with additional transitions" do
|
||||
context "with additional author transitions" do
|
||||
let(:tab) { "author" }
|
||||
let(:params) do
|
||||
{
|
||||
status4.id => { status5.id => ["always"] },
|
||||
status3.id => { status1.id => ["author"], status2.id => ["assignee"], status4.id => %w(author assignee) }
|
||||
status3.id => { status1.id => ["author"] }
|
||||
}
|
||||
end
|
||||
|
||||
@@ -100,24 +101,36 @@ RSpec.describe Workflows::BulkUpdateService, "integration", type: :model do
|
||||
subject
|
||||
|
||||
expect(Workflow.where(type_id: type.id, role_id: role.id).count)
|
||||
.to be 4
|
||||
.to be 1
|
||||
|
||||
w = Workflow.where(role_id: role.id, type_id: type.id, old_status_id: status4.id, new_status_id: status5.id).first
|
||||
assert !w.author
|
||||
assert !w.assignee
|
||||
w = Workflow.where(role_id: role.id, type_id: type.id, old_status_id: status3.id, new_status_id: status1.id).first
|
||||
assert w.author
|
||||
assert !w.assignee
|
||||
end
|
||||
end
|
||||
|
||||
context "with additional assignee transitions" do
|
||||
let(:tab) { "assignee" }
|
||||
let(:params) do
|
||||
{
|
||||
status3.id => { status2.id => ["assignee"] }
|
||||
}
|
||||
end
|
||||
|
||||
it "sets the workflows" do
|
||||
subject
|
||||
|
||||
expect(Workflow.where(type_id: type.id, role_id: role.id).count)
|
||||
.to be 1
|
||||
|
||||
w = Workflow.where(role_id: role.id, type_id: type.id, old_status_id: status3.id, new_status_id: status2.id).first
|
||||
assert !w.author
|
||||
assert w.assignee
|
||||
w = Workflow.where(role_id: role.id, type_id: type.id, old_status_id: status3.id, new_status_id: status4.id).first
|
||||
assert w.author
|
||||
assert w.assignee
|
||||
end
|
||||
end
|
||||
|
||||
context "without transitions" do
|
||||
let(:tab) { "always" }
|
||||
let(:params) do
|
||||
{}
|
||||
end
|
||||
@@ -135,6 +148,7 @@ RSpec.describe Workflows::BulkUpdateService, "integration", type: :model do
|
||||
end
|
||||
|
||||
context "with no params" do
|
||||
let(:tab) { "always" }
|
||||
let(:params) do
|
||||
nil
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user