Fix UI bugs for users that are observers on one team and admin or maintainer on another team (#11230)

This commit is contained in:
gillespi314
2023-04-18 15:11:05 -05:00
committed by GitHub
parent caab837a5f
commit 91b6dbb869
7 changed files with 102 additions and 18 deletions
+5
View File
@@ -0,0 +1,5 @@
- Fixed bug in manage hosts table where UI elements related to row selection were displayed to a team
observer user when that user was also a team and maintainer or admin on another team.
- Fixed bug in add policy UI where a user that is team maintainer or team admin cannot access the UI
to save a new policy if that user is also an observer on another team.
+26 -3
View File
@@ -3,6 +3,7 @@ import { InjectedRouter } from "react-router";
import { findLastIndex, trimStart } from "lodash";
import { AppContext } from "context/app";
import { TableContext } from "context/table";
import {
API_NO_TEAM_ID,
API_ALL_TEAMS_ID,
@@ -103,16 +104,23 @@ const getDefaultTeam = ({
if (!currentUser || !userTeams?.length) {
return undefined;
}
let defaultTeam: ITeamSummary | undefined;
if (permissions.isOnGlobalTeam(currentUser)) {
let defaultTeam: ITeamSummary | undefined;
if (includeAllTeams) {
defaultTeam = userTeams.find((t) => t.id === APP_CONTEXT_ALL_TEAMS_ID);
}
if (!defaultTeam && includeNoTeam) {
defaultTeam = userTeams.find((t) => t.id === APP_CONTEXT_NO_TEAM_ID);
}
return defaultTeam || userTeams.find((t) => t.id > APP_CONTEXT_NO_TEAM_ID);
}
return defaultTeam || userTeams.find((t) => t.id > APP_CONTEXT_NO_TEAM_ID);
return (
userTeams.find((t) => permissions.isTeamAdmin(currentUser, t.id)) ||
userTeams.find((t) => permissions.isTeamMaintainer(currentUser, t.id)) ||
userTeams.find((t) => t.id > APP_CONTEXT_NO_TEAM_ID)
);
};
const getTeamIdForApi = ({
@@ -201,6 +209,7 @@ export const useTeamIdParam = ({
includeAllTeams,
includeNoTeam,
permittedAccessByTeamRole,
resetSelectedRowsOnTeamChange = true,
}: {
location?: {
pathname: string;
@@ -212,6 +221,7 @@ export const useTeamIdParam = ({
includeAllTeams: boolean;
includeNoTeam: boolean;
permittedAccessByTeamRole?: Record<IUserRole, boolean>;
resetSelectedRowsOnTeamChange?: boolean;
}) => {
const { hash, pathname, query, search } = location;
const {
@@ -223,6 +233,8 @@ export const useTeamIdParam = ({
setCurrentTeam: setContextTeam,
} = useContext(AppContext);
const { setResetSelectedRows } = useContext(TableContext);
const userTeams = useMemo(
() =>
getUserTeams({ currentUser, availableTeams, permittedAccessByTeamRole }),
@@ -248,13 +260,24 @@ export const useTeamIdParam = ({
const handleTeamChange = useCallback(
(teamId: number) => {
if (resetSelectedRowsOnTeamChange) {
setResetSelectedRows(true);
}
router.replace(
pathname
.concat(rebuildQueryStringWithTeamId(search, teamId))
.concat(hash || "")
);
},
[pathname, search, hash, router]
[
resetSelectedRowsOnTeamChange,
router,
pathname,
search,
hash,
setResetSelectedRows,
]
);
// reconcile router location and redirect to default team as applicable
@@ -123,14 +123,11 @@ const ManageHostsPage = ({
const routeTemplate = route?.path ?? "";
const queryParams = location.query;
const {
availableTeams,
config,
currentUser,
filteredHostsPath,
isGlobalAdmin,
isGlobalMaintainer,
isTeamMaintainer,
isTeamAdmin,
isOnGlobalTeam,
isOnlyObserver,
isPremiumTier,
@@ -147,7 +144,11 @@ const ManageHostsPage = ({
currentTeamName,
isAnyTeamSelected,
isRouteOk,
isTeamAdmin,
isTeamMaintainer,
isTeamMaintainerOrTeamAdmin,
teamIdForApi,
userTeams,
handleTeamChange,
} = useTeamIdParam({
location,
@@ -1001,7 +1002,7 @@ const ManageHostsPage = ({
const renderTeamsFilterDropdown = () => (
<TeamsDropdown
currentUserTeams={availableTeams || []}
currentUserTeams={userTeams || []}
selectedTeamId={currentTeamId}
isDisabled={isLoadingHosts || isLoadingHostsCount} // TODO: why?
onChange={onTeamChange}
@@ -1120,13 +1121,13 @@ const ManageHostsPage = ({
<div className={`${baseClass}__title`}>
{isFreeTier && <h1>Hosts</h1>}
{isPremiumTier &&
availableTeams &&
(availableTeams.length > 1 || isOnGlobalTeam) &&
userTeams &&
(userTeams.length > 1 || isOnGlobalTeam) &&
renderTeamsFilterDropdown()}
{isPremiumTier &&
!isOnGlobalTeam &&
availableTeams &&
availableTeams.length === 1 && <h1>{availableTeams[0].name}</h1>}
userTeams &&
userTeams.length === 1 && <h1>{userTeams[0].name}</h1>}
</div>
</div>
</div>
@@ -1340,7 +1341,8 @@ const ManageHostsPage = ({
const tableColumns = generateVisibleTableColumns({
hiddenColumns,
isFreeTier,
isOnlyObserver,
isOnlyObserver:
isOnlyObserver || (!isOnGlobalTeam && !isTeamMaintainerOrTeamAdmin),
});
// Update last column
@@ -48,13 +48,17 @@ const AddPolicyModal = ({
setLastEditedQueryCritical(selectedPolicy.critical || false);
setPolicyTeamId(teamId);
setLastEditedQueryPlatform(selectedPolicy.platform || null);
router.push(PATHS.NEW_POLICY);
router.push(
!teamId ? PATHS.NEW_POLICY : `${PATHS.NEW_POLICY}?team_id=${teamId}`
);
};
const onCreateYourOwnPolicyClick = useCallback(() => {
setPolicyTeamId(teamId);
setLastEditedQueryBody(DEFAULT_POLICY.query);
router.push(PATHS.NEW_POLICY);
router.push(
!teamId ? PATHS.NEW_POLICY : `${PATHS.NEW_POLICY}?team_id=${teamId}`
);
}, [router, setLastEditedQueryBody, setPolicyTeamId, teamId]);
const policiesAvailable = DEFAULT_POLICIES.map((policy: IPolicyNew) => {
@@ -26,6 +26,7 @@ import QueryEditor from "pages/policies/PolicyPage/screens/QueryEditor";
import SelectTargets from "components/LiveQuery/SelectTargets";
import MainContent from "components/MainContent";
import SidePanelContent from "components/SidePanelContent";
import Spinner from "components/Spinner/Spinner";
import CustomLink from "components/CustomLink";
import RunQuery from "pages/policies/PolicyPage/screens/RunQuery";
import { DEFAULT_POLICY } from "pages/policies/constants";
@@ -57,6 +58,7 @@ const PolicyPage = ({
} = useContext(AppContext);
const {
lastEditedQueryBody,
policyTeamId,
selectedOsqueryTable,
setSelectedOsqueryTable,
setLastEditedQueryId,
@@ -69,7 +71,13 @@ const PolicyPage = ({
setPolicyTeamId,
} = useContext(PolicyContext);
const { isRouteOk, teamIdForApi } = useTeamIdParam({
const {
isRouteOk,
isTeamAdmin,
isTeamMaintainer,
isTeamObserver,
teamIdForApi,
} = useTeamIdParam({
location,
router,
includeAllTeams: true,
@@ -82,6 +90,29 @@ const PolicyPage = ({
},
});
// // TODO(Sarah): What should happen if a user without save permissions tries to directly navigate
// // to the new policy page? Should we redirect to the manage policies page?
// const hasSavePermissions =
// isGlobalAdmin || isGlobalMaintainer || isTeamAdmin || isTeamMaintainer;
//
// useEffect(() => {
// if (!isRouteOk) {
// return;
// }
// if (trimEnd(location.pathname, "/").endsWith("/new")) {
// !hasSavePermissions && router.push(paths.MANAGE_POLICIES);
// }
// }, [hasSavePermissions, isRouteOk, location.pathname, router]);
useEffect(() => {
if (!isRouteOk) {
return;
}
if (policyTeamId !== teamIdForApi) {
setPolicyTeamId(teamIdForApi || 0);
}
}, [isRouteOk, teamIdForApi, policyTeamId, setPolicyTeamId]);
useEffect(() => {
if (lastEditedQueryBody === "") {
setLastEditedQueryBody(DEFAULT_POLICY.query);
@@ -220,6 +251,9 @@ const PolicyPage = ({
showOpenSchemaActionText,
storedPolicy,
isStoredPolicyLoading,
isTeamAdmin,
isTeamMaintainer,
isTeamObserver,
storedPolicyError,
createPolicy,
onOsqueryTableSelect,
@@ -268,6 +302,10 @@ const PolicyPage = ({
isSidebarOpen &&
(isGlobalAdmin || isGlobalMaintainer || isAnyTeamMaintainerOrTeamAdmin);
if (!isRouteOk) {
return <Spinner />;
}
return (
<>
<MainContent className={baseClass}>
@@ -38,6 +38,9 @@ interface IPolicyFormProps {
showOpenSchemaActionText: boolean;
storedPolicy: IPolicy | undefined;
isStoredPolicyLoading: boolean;
isTeamAdmin: boolean;
isTeamMaintainer: boolean;
isTeamObserver: boolean;
isUpdatingPolicy: boolean;
onCreatePolicy: (formData: IPolicyFormData) => void;
onOsqueryTableSelect: (tableName: string) => void;
@@ -65,6 +68,9 @@ const PolicyForm = ({
showOpenSchemaActionText,
storedPolicy,
isStoredPolicyLoading,
isTeamAdmin,
isTeamMaintainer,
isTeamObserver,
isUpdatingPolicy,
onCreatePolicy,
onOsqueryTableSelect,
@@ -103,13 +109,10 @@ const PolicyForm = ({
const {
currentUser,
isTeamObserver,
isGlobalObserver,
isGlobalAdmin,
isGlobalMaintainer,
isOnGlobalTeam,
isTeamAdmin,
isTeamMaintainer,
isPremiumTier,
} = useContext(AppContext);
@@ -22,6 +22,9 @@ interface IQueryEditorProps {
storedPolicyError: Error | null;
showOpenSchemaActionText: boolean;
isStoredPolicyLoading: boolean;
isTeamAdmin: boolean;
isTeamMaintainer: boolean;
isTeamObserver: boolean;
createPolicy: (formData: IPolicyFormData) => Promise<any>;
onOsqueryTableSelect: (tableName: string) => void;
goToSelectTargets: () => void;
@@ -37,6 +40,9 @@ const QueryEditor = ({
storedPolicyError,
showOpenSchemaActionText,
isStoredPolicyLoading,
isTeamAdmin,
isTeamMaintainer,
isTeamObserver,
createPolicy,
onOsqueryTableSelect,
goToSelectTargets,
@@ -189,6 +195,9 @@ const QueryEditor = ({
onOpenSchemaSidebar={onOpenSchemaSidebar}
renderLiveQueryWarning={renderLiveQueryWarning}
backendValidators={backendValidators}
isTeamAdmin={isTeamAdmin}
isTeamMaintainer={isTeamMaintainer}
isTeamObserver={isTeamObserver}
isUpdatingPolicy={isUpdatingPolicy}
/>
</div>