Fix UI cancel error message lock wipe (#28071)

For #28018

some fixes for the UI of cancel activities including:

- showing proper error message
- correct permission checking for allowing users to cancel activity
- refresh all host details after lock or wipe command to get updated
host status.
This commit is contained in:
Gabriel Hernandez 2025-04-10 14:12:47 +01:00 committed by GitHub
parent 2d45272bc8
commit 1f9244ef8e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 39 additions and 18 deletions

View file

@ -24,7 +24,7 @@ export const isValidPemCertificate = (cert: string): boolean => {
return regexPemHeader.test(cert) && regexPemFooter.test(cert);
};
const hasStatusKey = (value: unknown): value is { status: number } => {
export const hasStatusKey = (value: unknown): value is { status: number } => {
return (
typeof value === "object" &&
value !== null &&

View file

@ -33,7 +33,7 @@ import { IHostPolicy } from "interfaces/policy";
import { IQueryStats } from "interfaces/query_stats";
import { IHostSoftware } from "interfaces/software";
import { ITeam } from "interfaces/team";
import { IHostUpcomingActivity } from "interfaces/activity";
import { ActivityType, IHostUpcomingActivity } from "interfaces/activity";
import {
IHostCertificate,
CERTIFICATES_DEFAULT_SORT,
@ -163,6 +163,7 @@ const HostDetailsPage = ({
config,
currentUser,
isGlobalAdmin = false,
isGlobalMaintainer,
isGlobalObserver,
isPremiumTier = false,
isOnlyObserver,
@ -836,6 +837,12 @@ const HostDetailsPage = ({
router.push(navPath);
};
const isHostTeamAdmin = permissions.isTeamAdmin(currentUser, host?.team_id);
const isHostTeamMaintainer = permissions.isTeamMaintainer(
currentUser,
host?.team_id
);
/* Context team id might be different that host's team id
Observer plus must be checked against host's team id */
const isGlobalOrHostsTeamObserverPlus =
@ -969,6 +976,12 @@ const HostDetailsPage = ({
? pastActivitiesIsError
: upcomingActivitiesIsError
}
canCancelActivities={
isGlobalAdmin ||
isGlobalMaintainer ||
isHostTeamAdmin ||
isHostTeamMaintainer
}
upcomingCount={upcomingActivities?.count || 0}
onChangeTab={onChangeActivityTab}
onNextPage={() => setActivityPage(activityPage + 1)}
@ -1204,6 +1217,16 @@ const HostDetailsPage = ({
hostId={host.id}
activity={selectedCancelActivity}
onCancelActivity={() => refetchUpcomingActivities()}
onSuccessCancel={(activity) => {
// only for windows and linux hosts we want to refetch host details
if (
(activity.type === ActivityType.RanScript &&
host.platform === "windows") ||
host.platform === "linux"
) {
refetchHostDetails();
}
}}
onExit={() => setSelectedCancelActivity(null)}
/>
)}

View file

@ -17,7 +17,8 @@ const baseClass = "cancel-activity-modal";
interface ICancelActivityModalProps {
hostId: number;
activity: IHostUpcomingActivity;
onCancelActivity: () => void;
onCancelActivity: (activity: IHostUpcomingActivity) => void;
onSuccessCancel: (activity: IHostUpcomingActivity) => void;
onExit: () => void;
}
@ -25,6 +26,7 @@ const CancelActivityModal = ({
hostId,
activity,
onCancelActivity,
onSuccessCancel,
onExit,
}: ICancelActivityModalProps) => {
const { renderFlash } = useContext(NotificationContext);
@ -37,10 +39,11 @@ const CancelActivityModal = ({
try {
await activitiesAPI.cancelHostActivity(hostId, activity.uuid);
renderFlash("success", "Activity successfully canceled.");
onSuccessCancel(activity);
} catch (err) {
renderFlash("error", getErrorMessage(err));
}
onCancelActivity();
onCancelActivity(activity);
onExit();
};

View file

@ -1,4 +1,4 @@
import { isAxiosError } from "axios";
import { hasStatusKey } from "pages/hosts/ManageHostsPage/helpers";
const DEFAULT_ERR_MESSAGE = "Couldn't cancel activity. Please try again.";
const LOCK_WIPE_ERR_MESSAGE =
@ -8,7 +8,7 @@ const ACTIVITY_ALREADY_HAPPENED_ERR_MESSAGE =
// eslint-disable-next-line import/prefer-default-export
export const getErrorMessage = (err: unknown) => {
if (isAxiosError(err)) {
if (hasStatusKey(err)) {
if (err.status === 404) return ACTIVITY_ALREADY_HAPPENED_ERR_MESSAGE;
// display server error message if error is 400

View file

@ -39,6 +39,7 @@ interface IActivityProps {
isError?: boolean;
className?: string;
upcomingCount: number;
canCancelActivities: boolean;
onChangeTab: (index: number, last: number, event: Event) => void;
onNextPage: () => void;
onPreviousPage: () => void;
@ -53,6 +54,7 @@ const Activity = ({
isError,
className,
upcomingCount,
canCancelActivities,
onChangeTab,
onNextPage,
onPreviousPage,
@ -107,6 +109,7 @@ const Activity = ({
isError={isError}
onNextPage={onNextPage}
onPreviousPage={onPreviousPage}
canCancelActivities={canCancelActivities}
/>
</TabPanel>
</Tabs>

View file

@ -1,8 +1,7 @@
import React, { useContext } from "react";
import React from "react";
import { IHostUpcomingActivity } from "interfaces/activity";
import { IHostUpcomingActivitiesResponse } from "services/entities/activities";
import { AppContext } from "context/app";
import DataError from "components/DataError";
import Pagination from "components/Pagination";
@ -16,6 +15,7 @@ const baseClass = "upcoming-activity-feed";
interface IUpcomingActivityFeedProps {
activities?: IHostUpcomingActivitiesResponse;
isError?: boolean;
canCancelActivities: boolean;
onShowDetails: ShowActivityDetailsHandler;
onCancel: (activity: IHostUpcomingActivity) => void;
onNextPage: () => void;
@ -25,17 +25,12 @@ interface IUpcomingActivityFeedProps {
const UpcomingActivityFeed = ({
activities,
isError = false,
canCancelActivities,
onShowDetails,
onCancel,
onNextPage,
onPreviousPage,
}: IUpcomingActivityFeedProps) => {
const {
isTeamMaintainerOrTeamAdmin,
isGlobalAdmin,
isGlobalMaintainer,
} = useContext(AppContext);
if (isError) {
return <DataError />;
}
@ -56,9 +51,6 @@ const UpcomingActivityFeed = ({
);
}
const canCancel =
isGlobalAdmin || isGlobalMaintainer || isTeamMaintainerOrTeamAdmin;
return (
<div className={baseClass}>
<div className={`${baseClass}__feed-list`}>
@ -71,7 +63,7 @@ const UpcomingActivityFeed = ({
tab="upcoming"
activity={activity}
onShowDetails={onShowDetails}
hideCancel={!canCancel}
hideCancel={!canCancelActivities}
onCancel={() => onCancel(activity)}
/>
);