-
Notifications
You must be signed in to change notification settings - Fork 478
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5ea213e
commit 60ced95
Showing
19 changed files
with
419 additions
and
60 deletions.
There are no files selected for viewing
154 changes: 154 additions & 0 deletions
154
frontend/components/ActivityDetails/InstallDetails/AppInstallDetails/AppInstallDetails.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
import React from "react"; | ||
import { useQuery } from "react-query"; | ||
|
||
import { | ||
SoftwareInstallStatus, | ||
getInstallStatusPredicate, | ||
} from "interfaces/software"; | ||
import mdmApi from "services/entities/mdm"; | ||
|
||
import Modal from "components/Modal"; | ||
import Button from "components/buttons/Button"; | ||
import Icon from "components/Icon"; | ||
import Textarea from "components/Textarea"; | ||
import DataError from "components/DataError/DataError"; | ||
import Spinner from "components/Spinner/Spinner"; | ||
import { IMdmCommandResult } from "interfaces/mdm"; | ||
import { IActivityDetails } from "interfaces/activity"; | ||
|
||
import { IconNames } from "components/icons"; | ||
import { | ||
getInstallDetailsStatusPredicate, | ||
INSTALL_DETAILS_STATUS_ICONS, | ||
} from "../constants"; | ||
|
||
const baseClass = "app-install-details"; | ||
|
||
export type IAppInstallDetails = Pick< | ||
IActivityDetails, | ||
| "host_id" | ||
| "command_uuid" | ||
| "host_display_name" | ||
| "software_title" | ||
| "app_store_id" | ||
| "status" | ||
>; | ||
|
||
export const AppInstallDetails = ({ | ||
status, | ||
command_uuid = "", | ||
host_display_name = "", | ||
software_title = "", | ||
}: IAppInstallDetails) => { | ||
const { data: result, isLoading, isError } = useQuery< | ||
IMdmCommandResult, | ||
Error | ||
>( | ||
["mdm_command_results", command_uuid], | ||
async () => { | ||
return mdmApi.getCommandResults(command_uuid).then((response) => { | ||
const results = response.results?.[0]; | ||
if (!results) { | ||
return Promise.reject(new Error("No data returned")); | ||
} | ||
return { | ||
...results, | ||
payload: atob(results.payload), | ||
result: atob(results.result), | ||
}; | ||
}); | ||
}, | ||
{ | ||
refetchOnWindowFocus: false, | ||
staleTime: 3000, | ||
} | ||
); | ||
|
||
if (isLoading) { | ||
return <Spinner />; | ||
} else if (isError) { | ||
return <DataError description="Close this modal and try again." />; | ||
} else if (!result) { | ||
// FIXME: Find a better solution for this. | ||
return <DataError description="No data returned." />; | ||
} | ||
|
||
// Note: We need to reconcile status values from two different sources. From props, we | ||
// get the status from the activity item details (which can be "failed", "pending", or | ||
// "installed"). From the command results API response, we also receive the raw status | ||
// from the MDM protocol, e.g., "NotNow" or "Acknowledged". We need to display some special | ||
// messaging for the "NotNow" status, which otherwise would be treated as "pending". | ||
const isStatusNotNow = result.status === "NotNow"; | ||
let iconName: IconNames; | ||
let predicate: string; | ||
let subordinate: string; | ||
if (isStatusNotNow) { | ||
iconName = INSTALL_DETAILS_STATUS_ICONS.pending; | ||
predicate = "tried to install"; | ||
subordinate = | ||
" but couldn’t because the host was locked or was running on battery power while in Power Nap. Fleet will try again"; | ||
} else { | ||
iconName = INSTALL_DETAILS_STATUS_ICONS[status as SoftwareInstallStatus]; | ||
predicate = getInstallDetailsStatusPredicate(status); | ||
subordinate = status === "pending" ? " when it comes online" : ""; | ||
} | ||
|
||
const showCommandResponse = isStatusNotNow || status !== "pending"; | ||
|
||
return ( | ||
<> | ||
<div className={`${baseClass}__software-install-details`}> | ||
<div className={`${baseClass}__status-message`}> | ||
{!!iconName && <Icon name={iconName} />} | ||
<span> | ||
Fleet {predicate} <b>{software_title}</b> on{" "} | ||
<b>{host_display_name}</b> | ||
{subordinate}. | ||
</span> | ||
</div> | ||
<div className={`${baseClass}__script-output`}> | ||
Request payload: | ||
<Textarea className={`${baseClass}__output-textarea`}> | ||
{result.payload} | ||
</Textarea> | ||
</div> | ||
{showCommandResponse && ( | ||
<div className={`${baseClass}__script-output`}> | ||
The response from <b>{host_display_name}</b>: | ||
<Textarea className={`${baseClass}__output-textarea`}> | ||
{result.result} | ||
</Textarea> | ||
</div> | ||
)} | ||
</div> | ||
</> | ||
); | ||
}; | ||
|
||
export const AppInstallDetailsModal = ({ | ||
details, | ||
onCancel, | ||
}: { | ||
details: IAppInstallDetails; | ||
onCancel: () => void; | ||
}) => { | ||
return ( | ||
<Modal | ||
title="Install details" | ||
onExit={onCancel} | ||
onEnter={onCancel} | ||
className={baseClass} | ||
> | ||
<> | ||
<div className={`${baseClass}__modal-content`}> | ||
<AppInstallDetails {...details} /> | ||
</div> | ||
<div className="modal-cta-wrap"> | ||
<Button onClick={onCancel} variant="brand"> | ||
Done | ||
</Button> | ||
</div> | ||
</> | ||
</Modal> | ||
); | ||
}; |
22 changes: 22 additions & 0 deletions
22
frontend/components/ActivityDetails/InstallDetails/AppInstallDetails/_styles.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
.app-install-details { | ||
.modal__content { | ||
margin-top: $pad-xlarge; | ||
} | ||
&__status-message { | ||
display: flex; | ||
align-items: center; | ||
gap: $pad-small; | ||
margin: 0; | ||
.icon { | ||
padding-top: 3px; | ||
align-self: flex-start; | ||
} | ||
} | ||
&__script-output { | ||
padding-top: $pad-xlarge; | ||
.textarea { | ||
margin-top: $pad-medium; | ||
overflow-wrap: break-word; | ||
} | ||
} | ||
} |
1 change: 1 addition & 0 deletions
1
frontend/components/ActivityDetails/InstallDetails/AppInstallDetails/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { AppInstallDetails, AppInstallDetailsModal } from "./AppInstallDetails"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
39 changes: 39 additions & 0 deletions
39
frontend/components/ActivityDetails/InstallDetails/constants.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { IconNames } from "components/icons"; | ||
import { SoftwareInstallStatus } from "interfaces/software"; | ||
|
||
export const INSTALL_DETAILS_STATUS_ICONS: Record< | ||
SoftwareInstallStatus, | ||
IconNames | ||
> = { | ||
pending: "pending-outline", | ||
installed: "success-outline", | ||
failed: "error-outline", | ||
} as const; | ||
|
||
const INSTALL_DETAILS_STATUS_PREDICATES: Record< | ||
SoftwareInstallStatus, | ||
string | ||
> = { | ||
pending: "will install", | ||
installed: "installed", | ||
failed: "failed to install", | ||
} as const; | ||
|
||
export const getInstallDetailsStatusPredicate = ( | ||
status: string | undefined | ||
) => { | ||
if (!status) { | ||
return INSTALL_DETAILS_STATUS_PREDICATES.pending; | ||
} | ||
return ( | ||
INSTALL_DETAILS_STATUS_PREDICATES[ | ||
status.toLowerCase() as SoftwareInstallStatus | ||
] || INSTALL_DETAILS_STATUS_PREDICATES.pending | ||
); | ||
}; | ||
|
||
export const SOFTWARE_INSTALL_OUTPUT_DISPLAY_LABELS = { | ||
pre_install_query_output: "Pre-install condition", | ||
output: "Software install output", | ||
post_install_script_output: "Post-install script output", | ||
} as const; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.