UI - Cleanup, tweak logic for showing query "Manage automations" button (#26152)

## For #23312 
### Follow-up for #26124 - see
[here](https://github.com/fleetdm/fleet/pull/26124#issuecomment-2640795826)

Hide Queries > Manage automations button when no All teams queries
present:

<img width="1392" alt="Screenshot 2025-02-06 at 12 10 50 PM"
src="https://github.com/user-attachments/assets/88739e75-74b7-4a8c-83d7-b72e982ee73a"
/>

If some of the following don't apply, delete the relevant line.


- [x] Added/updated automated tests
- [x] Manual QA for all new/changed functionality

---------

Co-authored-by: Jacob Shandling <jacob@fleetdm.com>
This commit is contained in:
jacobshandling 2025-02-06 13:52:37 -08:00 committed by GitHub
parent 6a0432fd8e
commit 3cab19e56d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 26 additions and 60 deletions

View file

@ -836,7 +836,6 @@ const ManagePolicyPage = ({
<PoliciesTable
policiesList={globalPolicies || []}
isLoading={isFetchingGlobalPolicies || isFetchingConfig}
onAddPolicyClick={onAddPolicyClick}
onDeletePolicyClick={onDeletePolicyClick}
canAddOrDeletePolicy={canAddOrDeletePolicy}
hasPoliciesToDelete={hasPoliciesToAutomateOrDelete}
@ -870,7 +869,6 @@ const ManagePolicyPage = ({
isLoading={
isFetchingTeamPolicies || isFetchingTeamConfig || isFetchingConfig
}
onAddPolicyClick={onAddPolicyClick}
onDeletePolicyClick={onDeletePolicyClick}
canAddOrDeletePolicy={canAddOrDeletePolicy}
hasPoliciesToDelete={hasPoliciesToAutomateOrDelete}

View file

@ -5,7 +5,6 @@ import { IPolicyStats } from "interfaces/policy";
import { ITeamSummary, APP_CONTEXT_ALL_TEAMS_ID } from "interfaces/team";
import { IEmptyTableProps } from "interfaces/empty_table";
import Button from "components/buttons/Button";
import TableContainer from "components/TableContainer";
import { ITableQueryData } from "components/TableContainer/TableContainer";
import EmptyTable from "components/EmptyTable";
@ -19,7 +18,6 @@ const DEFAULT_SORT_HEADER = "name";
interface IPoliciesTableProps {
policiesList: IPolicyStats[];
isLoading: boolean;
onAddPolicyClick?: () => void;
onDeletePolicyClick: (selectedTableIds: number[]) => void;
canAddOrDeletePolicy?: boolean;
hasPoliciesToDelete?: boolean;
@ -38,7 +36,6 @@ interface IPoliciesTableProps {
const PoliciesTable = ({
policiesList,
isLoading,
onAddPolicyClick,
onDeletePolicyClick,
canAddOrDeletePolicy,
hasPoliciesToDelete,

View file

@ -163,20 +163,12 @@ const ManageQueriesPage = ({
const enhancedQueries = queriesResponse?.queries.map(enhanceQuery);
const queriesAvailableToAutomate =
(teamIdForApi
(teamIdForApi !== API_ALL_TEAMS_ID
? enhancedQueries?.filter(
(query: IEnhancedQuery) => query.team_id === currentTeamId
)
: enhancedQueries) ?? [];
const onlyInheritedQueries = useMemo(() => {
if (teamIdForApi === API_ALL_TEAMS_ID) {
// global scope
return false;
}
return !enhancedQueries?.some((query) => query.team_id === teamIdForApi);
}, [teamIdForApi, enhancedQueries]);
const automatedQueryIds = queriesAvailableToAutomate
.filter((query) => query.automations_enabled)
.map((query) => query.id);
@ -280,9 +272,8 @@ const ManageQueriesPage = ({
queries={enhancedQueries || []}
totalQueriesCount={queriesResponse?.count}
hasNextResults={!!queriesResponse?.meta.has_next_results}
onlyInheritedQueries={onlyInheritedQueries}
curTeamScopeQueriesPresent={!!queriesAvailableToAutomate.length}
isLoading={isLoadingQueries || isFetchingQueries}
onCreateQueryClick={onCreateQueryClick}
onDeleteQueryClick={onDeleteQueryClick}
isOnlyObserver={isOnlyObserver}
isObserverPlus={isObserverPlus}
@ -394,15 +385,16 @@ const ManageQueriesPage = ({
{canCustomQuery && (
<div className={`${baseClass}__action-button-container`}>
{(isGlobalAdmin || isTeamAdmin) && !onlyInheritedQueries && (
<Button
onClick={onManageAutomationsClick}
className={`${baseClass}__manage-automations button`}
variant="inverse"
>
Manage automations
</Button>
)}
{(isGlobalAdmin || isTeamAdmin) &&
!!queriesAvailableToAutomate.length && (
<Button
onClick={onManageAutomationsClick}
className={`${baseClass}__manage-automations button`}
variant="inverse"
>
Manage automations
</Button>
)}
{canCustomQuery && (
<Button
variant="brand"

View file

@ -158,10 +158,9 @@ describe("QueriesTable", () => {
queries: [],
totalQueriesCount: 0,
hasNextResults: false,
onlyInheritedQueries: false,
curTeamScopeQueriesPresent: true,
isLoading: false,
onDeleteQueryClick: jest.fn(),
onCreateQueryClick: jest.fn(),
isOnlyObserver: false,
isObserverPlus: false,
isAnyTeamObserverPlus: false,
@ -185,10 +184,9 @@ describe("QueriesTable", () => {
queries: [],
totalQueriesCount: 0,
hasNextResults: false,
onlyInheritedQueries: false,
curTeamScopeQueriesPresent: true,
isLoading: false,
onDeleteQueryClick: jest.fn(),
onCreateQueryClick: jest.fn(),
isOnlyObserver: false,
isObserverPlus: false,
isAnyTeamObserverPlus: false,
@ -208,24 +206,14 @@ describe("QueriesTable", () => {
});
it("Renders the page-wide empty state when no queries are present (specific team)", () => {
const render = createCustomRenderer({
context: {
app: {
isGlobalAdmin: true,
currentUser: createMockUser(),
},
},
});
const testData: IQueriesTableProps[] = [
{
queries: [],
totalQueriesCount: 0,
hasNextResults: false,
onlyInheritedQueries: false,
curTeamScopeQueriesPresent: true,
isLoading: false,
onDeleteQueryClick: jest.fn(),
onCreateQueryClick: jest.fn(),
isOnlyObserver: false,
isObserverPlus: false,
isAnyTeamObserverPlus: false,
@ -250,10 +238,9 @@ describe("QueriesTable", () => {
queries: [...testGlobalQueries, ...testTeamQueries],
totalQueriesCount: 4,
hasNextResults: false,
onlyInheritedQueries: false,
curTeamScopeQueriesPresent: true,
isLoading: false,
onDeleteQueryClick: jest.fn(),
onCreateQueryClick: jest.fn(),
isOnlyObserver: false,
isObserverPlus: false,
isAnyTeamObserverPlus: false,
@ -281,10 +268,9 @@ describe("QueriesTable", () => {
queries: [],
totalQueriesCount: 0,
hasNextResults: false,
onlyInheritedQueries: false,
curTeamScopeQueriesPresent: true,
isLoading: false,
onDeleteQueryClick: jest.fn(),
onCreateQueryClick: jest.fn(),
isOnlyObserver: false,
isObserverPlus: false,
isAnyTeamObserverPlus: false,
@ -320,10 +306,9 @@ describe("QueriesTable", () => {
queries={testQueries}
totalQueriesCount={1}
hasNextResults={false}
onlyInheritedQueries={false}
curTeamScopeQueriesPresent
isLoading={false}
onDeleteQueryClick={jest.fn()}
onCreateQueryClick={jest.fn()}
isOnlyObserver={false}
isObserverPlus={false}
isAnyTeamObserverPlus={false}
@ -361,10 +346,9 @@ describe("QueriesTable", () => {
queries={testQueries}
totalQueriesCount={1}
hasNextResults={false}
onlyInheritedQueries={false}
curTeamScopeQueriesPresent
isLoading={false}
onDeleteQueryClick={jest.fn()}
onCreateQueryClick={jest.fn()}
isOnlyObserver={false}
isObserverPlus={false}
isAnyTeamObserverPlus={false}
@ -401,10 +385,9 @@ describe("QueriesTable", () => {
queries={testQueries}
totalQueriesCount={1}
hasNextResults={false}
onlyInheritedQueries={false}
curTeamScopeQueriesPresent
isLoading={false}
onDeleteQueryClick={jest.fn()}
onCreateQueryClick={jest.fn()}
isOnlyObserver={false}
isObserverPlus={false}
isAnyTeamObserverPlus={false}
@ -430,10 +413,9 @@ describe("QueriesTable", () => {
queries={[...testTeamQueries, ...testGlobalQueries]}
totalQueriesCount={4}
hasNextResults={false}
onlyInheritedQueries={false}
curTeamScopeQueriesPresent
isLoading={false}
onDeleteQueryClick={jest.fn()}
onCreateQueryClick={jest.fn()}
isOnlyObserver={false}
isObserverPlus={false}
isAnyTeamObserverPlus={false}

View file

@ -15,7 +15,6 @@ import { getNextLocationPath } from "utilities/helpers";
import { SingleValue } from "react-select-5";
import DropdownWrapper from "components/forms/fields/DropdownWrapper";
import { CustomOptionType } from "components/forms/fields/DropdownWrapper/DropdownWrapper";
import Button from "components/buttons/Button";
import TableContainer from "components/TableContainer";
import TableCount from "components/TableContainer/TableCount";
import CustomLink from "components/CustomLink";
@ -28,10 +27,9 @@ export interface IQueriesTableProps {
queries: IEnhancedQuery[] | null;
totalQueriesCount: number | undefined;
hasNextResults: boolean;
onlyInheritedQueries: boolean;
curTeamScopeQueriesPresent: boolean;
isLoading: boolean;
onDeleteQueryClick: (selectedTableQueryIds: number[]) => void;
onCreateQueryClick: () => void;
isOnlyObserver?: boolean;
isObserverPlus?: boolean;
isAnyTeamObserverPlus: boolean;
@ -86,10 +84,9 @@ const QueriesTable = ({
queries,
totalQueriesCount,
hasNextResults,
onlyInheritedQueries,
curTeamScopeQueriesPresent,
isLoading,
onDeleteQueryClick,
onCreateQueryClick,
isOnlyObserver,
isObserverPlus,
isAnyTeamObserverPlus,
@ -255,9 +252,9 @@ const QueriesTable = ({
generateColumnConfigs({
currentUser,
currentTeamId,
omitSelectionColumn: onlyInheritedQueries,
omitSelectionColumn: !curTeamScopeQueriesPresent,
}),
[currentUser, currentTeamId, onlyInheritedQueries]
[currentUser, currentTeamId, curTeamScopeQueriesPresent]
);
const searchable =
@ -299,7 +296,7 @@ const QueriesTable = ({
onQueryChange={onQueryChange}
searchable={searchable}
customControl={searchable ? renderPlatformDropdown : undefined}
disableMultiRowSelect={onlyInheritedQueries}
disableMultiRowSelect={!curTeamScopeQueriesPresent}
onClickRow={handleRowSelect}
selectedDropdownFilter={curTargetedPlatformFilter}
/>