mirror of
https://github.com/fleetdm/fleet
synced 2026-04-21 13:37:30 +00:00
Fleet UI: Policy details page followup (#43324)
This commit is contained in:
parent
fe72a6c1c4
commit
1d96eb2e3d
39 changed files with 337 additions and 160 deletions
3
changes/41753-policy-details-page
Normal file
3
changes/41753-policy-details-page
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
- Fleet UI: Added new policy details page with read-only view of policy information
|
||||
- Fleet UI: Updated edit policy page to redirect users with read-only access to policy details page.
|
||||
- Fleet UI: Added dedicated `/policies/:id/live` route for running policies
|
||||
|
|
@ -132,7 +132,7 @@ const generateTableHeaders = (
|
|||
</>
|
||||
}
|
||||
path={getPathWithQueryParams(PATHS.POLICY_DETAILS(id), {
|
||||
team_id,
|
||||
fleet_id: team_id,
|
||||
})}
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
export { default } from "./PolicyPage";
|
||||
|
|
@ -11,6 +11,7 @@ import { ILabelPolicy } from "interfaces/label";
|
|||
import { API_ALL_TEAMS_ID, APP_CONTEXT_ALL_TEAMS_ID } from "interfaces/team";
|
||||
import { PLATFORM_DISPLAY_NAMES, Platform } from "interfaces/platform";
|
||||
import globalPoliciesAPI from "services/entities/global_policies";
|
||||
import teamPoliciesAPI from "services/entities/team_policies";
|
||||
import teamsAPI, { ILoadTeamResponse } from "services/entities/teams";
|
||||
import { addGravatarUrlToResource } from "utilities/helpers";
|
||||
import { DOCUMENT_TITLE_SUFFIX } from "utilities/constants";
|
||||
|
|
@ -27,7 +28,7 @@ import Spinner from "components/Spinner";
|
|||
import TooltipWrapper from "components/TooltipWrapper";
|
||||
import Avatar from "components/Avatar";
|
||||
import ShowQueryModal from "components/modals/ShowQueryModal";
|
||||
import PolicyAutomations from "pages/policies/PolicyPage/components/PolicyAutomations";
|
||||
import PolicyAutomations from "pages/policies/edit/components/PolicyAutomations";
|
||||
|
||||
interface IPolicyDetailsPageProps {
|
||||
router: InjectedRouter;
|
||||
|
|
@ -35,7 +36,7 @@ interface IPolicyDetailsPageProps {
|
|||
location: {
|
||||
pathname: string;
|
||||
search: string;
|
||||
query: { team_id?: string };
|
||||
query: { fleet_id?: string };
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -108,34 +109,41 @@ const PolicyDetailsPage = ({
|
|||
IStoredPolicyResponse,
|
||||
Error,
|
||||
IPolicy
|
||||
>(["policy", policyId], () => globalPoliciesAPI.load(policyId as number), {
|
||||
enabled: isRouteOk && !!policyId,
|
||||
refetchOnWindowFocus: false,
|
||||
retry: false,
|
||||
select: (data: IStoredPolicyResponse) => data.policy,
|
||||
onSuccess: (returnedPolicy) => {
|
||||
setLastEditedQueryId(returnedPolicy.id);
|
||||
setLastEditedQueryName(returnedPolicy.name);
|
||||
setLastEditedQueryDescription(returnedPolicy.description);
|
||||
setLastEditedQueryBody(returnedPolicy.query);
|
||||
setLastEditedQueryResolution(returnedPolicy.resolution);
|
||||
setLastEditedQueryCritical(returnedPolicy.critical);
|
||||
setLastEditedQueryPlatform(returnedPolicy.platform);
|
||||
setLastEditedQueryLabelsIncludeAny(
|
||||
returnedPolicy.labels_include_any || []
|
||||
);
|
||||
setLastEditedQueryLabelsExcludeAny(
|
||||
returnedPolicy.labels_exclude_any || []
|
||||
);
|
||||
const deNulledTeamId = returnedPolicy.team_id ?? undefined;
|
||||
setPolicyTeamId(
|
||||
deNulledTeamId === API_ALL_TEAMS_ID
|
||||
? APP_CONTEXT_ALL_TEAMS_ID
|
||||
: deNulledTeamId
|
||||
);
|
||||
},
|
||||
onError: (error) => handlePageError(error),
|
||||
});
|
||||
>(
|
||||
["policy", policyId, teamIdForApi],
|
||||
() =>
|
||||
teamIdForApi && teamIdForApi > 0
|
||||
? teamPoliciesAPI.load(teamIdForApi, policyId as number)
|
||||
: globalPoliciesAPI.load(policyId as number),
|
||||
{
|
||||
enabled: isRouteOk && !!policyId,
|
||||
refetchOnWindowFocus: false,
|
||||
retry: false,
|
||||
select: (data: IStoredPolicyResponse) => data.policy,
|
||||
onSuccess: (returnedPolicy) => {
|
||||
setLastEditedQueryId(returnedPolicy.id);
|
||||
setLastEditedQueryName(returnedPolicy.name);
|
||||
setLastEditedQueryDescription(returnedPolicy.description);
|
||||
setLastEditedQueryBody(returnedPolicy.query);
|
||||
setLastEditedQueryResolution(returnedPolicy.resolution);
|
||||
setLastEditedQueryCritical(returnedPolicy.critical);
|
||||
setLastEditedQueryPlatform(returnedPolicy.platform);
|
||||
setLastEditedQueryLabelsIncludeAny(
|
||||
returnedPolicy.labels_include_any || []
|
||||
);
|
||||
setLastEditedQueryLabelsExcludeAny(
|
||||
returnedPolicy.labels_exclude_any || []
|
||||
);
|
||||
const deNulledTeamId = returnedPolicy.team_id ?? undefined;
|
||||
setPolicyTeamId(
|
||||
deNulledTeamId === API_ALL_TEAMS_ID
|
||||
? APP_CONTEXT_ALL_TEAMS_ID
|
||||
: deNulledTeamId
|
||||
);
|
||||
},
|
||||
onError: (error) => handlePageError(error),
|
||||
}
|
||||
);
|
||||
|
||||
const { data: teamData } = useQuery<ILoadTeamResponse>(
|
||||
["team", teamIdForApi],
|
||||
|
|
@ -187,7 +195,7 @@ const PolicyDetailsPage = ({
|
|||
const disabledLiveQuery = config?.server_settings.live_query_disabled;
|
||||
|
||||
const backToPoliciesPath = getPathWithQueryParams(PATHS.MANAGE_POLICIES, {
|
||||
team_id: teamIdForApi,
|
||||
fleet_id: teamIdForApi,
|
||||
});
|
||||
|
||||
const renderAuthor = (): JSX.Element | null => {
|
||||
|
|
@ -329,12 +337,9 @@ const PolicyDetailsPage = ({
|
|||
onClick={() => {
|
||||
policyId &&
|
||||
router.push(
|
||||
`${getPathWithQueryParams(
|
||||
PATHS.EDIT_POLICY(policyId),
|
||||
{
|
||||
team_id: teamIdForApi,
|
||||
}
|
||||
)}#targets`
|
||||
getPathWithQueryParams(PATHS.LIVE_POLICY(policyId), {
|
||||
fleet_id: teamIdForApi,
|
||||
})
|
||||
);
|
||||
}}
|
||||
disabled={!!disabledLiveQuery}
|
||||
|
|
@ -348,7 +353,7 @@ const PolicyDetailsPage = ({
|
|||
policyId &&
|
||||
router.push(
|
||||
getPathWithQueryParams(PATHS.EDIT_POLICY(policyId), {
|
||||
team_id: teamIdForApi,
|
||||
fleet_id: teamIdForApi,
|
||||
})
|
||||
);
|
||||
}}
|
||||
|
|
@ -6,36 +6,27 @@ import { useErrorHandler } from "react-error-boundary";
|
|||
import { AppContext } from "context/app";
|
||||
import { PolicyContext } from "context/policy";
|
||||
import useTeamIdParam from "hooks/useTeamIdParam";
|
||||
import { IHost, IHostResponse } from "interfaces/host";
|
||||
import { ILabel } from "interfaces/label";
|
||||
import {
|
||||
IPolicyFormData,
|
||||
IPolicy,
|
||||
IStoredPolicyResponse,
|
||||
} from "interfaces/policy";
|
||||
import { ITarget } from "interfaces/target";
|
||||
import {
|
||||
API_ALL_TEAMS_ID,
|
||||
APP_CONTEXT_ALL_TEAMS_ID,
|
||||
ITeam,
|
||||
} from "interfaces/team";
|
||||
import { API_ALL_TEAMS_ID, APP_CONTEXT_ALL_TEAMS_ID } from "interfaces/team";
|
||||
import globalPoliciesAPI from "services/entities/global_policies";
|
||||
import teamPoliciesAPI from "services/entities/team_policies";
|
||||
import teamsAPI, { ILoadTeamResponse } from "services/entities/teams";
|
||||
import hostAPI from "services/entities/hosts";
|
||||
import statusAPI from "services/entities/status";
|
||||
import { DOCUMENT_TITLE_SUFFIX, LIVE_POLICY_STEPS } from "utilities/constants";
|
||||
import PATHS from "router/paths";
|
||||
import { DOCUMENT_TITLE_SUFFIX } from "utilities/constants";
|
||||
import { getPathWithQueryParams } from "utilities/url";
|
||||
|
||||
import SidePanelPage from "components/SidePanelPage";
|
||||
import QuerySidePanel from "components/side_panels/QuerySidePanel";
|
||||
import QueryEditor from "pages/policies/PolicyPage/screens/QueryEditor";
|
||||
import SelectTargets from "components/LiveQuery/SelectTargets";
|
||||
import QueryEditor from "pages/policies/edit/screens/QueryEditor";
|
||||
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";
|
||||
|
||||
interface IPolicyPageProps {
|
||||
|
|
@ -44,12 +35,11 @@ interface IPolicyPageProps {
|
|||
location: {
|
||||
pathname: string;
|
||||
search: string;
|
||||
query: { host_ids: string; fleet_id: string };
|
||||
hash?: string;
|
||||
query: { fleet_id: string };
|
||||
};
|
||||
}
|
||||
|
||||
const baseClass = "policy-page";
|
||||
const baseClass = "edit-policy-page";
|
||||
|
||||
const PolicyPage = ({
|
||||
router,
|
||||
|
|
@ -144,14 +134,6 @@ const PolicyPage = ({
|
|||
};
|
||||
}, []);
|
||||
|
||||
const [step, setStep] = useState(
|
||||
location.hash === "#targets" ? LIVE_POLICY_STEPS[2] : LIVE_POLICY_STEPS[1]
|
||||
);
|
||||
const [selectedTargets, setSelectedTargets] = useState<ITarget[]>([]);
|
||||
const [targetedHosts, setTargetedHosts] = useState<IHost[]>([]);
|
||||
const [targetedLabels, setTargetedLabels] = useState<ILabel[]>([]);
|
||||
const [targetedTeams, setTargetedTeams] = useState<ITeam[]>([]);
|
||||
const [targetsTotalCount, setTargetsTotalCount] = useState(0);
|
||||
const [isLiveQueryRunnable, setIsLiveQueryRunnable] = useState(true);
|
||||
const [isSidebarOpen, setIsSidebarOpen] = useState(true);
|
||||
const [showOpenSchemaActionText, setShowOpenSchemaActionText] = useState(
|
||||
|
|
@ -203,23 +185,6 @@ const PolicyPage = ({
|
|||
}
|
||||
);
|
||||
|
||||
useQuery<IHostResponse, Error, IHost>(
|
||||
"hostFromURL",
|
||||
() =>
|
||||
hostAPI.loadHostDetails(parseInt(location.query.host_ids as string, 10)), // TODO(sarah): What should happen if this doesn't parse (e.g. the string is "foo")? Also, note that "1,2,3" parses as 1.
|
||||
{
|
||||
enabled: isRouteOk && !!location.query.host_ids,
|
||||
retry: false,
|
||||
select: (data: IHostResponse) => data.host,
|
||||
onSuccess: (host) => {
|
||||
const targets = selectedTargets;
|
||||
host.target_type = "hosts";
|
||||
targets.push(host);
|
||||
setSelectedTargets([...targets]);
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
/** Pesky bug affecting team level users:
|
||||
- Navigating to policies/:id immediately defaults the user to the first team they're on
|
||||
with the most permissions, in the URL bar because of useTeamIdParam
|
||||
|
|
@ -338,7 +303,7 @@ const PolicyPage = ({
|
|||
};
|
||||
|
||||
const renderScreen = () => {
|
||||
const step1Opts = {
|
||||
const queryEditorOpts = {
|
||||
router,
|
||||
baseClass,
|
||||
policyIdForEdit: policyId,
|
||||
|
|
@ -352,51 +317,22 @@ const PolicyPage = ({
|
|||
storedPolicyError,
|
||||
createPolicy,
|
||||
onOsqueryTableSelect,
|
||||
goToSelectTargets: () => setStep(LIVE_POLICY_STEPS[2]),
|
||||
goToSelectTargets: () =>
|
||||
router.push(
|
||||
getPathWithQueryParams(PATHS.LIVE_POLICY(policyId), {
|
||||
fleet_id: teamIdForApi,
|
||||
})
|
||||
),
|
||||
onOpenSchemaSidebar,
|
||||
renderLiveQueryWarning,
|
||||
teamIdForApi,
|
||||
currentAutomatedPolicies,
|
||||
};
|
||||
|
||||
const step2Opts = {
|
||||
baseClass,
|
||||
selectedTargets,
|
||||
targetedHosts,
|
||||
targetedLabels,
|
||||
targetedTeams,
|
||||
targetsTotalCount,
|
||||
goToQueryEditor: () => setStep(LIVE_POLICY_STEPS[1]),
|
||||
goToRunQuery: () => setStep(LIVE_POLICY_STEPS[3]),
|
||||
setSelectedTargets,
|
||||
setTargetedHosts,
|
||||
setTargetedLabels,
|
||||
setTargetedTeams,
|
||||
setTargetsTotalCount,
|
||||
isLivePolicy: true,
|
||||
};
|
||||
|
||||
const step3Opts = {
|
||||
selectedTargets,
|
||||
storedPolicy,
|
||||
setSelectedTargets,
|
||||
goToQueryEditor: () => setStep(LIVE_POLICY_STEPS[1]),
|
||||
targetsTotalCount,
|
||||
};
|
||||
|
||||
switch (step) {
|
||||
case LIVE_POLICY_STEPS[2]:
|
||||
return <SelectTargets {...step2Opts} />;
|
||||
case LIVE_POLICY_STEPS[3]:
|
||||
return <RunQuery {...step3Opts} />;
|
||||
default:
|
||||
return <QueryEditor {...step1Opts} />;
|
||||
}
|
||||
return <QueryEditor {...queryEditorOpts} />;
|
||||
};
|
||||
|
||||
const isFirstStep = step === LIVE_POLICY_STEPS[1];
|
||||
const showSidebar =
|
||||
isFirstStep &&
|
||||
isSidebarOpen &&
|
||||
(isGlobalAdmin || isGlobalMaintainer || isAnyTeamMaintainerOrTeamAdmin);
|
||||
|
||||
39
frontend/pages/policies/edit/_styles.scss
Normal file
39
frontend/pages/policies/edit/_styles.scss
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
.edit-policy-page {
|
||||
@include vertical-page-layout;
|
||||
|
||||
&__form {
|
||||
@include vertical-form-layout;
|
||||
}
|
||||
|
||||
&__warning {
|
||||
padding: $pad-medium;
|
||||
font-size: $x-small;
|
||||
color: $core-fleet-black;
|
||||
background-color: #fff0b9;
|
||||
border: 1px solid #f2c94c;
|
||||
border-radius: $border-radius;
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
&__observer-query-view {
|
||||
width: 90%;
|
||||
max-width: 1060px;
|
||||
margin: 0 auto;
|
||||
color: $core-fleet-black;
|
||||
|
||||
h1 {
|
||||
font-size: $medium;
|
||||
}
|
||||
p {
|
||||
font-size: $x-small;
|
||||
}
|
||||
}
|
||||
|
||||
.ace_content {
|
||||
min-height: 500px !important;
|
||||
}
|
||||
}
|
||||
|
|
@ -271,7 +271,19 @@ const PolicyForm = ({
|
|||
})
|
||||
);
|
||||
}
|
||||
}, [policyIdForEdit, isTeamMaintainerOrTeamAdmin, isStoredPolicyLoading]);
|
||||
}, [
|
||||
policyIdForEdit,
|
||||
isEditMode,
|
||||
isStoredPolicyLoading,
|
||||
isTeamObserver,
|
||||
isGlobalObserver,
|
||||
isTeamTechnician,
|
||||
isGlobalTechnician,
|
||||
isOnGlobalTeam,
|
||||
storedPolicy?.team_id,
|
||||
router,
|
||||
teamIdForApi,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedTargetType(
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
position: relative;
|
||||
font-size: $x-small;
|
||||
|
||||
.policy-page__warning {
|
||||
.edit-policy-page__warning {
|
||||
margin: 0;
|
||||
margin-bottom: $pad-large;
|
||||
}
|
||||
1
frontend/pages/policies/edit/index.ts
Normal file
1
frontend/pages/policies/edit/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { default } from "./EditPolicyPage";
|
||||
|
|
@ -14,7 +14,7 @@ import { getPathWithQueryParams } from "utilities/url";
|
|||
import { IPolicyFormData, IPolicy } from "interfaces/policy";
|
||||
|
||||
import BackButton from "components/BackButton";
|
||||
import PolicyForm from "pages/policies/PolicyPage/components/PolicyForm";
|
||||
import PolicyForm from "pages/policies/edit/components/PolicyForm";
|
||||
import { APP_CONTEXT_ALL_TEAMS_ID } from "interfaces/team";
|
||||
|
||||
interface IQueryEditorProps {
|
||||
|
|
@ -261,7 +261,7 @@ const QueryEditor = ({
|
|||
|
||||
const backPath = policyIdForEdit
|
||||
? getPathWithQueryParams(PATHS.POLICY_DETAILS(policyIdForEdit), {
|
||||
team_id: teamIdForApi,
|
||||
fleet_id: teamIdForApi,
|
||||
})
|
||||
: backToPoliciesPath();
|
||||
|
||||
204
frontend/pages/policies/live/LivePolicyPage/LivePolicyPage.tsx
Normal file
204
frontend/pages/policies/live/LivePolicyPage/LivePolicyPage.tsx
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
import React, { useState, useEffect, useContext, useCallback } from "react";
|
||||
import { useQuery } from "react-query";
|
||||
import { useErrorHandler } from "react-error-boundary";
|
||||
import { InjectedRouter, Params } from "react-router/lib/Router";
|
||||
import PATHS from "router/paths";
|
||||
import useTeamIdParam from "hooks/useTeamIdParam";
|
||||
|
||||
import { AppContext } from "context/app";
|
||||
import { PolicyContext } from "context/policy";
|
||||
import { LIVE_QUERY_STEPS, DOCUMENT_TITLE_SUFFIX } from "utilities/constants";
|
||||
import { getPathWithQueryParams } from "utilities/url";
|
||||
import globalPoliciesAPI from "services/entities/global_policies";
|
||||
import teamPoliciesAPI from "services/entities/team_policies";
|
||||
import hostAPI from "services/entities/hosts";
|
||||
import { IHost, IHostResponse } from "interfaces/host";
|
||||
import { ILabel } from "interfaces/label";
|
||||
import { ITeam } from "interfaces/team";
|
||||
import { IPolicy, IStoredPolicyResponse } from "interfaces/policy";
|
||||
import { ITarget } from "interfaces/target";
|
||||
|
||||
import MainContent from "components/MainContent";
|
||||
import SelectTargets from "components/LiveQuery/SelectTargets";
|
||||
|
||||
import RunQuery from "pages/policies/live/screens/RunQuery";
|
||||
|
||||
interface ILivePolicyPageProps {
|
||||
router: InjectedRouter;
|
||||
params: Params;
|
||||
location: {
|
||||
pathname: string;
|
||||
query: { host_ids?: string; fleet_id?: string };
|
||||
search: string;
|
||||
};
|
||||
}
|
||||
|
||||
const baseClass = "live-policy-page";
|
||||
|
||||
const LivePolicyPage = ({
|
||||
router,
|
||||
params: { id: paramsPolicyId },
|
||||
location,
|
||||
}: ILivePolicyPageProps): JSX.Element => {
|
||||
const policyId = paramsPolicyId ? parseInt(paramsPolicyId, 10) : null;
|
||||
const handlePageError = useErrorHandler();
|
||||
|
||||
const { currentTeamId } = useTeamIdParam({
|
||||
location,
|
||||
router,
|
||||
includeAllTeams: true,
|
||||
includeNoTeam: true,
|
||||
});
|
||||
|
||||
const { config } = useContext(AppContext);
|
||||
const {
|
||||
setLastEditedQueryId,
|
||||
setLastEditedQueryName,
|
||||
setLastEditedQueryDescription,
|
||||
setLastEditedQueryBody,
|
||||
setLastEditedQueryResolution,
|
||||
setLastEditedQueryCritical,
|
||||
setLastEditedQueryPlatform,
|
||||
setLastEditedQueryLabelsIncludeAny,
|
||||
setLastEditedQueryLabelsExcludeAny,
|
||||
} = useContext(PolicyContext);
|
||||
|
||||
const [queryParamHostsAdded, setQueryParamHostsAdded] = useState(false);
|
||||
const [step, setStep] = useState(LIVE_QUERY_STEPS[1]);
|
||||
const [selectedTargets, setSelectedTargets] = useState<ITarget[]>([]);
|
||||
const [targetedHosts, setTargetedHosts] = useState<IHost[]>([]);
|
||||
const [targetedLabels, setTargetedLabels] = useState<ILabel[]>([]);
|
||||
const [targetedTeams, setTargetedTeams] = useState<ITeam[]>([]);
|
||||
const [targetsTotalCount, setTargetsTotalCount] = useState(0);
|
||||
|
||||
const disabledLiveQuery = config?.server_settings.live_query_disabled;
|
||||
const teamIdForApi = currentTeamId === -1 ? undefined : currentTeamId;
|
||||
|
||||
// Reroute users out of live flow when live queries are globally disabled
|
||||
// Reroute users out of live flow when live queries are globally disabled
|
||||
useEffect(() => {
|
||||
if (disabledLiveQuery) {
|
||||
const path = policyId
|
||||
? PATHS.POLICY_DETAILS(policyId)
|
||||
: PATHS.MANAGE_POLICIES;
|
||||
|
||||
router.push(getPathWithQueryParams(path, { fleet_id: teamIdForApi }));
|
||||
}
|
||||
}, [disabledLiveQuery, policyId, router, teamIdForApi]);
|
||||
|
||||
const { data: storedPolicy } = useQuery<
|
||||
IStoredPolicyResponse,
|
||||
Error,
|
||||
IPolicy
|
||||
>(
|
||||
["policy", policyId, teamIdForApi],
|
||||
() =>
|
||||
teamIdForApi && teamIdForApi > 0
|
||||
? teamPoliciesAPI.load(teamIdForApi, policyId as number)
|
||||
: globalPoliciesAPI.load(policyId as number),
|
||||
{
|
||||
enabled: !!policyId,
|
||||
refetchOnWindowFocus: false,
|
||||
select: (data: IStoredPolicyResponse) => data.policy,
|
||||
onSuccess: (returnedPolicy) => {
|
||||
setLastEditedQueryId(returnedPolicy.id);
|
||||
setLastEditedQueryName(returnedPolicy.name);
|
||||
setLastEditedQueryDescription(returnedPolicy.description);
|
||||
setLastEditedQueryBody(returnedPolicy.query);
|
||||
setLastEditedQueryResolution(returnedPolicy.resolution);
|
||||
setLastEditedQueryCritical(returnedPolicy.critical);
|
||||
setLastEditedQueryPlatform(returnedPolicy.platform);
|
||||
setLastEditedQueryLabelsIncludeAny(
|
||||
returnedPolicy.labels_include_any || []
|
||||
);
|
||||
setLastEditedQueryLabelsExcludeAny(
|
||||
returnedPolicy.labels_exclude_any || []
|
||||
);
|
||||
},
|
||||
onError: (error) => handlePageError(error),
|
||||
}
|
||||
);
|
||||
|
||||
const hostIdFromURL = location.query.host_ids
|
||||
? parseInt(location.query.host_ids as string, 10)
|
||||
: null;
|
||||
|
||||
useQuery<IHostResponse, Error, IHost>(
|
||||
["hostFromURL", hostIdFromURL, teamIdForApi],
|
||||
() => hostAPI.loadHostDetails(hostIdFromURL as number),
|
||||
{
|
||||
enabled: !!hostIdFromURL && !queryParamHostsAdded,
|
||||
select: (data: IHostResponse) => data.host,
|
||||
onSuccess: (host) => {
|
||||
setTargetedHosts((prevHosts) =>
|
||||
prevHosts.filter((h) => h.id !== host.id).concat(host)
|
||||
);
|
||||
const targets = selectedTargets;
|
||||
host.target_type = "hosts";
|
||||
targets.push(host);
|
||||
setSelectedTargets([...targets]);
|
||||
if (!queryParamHostsAdded) {
|
||||
setQueryParamHostsAdded(true);
|
||||
}
|
||||
router.replace(location.pathname);
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Updates title that shows up on browser tabs
|
||||
useEffect(() => {
|
||||
if (storedPolicy?.name) {
|
||||
document.title = `Run ${storedPolicy.name} | Policies | ${DOCUMENT_TITLE_SUFFIX}`;
|
||||
} else {
|
||||
document.title = `Policies | ${DOCUMENT_TITLE_SUFFIX}`;
|
||||
}
|
||||
}, [location.pathname, storedPolicy?.name]);
|
||||
|
||||
const goToQueryEditor = useCallback(() => {
|
||||
const path = policyId ? PATHS.EDIT_POLICY(policyId) : PATHS.NEW_POLICY;
|
||||
|
||||
router.push(getPathWithQueryParams(path, { fleet_id: teamIdForApi }));
|
||||
}, [policyId, router, teamIdForApi]);
|
||||
|
||||
const renderScreen = () => {
|
||||
const step1Props = {
|
||||
baseClass,
|
||||
selectedTargets,
|
||||
targetedHosts,
|
||||
targetedLabels,
|
||||
targetedTeams,
|
||||
targetsTotalCount,
|
||||
goToQueryEditor,
|
||||
goToRunQuery: () => setStep(LIVE_QUERY_STEPS[2]),
|
||||
setSelectedTargets,
|
||||
setTargetedHosts,
|
||||
setTargetedLabels,
|
||||
setTargetedTeams,
|
||||
setTargetsTotalCount,
|
||||
isLivePolicy: true,
|
||||
};
|
||||
|
||||
const step2Props = {
|
||||
selectedTargets,
|
||||
storedPolicy,
|
||||
setSelectedTargets,
|
||||
goToQueryEditor,
|
||||
targetsTotalCount,
|
||||
};
|
||||
|
||||
switch (step) {
|
||||
case LIVE_QUERY_STEPS[2]:
|
||||
return <RunQuery {...step2Props} />;
|
||||
default:
|
||||
return <SelectTargets {...step1Props} />;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<MainContent className={baseClass}>
|
||||
<div className={`${baseClass}_wrapper`}>{renderScreen()}</div>
|
||||
</MainContent>
|
||||
);
|
||||
};
|
||||
|
||||
export default LivePolicyPage;
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
.policy-page {
|
||||
@include vertical-page-layout;
|
||||
|
||||
&__form {
|
||||
@include vertical-form-layout;
|
||||
.live-policy-page {
|
||||
&_wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__results {
|
||||
|
|
@ -12,34 +10,6 @@
|
|||
min-height: 400px;
|
||||
}
|
||||
|
||||
&__warning {
|
||||
padding: $pad-medium;
|
||||
font-size: $x-small;
|
||||
color: $core-fleet-black;
|
||||
background-color: #fff0b9;
|
||||
border: 1px solid #f2c94c;
|
||||
border-radius: $border-radius;
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
&__observer-query-view {
|
||||
width: 90%;
|
||||
max-width: 1060px;
|
||||
margin: 0 auto;
|
||||
color: $core-fleet-black;
|
||||
|
||||
h1 {
|
||||
font-size: $medium;
|
||||
}
|
||||
p {
|
||||
font-size: $x-small;
|
||||
}
|
||||
}
|
||||
|
||||
.ace_content {
|
||||
min-height: 500px !important;
|
||||
}
|
||||
1
frontend/pages/policies/live/LivePolicyPage/index.ts
Normal file
1
frontend/pages/policies/live/LivePolicyPage/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { default } from "./LivePolicyPage";
|
||||
|
|
@ -15,7 +15,7 @@ import { ICampaign, ICampaignState } from "interfaces/campaign";
|
|||
import { IPolicy } from "interfaces/policy";
|
||||
import { ITarget } from "interfaces/target";
|
||||
|
||||
import PolicyResults from "../components/PolicyResults";
|
||||
import PolicyResults from "pages/policies/edit/components/PolicyResults";
|
||||
|
||||
interface IRunQueryProps {
|
||||
storedPolicy: IPolicy | undefined;
|
||||
|
|
@ -42,10 +42,11 @@ import ManagePacksPage from "pages/packs/ManagePacksPage";
|
|||
import ManagePoliciesPage from "pages/policies/ManagePoliciesPage";
|
||||
import NoAccessPage from "pages/NoAccessPage";
|
||||
import PackComposerPage from "pages/packs/PackComposerPage";
|
||||
import PolicyDetailsPage from "pages/policies/PolicyDetailsPage";
|
||||
import PolicyPage from "pages/policies/PolicyPage";
|
||||
import PolicyDetailsPage from "pages/policies/details/PolicyDetailsPage";
|
||||
import EditPolicyPage from "pages/policies/edit";
|
||||
import QueryDetailsPage from "pages/queries/details/QueryDetailsPage";
|
||||
import LiveQueryPage from "pages/queries/live/LiveQueryPage";
|
||||
import LivePolicyPage from "pages/policies/live/LivePolicyPage";
|
||||
import EditQueryPage from "pages/queries/edit/EditQueryPage";
|
||||
import RegistrationPage from "pages/RegistrationPage";
|
||||
import ResetPasswordPage from "pages/ResetPasswordPage";
|
||||
|
|
@ -410,11 +411,15 @@ const routes = (
|
|||
<IndexRedirect to="manage" />
|
||||
<Route path="manage" component={ManagePoliciesPage} />
|
||||
<Route component={AuthAnyMaintainerAnyAdminRoutes}>
|
||||
<Route path="new" component={PolicyPage} />
|
||||
<Route path="new">
|
||||
<IndexRoute component={EditPolicyPage} />
|
||||
<Route path="live" component={LivePolicyPage} />
|
||||
</Route>
|
||||
</Route>
|
||||
<Route path=":id">
|
||||
<IndexRoute component={PolicyDetailsPage} />
|
||||
<Route path="edit" component={PolicyPage} />
|
||||
<Route path="edit" component={EditPolicyPage} />
|
||||
<Route path="live" component={LivePolicyPage} />
|
||||
</Route>
|
||||
</Route>
|
||||
<Redirect from="profile" to="account" /> {/* deprecated URL */}
|
||||
|
|
|
|||
|
|
@ -128,6 +128,8 @@ export default {
|
|||
`${URL_PREFIX}/policies/${policyId}`,
|
||||
EDIT_POLICY: (policyId: number): string =>
|
||||
`${URL_PREFIX}/policies/${policyId}/edit`,
|
||||
LIVE_POLICY: (policyId: number | null): string =>
|
||||
`${URL_PREFIX}/policies/${policyId || "new"}/live`,
|
||||
FORGOT_PASSWORD: `${URL_PREFIX}/login/forgot`,
|
||||
MFA: `${URL_PREFIX}/login/mfa`,
|
||||
NO_ACCESS: `${URL_PREFIX}/login/denied`,
|
||||
|
|
|
|||
Loading…
Reference in a new issue