Center-align setup experience app icons (#49962)

<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #46973

> **Draft:** on-device QA (Mac/iPhone/iPad) is pending hardware,
expected next week. Opening as draft for early review of the approach.

## Description

FMA and custom-package app icons were misaligned on the macOS setup
experience ("Setting up your device") screen — icons rendered at
different sizes and their "Install …" labels didn't line up.

**Root cause:** `SetupSoftwareProcessCell` forced `.software-icon__small
{ width: $pad-xlarge }` (32px, width only). That class lands on
different elements in `SoftwareIcon`'s two render paths, so it hit them
differently:
- **Fleet-maintained / VPP apps (icon URL)** → the class is on the
wrapper `<div>`; the 24px `<img>` inside stayed 24px, left-aligned.
- **Custom packages (no URL)** → the class is on the fallback **SVG**
itself, which got stretched to 32px wide.

Result: different icon sizes/positions by app type → the misalignment.

**Fix:** remove the width override so every app type renders
`SoftwareIcon` at its consistent, vertically-centered 24px "small" size.

## Testing

Verified in Storybook (added `SetupSoftwareProcessCell.stories.tsx`,
`MixedAlignment` story) with real matched brand icons (Chrome,
1Password, VS Code, Zoom), a generic custom-package icon, and a
URL/`<img>` icon stacked together:
- **Before** (with the override): icons render at mixed 24/32px sizes;
"Install …" labels don't align.

<img width="1135" height="398" alt="before"
src="https://github.com/user-attachments/assets/fe216ab4-0a7b-4211-b8aa-96e65e6ca3f5"
/>

- **After** (this change): all icons render at 24px, centered, labels
aligned.

<img width="1185" height="425" alt="after"
src="https://github.com/user-attachments/assets/28257eb8-df6e-4168-a0bb-28dda4bb40ba"
/>


On-device QA to follow once hardware is available.

## Notes for reviewer
- The `width: $pad-xlarge` (32px) was added in #33770, so 32px may have
been the *intended* icon size. This change makes them a consistent
**24px**. If a larger icon is desired, that's a follow-up done properly
via a real `SoftwareIcon` size (not a width-only override) — flagging
for PD input since this is `:product`-labeled.
- Included a Storybook story for visual verification/regression; happy
to drop it if that's not wanted here.

# Checklist for submitter

- [x] Changes file added for user-visible changes in `changes/`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

## Testing

- [ ] QA'd all new/changed functionality manually <!-- pending on-device
QA -->
- Added a Storybook story for visual verification (not an automated
test).


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved software process cell styling for more consistent icon sizing
and alignment.

* **Tests**
* Added Storybook scenarios covering fleet-maintained apps, custom
packages, uploaded icons, and mixed app layouts.


<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Rajendra Kadam
2026-07-27 19:42:22 +05:30
committed by GitHub
parent af65282522
commit 17669eca02
3 changed files with 70 additions and 4 deletions
@@ -0,0 +1 @@
- Fixed misaligned app icons on the macOS setup experience "Setting up your device" screen.
@@ -0,0 +1,69 @@
import React from "react";
import { Meta, StoryObj } from "@storybook/react";
import {
QueryClient,
QueryClientProvider,
QueryClientProviderProps,
} from "react-query";
import SetupSoftwareProcessCell from "./SetupSoftwareProcessCell";
// SoftwareIcon calls `useQuery` unconditionally (even when it doesn't fetch), so
// stories need a QueryClientProvider in scope or they throw "No QueryClient set".
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
});
type CustomQueryClientProviderProps = React.PropsWithChildren<QueryClientProviderProps>;
const CustomQueryClientProvider: React.FC<CustomQueryClientProviderProps> = QueryClientProvider;
// Small inline SVG data URI to exercise the <img> render path (VPP apps or an
// app with an uploaded custom icon).
const iconURL =
"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Crect width='24' height='24' rx='5' fill='%234a90d9'/%3E%3C/svg%3E";
const meta: Meta<typeof SetupSoftwareProcessCell> = {
title: "Components/TableContainer/SetupSoftwareProcessCell",
component: SetupSoftwareProcessCell,
decorators: [
(Story) => (
<CustomQueryClientProvider client={queryClient}>
<Story />
</CustomQueryClientProvider>
),
],
};
export default meta;
type Story = StoryObj<typeof SetupSoftwareProcessCell>;
// Fleet-maintained app — renders its real matched brand icon (SVG fallback).
export const FleetMaintainedApp: Story = {
args: { name: "Google Chrome" },
};
// Custom package with no matched icon — renders the generic package icon.
export const CustomPackage: Story = {
args: { name: "Acme Corp Agent" },
};
// App with an uploaded icon URL (VPP / custom icon) — renders an <img>.
export const WithIconURL: Story = {
args: { name: "Company Portal", url: iconURL },
};
// Real FMA brand icons, a custom package (generic icon), and a URL-based icon
// stacked together, to verify icons and "Install …" labels align across app
// types. Regression coverage for #46973.
export const MixedAlignment: Story = {
render: () => (
<div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
<SetupSoftwareProcessCell name="Google Chrome" />
<SetupSoftwareProcessCell name="1Password" />
<SetupSoftwareProcessCell name="Visual Studio Code" />
<SetupSoftwareProcessCell name="Zoom" />
<SetupSoftwareProcessCell name="Acme Corp Agent" />
<SetupSoftwareProcessCell name="Company Portal" url={iconURL} />
</div>
),
};
@@ -2,8 +2,4 @@
display: flex;
align-items: center;
gap: $pad-small;
.software-icon__small {
width: $pad-xlarge;
}
}