Skip to content

Commit

Permalink
Merge pull request #16246 from opf/project-index-turbofy
Browse files Browse the repository at this point in the history
Project index turbofy
  • Loading branch information
dombesz authored Aug 23, 2024
2 parents de0b020 + 7def0b9 commit 3012b28
Show file tree
Hide file tree
Showing 25 changed files with 641 additions and 308 deletions.
8 changes: 5 additions & 3 deletions app/components/filter/filter_button_component.html.erb
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
<%= render(Primer::Beta::Button.new(scheme: :secondary,
<%= component_wrapper tag: "turbo-frame" do %>
<%= render(Primer::Beta::Button.new(scheme: :secondary,
disabled:,
data: { "filter--filters-form-target": "filterFormToggle",
action: "filter--filters-form#toggleDisplayFilters" },
test_selector: "filter-component-toggle")) do |button| %>
<% button.with_trailing_visual_counter(count: filters_count, test_selector: "filters-button-counter") %>
<%= t(:label_filter) %>
<% button.with_trailing_visual_counter(count: filters_count, test_selector: "filters-button-counter") %>
<%= t(:label_filter) %>
<% end %>
<% end %>
6 changes: 6 additions & 0 deletions app/components/filter/filter_button_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,17 @@ module Filter
# rubocop:disable OpenProject/AddPreviewForViewComponent
class FilterButtonComponent < ApplicationComponent
# rubocop:enable OpenProject/AddPreviewForViewComponent
include OpTurbo::Streamable

options :query
options :disabled

def filters_count
@filters_count ||= query.filters.count
end

def wrapper_key
"filter-button"
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<%= primer_form_with(
url: projects_path,
id: QUERY_FORM_ID,
data: { "turbo-stream" => false },
method: :get
) do |form| %>
<% helpers.projects_query_params.except(:columns, :sortBy).each do |name, value| %>
Expand Down
264 changes: 133 additions & 131 deletions app/components/projects/index_page_header_component.html.erb
Original file line number Diff line number Diff line change
@@ -1,156 +1,158 @@
<%=
render(Primer::OpenProject::PageHeader.new(state: @state)) do |header|
header.with_title(data: { 'test-selector': 'project-query-name' }) do |title|
title.with_editable_form(model: query,
update_path: @query.new_record? ? project_queries_path(projects_query_params) : project_query_path(@query, projects_query_params),
method: @query.new_record? ? :post : :put,
cancel_path: projects_path(**projects_query_params, **{ query_id: query.id }.compact),
input_name: "name",
label: ProjectQuery.human_attribute_name(:name),
placeholder: I18n.t(:"projects.lists.new.placeholder"),
scope: 'query',
id: 'project-save-form')
page_title
end
header.with_breadcrumbs(breadcrumb_items, selected_item_font_weight: current_breadcrumb_element == page_title ? :bold : :normal)

if can_save?
header_save_action(
header:,
message: t("lists.can_be_saved"),
label: t("button_save"),
href: project_query_path(query, projects_query_params),
method: :patch
)
elsif can_save_as?
header_save_action(
header:,
message: t("lists.can_be_saved_as"),
label: t("button_save_as"),
href: new_project_query_path(projects_query_params)
)
end

if can_access_shares?
header.with_action_icon_button(
tag: :a,
href: dialog_project_query_members_path(query),
icon: "share-android",
mobile_icon: "share-android",
label: t(:label_share),
data: { controller: "async-dialog", test_selector: "toggle-share-dialog-button" }
)
end
<%= component_wrapper(tag: 'turbo-frame') do %>
<%=
render(Primer::OpenProject::PageHeader.new(state: @state)) do |header|
header.with_title(data: { 'test-selector': 'project-query-name' }) do |title|
title.with_editable_form(model: query,
update_path: @query.new_record? ? project_queries_path(projects_query_params) : project_query_path(@query, projects_query_params),
method: @query.new_record? ? :post : :put,
cancel_path: projects_path(**projects_query_params, **{ query_id: query.id }.compact),
input_name: "name",
label: ProjectQuery.human_attribute_name(:name),
placeholder: I18n.t(:"projects.lists.new.placeholder"),
scope: 'query',
id: 'project-save-form')
page_title
end
header.with_breadcrumbs(breadcrumb_items, selected_item_font_weight: current_breadcrumb_element == page_title ? :bold : :normal)

if can_toggle_favor?
if currently_favored?
header.with_action_icon_button(
icon: "star-fill",
mobile_icon: "star-fill",
label: t(:button_unfavorite),
classes: "op-primer--star-icon",
tag: :a,
href: helpers.build_favorite_path(query, format: :html),
data: { method: :delete, "test-selector": "project-query-unfavorite" },
if can_save?
header_save_action(
header:,
message: t("lists.can_be_saved"),
label: t("button_save"),
href: project_query_path(query, projects_query_params),
method: :patch
)
else
elsif can_save_as?
header_save_action(
header:,
message: t("lists.can_be_saved_as"),
label: t("button_save_as"),
href: new_project_query_path(projects_query_params)
)
end

if can_access_shares?
header.with_action_icon_button(
icon: "star",
mobile_icon: "star",
label: t(:button_favorite),
tag: :a,
href: helpers.build_favorite_path(query, format: :html),
data: { method: :post, "test-selector": "project-query-favorite" },
href: dialog_project_query_members_path(query),
icon: "share-android",
mobile_icon: "share-android",
label: t(:label_share),
data: { controller: "async-dialog", test_selector: "toggle-share-dialog-button" }
)
end
end

header.with_action_menu(
menu_arguments: {
anchor_align: :end
},
button_arguments: {
icon: "op-kebab-vertical",
"aria-label": t(:label_more),
data: { "test-selector": "project-more-dropdown-menu" }
}
) do |menu|
if can_rename?
menu.with_item(
label: t('button_rename'),
href: rename_project_query_path(query),
) do |item|
item.with_leading_visual_icon(icon: :pencil)
if can_toggle_favor?
if currently_favored?
header.with_action_icon_button(
icon: "star-fill",
mobile_icon: "star-fill",
label: t(:button_unfavorite),
classes: "op-primer--star-icon",
tag: :a,
href: helpers.build_favorite_path(query, format: :html),
data: { method: :delete, "test-selector": "project-query-unfavorite" },
)
else
header.with_action_icon_button(
icon: "star",
mobile_icon: "star",
label: t(:button_favorite),
tag: :a,
href: helpers.build_favorite_path(query, format: :html),
data: { method: :post, "test-selector": "project-query-favorite" },
)
end
end

if gantt_portfolio_project_ids.any?
header.with_action_menu(
menu_arguments: {
anchor_align: :end
},
button_arguments: {
icon: "op-kebab-vertical",
"aria-label": t(:label_more),
data: { "test-selector": "project-more-dropdown-menu" }
}
) do |menu|
if can_rename?
menu.with_item(
label: t('button_rename'),
href: rename_project_query_path(query),
) do |item|
item.with_leading_visual_icon(icon: :pencil)
end
end

if gantt_portfolio_project_ids.any?
menu.with_item(
tag: :a,
label: t('projects.index.open_as_gantt'),
href: gantt_portfolio_query_link,
id: 'projects-index-open-as-gantt',
content_arguments: { target: '_blank' }
) do |item|
item.with_leading_visual_icon(icon: 'op-view-timeline')
end
end

menu.with_item(
tag: :a,
label: t('projects.index.open_as_gantt'),
href: gantt_portfolio_query_link,
id: 'projects-index-open-as-gantt',
content_arguments: { target: '_blank' }
label: t(:label_overall_activity),
href: activities_path,
content_arguments: { rel: "nofollow" }
) do |item|
item.with_leading_visual_icon(icon: 'op-view-timeline')
item.with_leading_visual_icon(icon: 'tasklist')
end
end

menu.with_item(
tag: :a,
label: t(:label_overall_activity),
href: activities_path,
content_arguments: { rel: "nofollow" }
) do |item|
item.with_leading_visual_icon(icon: 'tasklist')
end

if can_save?
menu_save_item(
menu:,
label: t('button_save'),
href: project_query_path(query, projects_query_params),
method: :patch
)
end

if may_save_as?
menu_save_item(
menu:,
label: t('button_save_as'),
href: new_project_query_path(projects_query_params)
)
end
if can_save?
menu_save_item(
menu:,
label: t('button_save'),
href: project_query_path(query, projects_query_params),
method: :patch
)
end

menu.with_item(
tag: :a,
label: t('js.label_export'),
href: export_list_modal_projects_path(projects_query_params),
content_arguments: { data: { controller: "async-dialog" }, rel: "nofollow" }
) do |item|
item.with_leading_visual_icon(icon: 'sign-out')
end
if may_save_as?
menu_save_item(
menu:,
label: t('button_save_as'),
href: new_project_query_path(projects_query_params)
)
end

menu.with_item(
tag: :a,
label: t(:'queries.configure_view.heading'),
href: configure_view_modal_project_queries_path(projects_query_params),
content_arguments: { data: { controller: "async-dialog" }}
) do |item|
item.with_leading_visual_icon(icon: :gear)
end
menu.with_item(
tag: :a,
label: t('js.label_export'),
href: export_list_modal_projects_path(projects_query_params),
content_arguments: { data: { controller: "async-dialog" }, rel: "nofollow" }
) do |item|
item.with_leading_visual_icon(icon: 'sign-out')
end

if query.persisted?
menu.with_item(
tag: :a,
label: t(:button_delete),
scheme: :danger,
href: destroy_confirmation_modal_project_query_path(query.id),
label: t(:'queries.configure_view.heading'),
href: configure_view_modal_project_queries_path(projects_query_params),
content_arguments: { data: { controller: "async-dialog" }}
) do |item|
item.with_leading_visual_icon(icon: 'trash')
item.with_leading_visual_icon(icon: :gear)
end

if query.persisted?
menu.with_item(
tag: :a,
label: t(:button_delete),
scheme: :danger,
href: destroy_confirmation_modal_project_query_path(query.id),
content_arguments: { data: { controller: "async-dialog" }}
) do |item|
item.with_leading_visual_icon(icon: 'trash')
end
end
end
end
end
%>
%>
<% end %>
10 changes: 8 additions & 2 deletions app/components/projects/index_page_header_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
class Projects::IndexPageHeaderComponent < ApplicationComponent
include OpPrimer::ComponentHelpers
include Primer::FetchOrFallbackHelper
include OpTurbo::Streamable

attr_accessor :current_user,
:query,
Expand All @@ -56,6 +57,10 @@ def initialize(current_user:, query:, params:, state: STATE_DEFAULT)
self.params = params
end

def self.wrapper_key
"projects-index-page-header"
end

def gantt_portfolio_query_link
generator = ::Projects::GanttQueryGeneratorService.new(gantt_portfolio_project_ids)
gantt_index_path query_props: generator.call
Expand Down Expand Up @@ -137,7 +142,8 @@ def header_save_action(header:, message:, label:, href:, method: nil)
mobile_icon: nil, # Do not show on mobile as it is already part of the menu
mobile_label: nil,
href:,
data: { method: }
data: { "turbo-stream": true, method: },
target: ""
) do
render(
Primer::Beta::Octicon.new(
Expand All @@ -155,7 +161,7 @@ def menu_save_item(menu:, label:, href:, method: nil)
label:,
href:,
content_arguments: {
data: { method: }
data: { "turbo-stream": true, method: }
}
) do |item|
item.with_leading_visual_icon(icon: :"op-save")
Expand Down
Loading

0 comments on commit 3012b28

Please sign in to comment.