Skip to content

Commit 270e71c

Browse files
authored
Merge pull request #24753 from opf/bug-fnd-216
[FND-216] Show a proper blankslate when no project attributes are configured
2 parents 0299c6a + c817ff8 commit 270e71c

4 files changed

Lines changed: 152 additions & 37 deletions

File tree

app/components/work_package_types/project_attributes/index_component.html.erb

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,38 +7,48 @@
77
end
88
end
99

10-
flex.with_row do
11-
render(Primer::OpenProject::SubHeader.new(collapsed_search: false)) do |subheader|
12-
subheader.with_filter_input(
13-
name: "border-box-filter",
14-
label: t("types.edit.project_attributes.filter"),
15-
visually_hide_label: true,
16-
placeholder: t("types.edit.project_attributes.filter"),
17-
leading_visual: {
18-
icon: :search,
19-
size: :small
20-
},
21-
show_clear_button: true,
22-
clear_button_id: clear_button_id,
23-
data: {
24-
action: "input->filter--filter-list#filterLists",
25-
"filter--filter-list-target": "filter"
26-
}
27-
)
10+
if visible_sections.empty?
11+
flex.with_row do
12+
render(Primer::Beta::Blankslate.new(border: true, test_selector: "type-project-attributes-blankslate")) do |blankslate|
13+
blankslate.with_visual_icon(icon: :"list-unordered")
14+
blankslate.with_heading(tag: :h3) { t("#{blankslate_i18n_scope}.title") }
15+
blankslate.with_description { blankslate_description }
16+
end
2817
end
29-
end
30-
31-
visible_sections.each do |project_custom_field_section, project_custom_fields|
18+
else
3219
flex.with_row do
33-
render(
34-
WorkPackageTypes::ProjectAttributes::SectionComponent.new(
35-
variant: @variant,
36-
project_custom_field_section:,
37-
project_custom_fields:,
38-
linked: linked?,
39-
exclusion_state:
20+
render(Primer::OpenProject::SubHeader.new(collapsed_search: false)) do |subheader|
21+
subheader.with_filter_input(
22+
name: "border-box-filter",
23+
label: t("types.edit.project_attributes.filter"),
24+
visually_hide_label: true,
25+
placeholder: t("types.edit.project_attributes.filter"),
26+
leading_visual: {
27+
icon: :search,
28+
size: :small
29+
},
30+
show_clear_button: true,
31+
clear_button_id: clear_button_id,
32+
data: {
33+
action: "input->filter--filter-list#filterLists",
34+
"filter--filter-list-target": "filter"
35+
}
36+
)
37+
end
38+
end
39+
40+
visible_sections.each do |project_custom_field_section, project_custom_fields|
41+
flex.with_row do
42+
render(
43+
WorkPackageTypes::ProjectAttributes::SectionComponent.new(
44+
variant: @variant,
45+
project_custom_field_section:,
46+
project_custom_fields:,
47+
linked: linked?,
48+
exclusion_state:
49+
)
4050
)
41-
)
51+
end
4252
end
4353
end
4454
end

app/components/work_package_types/project_attributes/index_component.rb

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,28 @@ def exclusion_state
3838
@exclusion_state = linked? ? WorkPackageTypes::ExclusionState.for(@variant, ASPECT) : nil
3939
end
4040

41+
def blankslate_i18n_scope
42+
"types.edit.project_attributes.blankslate.#{linked? ? 'linked' : 'independent'}"
43+
end
44+
45+
def blankslate_description
46+
return t("#{blankslate_i18n_scope}.description") if linked?
47+
48+
link_translate("#{blankslate_i18n_scope}.description",
49+
links: { administration_url: admin_settings_project_custom_fields_path },
50+
external: false)
51+
end
52+
4153
def visible_sections
42-
return @project_custom_field_sections unless linked?
43-
44-
result = []
45-
@project_custom_field_sections.each do |section, custom_fields|
46-
shown = custom_fields.select { |cf| show_in_linked_mode?(cf) }
47-
result << [section, shown] if shown.any?
48-
end
49-
result
54+
@visible_sections ||=
55+
if linked?
56+
@project_custom_field_sections.filter_map do |section, custom_fields|
57+
shown = custom_fields.select { |cf| show_in_linked_mode?(cf) }
58+
[section, shown] if shown.any?
59+
end
60+
else
61+
@project_custom_field_sections
62+
end
5063
end
5164

5265
def show_in_linked_mode?(custom_field)

config/locales/en.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6286,6 +6286,13 @@ en:
62866286
actions:
62876287
label_disable_all: "Disable all"
62886288
label_enable_all: "Enable all"
6289+
blankslate:
6290+
independent:
6291+
description: "Once you [create project attributes](administration_url), they will be visible here and can be added to a type."
6292+
title: "No project attributes available"
6293+
linked:
6294+
description: "This type does not have any project attributes associated with it."
6295+
title: "No project attributes configured"
62896296
description: "Select the project attributes that you want to enable for this work package type. Enabled project attributes are displayed in a separate tab in work packages of this type. Users with the necessary permissions can view and edit these attributes there."
62906297
disabled: "Disabled"
62916298
exclusions:
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# frozen_string_literal: true
2+
3+
#-- copyright
4+
# OpenProject is an open source project management software.
5+
# Copyright (C) the OpenProject GmbH
6+
#
7+
# This program is free software; you can redistribute it and/or
8+
# modify it under the terms of the GNU General Public License version 3.
9+
#
10+
# See COPYRIGHT and LICENSE files for more details.
11+
#++
12+
13+
require "rails_helper"
14+
15+
RSpec.describe WorkPackageTypes::ProjectAttributes::IndexComponent, type: :component do
16+
include Rails.application.routes.url_helpers
17+
18+
current_user { create(:admin) }
19+
20+
let(:type) { create(:type) }
21+
let(:variant) { type.default_variant }
22+
let(:sections) { ProjectCustomFieldSection.grouped_in_order(ProjectCustomField.visible) }
23+
24+
subject(:rendered_component) do
25+
render_inline(described_class.new(variant:, project_custom_field_sections: sections))
26+
end
27+
28+
def blankslate_text(mode, key)
29+
I18n.t("types.edit.project_attributes.blankslate.#{mode}.#{key}")
30+
end
31+
32+
context "when the variant configures the aspect itself" do
33+
context "with no project attributes at all" do
34+
it "renders the blankslate instead of the filter", :aggregate_failures do
35+
expect(rendered_component).to have_test_selector("type-project-attributes-blankslate",
36+
text: blankslate_text(:independent, :title))
37+
expect(rendered_component).to have_link("create project attributes",
38+
href: admin_settings_project_custom_fields_path)
39+
expect(rendered_component).to have_no_field("border-box-filter")
40+
end
41+
end
42+
43+
context "with project attributes" do
44+
before { create(:project_custom_field) }
45+
46+
it "renders the sections and the filter", :aggregate_failures do
47+
expect(rendered_component).to have_no_test_selector("type-project-attributes-blankslate")
48+
expect(rendered_component).to have_css(".Box-row")
49+
expect(rendered_component).to have_field("border-box-filter")
50+
end
51+
end
52+
end
53+
54+
context "when the variant is linked for the aspect", with_flag: { type_variants: true } do
55+
let(:source_type) { create(:type) }
56+
let(:source) { source_type.default_variant }
57+
let(:custom_field) { create(:project_custom_field) }
58+
59+
before do
60+
custom_field
61+
link_configuration(variant, source:, aspect: TypeVariant::PROJECT_ATTRIBUTES)
62+
end
63+
64+
context "when the source enables no project attribute" do
65+
it "renders the blankslate instead of the filter", :aggregate_failures do
66+
expect(rendered_component).to have_test_selector("type-project-attributes-blankslate",
67+
text: blankslate_text(:linked, :title))
68+
expect(rendered_component).to have_text(blankslate_text(:linked, :description))
69+
expect(rendered_component).to have_no_field("border-box-filter")
70+
end
71+
end
72+
73+
context "when the source enables a project attribute" do
74+
before do
75+
ProjectCustomFieldTypeMapping.create!(type_variant: source, project_custom_field: custom_field)
76+
end
77+
78+
it "renders the sections and the filter", :aggregate_failures do
79+
expect(rendered_component).to have_no_test_selector("type-project-attributes-blankslate")
80+
expect(rendered_component).to have_css(".Box-row")
81+
expect(rendered_component).to have_field("border-box-filter")
82+
end
83+
end
84+
end
85+
end

0 commit comments

Comments
 (0)