Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,6 @@ gemfiles.each do |file|
send(:eval_gemfile, file) if File.readable?(file)
end

gem "openproject-octicons", "~>19.34.0"
gem "openproject-octicons_helper", "~>19.34.0"
gem "openproject-octicons", "~>19.35.0"
gem "openproject-octicons_helper", "~>19.35.0"
gem "openproject-primer_view_components", "~>0.85.0"
14 changes: 7 additions & 7 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -904,10 +904,10 @@ GEM
validate_email
validate_url
webfinger (~> 2.0)
openproject-octicons (19.34.0)
openproject-octicons_helper (19.34.0)
openproject-octicons (19.35.0)
openproject-octicons_helper (19.35.0)
actionview
openproject-octicons (= 19.34.0)
openproject-octicons (= 19.35.0)
railties
openproject-primer_view_components (0.85.0)
actionview (>= 7.2.0)
Expand Down Expand Up @@ -1684,8 +1684,8 @@ DEPENDENCIES
openproject-job_status!
openproject-ldap_groups!
openproject-meeting!
openproject-octicons (~> 19.34.0)
openproject-octicons_helper (~> 19.34.0)
openproject-octicons (~> 19.35.0)
openproject-octicons_helper (~> 19.35.0)
openproject-openid_connect!
openproject-primer_view_components (~> 0.85.0)
openproject-recaptcha!
Expand Down Expand Up @@ -2065,8 +2065,8 @@ CHECKSUMS
openproject-job_status (1.0.0)
openproject-ldap_groups (1.0.0)
openproject-meeting (1.0.0)
openproject-octicons (19.34.0) sha256=4efe8a58a2d8051b79c94b37e9a7f04fd242a4da12b50f027c3c7f441a042adc
openproject-octicons_helper (19.34.0) sha256=12eb7af2214e21631369c76464ebaa30de788e1074c4b3bd0fcef7e74cb9edb4
openproject-octicons (19.35.0) sha256=a5033550d0961b4a8cb0993512a899716d633e17c2b5147bc6a9ed74f3952b38
openproject-octicons_helper (19.35.0) sha256=c32d142a4bb7fda739b16768aa8846fd88ffc1750509d8056f516056e8767361
openproject-openid_connect (1.0.0)
openproject-primer_view_components (0.85.0) sha256=16bc8358ef600f0465488a2e3c86991a9c69ed84580bd450c2dbec6f268eeaca
openproject-recaptcha (1.0.0)
Expand Down
32 changes: 29 additions & 3 deletions app/components/open_project/common/border_box_list_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,14 @@ module Common
# header actions, collapsible behavior, and row rendering.
class BorderBoxListComponent < ApplicationComponent
include OpPrimer::ComponentHelpers
include Primer::FetchOrFallbackHelper

attr_reader :container, :current_user, :header_id, :footer_id
SCHEME_DEFAULT = :default
SCHEME_OPTIONS = [SCHEME_DEFAULT, :flat].freeze

attr_reader :container, :scheme, :collapsible, :current_user, :header_id, :footer_id

alias_method :collapsible?, :collapsible

# Optional header row.
#
Expand All @@ -53,6 +59,7 @@ class BorderBoxListComponent < ApplicationComponent
renders_one :header, ->(**system_arguments) {
system_arguments[:id] = header_id
system_arguments[:list_id] = list_id
system_arguments[:collapsible] = collapsible?

Header.new(**system_arguments)
}
Expand Down Expand Up @@ -152,18 +159,37 @@ class BorderBoxListComponent < ApplicationComponent

# @param container [String, Symbol, Class, Object] value passed to
# `dom_target` to derive DOM ids for the list and related controls.
# @param scheme [Symbol] visual scheme. `:default` renders the standard
# BorderBox header. `:flat` renders a transparent header with no
# separator line.
# @param collapsible [Boolean] whether the header renders a collapsible
# toggle. Defaults to `false`.
# @param current_user [User] user context passed to work-package items.
# @param system_arguments [Hash] forwarded to `Primer::Beta::BorderBox`.
# Pass `id:` to set the box id; related ids are derived from it.
def initialize(container:, current_user: User.current, **system_arguments)
def initialize( # rubocop:disable Metrics/AbcSize
container:,
scheme: SCHEME_DEFAULT,
collapsible: false,
current_user: User.current,
**system_arguments
)
super()

