Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fleet UI: Improve select targets dropdown #22348

Merged
merged 2 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
iansltx marked this conversation as resolved.
Show resolved Hide resolved
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;
}
}
Loading