Fleet UI: Multi-package Library, Add/Edit/Delete modals (#48400)#48520
Draft
RachelElysia wants to merge 2 commits into
Draft
Fleet UI: Multi-package Library, Add/Edit/Delete modals (#48400)#48520RachelElysia wants to merge 2 commits into
RachelElysia wants to merge 2 commits into
Conversation
Foundation slice for the multi-package title-details page. Renders title.packages[] when present and falls back to [software_package] so back-compat single-package titles look identical to before. No new modals yet — the AddPackageModal and per-installer Edit/Delete wiring land in a follow-up slice. - Types: optional installer_id on ISoftwarePackage; packages[] on ISoftwareTitle and ISoftwareTitleDetails. installer_id stays optional until #48397 ships and the server populates it everywhere. - API client: addSoftwarePackage takes software_title_id (multi-package add); editSoftwarePackage and deleteSoftwareInstaller take an optional installer_id so they target one specific package. - MSW: new frontend/test/handlers/multi-package-handlers.ts with a buildTitleWithPackages helper and handlers for GET (multi/empty), POST (happy + duplicate-hash + 10-limit + FMA-conflict + VPP-conflict), PATCH per-installer, and DELETE per-installer. - Library section iterates packages instead of operating on a single software_package; description copy updated to Figma. App-store / custom-package branches stay mutually exclusive at the data layer. TODOs flagged in code: - Strip issue refs (#48396/#48397/#48400) from comments before merging to main. - Make installer_id required once #48397 ships. - Drop the software_package fallback in renderLibrarySection once packages[] is always present.
…48400) Builds on the foundation slice with the per-package modal flows and the coordinated UI states for multi-package custom titles. Hides title-level status indicators (chips, page-level Edit) in favor of per-package indicators on each Library accordion row so the surfaces stay accurate when one package on a title differs from another. Single source of truth at the page level: `canActivateMultiplePackages` flips three behaviors together — the "+ Add package" action, the per-row self-service / auto-install icons, and the summary card's chip-hide and pencil-Edit treatment. True for custom non-FMA non-iOS titles (Mac/Linux/Windows binary + script packages); false for FMA, VPP, Google Play, and iOS in-house .ipa, which stay on the single-package path. New components - AddPackageModal: real in-place modal wrapping PackageForm. File-type chooser is restricted to the existing title's platform (helper at AddPackageModal/helpers.ts maps filename -> {accept, label}, with the .tar.gz workaround mirrored). Standard mode renders the first-added-wins banner; GitOps mode renders the SHA-256/YAML banner with the "YAML docs" link. Target defaults to Custom so labels are required. - PackageForm: new multiPackageContext prop embeds the right banner under the file uploader, swaps the Save button copy, hides the deploy slider, and shows the target-label selector above Advanced options. Caught and fixed a pre-existing duplication of the submit button text across the tooltipped/non-tooltipped branches that let the copy drift. - useBlockNavigation hook: extracts the `beforeunload` pattern that was duplicated across SoftwareCustomPackage, EditSoftwareModal, and the new AddPackageModal. Per-package wiring - selectedInstallerId state on the page resolves which package the Edit / Delete modal targets; row callbacks pass `pkg.installer_id`. - EditSoftwareModal title swaps to "Edit package" via the new canActivateMultiplePackages prop; PATCH carries the installer id. - DeleteSoftwareModal DELETE carries the installer id when set. - Per-package PoliciesModal: clicking the auto-install icon navigates to the single linked policy or opens a modal scoped to that package's policies, distinct from the title-aggregate modal owned by the SoftwareSummaryCard. Library accordion row - Custom non-iOS rows hide the Latest badge and render clickable self-service / auto-install indicator icons. A renderRowActionIcon helper deduplicates the tooltip + optional button + static-fallback pattern. - Latest badge tightened to FMA-only (`isFma && badgeState === "latest"`) so VPP/Play Store/iOS rows don't surface it either. - ariaLabels: "Edit package" (matches the modal title that opens) for self-service; "View auto-install policies" / "View patch policy" for the auto-install icon. Summary card - Hides Self-service / Auto install / Patch chips when canActivateMultiplePackages — per-row icons replace them. - Collapses the Actions dropdown to a single pencil-icon Edit button that opens the Edit Appearance modal directly; per-installer editing is on the accordion. The pencil button is wrapped in GitOpsModeTooltipWrapper so GitOps mode disables it with the standard "Managed by GitOps" tooltip. - "Custom package(s)" chip pluralizes via `pluralize()` from stringUtils. InfoBanner - Wired up the existing `icon` prop (previously unused per its TODO) so banners can render a leading Icon. CSS gates the layout shift behind the existing `__icon` modifier so callers without the prop are unaffected. Tests - AddPackageModal component tests (13): title, banner copy verbatim, GitOps mode variant + YAML link, file-type restriction across .pkg /.deb/.msi/.tar.gz/.sh, Save vs Add software label, Custom radio preselected. - EditSoftwareModal title swap (3 tests). - LibraryItemAccordion custom-package row (4 tests): hidden by default, self-service icon fires onSelfServiceClick, auto-install icon fires onAutoInstallClick, patch-policy variant uses the patch aria-label. - Updated SoftwareSummaryCard chip tests to use FMA mocks so they keep exercising the chip-render path; added a new test verifying chips are hidden for multi-package titles. - New helper tests: getFileTypeRestriction (10), MSW factories (8). - 411 SoftwarePage tests passing total (up from ~211 pre-PR). Verbatim copy from Figma page 2:130 throughout (including the "it's" apostrophe typo in the GitOps banner — preserved deliberately so design and code stay in sync). TODOs before merge to main: - Strip the #48396/#48397/#48400 issue refs sprinkled in comments. - Lock the `installer_id` field name once #48397 settles.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## feat/28108-multiple-custom-packages #48520 +/- ##
=======================================================================
+ Coverage 67.48% 67.55% +0.06%
=======================================================================
Files 3676 3680 +4
Lines 233629 233792 +163
Branches 12261 12337 +76
=======================================================================
+ Hits 157672 157931 +259
+ Misses 61806 61709 -97
- Partials 14151 14152 +1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
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.
Related issue: Resolves #48400
Description
Frontend implementation of the multi-package custom-package UI: the Library section iterates
title.packages[], exposes per-installer Edit/Delete/Download, and adds an in-place Add Package modal with file-type restriction and a GitOps-mode variant. Coordinated state changes on the Software title details page move title-level Self-service / Auto install / Patch indicators down to per-row icons so they stay accurate when one package on a title differs from another.Single source of truth at the page level:
canActivateMultiplePackagesflips three behaviors together — the "+ Add package" action, the per-row self-service / auto-install icons, and the summary card's chip-hide + pencil-Edit treatment. True for custom non-FMA non-iOS titles (Mac/Linux/Windows binary + script packages); false for FMA, VPP, Google Play, and iOS in-house.ipa, which stay on the single-package path.Two commits:
packages[],installer_id?), API client extension, MSW handlers for the new endpoints, initial Library iteration.AddPackageModal(real in-place modal wrappingPackageForm), per-installer wiring throughEditSoftwareModal/DeleteSoftwareModal, per-row clickable self-service / auto-install icons, page-levelselectedInstallerIdresolution, per-packagePoliciesModal, pencil-icon Edit on the summary card withGitOpsModeTooltipWrapper,useBlockNavigationhook (deduplicatesbeforeunloadacross 3 files), pluralized "Custom package(s)" chip viastringUtils.pluralize, Latest badge tightened to FMA-only,InfoBannericonprop wired up. Includes new component-level tests (AddPackageModal, EditSoftwareModal title swap, accordion icon row), helper tests (file-type restriction, MSW factories), and updated chip-render tests on the summary card. 411 SoftwarePage tests pass.Verbatim copy from Figma page 2:130 throughout, including the deliberately preserved apostrophe typo in the GitOps banner.
Screen recording
Testing
yarn tsc --noEmitcleannpx eslinton touched files clean (one pre-existingdefaultSoftware?: anywarning inPackageForm.tsx:114left as-is; out of scope)yarn test --testPathPattern="SoftwarePage|useBlockNavigation"— 411/411 passyarn startcovering: multi-package render, +Add package flow, per-row edit/delete, file-type restriction, GitOps mode banner + disabled pencil Edit, 10-cap tooltip, "Edit package" modal title swapNotes for reviewer
installer_idand the multi-package POST/PATCH/DELETE shapes via MSW. Real wiring is a no-op until the server populatespackages[]; the back-compat fallback (title.packages ?? [software_package].filter(Boolean)) keeps single-package titles rendering identically to pre-PR.installer_idfield name is a guess pending Multiple packages: packages[] API and add/edit/delete-package endpoints #48397; comments call out the search-and-replace path when locked.#48396/#48397/#48400issue refs sprinkled in comments (git blame is the audit trail)installer_idrequired onISoftwarePackageonce#48397shipssoftware_packageback-compat fallback inrenderLibrarySectiononcepackages[]is always presentOut of scope for this PR
SoftwareTitleDetailsPage) end-to-end tests — heavy harness setup; the page's behaviors are covered indirectly by component-level testsPackageFormstandalone tests — its multi-package behaviors are exercised end-to-end via theAddPackageModaltests