@container = container
@scheme = ActiveSupport::StringInquirer.new(fetch_or_fallback(SCHEME_OPTIONS, scheme, SCHEME_DEFAULT).to_s)
@collapsible = collapsible
@current_user = current_user
@system_arguments = system_arguments

@system_arguments[:id] ||= dom_target(container)
@system_arguments[:list_id] = dom_target(@system_arguments[:id], :list)
@system_arguments[:classes] = class_names(
@system_arguments[:classes],
"BorderBoxList",
"BorderBoxList--flat" => @scheme.flat?
)

@header_id = dom_target(@system_arguments[:id], :header)
@footer_id = dom_target(@system_arguments[:id], :footer)
end
Expand All @@ -183,7 +209,7 @@ def configure_header!
return unless header?

header.resolve_count!(items.size)
return unless footer?
return unless collapsible? && footer?

header.collapsible_id = [list_id, footer_id].compact.join(" ")
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,11 @@
align-self: flex-start
// Unfortunately, the invisible button style bites us here again.
margin-top: -6px

.BorderBoxList--flat
> .Box-header
background-color: transparent
border-bottom: none

> ul > .Box-row:first-of-type
border-top: none
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,38 @@ See COPYRIGHT and LICENSE files for more details.

<%= grid_layout("op-border-box-list-header", tag: :div) do |grid| %>
<% grid.with_area(:collapsible) do %>
<%=
render(
Primer::OpenProject::BorderBox::CollapsibleHeader.new(
collapsible_id:,
collapsed:,
multi_line: true
)
) do |collapsible|
%>
<% collapsible.with_title(tag: title_tag) { title } %>
<% if render_count? %>
<% collapsible.with_count(**counter_arguments) %>
<% if collapsible? %>
<%=
render(
Primer::OpenProject::BorderBox::CollapsibleHeader.new(
collapsible_id:,
collapsed:,
multi_line: true
)
) do |collapsible|
%>
<% collapsible.with_title(tag: title_tag) { title } %>
<% if render_count? %>
<% collapsible.with_count(**counter_arguments) %>
<% end %>
<% if description? %>
<% collapsible.with_description do %>
<%= description %>
<% end %>
<% end %>
<% end %>
<% if description? %>
<% collapsible.with_description do %>
<%= description %>
<% else %>
<%= render(Primer::BaseComponent.new(tag: :div, classes: "CollapsibleHeader CollapsibleHeader--multi-line")) do %>
<%= render(Primer::BaseComponent.new(tag: :div, classes: "CollapsibleHeader-title-line")) do %>
<%= render(Primer::Beta::Truncate.new(tag: title_tag, classes: "CollapsibleHeader-title Box-title")) { title } %>
<% if render_count? %>
<%= render(Primer::Beta::Counter.new(**counter_arguments, classes: class_names(counter_arguments[:classes], "CollapsibleHeader-count"))) %>
<% end %>
<% end %>
<% if description? %>
<%= render(Primer::Beta::Text.new(color: :subtle, trim: true, classes: "CollapsibleHeader-description")) do %>
<%= description %>
<% end %>
<% end %>
<% end %>
<% end %>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ class Header < ApplicationComponent
:count_arguments,
:title_tag,
:list_id,
:collapsed
:collapsed,
:collapsible

attr_writer :collapsible_id

