fix(products): polish the product list, empty state and create form - #1174
Merged
Conversation
- Sort the platform dropdown on create product alphabetically, through the shared byName comparator rather than the API's id order. - Only show the select toggle in the products header when the account has products, so the empty state isn't offering a selection mode for nothing. - Use the conveyor-belt-boxes icon on the "No products" empty state, matching the products entry in the sidebar nav instead of an unrelated open box. - Give the create button's spinner a right margin. It used `inline`, which sets margin-left, so the spinner sat flush against the "Creating..." label with a gap on the wrong side. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018YfRBMvuTVpXniu6MNi5jo
|
This pull request is automatically being deployed by Amplify Hosting (learn more). |
Follow-up polish on the products UI, aligning it with how the equivalent screens are already built. Empty state now matches the devices and scripting empty states: the action button comes first, followed by centered body2 help text, with no icon or heading. Previously it led with an icon and an h2, which no other list empty state does. Header buttons now go through useTranslation like every other header affordance. The select toggle reuses the existing header.showSelect and header.hideSelect keys already translated for the devices equivalent, and the strings on the products page pick up a new productsPage namespace. Also from the review pass: - Use IconButton's `hide` prop rather than a conditional wrapper, and its `to` prop rather than a hand-rolled history.push, which removes the second URLSearchParams construction in the toggle handler. - Derive hasProducts through a memoized selector so the header re-renders when the boolean flips instead of on every product mutation. - Filter and sort the platform types once when they are fetched rather than on every render of the create form. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018YfRBMvuTVpXniu6MNi5jo
… mode Creating a product requires the admin permission on the API, but the UI offered it to anyone. An org account manager could fill in the form and submit, then get an API error. Gate the affordances on ADMIN the way the scripting pages already do: - Header create button is disabled with an "Admin permissions required" tooltip, matching ScriptsListHeader. - The add page shows a notice and disables its inputs, so a direct link to /products/add explains itself rather than failing on submit. - The empty state hides its create button and says why. - The select toggle is hidden without admin, since it exists to reach bulk delete. The create form is now a real form element, so enter submits it. The submit button carries type="submit" and cancel is explicitly type="button". Select mode moves from a ?select=true query param to a /products/select route, matching /devices/select. The route passes `select` to the page as a prop instead of the page parsing the URL, which is how DevicesPage receives it. The header buttons and action bar navigate between the two routes, so the three copies of the query-param logic are gone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018YfRBMvuTVpXniu6MNi5jo
Deleting a product is at least as privileged as creating one, so gate it the same way. Follows DeleteDevice, which disables the button and wraps it in a tooltip naming the reason only when it is actually disabled. The product option menu's delete is disabled without the admin permission, with an "Admin permissions required" tooltip. Also gate the bulk delete in the products action bar. The select toggle is already hidden without admin, but /products/select can still be reached by typing the URL, which would otherwise leave a delete button that fails at the API. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018YfRBMvuTVpXniu6MNi5jo
Make Product creates a product, so it needs the same admin gate the products pages now use. It was still enabled for non-admins, who would get an API error on click. Disabled with an "Admin permissions required" tooltip, matching how the adjacent Delete Device explains why it is unavailable. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018YfRBMvuTVpXniu6MNi5jo
Three follow-ups from review of the admin gating: The Make Product tooltip wrapper was applied even for admins, where the title is empty and no tooltip renders anyway. MenuList arrow-key traversal skips a span-wrapped child, so that cost admins keyboard access to the item for nothing. Wrap only in the disabled branch, as the product option menu and DeleteDevice already do. The "Admin permissions required" title on the bulk delete never appeared: IconButton drops the tooltip entirely when disabled unless forceTitle is set, so a non-admin saw a greyed trash icon with no explanation. The create form kept `required` on the platform Select, whose native input is visually hidden. Browser validation blocked submit before handleCreate ran, making the platformRequired notice unreachable and anchoring the native bubble to an invisible control. Mark the form noValidate so the in-code checks report through the Notice. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018YfRBMvuTVpXniu6MNi5jo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Changes
Four small UI fixes on the Products pages. Follow-up to #1173, which is already merged — this is a separate PR on a branch restarted from
main.Alpha sort the platform dropdown (
ProductAddPage.tsx) — the Create Product platform list rendered in the API'sidorder, which is roughly chronological by when each platform was added, so Teltonika landed at the bottom underUnknown. Now sorted through the sharedbyNamecomparator from refactor(sort): route alphabetical sorts through a shared comparator #1169, so it picks up the same locale-aware, numeric-aware collator as the rest of the app rather than a new ad-hoc sort.Hide the select toggle when there are no products (
ProductsHeaderButtons.tsx) — the check-square button in the header rendered unconditionally, offering a selection mode over an empty list. Now gated ongetProducts().length.Empty state icon (
ProductsPage.tsx) — the "No products" screen usedbox-open; switched toconveyor-belt-boxes, matching the Products entry in the sidebar nav and the icon already used in the add-page products tile.Create button spinner spacing (
ProductAddPage.tsx) — the spinner usedinline, which setsmargin-left. On an icon that precedes its label that puts the gap on the wrong side: the spinner was pushed off the button's left edge and sat flush against "Creating...". Changed toinlineLeft, which setsmargin-right— the convention used elsewhere for leading icons.Verification
npm run typecheckpasses. The only output is the pre-existingtsconfigTS5101 deprecations onbaseUrl/downlevelIteration, which are present onmainand unrelated.One behavior note on the select toggle: products load asynchronously, so on a cold load of
/productsthe button is absent for a beat and then appears. That matches the intent (no products, no toggle) but it is a visible change from the button always being there.Generated by Claude Code