Skip to content

Commit

Permalink
Fleet UI: Improve select targets dropdown (#22348)
Browse files Browse the repository at this point in the history
  • Loading branch information
RachelElysia authored Sep 25, 2024
1 parent 38ba6cc commit 18026d5
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 61 deletions.
1 change: 1 addition & 0 deletions changes/21276-select-live-query-targets-improvements
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- UI Improvements to selecting live query targets (e.g. styling, closing behavior)
11 changes: 0 additions & 11 deletions frontend/components/LiveQuery/SelectTargets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -430,17 +430,6 @@ const SelectTargets = ({
);
};

if (isLoadingLabels || (isPremiumTier && isLoadingTeams)) {
return (
<div className={`${baseClass}__wrapper`}>
<h1>Select targets</h1>
<div className={`${baseClass}__page-loading`}>
<Spinner />
</div>
</div>
);
}

if (errorLabels || errorTeams) {
return (
<div className={`${baseClass}__wrapper`}>
Expand Down
90 changes: 58 additions & 32 deletions frontend/components/LiveQuery/TargetsInput/TargetsInput.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from "react";
import React, { useRef, useEffect, useState } from "react";
import { Row } from "react-table";
import { isEmpty, pullAllBy } from "lodash";

Expand All @@ -9,7 +9,6 @@ import DataError from "components/DataError";
// @ts-ignore
import InputFieldWithIcon from "components/forms/fields/InputFieldWithIcon/InputFieldWithIcon";
import TableContainer from "components/TableContainer";
import Spinner from "components/Spinner";
import { ITargestInputHostTableConfig } from "./TargetsInputHostsTableConfig";

interface ITargetsInputProps {
Expand Down Expand Up @@ -51,12 +50,39 @@ const TargetsInput = ({
handleRowSelect,
setSearchText,
}: ITargetsInputProps): JSX.Element => {
const dropdownRef = useRef<HTMLDivElement | null>(null);
const dropdownHosts =
searchResults && pullAllBy(searchResults, targetedHosts, "display_name");
const isActiveSearch =
!isEmpty(searchText) && (!hasFetchError || isTargetsLoading);

const [isActiveSearch, setIsActiveSearch] = useState(false);

const isSearchError = !isEmpty(searchText) && hasFetchError;

// Closes target search results when clicking outside of results
// But not during API loading state as it will reopen on API return
useEffect(() => {
if (!isTargetsLoading) {
const handleClickOutside = (event: MouseEvent) => {
if (
dropdownRef.current &&
!dropdownRef.current.contains(event.target as Node)
) {
setIsActiveSearch(false);
}
};

document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}
}, [isTargetsLoading]);

useEffect(() => {
setIsActiveSearch(
!isEmpty(searchText) && (!hasFetchError || isTargetsLoading)
);
}, [searchText, hasFetchError, isTargetsLoading]);
return (
<div>
<div className={baseClass}>
Expand All @@ -71,35 +97,35 @@ const TargetsInput = ({
placeholder={placeholder}
onChange={setSearchText}
/>
{isActiveSearch &&
(isTargetsLoading ? (
<Spinner />
) : (
<div className={`${baseClass}__hosts-search-dropdown`}>
<TableContainer<Row<IHost>>
columnConfigs={searchResultsTableConfig}
data={dropdownHosts}
isLoading={false}
emptyComponent={() => (
<div className="empty-search">
<div className="empty-search__inner">
<h4>No hosts match the current search criteria.</h4>
<p>
Expecting to see hosts? Try again in a few seconds as
the system catches up.
</p>
</div>
{isActiveSearch && (
<div
className={`${baseClass}__hosts-search-dropdown`}
ref={dropdownRef}
>
<TableContainer<Row<IHost>>
columnConfigs={searchResultsTableConfig}
data={dropdownHosts}
isLoading={isTargetsLoading}
emptyComponent={() => (
<div className="empty-search">
<div className="empty-search__inner">
<h4>No hosts match the current search criteria.</h4>
<p>
Expecting to see hosts? Try again in a few seconds as the
system catches up.
</p>
</div>
)}
showMarkAllPages={false}
isAllPagesSelected={false}
disableCount
disablePagination
disableMultiRowSelect
onClickRow={handleRowSelect}
/>
</div>
))}
</div>
)}
showMarkAllPages={false}
isAllPagesSelected={false}
disableCount
disablePagination
disableMultiRowSelect
onClickRow={handleRowSelect}
/>
</div>
)}
{isSearchError && (
<div className={`${baseClass}__hosts-search-dropdown`}>
<DataError />
Expand Down
36 changes: 18 additions & 18 deletions frontend/components/LiveQuery/TargetsInput/_styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@
overflow: auto;
}

&__data-table-block > div {
min-height: 89px;
}

// Properly vertically aligns host issue icon
.display_name__cell {
display: inline-flex;
Expand All @@ -39,7 +35,7 @@
}

.empty-search,
.error-search {
.data-error {
padding-top: 72px;
padding-bottom: 72px;
min-height: 225px;
Expand All @@ -48,16 +44,14 @@
box-shadow: 0px 4px 10px rgba(52, 59, 96, 0.15);
box-sizing: border-box;

&__inner {
h4 {
margin: 0;
margin-bottom: 16px;
font-size: $small;
}
p {
margin: 0;
font-size: $x-small;
}
h4 {
margin: 0;
margin-bottom: 16px;
font-size: $small;
}
p {
margin: 0;
font-size: $x-small;
}
}
}
Expand Down Expand Up @@ -99,9 +93,15 @@
}
}

// override the default styles for the spinner.
// TODO: set better default styles for the spinner
.data-table-block .data-table__no-rows {
min-height: 225px; // Match empty and error state
}

.loading-overlay {
height: 100%; // Match container height
}

.loading-spinner.centered {
margin: 1rem auto;
margin: auto;
}
}

0 comments on commit 18026d5

Please sign in to comment.