Expand All @@ -96,6 +97,9 @@ class Header < ApplicationComponent
# @param title_tag [Symbol] tag used for the title heading.
# @param list_id [String, nil] id of the collapsible list body.
# @param collapsed [Boolean] whether the collapsible header starts closed.
# @param collapsible [Boolean] whether the header renders a collapsible
# toggle. Defaults to `true`. Pass `false` to render a plain title
# without a toggle button.
# @param system_arguments [Hash] forwarded to `Primer::Beta::BorderBox#with_header`.
def initialize(
title:,
Expand All @@ -105,6 +109,7 @@ def initialize(
title_tag: :h4,
list_id: nil,
collapsed: false,
collapsible: true,
**system_arguments
)
super()
Expand All @@ -117,9 +122,15 @@ def initialize(
@list_id = list_id
@collapsible_id = list_id
@collapsed = collapsed
@collapsible = collapsible
@system_arguments = system_arguments
end

# @return [Boolean] whether a collapsible toggle should be rendered.
def collapsible?
collapsible
end

# Resolves inferred counts after the list slots have been captured.
#
# @param item_count [Integer] number of rendered item slots.
Expand Down
14 changes: 7 additions & 7 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
"@ng-select/ng-option-highlight": "^21.8.2",
"@ng-select/ng-select": "^21.8.0",
"@ngneat/content-loader": "^7.0.0",
"@openproject/octicons-angular": "^19.34.0",
"@openproject/octicons-angular": "^19.35.0",
"@openproject/primer-view-components": "^0.85.0",
"@openproject/reactivestates": "^3.0.1",
"@primer/css": "^22.1.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@ module Common
# @logical_path OpenProject/Common
class BorderBoxListComponentPreview < ViewComponent::Preview
# @label Default
def default
# @param collapsible [Boolean] toggle
def default(collapsible: false)
render OpenProject::Common::BorderBoxListComponent.new(
container: "border-box-list-preview"
container: "border-box-list-preview",
collapsible:
) do |list|
list.with_header(title: "Things we're building", count: true) do |header|
header.with_description { "There's lots to look forward to" }
Expand All @@ -57,13 +59,42 @@ def default
end
end

# @label Flat scheme
# @param collapsible [Boolean] toggle
def flat(collapsible: false)
render OpenProject::Common::BorderBoxListComponent.new(
container: "border-box-list-flat-preview",
scheme: :flat,
collapsible:
) do |list|
list.with_header(title: "Sprint backlog", count: true) do |header|
header.with_description { "3 points remaining" }
header.with_action_button do |button|
button.with_leading_visual_icon(icon: :rocket)
"Start sprint"
end
header.with_menu(button_aria_label: "Sprint actions") do |menu|
menu.with_item(label: "Edit sprint") do |menu_item|
menu_item.with_leading_visual_icon(icon: :pencil)
end
end
end

list.with_item { "User authentication stories" }
list.with_item { "Dashboard improvements" }
list.with_item { "API documentation" }
end
end

# @label With work package items
def with_work_package_items
# @param collapsible [Boolean] toggle
def with_work_package_items(collapsible: false)
work_packages = WorkPackage.includes(:project).limit(2).to_a
return preview_message("No work packages in the database.") if work_packages.empty?

render OpenProject::Common::BorderBoxListComponent.new(
container: "border-box-list-work-package-preview"
container: "border-box-list-work-package-preview",
collapsible:
) do |list|
list.with_header(title: "Work packages", count: true)

Expand All @@ -80,18 +111,21 @@ def with_work_package_items
end

# @label Playground
# @param collapsible [Boolean] toggle
# @param title_tag [Symbol] select [h2, h3, h4, h5]
# @param count [Symbol] select [inferred, hidden, explicit, zero]
# @param count_scheme [Symbol] select [primary, secondary]
# @param hide_zero_count toggle
def playground(
collapsible: false,
title_tag: :h4,
count: :inferred,
count_scheme: :primary,
hide_zero_count: true
)
render OpenProject::Common::BorderBoxListComponent.new(
container: "border-box-list-playground-preview"
container: "border-box-list-playground-preview",
collapsible:
) do |list|
list.with_header(
title: "Playground list",
Expand All @@ -114,9 +148,11 @@ def playground(

# @label Empty state
# List with a header and an empty state (Blankslate), no items.
def empty_state
# @param collapsible [Boolean] toggle
def empty_state(collapsible: false)
render OpenProject::Common::BorderBoxListComponent.new(
container: "border-box-list-empty-preview"
container: "border-box-list-empty-preview",
collapsible:
) do |list|
list.with_header(title: "Empty list", count: 0)
list.with_empty_state(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ See COPYRIGHT and LICENSE files for more details.
OpenProject::Common::BorderBoxListComponent.new(
container: inbox_container,
current_user:,
scheme: :flat,
padding: :condensed,
test_selector: "backlog-inbox",
data: {
Expand All @@ -43,6 +44,8 @@ See COPYRIGHT and LICENSE files for more details.
}
)
) do |list| %>
<% list.with_header(title: t(".title"), count: true) %>

<% list.with_empty_state(
title: t(".blankslate_title"),
description: t(".blankslate_description"),
Expand Down
Loading
Loading