-
Notifications
You must be signed in to change notification settings - Fork 2.6k
/
Copy pathindex_component.rb
184 lines (156 loc) · 6.05 KB
/
index_component.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# frozen_string_literal: true
# Component for rendering the relations tab content of a work package
#
# This includes:
# - Controls for adding new relations if the user has permission
# - Related work packages grouped by relation type (follows, precedes, blocks, etc.)
# - Child work packages
class WorkPackageRelationsTab::IndexComponent < ApplicationComponent
FRAME_ID = "work-package-relations-tab-content"
NEW_RELATION_ACTION_MENU = "new-relation-action-menu"
NEW_CHILD_ACTION_MENU = "new-child-action-menu"
I18N_NAMESPACE = "work_package_relations_tab"
include ApplicationHelper
include OpPrimer::ComponentHelpers
include Turbo::FramesHelper
include OpTurbo::Streamable
attr_reader :relations_mediator, :directionally_aware_grouped_relations, :relation_to_scroll_to
delegate :work_package, :relations, :children, :any_relations?, to: :relations_mediator
# Initialize the component with required data
#
# @param work_package [WorkPackage] The work package whose relations are being displayed
# @param relation_to_scroll_to [Relation, WorkPackage, nil] Optional relation or child to scroll to when rendering
def initialize(work_package: nil, relation_to_scroll_to: nil)
super()
@relations_mediator = WorkPackageRelationsTab::RelationsMediator.new(work_package:)
@directionally_aware_grouped_relations = group_relations_by_directional_context
@relation_to_scroll_to = relation_to_scroll_to
end
def self.wrapper_key
FRAME_ID
end
private
def should_render_add_child?
return false if work_package.milestone?
helpers.current_user.allowed_in_project?(:manage_subtasks, work_package.project)
end
def should_render_add_relations?
helpers.current_user.allowed_in_project?(:manage_work_package_relations, work_package.project)
end
def should_render_create_button?
should_render_add_child? || should_render_add_relations?
end
def group_relations_by_directional_context
relations.group_by do |relation|
relation.relation_type_for(work_package)
end
end
def render_relation_group(title:, relation_type:, items:, &_block)
render(border_box_container(
padding: :condensed,
data: { test_selector: "op-relation-group-#{relation_type}" }
)) do |border_box|
if relation_type == :children && should_render_add_child?
render_children_header(border_box, title, items)
else
render_header(border_box, title, items)
end
render_items(border_box, items, &_block)
end
end
def render_header(border_box, title, items)
border_box.with_header(py: 3) do
concat render(Primer::Beta::Text.new(mr: 2, font_size: :normal, font_weight: :bold)) { title }
concat render(Primer::Beta::Counter.new(count: items.size, round: true, scheme: :primary))
end
end
def render_children_header(border_box, title, items) # rubocop:disable Metrics/AbcSize
border_box.with_header(py: 3) do
flex_layout(justify_content: :space_between, align_items: :center) do |header|
header.with_column(mr: 2) do
concat render(Primer::Beta::Text.new(mr: 2, font_size: :normal, font_weight: :bold)) { title }
concat render(Primer::Beta::Counter.new(count: items.size, round: true, scheme: :primary))
end
header.with_column do
render(Primer::Alpha::ActionMenu.new(menu_id: NEW_CHILD_ACTION_MENU)) do |menu|
menu.with_show_button do |button|
button.with_leading_visual_icon(icon: :plus)
button.with_trailing_action_icon(icon: :"triangle-down")
t("work_package_relations_tab.label_add_child_button")
end
render_child_menu_items(menu)
end
end
end
end
end
def render_child_menu_items(menu) # rubocop:disable Metrics/AbcSize
return unless should_render_add_child?
if helpers.current_user.allowed_in_project?(:add_work_packages, work_package.project)
menu.with_item(
label: t("work_package_relations_tab.relations.new_child"),
href: new_project_work_packages_dialog_path(work_package.project, parent_id: work_package.id),
content_arguments: {
data: { turbo_stream: true }
}
) do |item|
item.with_description.with_content(t("work_package_relations_tab.relations.new_child_text"))
end
end
menu.with_item(
label: t("work_package_relations_tab.relations.existing_child"),
href: new_work_package_children_relation_path(work_package),
content_arguments: {
data: { turbo_stream: true }
}
) do |item|
item.with_description.with_content(t("work_package_relations_tab.relations.child_description"))
end
end
def render_items(border_box, items)
items.each do |item|
border_box.with_row(
test_selector: row_test_selector(item),
data: data_attribute(item)
) do
yield(item)
end
end
end
def data_attribute(item)
if scroll_to?(item)
{
controller: "work-packages--relations-tab--scroll",
application_target: "dynamic",
"work-packages--relations-tab--scroll-target": "scrollToRow"
}
end
end
def scroll_to?(item)
relation_to_scroll_to \
&& item.id == relation_to_scroll_to.id \
&& item.instance_of?(relation_to_scroll_to.class)
end
def new_relation_path(relation_type:)
raise ArgumentError, "Invalid relation type: #{relation_type}" unless Relation::TYPES.key?(relation_type)
if relation_type == Relation::TYPE_CHILD
raise NotImplementedError, "Child relations are not supported yet"
else
new_work_package_relation_path(work_package, relation_type:)
end
end
def new_button_test_selector(relation_type:)
"op-new-relation-button-#{relation_type}"
end
def row_test_selector(item)
related_work_package_id = find_related_work_package_id(item)
"op-relation-row-#{related_work_package_id}"
end
def find_related_work_package_id(item)
if item.is_a?(Relation)
item.from_id == work_package.id ? item.to_id : item.from_id
else
item.id
end
end
end