From 1b8500e20654526584aa80209a5352b9528ae2a0 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Sun, 19 Jul 2020 20:33:09 -0400 Subject: [PATCH 1/3] [Ingest Manager] Allow to force unenroll from the UI --- .../common/services/agent_status.ts | 6 +-- .../components/context_menu_actions.tsx | 31 ++++++++++--- .../components/actions_menu.tsx | 18 +++++--- .../sections/fleet/agent_list_page/index.tsx | 22 +++++++--- .../components/agent_unenroll_provider.tsx | 43 +++++++++++++------ 5 files changed, 88 insertions(+), 32 deletions(-) diff --git a/x-pack/plugins/ingest_manager/common/services/agent_status.ts b/x-pack/plugins/ingest_manager/common/services/agent_status.ts index 536003b0f743d9..fe4e094e1bb229 100644 --- a/x-pack/plugins/ingest_manager/common/services/agent_status.ts +++ b/x-pack/plugins/ingest_manager/common/services/agent_status.ts @@ -13,12 +13,12 @@ export function getAgentStatus(agent: Agent, now: number = Date.now()): AgentSta if (!agent.active) { return 'inactive'; } - if (!agent.last_checkin) { - return 'enrolling'; - } if (agent.unenrollment_started_at && !agent.unenrolled_at) { return 'unenrolling'; } + if (!agent.last_checkin) { + return 'enrolling'; + } const msLastCheckIn = new Date(lastCheckIn || 0).getTime(); const msSinceLastCheckIn = new Date().getTime() - msLastCheckIn; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/context_menu_actions.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/context_menu_actions.tsx index 8a9f0553895a1d..0be021396ffa2c 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/context_menu_actions.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/context_menu_actions.tsx @@ -22,6 +22,8 @@ type Props = { props: EuiButtonProps; children: JSX.Element; }; + isOpen?: boolean; + onChange?: (isOpen: boolean) => void; } & ( | { items: EuiContextMenuPanelProps['items']; @@ -31,10 +33,27 @@ type Props = { } ); -export const ContextMenuActions = React.memo(({ button, ...props }) => { - const [isOpen, setIsOpen] = useState(false); - const handleCloseMenu = useCallback(() => setIsOpen(false), [setIsOpen]); - const handleToggleMenu = useCallback(() => setIsOpen(!isOpen), [isOpen]); +export const ContextMenuActions: React.FunctionComponent = ({ + button, + onChange, + isOpen, + ...props +}) => { + const [isOpenState, setIsOpenState] = useState(false); + const handleCloseMenu = useCallback(() => { + if (onChange) { + onChange(false); + } else { + setIsOpenState(false); + } + }, [setIsOpenState, onChange]); + const handleToggleMenu = useCallback(() => { + if (onChange) { + onChange(!isOpen); + } else { + setIsOpenState(!isOpenState); + } + }, [isOpenState, onChange, isOpen]); return ( (({ button, ...props }) => { /> ) } - isOpen={isOpen} + isOpen={typeof isOpen !== 'undefined' ? isOpen : isOpenState} closePopover={handleCloseMenu} > {'items' in props ? ( @@ -65,4 +84,4 @@ export const ContextMenuActions = React.memo(({ button, ...props }) => { )} ); -}); +}; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/actions_menu.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/actions_menu.tsx index 75a67fb9288e55..7afc57b30cef48 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/actions_menu.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/components/actions_menu.tsx @@ -20,6 +20,7 @@ export const AgentDetailsActionMenu: React.FunctionComponent<{ const hasWriteCapabilites = useCapabilities().write; const refreshAgent = useAgentRefresh(); const [isReassignFlyoutOpen, setIsReassignFlyoutOpen] = useState(assignFlyoutOpenByDefault); + const isUnenrolling = agent.status === 'unenrolling'; const onClose = useMemo(() => { if (onCancelReassign) { @@ -59,7 +60,7 @@ export const AgentDetailsActionMenu: React.FunctionComponent<{ defaultMessage="Assign new agent config" /> , - + {(unenrollAgentsPrompt) => ( - + {isUnenrolling ? ( + + ) : ( + + )} )} , diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx index 034482c4cf9b55..3743f9b39191b3 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx @@ -74,8 +74,12 @@ const RowActions = React.memo<{ agent: Agent; onReassignClick: () => void; refre const { getHref } = useLink(); const hasWriteCapabilites = useCapabilities().write; + const isUnenrolling = agent.status === 'unenrolling'; + const [isMenuOpen, setIsMenuOpen] = useState(false); return ( setIsMenuOpen(isOpen)} items={[ void; refre /> , - + {(unenrollAgentsPrompt) => ( void; refre onClick={() => { unenrollAgentsPrompt([agent.id], 1, () => { refresh(); + setIsMenuOpen(false); }); }} > - + {isUnenrolling ? ( + + ) : ( + + )} )} , diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_unenroll_provider.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_unenroll_provider.tsx index 90d8ff545341de..6f1cba70bbcee2 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_unenroll_provider.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/components/agent_unenroll_provider.tsx @@ -14,6 +14,7 @@ import { agentRouteService } from '../../../services'; interface Props { children: (unenrollAgents: UnenrollAgents) => React.ReactElement; + forceUnenroll?: boolean; } export type UnenrollAgents = ( @@ -24,7 +25,10 @@ export type UnenrollAgents = ( type OnSuccessCallback = (agentsUnenrolled: string[]) => void; -export const AgentUnenrollProvider: React.FunctionComponent = ({ children }) => { +export const AgentUnenrollProvider: React.FunctionComponent = ({ + children, + forceUnenroll = false, +}) => { const core = useCore(); const [agents, setAgents] = useState([]); const [agentsCount, setAgentsCount] = useState(0); @@ -65,19 +69,24 @@ export const AgentUnenrollProvider: React.FunctionComponent = ({ children const { error } = await sendRequest({ path: agentRouteService.getUnenrollPath(agentId), method: 'post', + body: { + force: forceUnenroll, + }, }); if (error) { throw new Error(error.message); } - const successMessage = i18n.translate( - 'xpack.ingestManager.unenrollAgents.successSingleNotificationTitle', - { - defaultMessage: "Unenrolling agent '{id}'", - values: { id: agentId }, - } - ); + const successMessage = forceUnenroll + ? i18n.translate('xpack.ingestManager.unenrollAgents.successForceSingleNotificationTitle', { + defaultMessage: "Agent '{id}' unenrolled", + values: { id: agentId }, + }) + : i18n.translate('xpack.ingestManager.unenrollAgents.successSingleNotificationTitle', { + defaultMessage: "Unenrolling agent '{id}'", + values: { id: agentId }, + }); core.notifications.toasts.addSuccess(successMessage); if (onSuccessCallback.current) { @@ -107,11 +116,19 @@ export const AgentUnenrollProvider: React.FunctionComponent = ({ children + forceUnenroll ? ( + + ) : ( + + ) ) : ( Date: Tue, 21 Jul 2020 14:30:23 -0400 Subject: [PATCH 2/3] Update x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/context_menu_actions.tsx Co-authored-by: Jen Huang --- .../ingest_manager/components/context_menu_actions.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/context_menu_actions.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/context_menu_actions.tsx index 0be021396ffa2c..29b586090ec777 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/context_menu_actions.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/context_menu_actions.tsx @@ -74,7 +74,7 @@ export const ContextMenuActions: React.FunctionComponent = ({ /> ) } - isOpen={typeof isOpen !== 'undefined' ? isOpen : isOpenState} + isOpen={isOpen === undefined ? isOpenState : isOpen} closePopover={handleCloseMenu} > {'items' in props ? ( From ca2e7fcadac65e3a4366213517d7488dd51bb720 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Tue, 21 Jul 2020 15:37:17 -0400 Subject: [PATCH 3/3] Fix after review --- .../ingest_manager/components/context_menu_actions.tsx | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/context_menu_actions.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/context_menu_actions.tsx index 29b586090ec777..7d1f12447340f5 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/context_menu_actions.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/context_menu_actions.tsx @@ -33,12 +33,7 @@ type Props = { } ); -export const ContextMenuActions: React.FunctionComponent = ({ - button, - onChange, - isOpen, - ...props -}) => { +export const ContextMenuActions = React.memo(({ button, onChange, isOpen, ...props }) => { const [isOpenState, setIsOpenState] = useState(false); const handleCloseMenu = useCallback(() => { if (onChange) { @@ -84,4 +79,4 @@ export const ContextMenuActions: React.FunctionComponent = ({ )} ); -}; +});