diff --git a/changes/issue-6981-keep-policy-filter-across-team-changes b/changes/issue-6981-keep-policy-filter-across-team-changes
new file mode 100644
index 0000000000..29394340d0
--- /dev/null
+++ b/changes/issue-6981-keep-policy-filter-across-team-changes
@@ -0,0 +1 @@
+- keep policy filter on Manage Hosts Page changes across a team changes
diff --git a/frontend/components/TeamsDropdown/TeamsDropdown.tests.tsx b/frontend/components/TeamsDropdown/TeamsDropdown.tests.tsx
new file mode 100644
index 0000000000..93f427bf90
--- /dev/null
+++ b/frontend/components/TeamsDropdown/TeamsDropdown.tests.tsx
@@ -0,0 +1,82 @@
+import React from "react";
+import { render, screen } from "@testing-library/react";
+import { noop } from "lodash";
+import { renderWithAppContext } from "test/test-utils";
+
+import TeamsDropdown from "./TeamsDropdown";
+
+describe("TeamsDropdown - component", () => {
+ const USER_TEAMS = [
+ { 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 includeAll 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 teams' when no selectedTeamId is given", () => {
+ renderWithAppContext(
+ ,
+ { contextValue }
+ );
+
+ const selectedTeam = screen.getByText("All teams");
+ expect(selectedTeam).toBeInTheDocument();
+ });
+
+ it("renders the first team option when includeAll 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 };
+
+ 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
index a58f7b00d4..30b0f0c883 100644
--- a/frontend/components/TeamsDropdown/TeamsDropdown.tsx
+++ b/frontend/components/TeamsDropdown/TeamsDropdown.tsx
@@ -1,14 +1,14 @@
import React, { useContext, useMemo } from "react";
import classnames from "classnames";
-import { AppContext } from "context/app";
import { ITeamSummary } from "interfaces/team";
// @ts-ignore
import Dropdown from "components/forms/fields/Dropdown";
+import { AppContext } from "context/app";
const generateDropdownOptions = (
teams: ITeamSummary[] | undefined,
- includeAll: boolean | undefined
+ includeAll: boolean
) => {
if (!teams) {
return [];
@@ -30,12 +30,10 @@ const generateDropdownOptions = (
return options;
};
-
interface ITeamsDropdownProps {
currentUserTeams: ITeamSummary[];
- selectedTeamId: number;
- includeAll?: boolean; // Include "All Teams" option for all users
- disableAll?: boolean; // Disable "All Teams" option for global users
+ selectedTeamId?: number;
+ includeAll?: boolean; // Include the "All Teams" option;
isDisabled?: boolean;
onChange: (newSelectedValue: number) => void;
onOpen?: () => void;
@@ -47,22 +45,18 @@ const baseClass = "component__team-dropdown";
const TeamsDropdown = ({
currentUserTeams,
selectedTeamId,
- includeAll = false,
- disableAll = false,
+ includeAll = true,
isDisabled,
onChange,
onOpen,
onClose,
}: ITeamsDropdownProps): JSX.Element => {
- const { isOnGlobalTeam } = useContext(AppContext);
+ const { isOnGlobalTeam = false } = useContext(AppContext);
const teamOptions = useMemo(
() =>
- generateDropdownOptions(
- currentUserTeams,
- (isOnGlobalTeam && !disableAll) || includeAll
- ),
- [currentUserTeams, isOnGlobalTeam]
+ generateDropdownOptions(currentUserTeams, includeAll && isOnGlobalTeam),
+ [currentUserTeams, includeAll, isOnGlobalTeam]
);
const selectedValue = teamOptions.find(
diff --git a/frontend/components/forms/fields/AutoSizeInputField/AutoSizeInputField.tsx b/frontend/components/forms/fields/AutoSizeInputField/AutoSizeInputField.tsx
index a63ae03b16..1ef1d34caa 100644
--- a/frontend/components/forms/fields/AutoSizeInputField/AutoSizeInputField.tsx
+++ b/frontend/components/forms/fields/AutoSizeInputField/AutoSizeInputField.tsx
@@ -24,7 +24,7 @@ interface IAutoSizeInputFieldProps {
const baseClass = "component__auto-size-input-field";
-const TeamsDropdown = ({
+const AutoSizeInputField = ({
name,
placeholder,
value,
@@ -102,4 +102,4 @@ const TeamsDropdown = ({
);
};
-export default TeamsDropdown;
+export default AutoSizeInputField;
diff --git a/frontend/context/app.tsx b/frontend/context/app.tsx
index b693479ec7..c397e67809 100644
--- a/frontend/context/app.tsx
+++ b/frontend/context/app.tsx
@@ -57,32 +57,32 @@ type Props = {
};
type InitialStateType = {
- availableTeams: ITeamSummary[] | undefined;
+ availableTeams?: ITeamSummary[];
config: IConfig | null;
currentUser: IUser | null;
- currentTeam: ITeamSummary | undefined;
+ currentTeam?: ITeamSummary;
enrollSecret: IEnrollSecret[] | null;
- isPreviewMode: boolean | undefined;
- isSandboxMode: boolean | undefined;
- isFreeTier: boolean | undefined;
- isPremiumTier: boolean | undefined;
- isGlobalAdmin: boolean | undefined;
- isGlobalMaintainer: boolean | undefined;
- isGlobalObserver: boolean | undefined;
- isOnGlobalTeam: boolean | undefined;
- isAnyTeamMaintainer: boolean | undefined;
- isAnyTeamMaintainerOrTeamAdmin: boolean | undefined;
- isTeamObserver: boolean | undefined;
- isTeamMaintainer: boolean | undefined;
- isTeamMaintainerOrTeamAdmin: boolean | undefined;
- isAnyTeamAdmin: boolean | undefined;
- isTeamAdmin: boolean | undefined;
- isOnlyObserver: boolean | undefined;
- isNoAccess: boolean | undefined;
+ isPreviewMode?: boolean;
+ isSandboxMode?: boolean;
+ isFreeTier?: boolean;
+ isPremiumTier?: boolean;
+ isGlobalAdmin?: boolean;
+ isGlobalMaintainer?: boolean;
+ isGlobalObserver?: boolean;
+ isOnGlobalTeam?: boolean;
+ isAnyTeamMaintainer?: boolean;
+ isAnyTeamMaintainerOrTeamAdmin?: boolean;
+ isTeamObserver?: boolean;
+ isTeamMaintainer?: boolean;
+ isTeamMaintainerOrTeamAdmin?: boolean;
+ isAnyTeamAdmin?: boolean;
+ isTeamAdmin?: boolean;
+ isOnlyObserver?: boolean;
+ isNoAccess?: boolean;
sandboxExpiry?: string;
setAvailableTeams: (availableTeams: ITeamSummary[]) => void;
setCurrentUser: (user: IUser) => void;
- setCurrentTeam: (team: ITeamSummary | undefined) => void;
+ setCurrentTeam: (team?: ITeamSummary) => void;
setConfig: (config: IConfig) => void;
setEnrollSecret: (enrollSecret: IEnrollSecret[]) => void;
setSandboxExpiry: (sandboxExpiry: string) => void;
@@ -90,7 +90,7 @@ type InitialStateType = {
export type IAppContext = InitialStateType;
-const initialState = {
+export const initialState = {
availableTeams: undefined,
config: null,
currentUser: null,
diff --git a/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/TeamDetailsWrapper.tsx b/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/TeamDetailsWrapper.tsx
index 9206e50dc2..1c54fa78cb 100644
--- a/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/TeamDetailsWrapper.tsx
+++ b/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/TeamDetailsWrapper.tsx
@@ -414,7 +414,7 @@ const TeamDetailsWrapper = ({
selectedTeamId={toNumber(routeParams.team_id)}
currentUserTeams={adminTeams || []}
isDisabled={isLoadingTeams}
- disableAll
+ includeAll={false}
onChange={(newSelectedValue: number) =>
handleTeamSelect(newSelectedValue)
}
diff --git a/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx b/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx
index ef3d1f8661..8a6b478695 100644
--- a/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx
+++ b/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx
@@ -338,13 +338,7 @@ const ManageHostsPage = ({
useQuery(
["policy"],
- () => {
- const teamId = parseInt(queryParams?.team_id, 10) || 0;
- const request = teamId
- ? teamPoliciesAPI.load(teamId, policyId)
- : globalPoliciesAPI.load(policyId);
- return request;
- },
+ () => globalPoliciesAPI.load(policyId),
{
enabled: !!policyId,
onSuccess: ({ policy: policyAPIResponse }) => {
@@ -408,10 +402,6 @@ const ManageHostsPage = ({
}
};
- const getLabelSelected = () => {
- return selectedFilters.find((f) => f.includes(LABEL_SLUG_PREFIX));
- };
-
const getStatusSelected = () => {
return selectedFilters.find((f) => !f.includes(LABEL_SLUG_PREFIX));
};
@@ -714,22 +704,19 @@ const ManageHostsPage = ({
const handleTeamSelect = (teamId: number) => {
const { MANAGE_HOSTS } = PATHS;
+
const teamIdParam = getValidatedTeamId(
availableTeams || [],
teamId,
currentUser,
- isOnGlobalTeam as boolean
+ isOnGlobalTeam ?? false
);
- const slimmerParams = omit(queryParams, [
- "policy_id",
- "policy_response",
- "team_id",
- ]);
+ const slimmerParams = omit(queryParams, ["team_id"]);
const newQueryParams = !teamIdParam
? slimmerParams
- : Object.assign({}, slimmerParams, { team_id: teamIdParam });
+ : Object.assign(slimmerParams, { team_id: teamIdParam });
const nextLocation = getNextLocationPath({
pathPrefix: MANAGE_HOSTS,
@@ -1168,9 +1155,7 @@ const ManageHostsPage = ({
const renderTeamsFilterDropdown = () => (
handleTeamSelect(newSelectedValue)
@@ -1257,7 +1242,7 @@ const ManageHostsPage = ({
/>
diff --git a/frontend/test/test-utils.tsx b/frontend/test/test-utils.tsx
new file mode 100644
index 0000000000..a26af30994
--- /dev/null
+++ b/frontend/test/test-utils.tsx
@@ -0,0 +1,23 @@
+import React from "react";
+import { render, RenderOptions } from "@testing-library/react";
+
+import { AppContext, IAppContext, initialState } from "context/app";
+
+type RenderOptionsWithProviderProps = RenderOptions & {
+ contextValue: Partial;
+};
+
+/**
+ * A custom render method that provides a configurable App context when testing components
+ */
+// eslint-disable-next-line import/prefer-default-export
+export const renderWithAppContext = (
+ component: React.ReactNode,
+ { contextValue, ...renderOptions }: RenderOptionsWithProviderProps
+) => {
+ const value: IAppContext = { ...initialState, ...contextValue };
+ return render(
+ {component},
+ renderOptions
+ );
+};