Collapse rarely-changed config sections on org & person edit forms - #2038
Collapse rarely-changed config sections on org & person edit forms#2038maebeale wants to merge 14 commits into
Conversation
The org edit form's Workshop settings option grid and Background info block
forced a long scroll on every edit even though they rarely change. Wrap each
in a native <details>/<summary> so they collapse to a one-line summary — the
category summary shows the current selections ("None selected" / "Hospitals")
so you can see the value without expanding. Background info stays open on new
orgs and when the form has errors so required fields aren't hidden.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR shortens the Organization edit experience by collapsing two long, rarely-edited sections into native <details>/<summary> accordions, preserving visibility of the current selections and keeping required/background fields discoverable on new records and validation errors.
Changes:
- Wrapped each organization category group (“Workshop settings” grid) in a
<details>with a one-line summary showing the currently selected category names. - Wrapped the “Background Info” block in a
<details>that defaults open for new organizations and when the form has errors.
Put the chevron directly beside each section's label/value (with a hover color) instead of far-right, where it was easy to miss as a click target. Also collapse the Addresses section the same way — usually there's just one address — summarizing to the single address, a count, or "None"; it stays open on new orgs and when an address or the org has validation errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wrap the rarely-changed configuration sections on both edit forms in native <details>/<summary> so they collapse to a one-line summary with an inline chevron, cutting the scroll on every edit. Summaries show the current value (selected sectors/categories, addresses, emails, phones, hidden profile toggles as "Hide X"); Background/Addresses/Emails/Phones/Extras stay open on new records and when there are errors so required/invalid fields aren't hidden. Org: keep name, Windows audience (50/50 with Sectors), Sectors and Workshop settings in the left column beside the logo so it no longer leaves dead space, and move Associated records below Comments (now one row). Add PersonDecorator/OrganizationDecorator#profile_display_summary (+ specs) for the "Hide X" rollup. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.
Suppressed comments (1)
app/views/organizations/_associated_records.html.erb:5
- nit: The new comment says this wraps to a “2/3-col grid” on narrower screens, but the classes now set
sm:grid-cols-3(no 2-column breakpoint). Updating the comment avoids future confusion when adjusting responsive layout.
<%# One row on md+ (grid-flow-col + equal auto columns); wraps to a 2/3-col grid
on narrower screens. %>
- Org: Windows audience is now a collapsible summary parallel (50/50) with Sectors; Associated records moved below the save button (edit page, one row); shrink the logo box via a new size: local on the shared image field. - Person: Emails and Phones sit parallel (50/50), secondary email wraps; name fields go 2-up on mobile; contact-method row flex-wraps in the narrow column; Licenses/Extras collapse; Affiliations/Comments/Communications are collapsible (expanded by default); the shared communications box is now a <details>. - Sector/age-range collapsed summaries mark the primary (bold + ⭐) and sector leader (👑 + "(sector leader)") via *Decorator#sectors_summary / PersonDecorator#age_ranges_summary (+ specs). - Fix: give the Affiliations/Addresses <details> named groups so the section's group no longer fires the inner tooltip/nested-field group-hover/open; add pointer-events-none to the affiliation hover tooltips so they can't block the collapse chevron. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 14 changed files in this pull request and generated no new comments.
Suppressed comments (2)
app/views/people/_form.html.erb:442
- 🤖 From Copilot: should-fix:
licenses_opendoesn’t account for nestedprofessional_licensevalidation errors, so a failed save could re-render with the Professional licenses section collapsed and the invalid fields hidden.
<% licenses_open = !f.object.persisted? || f.object.errors.any? %>
app/views/people/_form.html.erb:30
- 🤖 From Copilot: should-fix:
contacts_openonly checksf.object.errors, so a validation error on a nestedcontact_methodcan leave the Phones section collapsed and hide the inline error messages on re-render.
This issue also appears on line 442 of the same file.
<% contacts_open = !f.object.persisted? || f.object.errors.any? %>
<% phone_values = f.object.contact_methods.reject(&:marked_for_destruction?).filter_map { |cm| cm.value.presence } %>
The grid-flow-col approach still wrapped to two rows; use a flex row (each item flex-1, min-w-0 so labels truncate rather than wrap) so all associated-record buttons sit on a single equal-width row on md+, stacking only on mobile. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 14 changed files in this pull request and generated no new comments.
Suppressed comments (2)
app/views/people/_form.html.erb:443
- 🤖 From Copilot: should-fix: This section opens based on
f.object.errors, but uniqueness/format errors can be attached to nestedprofessional_licensesrecords; if those don’t bubble to the parent, the section can stay collapsed and hide the validation error.
<% licenses = f.object.professional_licenses.reject(&:marked_for_destruction?) %>
<% licenses_open = !f.object.persisted? || f.object.errors.any? %>
<details class="form-group space-y-4 group"<%= " open".html_safe if licenses_open %>>
app/views/people/_form.html.erb:30
- 🤖 From Copilot: should-fix: The Emails/Phones sections only auto-open on
f.object.errors, but validation errors can live on nestedcontact_methodsrecords; that can leave the Phones section collapsed on a failed submit and hide the inline error messages.
This issue also appears on line 441 of the same file.
<%# Emails and Phones sit parallel (50/50). Each collapses to the value(s)
on file; both open on a new person or when there are errors. %>
<% primary_email = f.object.user&.email.presence || f.object.email.presence %>
<% email_summary = [ primary_email, f.object.email_2.presence ].compact %>
<% contacts_open = !f.object.persisted? || f.object.errors.any? %>
<% phone_values = f.object.contact_methods.reject(&:marked_for_destruction?).filter_map { |cm| cm.value.presence } %>
Order by label so Stories and Story ideas land next to each other; keeps the single-row layout. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 14 changed files in this pull request and generated no new comments.
Suppressed comments (2)
app/decorators/person_decorator.rb:115
- blocker: This age-range summary doesn’t exclude nested items marked for destruction, so after removing an age range and triggering a validation re-render, the collapsed summary can still show age ranges the user just removed.
def age_ranges_summary
items = object.age_range_items_ordered
return "None selected" if items.empty?
app/decorators/application_decorator.rb:31
- blocker: This summary includes nested sector tags that are marked for destruction, so after removing a sector and hitting a validation error (re-render), the collapsed summary can still show sectors the user just removed.
items = object.sectorable_items_primary_first.reject { |item| item.sector&.name == Sector::OTHER_SECTOR_NAME }
Add a wrap: option to index_button that renders a fixed two-line-tall button whose label wraps (line-clamp-2 + min-h) instead of truncating on one line, so the single-row org associated-records buttons all line up to the same height. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.
Suppressed comments (1)
app/helpers/application_helper.rb:325
- 🤖 From Copilot: should-fix: This helper introduces single-quoted Ruby strings (e.g. in the
wrapinterpolations), which violates the repo’s "always use double quotes" RuboCop convention; switch these to double quotes to keep style consistent.
label_tag = content_tag(:span, label, class: "font-medium #{text} #{wrap ? 'line-clamp-2' : 'truncate'}")
Give the Story ideas button an explicit two-line label so it matches the two-lines-tall neighbors; the shared min-h already keeps every button (Stories included) the same two-line height. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
min-h-[3.5rem] was shorter than an actual two-line button, so single-line buttons (e.g. Stories) came up short and their count pill sat higher. Add h-full so each button stretches to the flex row's tallest sibling, aligning every box height and centering the counts in the same vertical space. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.
Suppressed comments (2)
app/helpers/application_helper.rb:325
- should-fix: This adds single-quoted strings inside a Ruby expression; use double quotes for consistency with the repo’s string-literal convention.
label_tag = content_tag(:span, label, class: "font-medium #{text} #{wrap ? 'line-clamp-2' : 'truncate'}")
app/helpers/application_helper.rb:314
- should-fix: This introduces a single-quoted string literal inside an interpolated class string; this codebase’s style guide prefers double quotes, and this can also trip RuboCop string-literal rules.
This issue also appears on line 325 of the same file.
#{'h-full min-h-[3.5rem]' if wrap}
Lead with the organization type (the specify-text when "Other"), then a pill for each filled optional field (Email, Website, Description, Mission/vision/values). FileMaker Project ID is left out since it's admin-only internal data and the summary is visible to org owners. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated 1 comment.
Suppressed comments (1)
app/helpers/application_helper.rb:325
- 🤖 From Copilot: should-fix: This line uses single-quoted string literals (
'line-clamp-2'/'truncate'), which violates the repo’s double-quote string convention and may trip RuboCop.
label_tag = content_tag(:span, label, class: "font-medium #{text} #{wrap ? 'line-clamp-2' : 'truncate'}")
| link_to path, | ||
| data: { turbo_prefetch: false }.merge(data), | ||
| class: "group flex items-center gap-3 w-full px-3 py-2 rounded-lg | ||
| #{'h-full min-h-[3.5rem]' if wrap} |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.
Suppressed comments (2)
app/helpers/application_helper.rb:315
- 🤖 From Copilot: nit: This introduces single-quoted string literals inside a double-quoted string interpolation, which violates this repo’s RuboCop rule to always use double quotes for strings.
class: "group flex items-center gap-3 w-full px-3 py-2 rounded-lg
#{'h-full min-h-[3.5rem]' if wrap}
border #{border} #{bg} #{hover_bg}
app/helpers/application_helper.rb:326
- 🤖 From Copilot: nit: This uses single quotes for string literals ('line-clamp-2'/'truncate'), but the project convention is double quotes everywhere, so RuboCop is likely to flag this.
label_tag = content_tag(:span, label, class: "font-medium #{text} #{wrap ? 'line-clamp-2' : 'truncate'}")
- Sectors (both forms) and Age ranges (person) now put the names in a flex column beside the title so wrapped lines indent under the names rather than the title. - Shout-out is in the general person params (not admin-only), so make its Background summary pill grey like Bio instead of admin-blue. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.
Suppressed comments (3)
app/helpers/application_helper.rb:316
- 🤖 From Copilot: should-fix: This introduces single-quoted string literals inside a file that enforces double-quoted strings (rubocop-rails-omakase), which is likely to fail lint.
link_to path,
data: { turbo_prefetch: false }.merge(data),
class: "group flex items-center gap-3 w-full px-3 py-2 rounded-lg
#{'h-full min-h-[3.5rem]' if wrap}
border #{border} #{bg} #{hover_bg}
transition-colors duration-200 shadow-sm" do
app/helpers/application_helper.rb:326
- 🤖 From Copilot: should-fix: This uses single-quoted string literals inside a double-quoted interpolation, which violates the project’s double-quote string convention and can be avoided cleanly by extracting the conditional class.
end
label_tag = content_tag(:span, label, class: "font-medium #{text} #{wrap ? 'line-clamp-2' : 'truncate'}")
app/views/shared/_form_image_field.html.erb:58
- 🤖 From Copilot: should-fix: This line now touches the
roundedclass interpolation; using single-quoted string literals here conflicts with the repo’s enforced double-quote convention and can be rewritten without nested quotes.
<%= image_tag file,
id: image_dom_id,
alt: "#{label}",
data: { file_preview_target: "preview" },
class: "#{size} object-cover border border-gray-300 shadow-sm #{rounded ? 'rounded-full' : ''}" %>
Wrap each chip (icon + name + "(sector leader)") in a whitespace-nowrap span so it never splits across a wrap; line breaks fall between chips at the comma. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Social media links is now a collapsible section summarizing which platforms have a URL on file (grey pills, or "None") via PersonDecorator#social_media_summary. - Shrink the person avatar box to w-24 h-24 to match the org logo. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.
Suppressed comments (1)
app/helpers/application_helper.rb:325
- nit: This introduces single-quoted strings inside
index_button, but this repo’s RuboCop style requires double quotes for strings; switching these to double quotes avoids a style violation.
label_tag = content_tag(:span, label, class: "font-medium #{text} #{wrap ? 'line-clamp-2' : 'truncate'}")
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.
Suppressed comments (2)
app/helpers/application_helper.rb:315
- 🤖 From Copilot: should-fix: This introduces a single-quoted string literal inside interpolation; the repo’s RuboCop config typically enforces double quotes and this will likely fail linting. Use double quotes for the conditional class string.
class: "group flex items-center gap-3 w-full px-3 py-2 rounded-lg
#{'h-full min-h-[3.5rem]' if wrap}
border #{border} #{bg} #{hover_bg}
app/helpers/application_helper.rb:325
- 🤖 From Copilot: should-fix: Single quotes in the ternary (
'line-clamp-2'/'truncate') violate the project’s double-quote string convention and may trigger RuboCop failures.
label_tag = content_tag(:span, label, class: "font-medium #{text} #{wrap ? 'line-clamp-2' : 'truncate'}")
space-y-4 on the collapsible <details> put a 1rem margin-bottom on the summary (Tailwind space-y = margin on non-last child), which rendered even when collapsed — so sections with it were taller and their gaps larger than the profile-preferences-section ones. Drop space-y-4 from the section <details> (the open-state gap is handled by mt-2 on the content div, re-added where missing) so every collapsed row is the same height and the between-row spacing is uniform. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.
Suppressed comments (3)
app/helpers/application_helper.rb:315
- 🤖 From Copilot: nit: This introduces single-quoted string literals inside interpolation (e.g.,
#{'...' if wrap}), which conflicts with the repo’s documented “always use double quotes” Ruby style and may fail linting.
class: "group flex items-center gap-3 w-full px-3 py-2 rounded-lg
#{'h-full min-h-[3.5rem]' if wrap}
border #{border} #{bg} #{hover_bg}
app/views/organizations/_form.html.erb:71
- 🤖 From Copilot: should-fix:
windows_typeselect is rendered withlabel: false, which likely removes the associated<label>and can regress screen-reader accessibility; consider keeping ansr-onlylabel (or at least anaria-label) even though the visible text is in the<summary>.
<%= f.association :windows_type,
label: false,
include_blank: true,
required: false,
input_html: {
app/helpers/application_helper.rb:325
- 🤖 From Copilot: nit: Same single-quote style issue in the ternary; using double quotes here keeps the helper consistent with the repo’s Ruby string-literal convention.
label_tag = content_tag(:span, label, class: "font-medium #{text} #{wrap ? 'line-clamp-2' : 'truncate'}")
🤖 suggested review level: 3 Read 📖 mostly view-markup + small decorator methods; form fields stay in the DOM, submission behavior unchanged
What is the goal of this PR and why is this important?
How did you approach the change?
<details>/<summary>(matching the address-fields pattern) with an inline chevron beside the label/value and a hover cue — no JS.*Decorator#sectors_summary/age_ranges_summary), addresses, emails, phones, licenses (names), and profile prefs asHide phone and website/All shown. Background (person) showsBio present/Shout-out present(shout-out styled admin-only).<details>).size:local on the shared image field); Associated records moved below the save button and fits on one row. Person: Emails ‖ Phones parallel (secondary email wraps; contact-method row flex-wraps), name fields 2-up on mobile, demographics under a collapsible Extras header.Fixes folded in
<details>groups so the section'sgroupno longer triggers the inner tooltip / nested-fieldgroup-hover/group-open; addedpointer-events-noneto the affiliation hover tooltips so they can't block the collapse chevron.Notes
visible: :all; communications specs scopedetailsnotsection).