Skip to content

fix: always show kebab menu in payroll list for consistent alignment#1457

Merged
jeffredodd merged 4 commits intomainfrom
fix/always-show-payroll-kebab-menu
Apr 7, 2026
Merged

fix: always show kebab menu in payroll list for consistent alignment#1457
jeffredodd merged 4 commits intomainfrom
fix/always-show-payroll-kebab-menu

Conversation

@jeffredodd
Copy link
Copy Markdown
Contributor

@jeffredodd jeffredodd commented Apr 3, 2026

Summary

  • Always render the kebab (hamburger) menu on every row in the PayrollList, even when no actions (skip/delete) are available
  • When no actions exist, the menu shows a disabled "No actions available" item
  • This fixes button misalignment caused by the menu icon appearing on some rows but not others (e.g. processed payrolls, payrolls with blockers, future pay periods)

Screenshots

Before

Screenshot 2026-04-02 at 10 07 04 PM

After

Screenshot 2026-04-06 at 8 50 08 AM

Test plan

  • All 23 existing PayrollList tests pass (3 updated to match new behavior)
  • Verify in Storybook: PayrollListWithBlockersStory and PayrollListWithWireInStatusesStory now show the kebab icon on every row
  • Open the menu on a row with no actions and confirm it shows "No actions available" (greyed out)
  • Verify skip/delete menus still work as before on eligible payrolls

Made with Cursor

@jeffredodd jeffredodd marked this pull request as ready for review April 3, 2026 05:07
Copilot AI review requested due to automatic review settings April 3, 2026 05:07
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR ensures the Payroll list row actions column stays consistently aligned by always rendering the kebab (hamburger) menu for each row, showing a disabled “No actions available” item when no actions apply.

Changes:

  • Always render the row kebab menu (including for processed payrolls and other no-action states).
  • Add a new i18n string for the disabled empty-actions menu item.
  • Update PayrollListPresentation tests to reflect the new always-visible menu behavior.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/types/i18next.d.ts Adds the new noActionsAvailable key to the PayrollList i18n type definition.
src/i18n/en/Payroll.PayrollList.json Adds the English translation for “No actions available”.
src/components/Payroll/PayrollList/PayrollListPresentation.tsx Renders HamburgerMenu for all rows and falls back to a disabled “No actions available” item when needed.
src/components/Payroll/PayrollList/PayrollListPresentation.test.tsx Updates assertions to expect the menu to be present and to show the disabled fallback item.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +296 to +304
<HamburgerMenu
menuLabel={t('payrollMenuLabel')}
items={[
{
label: t('noActionsAvailable'),
onClick: () => {},
isDisabled: true,
},
]}
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The disabled "No actions available" menu item is defined in multiple places (the processed branch and the default menuItems fallback). Consider extracting a shared noActionsAvailable menu-item definition to avoid duplication and prevent the two instances from drifting over time (label/disabled behavior/etc.).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member

@serikjensen serikjensen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flagging this one for additional design work

@jeffredodd jeffredodd marked this pull request as draft April 3, 2026 21:40
@jeffredodd jeffredodd force-pushed the fix/always-show-payroll-kebab-menu branch from 2e57997 to eb6267a Compare April 6, 2026 16:03
@jeffredodd jeffredodd marked this pull request as ready for review April 6, 2026 16:05
@jeffredodd
Copy link
Copy Markdown
Contributor Author

Screenshot 2026-04-07 at 8 46 53 AM @aaronlee777 you requested to see what it looked like w/o kababs.

Copy link
Copy Markdown

@boostsecurity-io-ai boostsecurity-io-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 5 New Security Fixes

You just committed 5 security fixes. 😎 Keep up the great work!

🎯 Take a look at what findings you fixed.
Findings
CWE-918: Server-Side Request Forgery (SSRF)
Original Rule ID: rules_lgpl_javascript_ssrf_rule-node-ssrf
The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.

This rule detected user-controlled URLs being passed to Node.js HTTP client
libraries including axios.get(), axios.post(), fetch(), http.get(),
http.request(), needle(), request(), urllib.request(),
superagent.get(), bent(),...
 📘 Learn More
const res = await fetch(`${proxyBase}/v1/companies/${companyId}/${endpoint}`, {
CWE-918: Server-Side Request Forgery (SSRF)
Original Rule ID: rules_lgpl_javascript_ssrf_rule-node-ssrf
The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.

This rule detected user-controlled URLs being passed to Node.js HTTP client
libraries including axios.get(), axios.post(), fetch(), http.get(),
http.request(), needle(), request(), urllib.request(),
superagent.get(), bent(),...
 📘 Learn More
const pollRes = await fetch(`${safeHost}/demos/${demoId}`, {
CWE-918: Server-Side Request Forgery (SSRF)
Original Rule ID: rules_lgpl_javascript_ssrf_rule-node-ssrf
The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.

This rule detected user-controlled URLs being passed to Node.js HTTP client
libraries including axios.get(), axios.post(), fetch(), http.get(),
http.request(), needle(), request(), urllib.request(),
superagent.get(), bent(),...
 📘 Learn More
`${safeHost}/fe_sdk/${env.FLOW_TOKEN}/v1/companies/${companyId}/locations`,
CWE-918: Server-Side Request Forgery (SSRF)
Original Rule ID: rules_lgpl_javascript_ssrf_rule-node-ssrf
The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.

This rule detected user-controlled URLs being passed to Node.js HTTP client
libraries including axios.get(), axios.post(), fetch(), http.get(),
http.request(), needle(), request(), urllib.request(),
superagent.get(), bent(),...
 📘 Learn More
const res = await fetch(`${proxyBase}/v1/companies`, {
CWE-918: Server-Side Request Forgery (SSRF)
Original Rule ID: rules_lgpl_javascript_ssrf_rule-node-ssrf
The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.

This rule detected user-controlled URLs being passed to Node.js HTTP client
libraries including axios.get(), axios.post(), fetch(), http.get(),
http.request(), needle(), request(), urllib.request(),
superagent.get(), bent(),...
 📘 Learn More
const createRes = await fetch(`${safeHost}/demos`, {

Scanner: boostsecurity - Semgrep

jeffredodd and others added 4 commits April 7, 2026 08:51
The kebab menu was conditionally hidden when no actions (skip/delete)
were available, causing button misalignment across rows. Now the menu
is always rendered with a disabled "No actions available" item when
no real actions exist.

Made-with: Cursor
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…abled item

Replace the disabled "No actions available" menu item with a hidden
ButtonIcon placeholder that preserves row alignment. Uses the actual
ButtonIcon component via ComponentsContext so the placeholder
automatically matches partner overrides.

Made-with: Cursor
Extract kebab-eligibility logic into a reusable hasKebabActions helper
and conditionally render the placeholder ButtonIcon only when at least
one payroll in the list has menu actions. This removes the empty kebab
column when no actions are available, giving the table a cleaner layout.

Adds a Storybook story to verify the no-kebab-actions case.

Made-with: Cursor
@jeffredodd jeffredodd force-pushed the fix/always-show-payroll-kebab-menu branch from 7b0f795 to 451eacf Compare April 7, 2026 15:51
@jeffredodd jeffredodd merged commit 7b5b1cf into main Apr 7, 2026
17 checks passed
@jeffredodd jeffredodd deleted the fix/always-show-payroll-kebab-menu branch April 7, 2026 16:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants