.
+ // The gap has to live there — not on the button itself.
+ .children-wrapper {
+ gap: $pad-small;
+ }
+
+ &--form-field {
+ padding: 8px 16px;
+ background-color: $ui-light-grey;
+ border-radius: $border-radius;
+ }
+ }
+
+ &__button-label {
+ color: $core-fleet-black;
+ font-weight: 600;
+ font-size: 24px;
+ line-height: normal;
+ max-width: 500px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ &__button--form-field &__button-label {
+ font-size: $x-small;
+ }
+
+ &__icon {
+ svg {
+ transition: transform 0.25s ease;
+ }
+
+ &--open svg {
+ transform: rotate(180deg);
+ }
+ }
+
+ &__search-row {
+ // Sits at Menu level (above the scrolling MenuList). Menu owns the outer
+ // pad-medium inset; padding-bottom here provides the pad-medium gap
+ // between the search input and the first option below.
+ padding-bottom: $pad-medium;
+ background-color: $core-fleet-white;
+ }
+
+ &__search-field {
+ position: relative;
+ display: flex;
+
+ .icon {
+ position: absolute;
+ left: 12px;
+ top: 50%;
+ transform: translateY(-50%);
+ pointer-events: none;
+ }
+ }
+
+ &__search-input {
+ @include menu-search-input;
+ }
+
+ // Even with tabIndex=-1 the MenuList can still receive programmatic focus
+ // (e.g. click-to-scroll). Suppress the browser's default focus outline so
+ // the scroll container never renders a stray blue ring.
+ &__menu-list:focus,
+ &__menu-list:focus-visible {
+ outline: none;
+ }
+
+ // Scroll-fade anchor sits at the bottom of the options area with
+ // zero flow height, so toggling the fade's visibility never changes
+ // MenuList.scrollHeight (which would clamp scrollTop and jump at the
+ // very bottom of the list). Negative bottom pulls the anchor past
+ // MenuList's pad-small paddingBottom so the gradient sits flush
+ // against the outer edge of the scroll area rather than 8px above it.
+ //
+ // The visible gradient is a ::before pseudo-element sized 35px,
+ // toggled via opacity on the --visible modifier — that keeps the fade
+ // out of layout entirely regardless of visibility.
+ &__scroll-fade {
+ position: sticky;
+ bottom: -$pad-small;
+ height: 0;
+ pointer-events: none;
+ z-index: 9;
+
+ &::before {
+ content: "";
+ position: absolute;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ height: 35px;
+ // Fade from opaque Fleet-white at the bottom to transparent
+ // Fleet-white at the top. Uses the shared -transparent variant
+ // (same RGB as $core-fleet-white with alpha 0 in both light and
+ // dark themes) so dark-mode variable swaps carry through with no
+ // additional overrides — same pattern as the horizontal table
+ // shadows.
+ background: linear-gradient(
+ to top,
+ $core-fleet-white 0%,
+ $core-fleet-white-transparent 100%
+ );
+ opacity: 0;
+ pointer-events: none;
+ }
+
+ &--visible::before {
+ opacity: 1;
+ }
+ }
+
+ &__add-fleet-footer {
+ // padding-top pushes "Add fleet" pad-medium below the border-top divider.
+ padding-top: $pad-medium;
+ background-color: $core-fleet-white;
+ display: flex;
+ border-top: solid 1px $ui-fleet-black-10;
+ }
+}
diff --git a/frontend/components/FleetsDropdown/index.tsx b/frontend/components/FleetsDropdown/index.tsx
new file mode 100644
index 0000000000..8ae5b70fa5
--- /dev/null
+++ b/frontend/components/FleetsDropdown/index.tsx
@@ -0,0 +1 @@
+export { default } from "./FleetsDropdown";
diff --git a/frontend/components/TeamsDropdown/TeamsDropdown.stories.tsx b/frontend/components/TeamsDropdown/TeamsDropdown.stories.tsx
deleted file mode 100644
index dea9039416..0000000000
--- a/frontend/components/TeamsDropdown/TeamsDropdown.stories.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import React from "react";
-import { Meta, StoryObj } from "@storybook/react";
-import { noop } from "lodash";
-
-import TeamsDropdown from ".";
-
-const meta: Meta
= {
- title: "Components/TeamsDropdown",
- component: TeamsDropdown,
- decorators: [
- (Story) => (
-
-
-
- ),
- ],
- args: {
- currentUserTeams: [
- { id: 1, name: "Team 1" },
- { id: 2, name: "Team 2" },
- ],
- onChange: noop,
- },
-};
-
-export default meta;
-
-type Story = StoryObj;
-
-export const Basic: Story = {};
diff --git a/frontend/components/TeamsDropdown/TeamsDropdown.tests.tsx b/frontend/components/TeamsDropdown/TeamsDropdown.tests.tsx
deleted file mode 100644
index 30bcea4d26..0000000000
--- a/frontend/components/TeamsDropdown/TeamsDropdown.tests.tsx
+++ /dev/null
@@ -1,88 +0,0 @@
-import React from "react";
-import { render, screen } from "@testing-library/react";
-import { noop } from "lodash";
-// TODOL Replace renderWithAppContext with createCustomRenderer
-import { renderWithAppContext } from "test/test-utils";
-import { APP_CONTEXT_NO_TEAM_ID } from "interfaces/team";
-
-import TeamsDropdown from "./TeamsDropdown";
-
-describe("TeamsDropdown - component", () => {
- const USER_TEAMS = [
- { id: -1, name: "All fleets" },
- { id: 1, name: "Team 1" },
- { id: 2, name: "Team 2" },
- ];
-
- it("renders the given selected team from selectedTeamId", () => {
- render(
-
- );
-
- const selectedTeam = screen.getByText("Team 1");
- expect(selectedTeam).toBeInTheDocument();
- });
-
- it("renders the first team option when includeAllTeams is false and when no selectedTeamId is given", () => {
- render(
-
- );
-
- const selectedTeam = screen.getByText("Team 1");
- expect(selectedTeam).toBeInTheDocument();
- });
-
- describe("user is on the global team", () => {
- const contextValue = {
- isOnGlobalTeam: true,
- };
-
- it("renders 'All fleets' when no selectedTeamId is given", () => {
- renderWithAppContext(
- ,
- { contextValue }
- );
-
- const selectedTeam = screen.getByText("All fleets");
- expect(selectedTeam).toBeInTheDocument();
- });
-
- it("renders the first team option when includeAllTeams is false and when no selectedTeamId is given", () => {
- renderWithAppContext(
- ,
- { contextValue }
- );
-
- const selectedTeam = screen.getByText("Team 1");
- expect(selectedTeam).toBeInTheDocument();
- });
- });
-
- describe("user is not on the global team", () => {
- const contextValue = { isOnGlobalTeam: false };
- const filteredUserTeams = USER_TEAMS.filter(
- (t) => t.id > APP_CONTEXT_NO_TEAM_ID
- );
-
- it("renders the first team when no selectedTeamId is given", () => {
- renderWithAppContext(
- ,
- { contextValue }
- );
-
- expect(screen.getByText("Team 1")).toBeInTheDocument();
- });
- });
-});
diff --git a/frontend/components/TeamsDropdown/TeamsDropdown.tsx b/frontend/components/TeamsDropdown/TeamsDropdown.tsx
deleted file mode 100644
index 2d5cf3d1d0..0000000000
--- a/frontend/components/TeamsDropdown/TeamsDropdown.tsx
+++ /dev/null
@@ -1,318 +0,0 @@
-import React, { useMemo } from "react";
-import Select, {
- components,
- DropdownIndicatorProps,
- GroupBase,
- OptionProps,
- StylesConfig,
-} from "react-select-5";
-
-import { COLORS } from "styles/var/colors";
-import { PADDING } from "styles/var/padding";
-import { FONT_SIZES, FONT_WEIGHTS } from "styles/var/fonts";
-
-import classnames from "classnames";
-
-import { IDropdownOption } from "interfaces/dropdownOption";
-import {
- APP_CONTEXT_ALL_TEAMS_SUMMARY,
- ITeamSummary,
- APP_CONTEXT_NO_TEAM_SUMMARY,
-} from "interfaces/team";
-
-import Icon from "components/Icon";
-
-export interface INumberDropdownOption extends Omit {
- value: number; // Redefine the value property to be just number
-}
-
-const generateDropdownOptions = (
- teams: ITeamSummary[] | undefined,
- includeAllTeams: boolean,
- includeNoTeams?: boolean
-): INumberDropdownOption[] => {
- if (!teams) {
- return [];
- }
-
- const options: INumberDropdownOption[] = teams.map((team) => ({
- disabled: false,
- label: team.name,
- value: team.id,
- }));
-
- const filtered = options.filter(
- (o) =>
- !(
- (o.label === APP_CONTEXT_NO_TEAM_SUMMARY.name && !includeNoTeams) ||
- (o.label === APP_CONTEXT_ALL_TEAMS_SUMMARY.name && !includeAllTeams)
- )
- );
-
- return filtered;
-};
-
-const getOptionBackgroundColor = (
- state: OptionProps<
- INumberDropdownOption,
- false,
- GroupBase
- >
-) => {
- return state.isFocused ? COLORS["ui-fleet-black-5"] : "transparent";
-};
-
-interface ITeamsDropdownProps {
- currentUserTeams: ITeamSummary[];
- selectedTeamId?: number;
- includeAllTeams?: boolean;
- includeNoTeams?: boolean;
- isDisabled?: boolean;
- onChange: (newSelectedValue: number) => void;
- onOpen?: () => void;
- onClose?: () => void;
- /** Indicates that this teams dropdown should be styled as a form field */
- asFormField?: boolean;
-}
-
-const baseClass = "team-dropdown";
-
-const TeamsDropdown = ({
- currentUserTeams,
- selectedTeamId,
- includeAllTeams = true,
- includeNoTeams = false,
- isDisabled = false,
- onChange,
- onOpen,
- onClose,
- asFormField = false,
-}: ITeamsDropdownProps): JSX.Element => {
- const teamOptions: INumberDropdownOption[] = useMemo(
- () =>
- generateDropdownOptions(
- currentUserTeams,
- includeAllTeams,
- includeNoTeams
- ),
- [currentUserTeams, includeAllTeams, includeNoTeams]
- );
-
- const selectedValue = teamOptions.find(
- (option) => selectedTeamId === option.value
- )
- ? selectedTeamId
- : teamOptions[0]?.value;
-
- const dropdownWrapperClasses = classnames(`${baseClass}-wrapper`, {
- disabled: isDisabled || undefined,
- });
-
- const CustomDropdownIndicator = (
- props: DropdownIndicatorProps<
- INumberDropdownOption,
- false,
- GroupBase
- >
- ) => {
- const { isFocused, selectProps } = props;
- const color =
- isFocused || selectProps.menuIsOpen
- ? "core-fleet-black"
- : "ui-fleet-black-75";
-
- return (
-
-
-
- );
- };
-
- const [variableControlStyles, variableSingleValueStyles] = asFormField
- ? [
- {
- padding: ".5rem 1rem",
- backgroundColor: COLORS["ui-light-grey"],
- },
- {},
- ]
- : [
- {
- padding: "8px 0",
- backgroundColor: "initial",
- border: 0,
- },
- {
- fontSize: "24px",
- },
- ];
-
- // see https://react-select.com/styles#the-styles-prop
- const customStyles: StylesConfig = {
- control: (baseStyles, state) => ({
- ...baseStyles,
- ...variableControlStyles,
- display: "flex",
- flexDirection: "row",
- borderRadius: "4px",
- boxShadow: "none",
- cursor: "pointer",
- "&:hover": {
- boxShadow: "none",
- ".team-dropdown__single-value": {
- color: COLORS["core-fleet-black"],
- },
- ".team-dropdown__indicator path": {
- stroke: COLORS["ui-fleet-black-75-over"],
- },
- },
- // When tabbing
- // Relies on --is-focused for styling as &:focus-visible cannot be applied
- "&.team-dropdown__control--is-focused": {
- ".team-dropdown__indicator path": {
- stroke: COLORS["ui-fleet-black-75-over"],
- },
- },
- ...(state.isDisabled && {
- ".team-dropdown__single-value": {
- color: COLORS["ui-fleet-black-50"],
- },
- ".team-dropdown__indicator path": {
- stroke: COLORS["ui-fleet-black-50"],
- },
- }),
- // When clicking
- "&:active": {
- ".team-dropdown__single-value": {
- color: COLORS["ui-fleet-black-75-down"],
- },
- ".team-dropdown__indicator path": {
- stroke: COLORS["ui-fleet-black-75-down"],
- },
- },
- ...(state.menuIsOpen && {
- ".team-dropdown__indicator svg": {
- transform: "rotate(180deg)",
- transition: "transform 0.25s ease",
- },
- }),
- }),
- singleValue: (baseStyles) => ({
- ...baseStyles,
- ...variableSingleValueStyles,
- color: COLORS["core-fleet-black"],
- lineHeight: "normal",
- paddingLeft: 0,
- paddingRight: "8px",
- margin: 0,
- fontWeight: "600",
- // omit grid-column-end for automatic width
- gridArea: "1/1/2",
- }),
- dropdownIndicator: (baseStyles) => ({
- ...baseStyles,
- display: "flex",
- padding: "2px",
- margin: "0 5px",
- svg: {
- transition: "transform 0.25s ease",
- },
- }),
- menu: (baseStyles) => ({
- ...baseStyles,
- backgroundColor: COLORS["core-fleet-white"],
- boxShadow: `0 2px 6px rgba(0, 0, 0, 0.1), 0 0 0 1px ${COLORS["ui-fleet-black-10"]}`,
- borderRadius: "4px",
- zIndex: 6,
- overflow: "hidden",
- border: 0,
- marginTop: 0,
- minWidth: "330px",
- maxHeight: "none",
- position: "absolute",
- left: "0",
- animation: "fade-in 150ms ease-out",
- }),
- // Placeholder is never shown on teams dropdown
- menuList: (baseStyles) => ({
- ...baseStyles,
- padding: PADDING["pad-small"],
- ".team-dropdown__menu-notice--no-options": {
- textAlign: "left",
- color: COLORS["ui-fleet-black-50"],
- fontSize: FONT_SIZES["xx-small"],
- fontWeight: FONT_WEIGHTS.regular,
- },
- }),
- valueContainer: (baseStyles) => ({
- ...baseStyles,
- padding: 0,
- }),
- input: (baseStyles) => ({
- ...baseStyles,
- overflow: "hidden",
- textOverflow: "ellipsis",
- whiteSpace: "nowrap",
- margin: 0,
- color: COLORS["core-fleet-black"],
- }),
- option: (baseStyles, state) => ({
- ...baseStyles,
- padding: "10px 8px",
- fontSize: "13px",
- borderRadius: "4px",
- backgroundColor: getOptionBackgroundColor(state),
- fontWeight: state.isSelected ? "600" : "normal",
- color: COLORS["core-fleet-black"],
- "&:hover": {
- backgroundColor: state.isDisabled
- ? "transparent"
- : COLORS["ui-fleet-black-5"],
- },
- "&:active": {
- backgroundColor: state.isDisabled
- ? "transparent"
- : COLORS["ui-fleet-black-5"],
- },
- ...(state.isDisabled && {
- color: COLORS["ui-fleet-black-50"],
- fontStyle: "italic",
- }),
- }),
- };
-
- return (
-
-
- );
-};
-
-export default TeamsDropdown;
diff --git a/frontend/components/TeamsDropdown/_styles.scss b/frontend/components/TeamsDropdown/_styles.scss
deleted file mode 100644
index 12bfc4e089..0000000000
--- a/frontend/components/TeamsDropdown/_styles.scss
+++ /dev/null
@@ -1 +0,0 @@
-// All styling in customStyles part of react-select-5
diff --git a/frontend/components/TeamsDropdown/index.tsx b/frontend/components/TeamsDropdown/index.tsx
deleted file mode 100644
index 2006101341..0000000000
--- a/frontend/components/TeamsDropdown/index.tsx
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from "./TeamsDropdown";
diff --git a/frontend/components/TeamsHeader/TeamsHeader.tsx b/frontend/components/TeamsHeader/TeamsHeader.tsx
index 72edca3830..7d46dbbe73 100644
--- a/frontend/components/TeamsHeader/TeamsHeader.tsx
+++ b/frontend/components/TeamsHeader/TeamsHeader.tsx
@@ -2,7 +2,7 @@ import React from "react";
import { ITeamSummary } from "interfaces/team";
-import TeamsDropdown from "components/TeamsDropdown";
+import FleetsDropdown from "components/FleetsDropdown";
interface ITeamsHeader {
isOnGlobalTeam?: boolean;
@@ -20,11 +20,11 @@ const TeamsHeader = ({
if (userTeams) {
if (userTeams.length > 1 || isOnGlobalTeam) {
return (
-
);
}
diff --git a/frontend/docs/patterns.md b/frontend/docs/patterns.md
index 6739cad21d..3fca49fa4c 100644
--- a/frontend/docs/patterns.md
+++ b/frontend/docs/patterns.md
@@ -456,7 +456,7 @@ There's also a `PRIMO_TOOLTIP` constant in `utilities/constants.tsx` for disable
#### What it affects
- **"Create fleet" button**: disabled on ManageFleetsPage
-- **Fleet switcher**: hidden (both the page `TeamsDropdown` header and the command palette fleet picker)
+- **Fleet switcher**: hidden (both the page `FleetsDropdown` header and the command palette fleet picker)
- **Selected fleet**: `useTeamIdParam` defaults to "Unassigned" instead of "All fleets"
- **Empty states**: skip the fleet-scoped copy premium normally shows, falling back to the generic header that free tier already uses (e.g., "No policies yet" instead of "No policies for this fleet" or "No policies apply to all fleets")
- **User form**: fleets dropdown disabled
diff --git a/frontend/pages/DashboardPage/DashboardPage.tsx b/frontend/pages/DashboardPage/DashboardPage.tsx
index 2f9bf3fac3..fc7a038f05 100644
--- a/frontend/pages/DashboardPage/DashboardPage.tsx
+++ b/frontend/pages/DashboardPage/DashboardPage.tsx
@@ -52,7 +52,7 @@ import {
import { ITableQueryData } from "components/TableContainer/TableContainer";
-import TeamsDropdown from "components/TeamsDropdown";
+import FleetsDropdown from "components/FleetsDropdown";
import Spinner from "components/Spinner";
import CustomLink from "components/CustomLink";
import { SingleValue } from "react-select-5";
@@ -907,9 +907,9 @@ const DashboardPage = ({ router, location }: IDashboardProps): JSX.Element => {
if (userTeams) {
if (userTeams.length > 1 || isOnGlobalTeam) {
return (
-
);
diff --git a/frontend/pages/DashboardPage/cards/ActivityFeed/components/ActivityTypeDropdown/_styles.scss b/frontend/pages/DashboardPage/cards/ActivityFeed/components/ActivityTypeDropdown/_styles.scss
index 0a3dc5f0ff..d425e9c1ea 100644
--- a/frontend/pages/DashboardPage/cards/ActivityFeed/components/ActivityTypeDropdown/_styles.scss
+++ b/frontend/pages/DashboardPage/cards/ActivityFeed/components/ActivityTypeDropdown/_styles.scss
@@ -13,36 +13,7 @@
}
&__search-input {
- width: 100%;
- line-height: $line-height;
- background-color: $core-fleet-white;
- border: solid 1px $ui-fleet-black-10;
- border-radius: $border-radius;
- font-size: $small;
- padding: 9.5px 12px 9.5px 36px;
- color: $core-fleet-blue;
- font-family: "Inter", sans-serif;
- font-size: $x-small;
- box-sizing: border-box;
- height: 36px;
-
- &::placeholder {
- color: $ui-fleet-black-50;
- }
-
- &:focus,
- &:hover {
- outline: none;
- border-color: $ui-fleet-black-75;
-
- + .icon {
- svg {
- path {
- fill: $ui-fleet-black-75;
- }
- }
- }
- }
+ @include menu-search-input;
&--disabled {
color: $ui-fleet-black-50;
diff --git a/frontend/pages/ManageControlsPage/ManageControlsPage.tsx b/frontend/pages/ManageControlsPage/ManageControlsPage.tsx
index 3293aedfd7..32a82e0e84 100644
--- a/frontend/pages/ManageControlsPage/ManageControlsPage.tsx
+++ b/frontend/pages/ManageControlsPage/ManageControlsPage.tsx
@@ -10,7 +10,7 @@ import useTeamIdParam from "hooks/useTeamIdParam";
import TabNav from "components/TabNav";
import TabText from "components/TabText";
import MainContent from "components/MainContent";
-import TeamsDropdown from "components/TeamsDropdown";
+import FleetsDropdown from "components/FleetsDropdown";
import { parseOSUpdatesCurrentVersionsQueryParams } from "./OSUpdates/components/CurrentVersionSection/CurrentVersionSection";
interface IControlsSubNavItem {
@@ -217,12 +217,12 @@ const ManageControlsPage = ({
if (isPremiumTier && !config?.partnerships?.enable_primo && userTeams) {
if (userTeams.length > 1 || isOnGlobalTeam) {
return (
-
);
}
diff --git a/frontend/pages/SoftwarePage/SoftwareLibrary/SelfServiceCategoriesPage/SelfServiceCategoriesPage.tests.tsx b/frontend/pages/SoftwarePage/SoftwareLibrary/SelfServiceCategoriesPage/SelfServiceCategoriesPage.tests.tsx
index c1025c6aff..ba2eebe469 100644
--- a/frontend/pages/SoftwarePage/SoftwareLibrary/SelfServiceCategoriesPage/SelfServiceCategoriesPage.tests.tsx
+++ b/frontend/pages/SoftwarePage/SoftwareLibrary/SelfServiceCategoriesPage/SelfServiceCategoriesPage.tests.tsx
@@ -89,10 +89,10 @@ describe("SelfServiceCategoriesPage", () => {
expect(
screen.getByText("This feature is included in Fleet Premium.")
).toBeInTheDocument();
- // Fleet Free has no concept of teams — the dropdown must be hidden, and
+ // Fleet Free has no concept of fleets — the dropdown must be hidden, and
// a static page title takes its place.
expect(
- container.querySelector(".team-dropdown-wrapper")
+ container.querySelector(".fleet-dropdown-wrapper")
).not.toBeInTheDocument();
expect(
screen.getByRole("heading", { level: 1, name: "Self-service categories" })
diff --git a/frontend/pages/SoftwarePage/SoftwareLibrary/SelfServiceCategoriesPage/SelfServiceCategoriesPage.tsx b/frontend/pages/SoftwarePage/SoftwareLibrary/SelfServiceCategoriesPage/SelfServiceCategoriesPage.tsx
index 464fd50867..9f1870fb64 100644
--- a/frontend/pages/SoftwarePage/SoftwareLibrary/SelfServiceCategoriesPage/SelfServiceCategoriesPage.tsx
+++ b/frontend/pages/SoftwarePage/SoftwareLibrary/SelfServiceCategoriesPage/SelfServiceCategoriesPage.tsx
@@ -22,7 +22,7 @@ import MainContent from "components/MainContent";
import PageDescription from "components/PageDescription";
import PremiumFeatureMessage from "components/PremiumFeatureMessage";
import Spinner from "components/Spinner";
-import TeamsDropdown from "components/TeamsDropdown";
+import FleetsDropdown from "components/FleetsDropdown";
import TooltipTruncatedText from "components/TooltipTruncatedText";
import UploadList from "components/UploadList";
@@ -143,12 +143,12 @@ const SelfServiceCategoriesPage = ({
{isPremiumTier && !isPrimoMode ? (
-
) : (
diff --git a/frontend/pages/SoftwarePage/SoftwareLibrary/SelfServiceCategoriesPage/_styles.scss b/frontend/pages/SoftwarePage/SoftwareLibrary/SelfServiceCategoriesPage/_styles.scss
index ed3f601e4b..6e5ba0b1f9 100644
--- a/frontend/pages/SoftwarePage/SoftwareLibrary/SelfServiceCategoriesPage/_styles.scss
+++ b/frontend/pages/SoftwarePage/SoftwareLibrary/SelfServiceCategoriesPage/_styles.scss
@@ -5,7 +5,7 @@
&__fleet-row {
align-self: stretch;
- .team-dropdown-wrapper {
+ .fleet-dropdown-wrapper {
@include normalize-team-header;
}
}
diff --git a/frontend/pages/SoftwarePage/SoftwareOSDetailsPage/_styles.scss b/frontend/pages/SoftwarePage/SoftwareOSDetailsPage/_styles.scss
index bd7f635e7a..dbf63bfad0 100644
--- a/frontend/pages/SoftwarePage/SoftwareOSDetailsPage/_styles.scss
+++ b/frontend/pages/SoftwarePage/SoftwareOSDetailsPage/_styles.scss
@@ -1,7 +1,7 @@
.software-os-details-page {
@include vertical-page-layout;
- .team-dropdown-wrapper {
+ .fleet-dropdown-wrapper {
@include normalize-team-header;
}
diff --git a/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/_styles.scss b/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/_styles.scss
index 01e9730b69..d038655bc6 100644
--- a/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/_styles.scss
+++ b/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/_styles.scss
@@ -1,7 +1,7 @@
.software-title-details-page {
@include vertical-page-layout;
- .team-dropdown-wrapper {
+ .fleet-dropdown-wrapper {
@include normalize-team-header;
}
diff --git a/frontend/pages/SoftwarePage/SoftwareVersionDetailsPage/_styles.scss b/frontend/pages/SoftwarePage/SoftwareVersionDetailsPage/_styles.scss
index 4e70917c25..8168ad74c3 100644
--- a/frontend/pages/SoftwarePage/SoftwareVersionDetailsPage/_styles.scss
+++ b/frontend/pages/SoftwarePage/SoftwareVersionDetailsPage/_styles.scss
@@ -1,7 +1,7 @@
.software-version-details-page {
@include vertical-page-layout;
- .team-dropdown-wrapper {
+ .fleet-dropdown-wrapper {
@include normalize-team-header;
}
diff --git a/frontend/pages/SoftwarePage/SoftwareVulnerabilityDetailsPage/_styles.scss b/frontend/pages/SoftwarePage/SoftwareVulnerabilityDetailsPage/_styles.scss
index b42948cac2..bca98258a1 100644
--- a/frontend/pages/SoftwarePage/SoftwareVulnerabilityDetailsPage/_styles.scss
+++ b/frontend/pages/SoftwarePage/SoftwareVulnerabilityDetailsPage/_styles.scss
@@ -1,7 +1,7 @@
.software-vulnerability-details-page {
@include vertical-page-layout;
- .team-dropdown-wrapper {
+ .fleet-dropdown-wrapper {
@include normalize-team-header;
}
diff --git a/frontend/pages/admin/ManageFleetsPage/TeamDetailsWrapper/TeamDetailsWrapper.tsx b/frontend/pages/admin/ManageFleetsPage/TeamDetailsWrapper/TeamDetailsWrapper.tsx
index fe58613274..7acf986235 100644
--- a/frontend/pages/admin/ManageFleetsPage/TeamDetailsWrapper/TeamDetailsWrapper.tsx
+++ b/frontend/pages/admin/ManageFleetsPage/TeamDetailsWrapper/TeamDetailsWrapper.tsx
@@ -26,7 +26,7 @@ import Spinner from "components/Spinner";
import TabNav from "components/TabNav";
import TabText from "components/TabText";
import BackButton from "components/BackButton";
-import TeamsDropdown from "components/TeamsDropdown";
+import FleetsDropdown from "components/FleetsDropdown";
import MainContent from "components/MainContent";
import { notify } from "components/ToastNotification";
import DeleteFleetModal from "../components/DeleteFleetModal";
@@ -402,11 +402,11 @@ const TeamDetailsWrapper = ({
{userTeams?.length === 1 ? (
{currentTeamDetails.name}
) : (
-
)}
diff --git a/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx b/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx
index acf379530a..076eef4bac 100644
--- a/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx
+++ b/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx
@@ -96,7 +96,7 @@ import { ITableQueryData } from "components/TableContainer/TableContainer";
import TableCount from "components/TableContainer/TableCount";
import DataError from "components/DataError";
import { IActionButtonProps } from "components/TableContainer/DataTable/ActionButton/ActionButton";
-import TeamsDropdown from "components/TeamsDropdown";
+import FleetsDropdown from "components/FleetsDropdown";
import Spinner from "components/Spinner";
import MainContent from "components/MainContent";
import EmptyState from "components/EmptyState";
@@ -1594,11 +1594,11 @@ const ManageHostsPage = ({
if (isPremiumTier && !isPrimoMode && userTeams) {
if (userTeams.length > 1 || isOnGlobalTeam) {
return (
-
);
}
diff --git a/frontend/pages/hosts/details/cards/Software/SelfService/components/CategoryFilter/_styles.scss b/frontend/pages/hosts/details/cards/Software/SelfService/components/CategoryFilter/_styles.scss
index 745c6714fb..6459ea6045 100644
--- a/frontend/pages/hosts/details/cards/Software/SelfService/components/CategoryFilter/_styles.scss
+++ b/frontend/pages/hosts/details/cards/Software/SelfService/components/CategoryFilter/_styles.scss
@@ -61,34 +61,6 @@
}
&__search-input {
- width: 100%;
- line-height: $line-height;
- background-color: $core-fleet-white;
- border: solid 1px $ui-fleet-black-10;
- border-radius: $border-radius;
- padding: 9.5px 12px 9.5px 36px;
- color: $core-fleet-black;
- font-family: "Inter", sans-serif;
- font-size: $x-small;
- box-sizing: border-box;
- height: 36px;
-
- &::placeholder {
- color: $ui-fleet-black-50;
- }
-
- &:focus,
- &:hover {
- outline: none;
- border-color: $ui-fleet-black-75;
-
- + .icon {
- svg {
- path {
- fill: $ui-fleet-black-75;
- }
- }
- }
- }
+ @include menu-search-input;
}
}
diff --git a/frontend/pages/policies/ManagePoliciesPage/ManagePoliciesPage.tsx b/frontend/pages/policies/ManagePoliciesPage/ManagePoliciesPage.tsx
index 8c15186942..65ec106f88 100644
--- a/frontend/pages/policies/ManagePoliciesPage/ManagePoliciesPage.tsx
+++ b/frontend/pages/policies/ManagePoliciesPage/ManagePoliciesPage.tsx
@@ -55,7 +55,7 @@ import { SingleValue } from "react-select-5";
import DropdownWrapper from "components/forms/fields/DropdownWrapper";
import { CustomOptionType } from "components/forms/fields/DropdownWrapper/DropdownWrapper";
import Spinner from "components/Spinner";
-import TeamsDropdown from "components/TeamsDropdown";
+import FleetsDropdown from "components/FleetsDropdown";
import TableDataError from "components/DataError";
import MainContent from "components/MainContent";
import PageDescription from "components/PageDescription";
@@ -963,11 +963,11 @@ const ManagePolicyPage = ({
if (isPremiumTier && !isPrimoMode) {
if ((userTeams && userTeams.length > 1) || isOnGlobalTeam) {
return (
-
);
}
diff --git a/frontend/pages/queries/ManageQueriesPage/ManageQueriesPage.tsx b/frontend/pages/queries/ManageQueriesPage/ManageQueriesPage.tsx
index 2968cb2ff6..36e310e319 100644
--- a/frontend/pages/queries/ManageQueriesPage/ManageQueriesPage.tsx
+++ b/frontend/pages/queries/ManageQueriesPage/ManageQueriesPage.tsx
@@ -37,7 +37,7 @@ import Button from "components/buttons/Button";
import AutomationsButton from "components/buttons/AutomationsButton";
import TableDataError from "components/DataError";
import MainContent from "components/MainContent";
-import TeamsDropdown from "components/TeamsDropdown";
+import FleetsDropdown from "components/FleetsDropdown";
import useTeamIdParam from "hooks/useTeamIdParam";
import TooltipWrapper from "components/TooltipWrapper";
import QueriesTable from "./components/QueriesTable";
@@ -282,9 +282,9 @@ const ManageQueriesPage = ({
if (isPremiumTier && userTeams && !config?.partnerships?.enable_primo) {
if (userTeams.length > 1 || isOnGlobalTeam) {
return (
-
);
diff --git a/frontend/pages/queries/edit/components/SaveAsNewQueryModal/SaveAsNewQueryModal.tsx b/frontend/pages/queries/edit/components/SaveAsNewQueryModal/SaveAsNewQueryModal.tsx
index 3caa6741b9..97e787b934 100644
--- a/frontend/pages/queries/edit/components/SaveAsNewQueryModal/SaveAsNewQueryModal.tsx
+++ b/frontend/pages/queries/edit/components/SaveAsNewQueryModal/SaveAsNewQueryModal.tsx
@@ -25,7 +25,7 @@ import {
import Modal from "components/Modal";
import Button from "components/buttons/Button";
import InputField from "components/forms/fields/InputField";
-import TeamsDropdown from "components/TeamsDropdown";
+import FleetsDropdown from "components/FleetsDropdown";
import { useTeamIdParam } from "hooks/useTeamIdParam";
const baseClass = "save-as-new-query-modal";
@@ -201,10 +201,10 @@ const SaveAsNewQueryModal = ({
{isPremiumTier && (userTeams?.length || 0) > 1 && (
diff --git a/frontend/styles/var/mixins.scss b/frontend/styles/var/mixins.scss
index bc834af172..3ec9315cda 100644
--- a/frontend/styles/var/mixins.scss
+++ b/frontend/styles/var/mixins.scss
@@ -475,3 +475,36 @@ $max-width: 2560px;
background-repeat: no-repeat;
background-color: $core-fleet-white; // area below gradient — transitionable
}
+
+// Shared styling for a search input rendered inside a dropdown menu (icon on
+// the left, 36px tall, Fleet-black-10 border). Used by FleetsDropdown,
+// CategoryFilter, and ActivityTypeDropdown.
+// TODO: extend Fleet's SearchField / InputFieldWithIcon to cover this
+// pattern — out of scope for the FleetsDropdown rework.
+@mixin menu-search-input {
+ width: 100%;
+ height: 36px;
+ box-sizing: border-box;
+ padding: 9.5px 12px 9.5px 36px;
+ line-height: $line-height;
+ font-family: "Inter", sans-serif;
+ font-size: $x-small;
+ color: $core-fleet-black;
+ background-color: $core-fleet-white;
+ border: solid 1px $ui-fleet-black-10;
+ border-radius: $border-radius;
+
+ &::placeholder {
+ color: $ui-fleet-black-50;
+ }
+
+ &:hover,
+ &:focus {
+ outline: none;
+ border-color: $ui-fleet-black-75;
+
+ + .icon svg path {
+ fill: $ui-fleet-black-75;
+ }
+ }
+}