diff --git a/frontend/components/ActivityDetails/InstallDetails/SoftwareInstallDetails/_styles.scss b/frontend/components/ActivityDetails/InstallDetails/SoftwareInstallDetails/_styles.scss index 5e8df96d67..8cdc2ef600 100644 --- a/frontend/components/ActivityDetails/InstallDetails/SoftwareInstallDetails/_styles.scss +++ b/frontend/components/ActivityDetails/InstallDetails/SoftwareInstallDetails/_styles.scss @@ -7,6 +7,10 @@ align-items: center; gap: $pad-small; margin: 0; + .icon { + padding-top: 3px; + align-self: flex-start; + } } &__script-output { padding-top: $pad-xlarge; diff --git a/frontend/interfaces/software.ts b/frontend/interfaces/software.ts index 447ec6f81b..f6021202ad 100644 --- a/frontend/interfaces/software.ts +++ b/frontend/interfaces/software.ts @@ -291,3 +291,13 @@ export const INSTALL_STATUS_ICONS: Record = { installed: "success-outline", failed: "error-outline", } as const; + +export type IHostSoftwareWithLastInstall = IHostSoftware & { + last_install: ISoftwareLastInstall; +}; + +export const hasLastInstall = ( + software: IHostSoftware +): software is IHostSoftwareWithLastInstall => { + return !!software.last_install; +}; diff --git a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx index 6e1d83d5a5..f1b2589b11 100644 --- a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx +++ b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx @@ -1046,6 +1046,7 @@ const HostDetailsPage = ({ )} {selectedSoftwareDetails && ( setSelectedSoftwareDetails(null)} /> diff --git a/frontend/pages/hosts/details/cards/Software/HostSoftwareTableConfig.tsx b/frontend/pages/hosts/details/cards/Software/HostSoftwareTableConfig.tsx index 5825f48146..b01806032f 100644 --- a/frontend/pages/hosts/details/cards/Software/HostSoftwareTableConfig.tsx +++ b/frontend/pages/hosts/details/cards/Software/HostSoftwareTableConfig.tsx @@ -4,7 +4,9 @@ import { CellProps, Column } from "react-table"; import { cloneDeep } from "lodash"; import { + IHostAppStoreApp, IHostSoftware, + IHostSoftwarePackage, SoftwareInstallStatus, formatSoftwareType, } from "interfaces/software"; @@ -53,14 +55,16 @@ const generateActions = ({ isFleetdHost, softwareId, status, - hasSoftwareToInstall, + software_package, + app_store_app, }: { canInstall: boolean; installingSoftwareId: number | null; isFleetdHost: boolean; softwareId: number; status: SoftwareInstallStatus | null; - hasSoftwareToInstall?: boolean; + software_package: IHostSoftwarePackage | null; + app_store_app: IHostAppStoreApp | null; }) => { // this gives us a clean slate of the default actions so we can modify // the options. @@ -73,6 +77,7 @@ const generateActions = ({ throw new Error("Install action not found in default actions"); } + const hasSoftwareToInstall = !!software_package || !!app_store_app; // remove install if there is no package to install if (!hasSoftwareToInstall || !canInstall) { actions.splice(indexInstallAction, 1); @@ -202,7 +207,8 @@ export const generateSoftwareTableHeaders = ({ installingSoftwareId, softwareId, status, - hasSoftwareToInstall: !!software_package || !!app_store_app, + software_package, + app_store_app, })} onChange={(action) => onSelectAction(original, action)} /> diff --git a/frontend/pages/hosts/details/cards/Software/SoftwareDetailsModal/SoftwareDetailsModal.tsx b/frontend/pages/hosts/details/cards/Software/SoftwareDetailsModal/SoftwareDetailsModal.tsx index a3148cd521..78638520cb 100644 --- a/frontend/pages/hosts/details/cards/Software/SoftwareDetailsModal/SoftwareDetailsModal.tsx +++ b/frontend/pages/hosts/details/cards/Software/SoftwareDetailsModal/SoftwareDetailsModal.tsx @@ -3,8 +3,10 @@ import { Tab, TabList, TabPanel, Tabs } from "react-tabs"; import { IHostSoftware, + IHostSoftwareWithLastInstall, ISoftwareInstallVersion, formatSoftwareType, + hasLastInstall, } from "interfaces/software"; import Modal from "components/Modal"; @@ -13,6 +15,7 @@ import Button from "components/buttons/Button"; import DataSet from "components/DataSet"; import { dateAgo } from "utilities/date_format"; +import { AppInstallDetails } from "components/ActivityDetails/InstallDetails/AppInstallDetails"; import { SoftwareInstallDetails } from "components/ActivityDetails/InstallDetails/SoftwareInstallDetails"; import TooltipTruncatedText from "components/TooltipTruncatedText"; @@ -88,69 +91,96 @@ const SoftwareDetailsInfo = ({ }; interface ISoftwareDetailsModalProps { + hostDisplayName: string; software: IHostSoftware; onExit: () => void; } +const SoftwareDetailsContent = ({ + software, +}: Pick) => { + const { installed_versions } = software; + + // special case when we dont have installed versions. We can only show the + // software type atm. + if (!installed_versions || installed_versions.length === 0) { + return ( +
+ +
+ ); + } + + return ( +
+ {installed_versions?.map((installedVersion) => { + return ( + + ); + })} +
+ ); +}; + +const TabsContent = ({ + hostDisplayName, + software, +}: { + hostDisplayName: string; + software: IHostSoftwareWithLastInstall; +}) => { + return ( + + + + Software details + Install details + + + + + + {software.app_store_app ? ( + + ) : ( + + )} + + + + ); +}; + const SoftwareDetailsModal = ({ + hostDisplayName, software, onExit, }: ISoftwareDetailsModalProps) => { - const installUuid = software.last_install?.install_uuid || ""; - - const renderSoftwareDetails = () => { - const { installed_versions } = software; - - // special case when we dont have installed versions. We can only show the - // software type atm. - if (!installed_versions || installed_versions.length === 0) { - return ( -
- -
- ); - } - - return ( -
- {installed_versions?.map((installedVersion) => { - return ( - - ); - })} -
- ); - }; - - const renderTabs = () => { - return ( - - - - Software details - Install Details - - {renderSoftwareDetails()} - - - - - - ); - }; - return ( <> - {software.last_install ? renderTabs() : renderSoftwareDetails()} + {!hasLastInstall(software) ? ( + + ) : ( + + )}