mirror of
https://github.com/empayre/fleet.git
synced 2024-11-06 08:55:24 +00:00
Refine manage hosts page to better handle timing and loading issues (#3402)
This commit is contained in:
parent
040b8eddc3
commit
5b64985ece
1
changes/issue-3298-3297-refine-manage-hosts
Normal file
1
changes/issue-3298-3297-refine-manage-hosts
Normal file
@ -0,0 +1 @@
|
||||
* Refine manage hosts page to better handle timing and loading issues.
|
@ -1,4 +1,5 @@
|
||||
import React, { useContext, useMemo } from "react";
|
||||
import classnames from "classnames";
|
||||
import { AppContext } from "context/app";
|
||||
import { ITeam } from "interfaces/team";
|
||||
|
||||
@ -34,6 +35,7 @@ interface ITeamsDropdownProps {
|
||||
currentUserTeams: ITeam[];
|
||||
selectedTeamId: number;
|
||||
includeAll?: boolean;
|
||||
isDisabled?: boolean;
|
||||
onChange: (newSelectedValue: number) => void;
|
||||
onOpen?: () => void;
|
||||
onClose?: () => void;
|
||||
@ -45,6 +47,7 @@ const TeamsDropdown = ({
|
||||
currentUserTeams,
|
||||
selectedTeamId,
|
||||
includeAll,
|
||||
isDisabled,
|
||||
onChange,
|
||||
onOpen,
|
||||
onClose,
|
||||
@ -63,8 +66,12 @@ const TeamsDropdown = ({
|
||||
? selectedTeamId
|
||||
: teamOptions[0]?.value;
|
||||
|
||||
const dropdownWrapperClasses = classnames(`${baseClass}-wrapper`, {
|
||||
disabled: isDisabled || undefined,
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={dropdownWrapperClasses}>
|
||||
{teamOptions.length && (
|
||||
<Dropdown
|
||||
value={selectedValue}
|
||||
@ -72,6 +79,7 @@ const TeamsDropdown = ({
|
||||
className={baseClass}
|
||||
options={teamOptions}
|
||||
searchable={false}
|
||||
disabled={isDisabled || false}
|
||||
onChange={onChange}
|
||||
onOpen={onOpen}
|
||||
onClose={onClose}
|
||||
|
@ -1,3 +1,10 @@
|
||||
.component__team-dropdown-wrapper {
|
||||
&.disabled {
|
||||
cursor: auto;
|
||||
opacity: 0.75;
|
||||
}
|
||||
}
|
||||
|
||||
.component__team-dropdown {
|
||||
border: 0 !important;
|
||||
position: relative;
|
||||
|
@ -22,7 +22,7 @@ const FormField = ({
|
||||
label,
|
||||
name,
|
||||
type,
|
||||
}: IFormFieldProps) => {
|
||||
}: IFormFieldProps): JSX.Element => {
|
||||
const renderLabel = () => {
|
||||
const labelWrapperClasses = classnames(`${baseClass}__label`, {
|
||||
[`${baseClass}__label--error`]: !isEmpty(error),
|
||||
|
@ -253,6 +253,7 @@ const TeamDetailsWrapper = ({
|
||||
<TeamsDropdown
|
||||
selectedTeamId={toNumber(routeParams.team_id)}
|
||||
currentUserTeams={adminTeams || []}
|
||||
isDisabled={isLoadingTeams}
|
||||
onChange={(newSelectedValue: number) =>
|
||||
handleTeamSelect(newSelectedValue)
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ import TableContainer from "components/TableContainer";
|
||||
import TableDataError from "components/TableDataError";
|
||||
import { IActionButtonProps } from "components/TableContainer/DataTable/ActionButton";
|
||||
import TeamsDropdown from "components/TeamsDropdown";
|
||||
import Spinner from "components/Spinner";
|
||||
|
||||
import { getValidatedTeamId } from "fleet/helpers";
|
||||
import {
|
||||
@ -1078,6 +1079,7 @@ const ManageHostsPage = ({
|
||||
selectedTeamId={
|
||||
(policyId && policy?.team_id) || (currentTeam?.id as number)
|
||||
}
|
||||
isDisabled={isHostsLoading || isHostCountLoading}
|
||||
onChange={(newSelectedValue: number) =>
|
||||
handleTeamSelect(newSelectedValue)
|
||||
}
|
||||
@ -1461,7 +1463,7 @@ const ManageHostsPage = ({
|
||||
);
|
||||
};
|
||||
|
||||
const renderTable = (selectedTeam: number) => {
|
||||
const renderTable = () => {
|
||||
if (
|
||||
!config ||
|
||||
!currentUser ||
|
||||
@ -1481,7 +1483,8 @@ const ManageHostsPage = ({
|
||||
(getStatusSelected() === ALL_HOSTS_LABEL && selectedLabel.count === 0) ||
|
||||
(getStatusSelected() === ALL_HOSTS_LABEL &&
|
||||
filteredHostCount === 0 &&
|
||||
searchQuery === "")
|
||||
searchQuery === "" &&
|
||||
!isHostsLoading)
|
||||
) {
|
||||
return (
|
||||
<NoHosts
|
||||
@ -1491,6 +1494,11 @@ const ManageHostsPage = ({
|
||||
);
|
||||
}
|
||||
|
||||
// Hosts not ready to render
|
||||
if (isHostsLoading && filteredHostCount === 0) {
|
||||
return <Spinner />;
|
||||
}
|
||||
|
||||
const secondarySelectActions: IActionButtonProps[] = [
|
||||
{
|
||||
name: "transfer",
|
||||
@ -1544,8 +1552,6 @@ const ManageHostsPage = ({
|
||||
);
|
||||
};
|
||||
|
||||
const selectedTeam = currentTeam?.id || 0;
|
||||
|
||||
const renderNoEnrollSecretBanner = () => {
|
||||
const noTeamEnrollSecrets =
|
||||
currentTeam &&
|
||||
@ -1624,7 +1630,7 @@ const ManageHostsPage = ({
|
||||
{renderSoftwareVulnerabilities()}
|
||||
</div>
|
||||
))}
|
||||
{config && (!isPremiumTier || teams) && renderTable(selectedTeam)}
|
||||
{config && (!isPremiumTier || teams) ? renderTable() : <Spinner />}
|
||||
</div>
|
||||
)}
|
||||
{!isLabelsLoading && renderSidePanel()}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useState, useCallback, useContext } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { useQuery } from "react-query";
|
||||
|
||||
import { IPack } from "interfaces/pack";
|
||||
@ -12,10 +12,10 @@ import { renderFlash } from "redux/nodes/notifications/actions";
|
||||
|
||||
import PATHS from "router/paths";
|
||||
// @ts-ignore
|
||||
import deepDifference from "utilities/deep_difference";
|
||||
|
||||
import Button from "components/buttons/Button";
|
||||
import TableDataError from "components/TableDataError";
|
||||
import Spinner from "components/Spinner";
|
||||
import PacksListWrapper from "./components/PacksListWrapper";
|
||||
import RemovePackModal from "./components/RemovePackModal";
|
||||
|
||||
@ -196,7 +196,7 @@ const ManagePacksPage = ({ router }: IManagePacksPageProps): JSX.Element => {
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
{!isLoadingPacks &&
|
||||
{!isLoadingPacks ? (
|
||||
renderTable(
|
||||
onRemovePackClick,
|
||||
onEnablePackClick,
|
||||
@ -205,7 +205,10 @@ const ManagePacksPage = ({ router }: IManagePacksPageProps): JSX.Element => {
|
||||
packs,
|
||||
packsError,
|
||||
isLoadingPacks
|
||||
)}
|
||||
)
|
||||
) : (
|
||||
<Spinner />
|
||||
)}
|
||||
</div>
|
||||
{showRemovePackModal && (
|
||||
<RemovePackModal
|
||||
|
@ -20,11 +20,11 @@ import fleetQueriesAPI from "services/entities/queries";
|
||||
import teamsAPI from "services/entities/teams";
|
||||
// @ts-ignore
|
||||
import { renderFlash } from "redux/nodes/notifications/actions";
|
||||
import sortUtils from "utilities/sort";
|
||||
|
||||
import sortUtils from "utilities/sort";
|
||||
import paths from "router/paths";
|
||||
import Button from "components/buttons/Button";
|
||||
// @ts-ignore
|
||||
import Spinner from "components/Spinner";
|
||||
import TeamsDropdown from "components/TeamsDropdown";
|
||||
import IconToolTip from "components/IconToolTip";
|
||||
import TableDataError from "components/TableDataError";
|
||||
@ -153,13 +153,13 @@ const ManageSchedulePage = ({
|
||||
() => teamsAPI.loadAll({}),
|
||||
{
|
||||
enabled: !!isPremiumTier,
|
||||
refetchOnMount: false,
|
||||
refetchOnWindowFocus: false,
|
||||
select: (data) => {
|
||||
return currentUser?.teams
|
||||
? filterAndSortTeamOptions(data.teams, currentUser.teams)
|
||||
: data.teams;
|
||||
},
|
||||
refetchOnMount: false,
|
||||
refetchOnWindowFocus: false,
|
||||
}
|
||||
);
|
||||
|
||||
@ -167,9 +167,9 @@ const ManageSchedulePage = ({
|
||||
["fleetQueries"],
|
||||
() => fleetQueriesAPI.loadAll(),
|
||||
{
|
||||
select: (data) => data.queries,
|
||||
refetchOnMount: false,
|
||||
refetchOnWindowFocus: false,
|
||||
select: (data) => data.queries,
|
||||
}
|
||||
);
|
||||
|
||||
@ -450,7 +450,7 @@ const ManageSchedulePage = ({
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
{!isLoadingTeams &&
|
||||
{!isLoadingTeams ? (
|
||||
renderTable(
|
||||
onRemoveScheduledQueryClick,
|
||||
onEditScheduledQueryClick,
|
||||
@ -459,7 +459,10 @@ const ManageSchedulePage = ({
|
||||
toggleScheduleEditorModal,
|
||||
isOnGlobalTeam || false,
|
||||
selectedTeamData
|
||||
)}
|
||||
)
|
||||
) : (
|
||||
<Spinner />
|
||||
)}
|
||||
</div>
|
||||
{/* must use ternary for NaN */}
|
||||
{selectedTeamId && allTeamsScheduledQueriesList.length > 0 ? (
|
||||
|
@ -4,3 +4,10 @@
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
#app {
|
||||
.Select.is-disabled > .Select-control {
|
||||
background: transparent;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user