UI – Update empty Software versions table when installable software present (#21118)

## Addresses 1a of #21053 
<img width="1498" alt="Screenshot 2024-08-06 at 7 56 38 PM"
src="https://github.com/user-attachments/assets/d2e97e07-acd7-4f0b-a609-b8b9546a742d">

- [x] Manual QA for all new/changed functionality

---------

Co-authored-by: Jacob Shandling <jacob@fleetdm.com>
This commit is contained in:
jacobshandling 2024-08-07 09:26:39 -07:00 committed by GitHub
parent c221fa3eee
commit 50ba783a25
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 58 additions and 9 deletions

View file

@ -60,6 +60,7 @@ interface ISoftwareTableProps {
router: InjectedRouter;
data?: ISoftwareTitlesResponse | ISoftwareVersionsResponse;
showVersions: boolean;
installableSoftwareExists: boolean;
isSoftwareEnabled: boolean;
query: string;
perPage: number;
@ -78,6 +79,7 @@ const SoftwareTable = ({
router,
data,
showVersions,
installableSoftwareExists,
isSoftwareEnabled,
query,
perPage,
@ -335,6 +337,8 @@ const SoftwareTable = ({
softwareFilter={softwareFilter}
isSoftwareDisabled={!isSoftwareEnabled}
noSearchQuery={query === ""}
isCollectingSoftware={data?.counts_updated_at === null}
installableSoftwareExists={installableSoftwareExists}
/>
)}
defaultSortHeader={orderKey}

View file

@ -61,7 +61,7 @@ const SoftwareTitles = ({
}: ISoftwareTitlesProps) => {
const showVersions = location.pathname === PATHS.SOFTWARE_VERSIONS;
// request to get software data
// for Titles view, request to get software data
const {
data: titlesData,
isFetching: isTitlesFetching,
@ -94,7 +94,9 @@ const SoftwareTitles = ({
}
);
// request to get software versions data
// For Versions view, request software versions data. If empty, request titles available for
// install to determine empty state copy
const {
data: versionsData,
isFetching: isVersionsFetching,
@ -127,11 +129,45 @@ const SoftwareTitles = ({
}
);
if (isTitlesLoading || isVersionsLoading) {
const {
data: titlesAvailableForInstallResponse,
isFetching: isTitlesAFIFetching,
isLoading: isTitlesAFILoading,
isError: isTitlesAFIError,
} = useQuery<
ISoftwareTitlesResponse,
Error,
ISoftwareTitlesResponse,
[ISoftwareTitlesQueryKey]
>(
[
{
scope: "software-titles",
page: 1,
perPage,
query: "",
orderDirection,
orderKey,
teamId,
availableForInstall: true,
},
],
({ queryKey: [queryKey] }) =>
softwareAPI.getSoftwareTitles(omit(queryKey, "scope")),
{
...QUERY_OPTIONS,
enabled:
location.pathname === PATHS.SOFTWARE_VERSIONS &&
versionsData &&
versionsData.count === 0,
}
);
if (isTitlesLoading || isVersionsLoading || isTitlesAFILoading) {
return <Spinner />;
}
if (isTitlesError || isVersionsError) {
if (isTitlesError || isVersionsError || isTitlesAFIError) {
return <TableDataError className={`${baseClass}__table-error`} />;
}
@ -141,6 +177,7 @@ const SoftwareTitles = ({
router={router}
data={showVersions ? versionsData : titlesData}
showVersions={showVersions}
installableSoftwareExists={!!titlesAvailableForInstallResponse?.count}
isSoftwareEnabled={isSoftwareEnabled}
query={query}
perPage={perPage}
@ -149,7 +186,9 @@ const SoftwareTitles = ({
softwareFilter={softwareFilter}
currentPage={currentPage}
teamId={teamId}
isLoading={isTitlesFetching || isVersionsFetching}
isLoading={
isTitlesFetching || isVersionsFetching || isTitlesAFIFetching
}
resetPageIndex={resetPageIndex}
/>
</div>

View file

@ -17,6 +17,8 @@ export interface IEmptySoftwareTableProps {
noSearchQuery?: boolean;
/** isCollectingSoftware is only used on the Dashboard page with a TODO to revisit */
isCollectingSoftware?: boolean;
/** true if the team has any software installers or VPP apps available to install on hosts */
installableSoftwareExists?: boolean;
}
const generateTypeText = (
@ -38,6 +40,7 @@ const EmptySoftwareTable = ({
isSoftwareDisabled,
noSearchQuery,
isCollectingSoftware,
installableSoftwareExists,
}: IEmptySoftwareTableProps): JSX.Element => {
const softwareTypeText = generateTypeText(tableName, softwareFilter);
@ -50,10 +53,14 @@ const EmptySoftwareTable = ({
emptySoftware.header = "No software detected";
}
if (softwareFilter === "allSoftware" && installableSoftwareExists) {
emptySoftware.header = "No software detected";
emptySoftware.info = "Install software on your hosts to see versions.";
}
if (isCollectingSoftware) {
emptySoftware.header = "No software detected";
emptySoftware.info =
"This report is updated every hour to protect the performance of your devices.";
emptySoftware.info = `Expecting to see ${softwareTypeText}? Check back later.`;
}
if (isSoftwareDisabled) {

View file

@ -47,7 +47,6 @@ type IInstalledVersionsCellProps = CellProps<
IHostSoftware["installed_versions"]
>;
type IVulnerabilitiesCellProps = IInstalledVersionsCellProps;
// type IActionsCellProps = CellProps<IHostSoftware, IHostSoftware["id"]>;
const generateActions = ({
userHasSWInstallPermission,

View file

@ -63,7 +63,7 @@ export interface ISoftwareVersionsQueryKey extends ISoftwareApiParams {
export interface ISoftwareTitlesQueryKey extends ISoftwareApiParams {
// used to trigger software refetches from sibling pages
addedSoftwareToken: string | null;
addedSoftwareToken?: string | null;
scope: "software-titles";
}