diff --git a/frontend/pages/policies/ManagePoliciesPage/_styles.scss b/frontend/pages/policies/ManagePoliciesPage/_styles.scss
index 280573d619..4c997acb4a 100644
--- a/frontend/pages/policies/ManagePoliciesPage/_styles.scss
+++ b/frontend/pages/policies/ManagePoliciesPage/_styles.scss
@@ -8,7 +8,6 @@
align-items: center;
justify-content: space-between;
height: 38px;
- margin-bottom: $pad-small;
}
&__header {
@@ -130,7 +129,7 @@
top: 0;
border: 0;
cursor: pointer;
-
+
@include button-variant(
$core-vibrant-blue,
$core-vibrant-blue-over,
diff --git a/frontend/pages/policies/ManagePoliciesPage/components/TeamsDropdown/TeamsDropdown.tsx b/frontend/pages/policies/ManagePoliciesPage/components/TeamsDropdown/TeamsDropdown.tsx
deleted file mode 100644
index 746c8b608f..0000000000
--- a/frontend/pages/policies/ManagePoliciesPage/components/TeamsDropdown/TeamsDropdown.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-import React, { useContext, useMemo } from "react";
-import { isEmpty } from "lodash";
-import { AppContext } from "context/app";
-
-import { ITeam } from "interfaces/team";
-
-// @ts-ignore
-import Dropdown from "components/forms/fields/Dropdown";
-
-const generateDropdownOptions = (
- teams: ITeam[] | undefined,
- includeAll: boolean | undefined
-) => {
- if (!teams) {
- return [];
- }
-
- const options = teams.map((team) => ({
- disabled: false,
- label: team.name,
- value: team.id,
- }));
-
- if (includeAll) {
- options.unshift({
- disabled: false,
- label: "All teams",
- value: 0,
- });
- }
-
- return options;
-};
-
-const TeamsDropdown = (dropdownProps: {
- currentUserTeams: ITeam[];
- onChange: (id: number) => void;
- selectedTeam: number;
-}): JSX.Element => {
- const { currentUserTeams, onChange, selectedTeam } = dropdownProps;
- const { isOnGlobalTeam } = useContext(AppContext);
-
- const dropdownOptions = useMemo(
- () => generateDropdownOptions(currentUserTeams, isOnGlobalTeam),
- [currentUserTeams, isOnGlobalTeam]
- );
-
- const selectedValue = dropdownOptions.find(
- (option) => selectedTeam === option.value
- )
- ? selectedTeam
- : dropdownOptions[0]?.value;
-
- return isEmpty(currentUserTeams) ? (
-
{isTableDataLoading && !fleetQueriesError &&
}
{!isTableDataLoading && fleetQueriesError ? (
diff --git a/frontend/pages/queries/ManageQueriesPage/_styles.scss b/frontend/pages/queries/ManageQueriesPage/_styles.scss
index a453d9cf59..db1dd20546 100644
--- a/frontend/pages/queries/ManageQueriesPage/_styles.scss
+++ b/frontend/pages/queries/ManageQueriesPage/_styles.scss
@@ -1,14 +1,18 @@
.manage-queries-page {
&__header-wrap {
+ height: 38px;
display: flex;
align-items: center;
justify-content: space-between;
- margin-bottom: $pad-xxlarge;
}
&__header {
display: flex;
align-items: center;
+
+ .form-field {
+ margin-bottom: 0;
+ }
}
&__text {
@@ -37,8 +41,7 @@
}
&__description {
- margin: 0 0 $pad-medium;
- padding-top: $pad-xsmall;
+ margin: 0 0 $pad-xxlarge;
h2 {
text-transform: uppercase;
diff --git a/frontend/pages/schedule/ManageSchedulePage/ManageSchedulePage.tsx b/frontend/pages/schedule/ManageSchedulePage/ManageSchedulePage.tsx
index 3615f4caad..a374f47ecc 100644
--- a/frontend/pages/schedule/ManageSchedulePage/ManageSchedulePage.tsx
+++ b/frontend/pages/schedule/ManageSchedulePage/ManageSchedulePage.tsx
@@ -5,7 +5,6 @@ import { useQuery } from "react-query";
import { useDispatch, useSelector } from "react-redux";
import { AppContext } from "context/app";
import { push } from "react-router-redux";
-import { find } from "lodash";
// @ts-ignore
import deepDifference from "utilities/deep_difference";
@@ -20,12 +19,12 @@ import fleetQueriesAPI from "services/entities/queries";
import teamsAPI from "services/entities/teams";
// @ts-ignore
import { renderFlash } from "redux/nodes/notifications/actions";
-import permissionUtils from "utilities/permissions";
+import sortUtils from "utilities/sort";
import paths from "router/paths";
import Button from "components/buttons/Button";
// @ts-ignore
-import Dropdown from "components/forms/fields/Dropdown";
+import TeamsDropdown from "components/TeamsDropdown";
import IconToolTip from "components/IconToolTip";
import TableDataError from "components/TableDataError";
import ScheduleListWrapper from "./components/ScheduleListWrapper";
@@ -117,33 +116,46 @@ interface IFormData {
team_id?: number;
}
-interface ITeamOptions {
- disabled: boolean;
- label: string;
- value: string | number;
-}
-
const ManageSchedulePage = ({
params: { team_id },
- location,
}: ITeamSchedulesPageProps): JSX.Element => {
const dispatch = useDispatch();
const { MANAGE_PACKS, MANAGE_SCHEDULE, MANAGE_TEAM_SCHEDULE } = paths;
const handleAdvanced = () => dispatch(push(MANAGE_PACKS));
- const {
- currentUser,
- isOnGlobalTeam,
- isPremiumTier,
- isAnyTeamMaintainerOrTeamAdmin,
- } = useContext(AppContext);
+ const { currentUser, isOnGlobalTeam, isPremiumTier, isFreeTier } = useContext(
+ AppContext
+ );
- const { data: teams } = useQuery(["teams"], () => teamsAPI.loadAll({}), {
- enabled: !!isPremiumTier,
- select: (data) => data.teams,
- refetchOnMount: false,
- refetchOnWindowFocus: false,
- });
+ const filterAndSortTeamOptions = (allTeams: ITeam[], userTeams: ITeam[]) => {
+ const filteredSortedTeams = allTeams
+ .sort((teamA: ITeam, teamB: ITeam) =>
+ sortUtils.caseInsensitiveAsc(teamA.name, teamB.name)
+ )
+ .filter((team: ITeam) => {
+ const userTeam = userTeams.find(
+ (thisUserTeam) => thisUserTeam.id === team.id
+ );
+ return userTeam?.role !== "observer" ? team : null;
+ });
+
+ return filteredSortedTeams;
+ };
+
+ const { data: teams, isLoading: isLoadingTeams } = useQuery(
+ ["teams"],
+ () => teamsAPI.loadAll({}),
+ {
+ enabled: !!isPremiumTier,
+ select: (data) => {
+ return currentUser?.teams
+ ? filterAndSortTeamOptions(data.teams, currentUser.teams)
+ : data.teams;
+ },
+ refetchOnMount: false,
+ refetchOnWindowFocus: false,
+ }
+ );
const { data: fleetQueries } = useQuery(
["fleetQueries"],
@@ -155,51 +167,18 @@ const ManageSchedulePage = ({
}
);
- let teamId = parseInt(team_id, 10);
+ const teamId = team_id ? parseInt(team_id, 10) : 0;
- // isTeamMaintainerOrTeamAdmin set locally and not in AppContext
- const isTeamMaintainerOrTeamAdmin = (() => {
- return !!permissionUtils.isTeamMaintainerOrTeamAdmin(currentUser, teamId);
- })();
-
- const onChangeSelectedTeam = (selectedTeamId: number) => {
- if (isNaN(selectedTeamId)) {
- dispatch(push(MANAGE_SCHEDULE));
- } else {
+ const handleTeamSelect = (selectedTeamId: number) => {
+ if (selectedTeamId) {
dispatch(push(MANAGE_TEAM_SCHEDULE(selectedTeamId)));
+ } else {
+ dispatch(push(MANAGE_SCHEDULE));
}
};
- const loadFirstMaintainerOrAdminTeam = () => {
- if (currentUser) {
- const adminOrMaintainerTeam = currentUser.teams.find((team) => {
- return team.role === "admin" || team.role === "maintainer"
- ? team.id
- : null;
- });
- if (adminOrMaintainerTeam) {
- teamId = adminOrMaintainerTeam.id;
- onChangeSelectedTeam(teamId);
- }
- }
- };
-
- if (!isOnGlobalTeam && !isTeamMaintainerOrTeamAdmin && !teamId) {
- loadFirstMaintainerOrAdminTeam();
- }
-
- if (!isOnGlobalTeam && !isTeamMaintainerOrTeamAdmin && teamId) {
- if (currentUser) {
- const canLoadTeam = currentUser.teams.find((team) => {
- return (
- (team.role === "admin" || team.role === "maintainer") &&
- team.id === teamId
- );
- });
- if (!canLoadTeam) {
- loadFirstMaintainerOrAdminTeam();
- }
- }
+ if (!isOnGlobalTeam && !teamId && teams) {
+ handleTeamSelect(teams[0].id);
}
// TODO: move team scheduled queries and global scheduled queries into services entities, remove redux
@@ -233,7 +212,7 @@ const ManageSchedulePage = ({
const inheritedQueryOrQueries =
allTeamsScheduledQueriesList.length === 1 ? "query" : "queries";
- const selectedTeam = isNaN(teamId) ? "global" : teamId;
+ const selectedTeam = !teamId ? "global" : teamId;
const selectedTeamData =
teams?.find((team: ITeam) => selectedTeam === team.id) || undefined;
@@ -271,55 +250,6 @@ const ManageSchedulePage = ({
setShowRemoveScheduledQueryModal(!showRemoveScheduledQueryModal);
}, [showRemoveScheduledQueryModal, setShowRemoveScheduledQueryModal]);
- const generateTeamOptionsDropdownItems = (): ITeamOptions[] => {
- const teamOptions: ITeamOptions[] = [];
-
- if (isAnyTeamMaintainerOrTeamAdmin && currentUser) {
- currentUser.teams.forEach((team) => {
- if (team.role === "admin" || team.role === "maintainer") {
- teamOptions.push({
- disabled: false,
- label: team.name,
- value: team.id,
- });
- }
- });
- } else if (isOnGlobalTeam && teams) {
- teamOptions.push({
- disabled: false,
- label: "All teams",
- value: "global",
- });
-
- teams.forEach((team: ITeam) => {
- teamOptions.push({
- disabled: false,
- label: team.name,
- value: team.id,
- });
- });
- }
-
- return teamOptions;
- };
-
- const renderTitleOrDropdown = (): JSX.Element => {
- const dropDownOptions = generateTeamOptionsDropdownItems();
- return dropDownOptions.length === 1 ? (
-
{dropDownOptions[0].label}
- ) : (
-
- onChangeSelectedTeam(newSelectedValue)
- }
- />
- );
- };
-
const onRemoveScheduledQueryClick = (
selectedTableQueryIds: number[]
): void => {
@@ -435,57 +365,33 @@ const ManageSchedulePage = ({
[dispatch, teamId, toggleScheduleEditorModal]
);
- if (selectedTeam === "global" && isTeamMaintainerOrTeamAdmin) {
- const teamMaintainerTeams = generateTeamOptionsDropdownItems();
- if (teamMaintainerTeams.length) {
- dispatch(
- push(MANAGE_TEAM_SCHEDULE(Number(teamMaintainerTeams[0].value)))
- );
- }
- }
-
return (
- {!isPremiumTier ? (
-
-
- Schedule
-
-
-
- Schedule recurring queries for your hosts. Fleet’s query
- schedule lets you add queries which are executed at regular
- intervals.
-
-
+
+
+ {isFreeTier &&
Schedule
}
+ {isPremiumTier && teams && teams.length > 1 && (
+
+ handleTeamSelect(newSelectedValue)
+ }
+ />
+ )}
+ {isPremiumTier && teams && teams.length === 1 && (
+ {teams[0].name}
+ )}
- ) : (
-
- {renderTitleOrDropdown()}
-
- {isNaN(teamId) ? (
-
- Schedule queries to run at regular intervals across{" "}
- all of your hosts.
-
- ) : (
-
- Schedule additional queries for all hosts assigned to this
- team.
-
- )}
-
-
- )}
+
- {/* Hide CTA Buttons if no schedule or schedule error */}
{allScheduledQueriesList.length !== 0 &&
allScheduledQueriesError.length !== 0 && (
- {!isTeamMaintainerOrTeamAdmin && (
+ {isOnGlobalTeam && (
-
- {renderTable(
- onRemoveScheduledQueryClick,
- onEditScheduledQueryClick,
- allScheduledQueriesList,
- allScheduledQueriesError,
- toggleScheduleEditorModal,
- isOnGlobalTeam || false,
- selectedTeamData
+
+ {!isLoadingTeams && (
+
+ {!teamId ? (
+
+ Schedule queries to run at regular intervals across{" "}
+ all of your hosts.
+
+ ) : (
+
+ Schedule queries for{" "}
+ all hosts assigned to this team.
+
+ )}
+
)}
+
+ {!isLoadingTeams &&
+ renderTable(
+ onRemoveScheduledQueryClick,
+ onEditScheduledQueryClick,
+ allScheduledQueriesList,
+ allScheduledQueriesError,
+ toggleScheduleEditorModal,
+ isOnGlobalTeam || false,
+ selectedTeamData
+ )}
+
{/* must use ternary for NaN */}
{teamId && allTeamsScheduledQueriesList.length > 0 ? (
<>
diff --git a/frontend/pages/schedule/ManageSchedulePage/_styles.scss b/frontend/pages/schedule/ManageSchedulePage/_styles.scss
index f453fc4abc..72cb0cc5b7 100644
--- a/frontend/pages/schedule/ManageSchedulePage/_styles.scss
+++ b/frontend/pages/schedule/ManageSchedulePage/_styles.scss
@@ -3,7 +3,7 @@
display: flex;
align-items: center;
justify-content: space-between;
- margin-bottom: $pad-xxlarge;
+ height: 38px;
}
&__header {
@@ -42,7 +42,7 @@
&__description {
margin: 0;
- padding-top: $pad-xsmall;
+ margin-bottom: $pad-xxlarge;
h2 {
text-transform: uppercase;
@@ -86,95 +86,12 @@
}
}
- &__team-dropdown {
- border: 0 !important;
- position: relative;
-
- :hover {
- cursor: pointer !important;
- }
-
- &.is-focused {
- .Select-control {
- border: 0 !important;
- height: 32px;
- }
- }
-
- .Select-menu-outer {
- position: absolute;
- left: -12px;
- border-radius: 6px;
- }
- }
-
.Select.is-open {
.Select-value-label {
color: $core-vibrant-blue !important;
}
}
- &__header {
- .Select-control {
- background-color: #fff;
- border: 0 !important;
- border-radius: none;
- position: none;
- width: max-content; // move select arrow
- height: 20px;
-
- &:hover {
- box-shadow: none;
- }
-
- &:hover .Select-value-label {
- color: $core-vibrant-blue !important;
- }
-
- .Select-arrow-zone {
- padding-left: $pad-small;
-
- .Select-arrow {
- top: 1px !important;
- margin-top: 0 !important;
- }
- }
- .Select-multi-value-wrapper {
- width: max-content; // move select arrow
- height: 20px;
- margin-bottom: $pad-xsmall;
-
- .Select-input {
- display: none !important;
- }
-
- .Select-value {
- position: relative; // move select arrow
- display: inline-block; // move select arrow
- line-height: 28px;
- padding: 0;
- border: 0 !important;
- background-color: #fff !important;
- right: 0;
- left: 0;
- bottom: 0;
- top: 0;
-
- &.is-focused {
- border: 0 !important;
- }
- :hover {
- border: 0 !important;
- }
-
- .Select-value-label {
- font-size: $large !important;
- }
- }
- }
- }
- }
-
&__inherited-queries-button {
margin: $pad-medium 0 0 0;
color: $core-vibrant-blue;
diff --git a/frontend/styles/global/_global.scss b/frontend/styles/global/_global.scss
index f4a260f003..aa1c541959 100644
--- a/frontend/styles/global/_global.scss
+++ b/frontend/styles/global/_global.scss
@@ -49,10 +49,9 @@ a {
}
.body-wrap {
- padding: $pad-xxlarge 30px 0;
+ padding: $pad-xxlarge;
border-radius: 3px;
background-color: $core-white;
- border: solid 1px $core-white;
min-width: 798px;
}