mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 09:28:54 +00:00
Fleet UI: Merge queries/policies tests and polish (#18737)
This commit is contained in:
parent
24696a6f1b
commit
973b0780d4
11 changed files with 459 additions and 138 deletions
|
|
@ -15,7 +15,7 @@ const InheritedBadge = ({
|
|||
}: IInheritedBadgeProps) => {
|
||||
const tooltipId = uniqueId();
|
||||
return (
|
||||
<div className={`${baseClass}`}>
|
||||
<div className={baseClass}>
|
||||
<span
|
||||
className={`${baseClass}__element-text`}
|
||||
data-tooltip-id={tooltipId}
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ interface IManageHostsProps {
|
|||
router: InjectedRouter;
|
||||
params: Params;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
location: any; // no type in react-router v3
|
||||
location: any; // no type in react-router v3 TODO: Improve this type
|
||||
}
|
||||
|
||||
const CSV_HOSTS_TITLE = "Hosts";
|
||||
|
|
|
|||
|
|
@ -664,7 +664,6 @@ const ManagePolicyPage = ({
|
|||
null
|
||||
}
|
||||
isPremiumTier={isPremiumTier}
|
||||
isSandboxMode={isSandboxMode}
|
||||
searchQuery={searchQuery}
|
||||
sortHeader={sortHeader}
|
||||
sortDirection={sortDirection}
|
||||
|
|
@ -684,7 +683,6 @@ const ManagePolicyPage = ({
|
|||
currentTeam={currentTeamSummary}
|
||||
currentAutomatedPolicies={currentAutomatedPolicies}
|
||||
isPremiumTier={isPremiumTier}
|
||||
isSandboxMode={isSandboxMode}
|
||||
renderPoliciesCount={() =>
|
||||
(!isFetchingGlobalCount &&
|
||||
renderPoliciesCount(globalPoliciesCount)) ||
|
||||
|
|
|
|||
|
|
@ -193,30 +193,31 @@
|
|||
}
|
||||
}
|
||||
|
||||
.critical-badge,
|
||||
.inherited-badge {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.inherited-badge {
|
||||
display: flex;
|
||||
padding: 4px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-weight: $bold;
|
||||
font-size: $xxx-small;
|
||||
color: $core-fleet-black;
|
||||
border-radius: 4px;
|
||||
background: $ui-vibrant-blue-10;
|
||||
}
|
||||
|
||||
.policy-name-text {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.critical-badge,
|
||||
.policy-has-not-run {
|
||||
.critical-badge-icon {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
@include tooltip5-arrow-styles;
|
||||
|
||||
.react-tooltip {
|
||||
@include tooltip-text;
|
||||
font-style: normal;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.inherited-badge {
|
||||
overflow: initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,31 @@
|
|||
import React from "react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { screen, waitFor } from "@testing-library/react";
|
||||
import { noop } from "lodash";
|
||||
import { createCustomRenderer } from "test/test-utils";
|
||||
|
||||
import createMockUser from "__mocks__/userMock";
|
||||
import createMockPolicy from "__mocks__/policyMock";
|
||||
import PoliciesTable from "./PoliciesTable";
|
||||
|
||||
describe("Policies table", () => {
|
||||
const testCriticalPolicy = createMockPolicy({ critical: true });
|
||||
it("Renders the page-wide empty state when no policies are present", async () => {
|
||||
const render = createCustomRenderer({
|
||||
context: {
|
||||
app: {
|
||||
isGlobalAdmin: true,
|
||||
currentUser: createMockUser(),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
it("Renders a tooltip including 'Premium feature' copy for a critical policy in Sandbox mode", () => {
|
||||
render(
|
||||
<PoliciesTable
|
||||
policiesList={[testCriticalPolicy]}
|
||||
policiesList={[]}
|
||||
isLoading={false}
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
onDeletePolicyClick={() => {}}
|
||||
currentTeam={{ id: -1, name: "All teams" }}
|
||||
isPremiumTier
|
||||
isSandboxMode
|
||||
searchQuery=""
|
||||
page={0}
|
||||
onQueryChange={noop}
|
||||
|
|
@ -25,18 +33,52 @@ describe("Policies table", () => {
|
|||
/>
|
||||
);
|
||||
|
||||
expect(
|
||||
screen.getByText("This policy has been marked as critical.", {
|
||||
exact: false,
|
||||
})
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText("This is a premium feature.", { exact: false })
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText("You don't have any policies")).toBeInTheDocument();
|
||||
expect(screen.queryByText("Name")).toBeNull();
|
||||
});
|
||||
|
||||
it("Renders a tooltip excluding 'Premium feature' copy for a critical policy not in Sandbox mode", () => {
|
||||
it("Renders the empty search state when search query exists for server side search with no results", async () => {
|
||||
const render = createCustomRenderer({
|
||||
context: {
|
||||
app: {
|
||||
isGlobalAdmin: true,
|
||||
currentUser: createMockUser(),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
render(
|
||||
<PoliciesTable
|
||||
policiesList={[]}
|
||||
isLoading={false}
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
onDeletePolicyClick={() => {}}
|
||||
currentTeam={{ id: -1, name: "All teams" }}
|
||||
isPremiumTier
|
||||
searchQuery="shouldn't match anything"
|
||||
page={0}
|
||||
onQueryChange={noop}
|
||||
renderPoliciesCount={() => null}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByText("No matching policies")).toBeInTheDocument();
|
||||
expect(screen.queryByText("Name")).toBeNull();
|
||||
});
|
||||
|
||||
it("Renders a critical badge and tooltip for a critical policy", async () => {
|
||||
const render = createCustomRenderer({
|
||||
context: {
|
||||
app: {
|
||||
isGlobalAdmin: true,
|
||||
currentUser: createMockUser(),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const testCriticalPolicy = createMockPolicy({ critical: true });
|
||||
|
||||
const { user } = render(
|
||||
<PoliciesTable
|
||||
policiesList={[testCriticalPolicy]}
|
||||
isLoading={false}
|
||||
|
|
@ -44,7 +86,6 @@ describe("Policies table", () => {
|
|||
onDeletePolicyClick={() => {}}
|
||||
currentTeam={{ id: -1, name: "All teams" }}
|
||||
isPremiumTier
|
||||
isSandboxMode={false}
|
||||
searchQuery=""
|
||||
page={0}
|
||||
onQueryChange={noop}
|
||||
|
|
@ -52,13 +93,141 @@ describe("Policies table", () => {
|
|||
/>
|
||||
);
|
||||
|
||||
expect(
|
||||
screen.getByText("This policy has been marked as critical.", {
|
||||
exact: false,
|
||||
})
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByText("This is a premium feature.", { exact: false })
|
||||
).toBeNull();
|
||||
await waitFor(() => {
|
||||
waitFor(() => {
|
||||
user.hover(screen.getByTestId("policy-icon"));
|
||||
});
|
||||
|
||||
expect(
|
||||
screen.getByText("This policy has been marked as critical.")
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it("Renders an inherited badge and tooltip for inherited policy on a team's policies page", async () => {
|
||||
const render = createCustomRenderer({
|
||||
context: {
|
||||
app: {
|
||||
isGlobalAdmin: true,
|
||||
currentUser: createMockUser(),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const testInheritedPolicy = createMockPolicy({ team_id: null });
|
||||
|
||||
const { user } = render(
|
||||
<PoliciesTable
|
||||
policiesList={[testInheritedPolicy]}
|
||||
isLoading={false}
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
onDeletePolicyClick={() => {}}
|
||||
currentTeam={{ id: 2, name: "Team 2" }}
|
||||
isPremiumTier
|
||||
searchQuery=""
|
||||
page={0}
|
||||
onQueryChange={noop}
|
||||
renderPoliciesCount={() => null}
|
||||
/>
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
waitFor(() => {
|
||||
user.hover(screen.getByText("Inherited"));
|
||||
});
|
||||
|
||||
expect(
|
||||
screen.getByText("This policy runs on all hosts.")
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it("Does not render an inherited badge and tooltip for global policy on the All teams's policies page", () => {
|
||||
const render = createCustomRenderer({
|
||||
context: {
|
||||
app: {
|
||||
isGlobalAdmin: true,
|
||||
currentUser: createMockUser(),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const testGlobalPolicy = createMockPolicy({ team_id: null });
|
||||
|
||||
render(
|
||||
<PoliciesTable
|
||||
policiesList={[testGlobalPolicy]}
|
||||
isLoading={false}
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
onDeletePolicyClick={() => {}}
|
||||
currentTeam={{ id: -1, name: "All teams" }}
|
||||
isPremiumTier
|
||||
searchQuery=""
|
||||
page={0}
|
||||
onQueryChange={noop}
|
||||
renderPoliciesCount={() => null}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.queryByText("Inherited")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("Renders the correct number of checkboxes for team policies and not inherited policies on a team's policies page and can check select all box", async () => {
|
||||
const render = createCustomRenderer({
|
||||
context: {
|
||||
app: {
|
||||
isGlobalAdmin: true,
|
||||
currentUser: createMockUser(),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const testInheritedPolicies = [
|
||||
createMockPolicy({ team_id: null, name: "Inherited policy 1" }),
|
||||
createMockPolicy({ id: 2, team_id: null, name: "Inherited policy 2" }),
|
||||
createMockPolicy({ id: 3, team_id: null, name: "Inherited policy 3" }),
|
||||
];
|
||||
|
||||
const testTeamPolicies = [
|
||||
createMockPolicy({ id: 4, team_id: 2, name: "Team policy 1" }),
|
||||
createMockPolicy({ id: 5, team_id: 2, name: "Team policy 2" }),
|
||||
];
|
||||
|
||||
const { container, user } = render(
|
||||
<PoliciesTable
|
||||
policiesList={[...testInheritedPolicies, ...testTeamPolicies]}
|
||||
isLoading={false}
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
onDeletePolicyClick={() => {}}
|
||||
currentTeam={{ id: 2, name: "Team 2" }}
|
||||
isPremiumTier
|
||||
searchQuery=""
|
||||
page={0}
|
||||
onQueryChange={noop}
|
||||
renderPoliciesCount={() => null}
|
||||
canAddOrDeletePolicy
|
||||
hasPoliciesToDelete
|
||||
/>
|
||||
);
|
||||
|
||||
const numberOfCheckboxes = container.querySelectorAll(
|
||||
"input[type='checkbox']"
|
||||
).length;
|
||||
|
||||
expect(numberOfCheckboxes).toBe(
|
||||
testTeamPolicies.length + 1 // +1 for Select all checkbox
|
||||
);
|
||||
|
||||
const checkbox = container.querySelectorAll(
|
||||
"input[type='checkbox']"
|
||||
)[0] as HTMLInputElement;
|
||||
|
||||
await waitFor(() => {
|
||||
waitFor(() => {
|
||||
user.click(checkbox);
|
||||
});
|
||||
|
||||
expect(checkbox.checked).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ interface IPoliciesTableProps {
|
|||
currentTeam: ITeamSummary | undefined;
|
||||
currentAutomatedPolicies?: number[];
|
||||
isPremiumTier?: boolean;
|
||||
isSandboxMode?: boolean;
|
||||
renderPoliciesCount: () => JSX.Element | null;
|
||||
onQueryChange: (newTableQuery: ITableQueryData) => void;
|
||||
searchQuery: string;
|
||||
|
|
@ -45,7 +44,6 @@ const PoliciesTable = ({
|
|||
currentTeam,
|
||||
currentAutomatedPolicies,
|
||||
isPremiumTier,
|
||||
isSandboxMode,
|
||||
onQueryChange,
|
||||
renderPoliciesCount,
|
||||
searchQuery,
|
||||
|
|
@ -104,8 +102,7 @@ const PoliciesTable = ({
|
|||
hasPermissionAndPoliciesToDelete,
|
||||
},
|
||||
policiesList,
|
||||
isPremiumTier,
|
||||
isSandboxMode
|
||||
isPremiumTier
|
||||
)}
|
||||
data={generateDataSet(
|
||||
policiesList,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
millisecondsToHours,
|
||||
millisecondsToMinutes,
|
||||
} from "date-fns";
|
||||
import ReactTooltip from "react-tooltip";
|
||||
import { Tooltip as ReactTooltip5 } from "react-tooltip-5";
|
||||
// @ts-ignore
|
||||
import Checkbox from "components/forms/fields/Checkbox";
|
||||
import HeaderCell from "components/TableContainer/DataTable/HeaderCell";
|
||||
|
|
@ -18,7 +18,7 @@ import PATHS from "router/paths";
|
|||
import sortUtils from "utilities/sort";
|
||||
import { PolicyResponse } from "utilities/constants";
|
||||
import { buildQueryStringFromParams } from "utilities/url";
|
||||
import { COLORS } from "styles/var/colors";
|
||||
import InheritedBadge from "components/InheritedBadge";
|
||||
import { getConditionalSelectHeaderCheckboxProps } from "components/TableContainer/utilities/config_utils";
|
||||
import PassingColumnHeader from "../PassingColumnHeader";
|
||||
|
||||
|
|
@ -87,11 +87,11 @@ const getPolicyRefreshTime = (ms: number): string => {
|
|||
|
||||
const getTooltip = (osqueryPolicyMs: number): JSX.Element => {
|
||||
return (
|
||||
<span className={`tooltip__tooltip-text`}>
|
||||
<>
|
||||
Fleet is collecting policy results. Try again
|
||||
<br />
|
||||
in about {getPolicyRefreshTime(osqueryPolicyMs)} as the system catches up.
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -104,8 +104,7 @@ const generateTableHeaders = (
|
|||
tableType?: string;
|
||||
},
|
||||
policiesList: IPolicyStats[] = [],
|
||||
isPremiumTier?: boolean,
|
||||
isSandboxMode?: boolean
|
||||
isPremiumTier?: boolean
|
||||
): IDataColumn[] => {
|
||||
const { selectedTeamId, hasPermissionAndPoliciesToDelete } = options;
|
||||
const viewingTeamPolicies = selectedTeamId !== -1;
|
||||
|
|
@ -143,11 +142,10 @@ const generateTableHeaders = (
|
|||
<>
|
||||
<div className="policy-name-text">{cellProps.cell.value}</div>
|
||||
{isPremiumTier && cellProps.row.original.critical && (
|
||||
<>
|
||||
<div className="critical-badge">
|
||||
<span
|
||||
className="critical-badge"
|
||||
data-tip
|
||||
data-for={`critical-tooltip-${cellProps.row.original.id}`}
|
||||
className="critical-badge-icon"
|
||||
data-tooltip-id={`critical-tooltip-${cellProps.row.original.id}`}
|
||||
>
|
||||
<Icon
|
||||
className="critical-policy-icon"
|
||||
|
|
@ -156,44 +154,21 @@ const generateTableHeaders = (
|
|||
color="core-fleet-blue"
|
||||
/>
|
||||
</span>
|
||||
<ReactTooltip
|
||||
<ReactTooltip5
|
||||
className="critical-tooltip"
|
||||
disableStyleInjection
|
||||
place="top"
|
||||
type="dark"
|
||||
effect="solid"
|
||||
opacity={1}
|
||||
id={`critical-tooltip-${cellProps.row.original.id}`}
|
||||
backgroundColor={COLORS["tooltip-bg"]}
|
||||
offset={8}
|
||||
positionStrategy="fixed"
|
||||
>
|
||||
This policy has been marked as critical.
|
||||
{isSandboxMode && (
|
||||
<>
|
||||
<br />
|
||||
This is a premium feature.
|
||||
</>
|
||||
)}
|
||||
</ReactTooltip>
|
||||
</>
|
||||
</ReactTooltip5>
|
||||
</div>
|
||||
)}
|
||||
{viewingTeamPolicies && !cellProps.row.original.team_id && (
|
||||
<>
|
||||
<span
|
||||
className="inherited-badge"
|
||||
data-tip
|
||||
data-for={`inherited-tooltip-${cellProps.row.original.id}`}
|
||||
>
|
||||
Inherited
|
||||
</span>
|
||||
<ReactTooltip
|
||||
className="inherited-tooltip"
|
||||
place="top"
|
||||
type="dark"
|
||||
effect="solid"
|
||||
id={`inherited-tooltip-${cellProps.row.original.id}`}
|
||||
backgroundColor={COLORS["tooltip-bg"]}
|
||||
>
|
||||
This policy runs on all hosts.
|
||||
</ReactTooltip>
|
||||
</>
|
||||
<InheritedBadge tooltipContent="This policy runs on all hosts." />
|
||||
)}
|
||||
</>
|
||||
}
|
||||
|
|
@ -228,24 +203,24 @@ const generateTableHeaders = (
|
|||
);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<div className="policy-has-not-run">
|
||||
<span
|
||||
className="text-cell text-muted has-not-run tooltip"
|
||||
data-tip
|
||||
data-for={`passing_${cellProps.row.original.id.toString()}`}
|
||||
data-tooltip-id={`passing_${cellProps.row.original.id.toString()}`}
|
||||
>
|
||||
---
|
||||
</span>
|
||||
<ReactTooltip
|
||||
place="bottom"
|
||||
effect="solid"
|
||||
backgroundColor={COLORS["tooltip-bg"]}
|
||||
<ReactTooltip5
|
||||
className="policy-has-not-run-tooltip"
|
||||
disableStyleInjection
|
||||
place="top"
|
||||
opacity={1}
|
||||
id={`passing_${cellProps.row.original.id.toString()}`}
|
||||
data-html
|
||||
offset={8}
|
||||
positionStrategy="fixed"
|
||||
>
|
||||
{getTooltip(cellProps.row.original.next_update_ms)}
|
||||
</ReactTooltip>
|
||||
</>
|
||||
</ReactTooltip5>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
|
@ -279,33 +254,30 @@ const generateTableHeaders = (
|
|||
);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<div className="policy-has-not-run">
|
||||
<span
|
||||
className="text-cell text-muted has-not-run tooltip"
|
||||
data-tip
|
||||
data-for={`failing_${cellProps.row.original.id.toString()}`}
|
||||
data-tooltip-id={`passing_${cellProps.row.original.id.toString()}`}
|
||||
>
|
||||
---
|
||||
</span>
|
||||
<ReactTooltip
|
||||
place="bottom"
|
||||
effect="solid"
|
||||
backgroundColor={COLORS["tooltip-bg"]}
|
||||
id={`failing_${cellProps.row.original.id.toString()}`}
|
||||
data-html
|
||||
<ReactTooltip5
|
||||
className="policy-has-not-run-tooltip"
|
||||
disableStyleInjection
|
||||
place="top"
|
||||
opacity={1}
|
||||
id={`passing_${cellProps.row.original.id.toString()}`}
|
||||
offset={8}
|
||||
positionStrategy="fixed"
|
||||
>
|
||||
{getTooltip(cellProps.row.original.next_update_ms)}
|
||||
</ReactTooltip>
|
||||
</>
|
||||
</ReactTooltip5>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
sortType: "caseInsensitive",
|
||||
},
|
||||
];
|
||||
console.log(
|
||||
"hasPermissionAndPoliciesToDelete",
|
||||
hasPermissionAndPoliciesToDelete
|
||||
);
|
||||
|
||||
if (hasPermissionAndPoliciesToDelete) {
|
||||
tableHeaders.unshift({
|
||||
id: "selection",
|
||||
|
|
|
|||
|
|
@ -26,10 +26,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.has-not-run {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.no-team-policy {
|
||||
border: 1px solid #e2e4ea;
|
||||
box-sizing: border-box;
|
||||
|
|
|
|||
|
|
@ -149,8 +149,17 @@
|
|||
.inherited-badge {
|
||||
overflow: initial;
|
||||
}
|
||||
.observer-can-run-badge {
|
||||
@include tooltip5-arrow-styles;
|
||||
|
||||
.react-tooltip {
|
||||
@include tooltip-text;
|
||||
font-style: normal;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
.query-icon {
|
||||
.observer-can-run-query-icon {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
|
@ -158,9 +167,6 @@
|
|||
display: flex;
|
||||
gap: $pad-xsmall;
|
||||
}
|
||||
.observer-can-run-tooltip {
|
||||
font-weight: $regular;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $break-md) {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import React from "react";
|
||||
|
||||
import { screen } from "@testing-library/react";
|
||||
import { screen, waitFor } from "@testing-library/react";
|
||||
|
||||
import { createCustomRenderer } from "test/test-utils";
|
||||
import createMockUser from "__mocks__/userMock";
|
||||
import createMockQuery from "__mocks__/queryMock";
|
||||
|
||||
import { ISchedulableQuery } from "interfaces/schedulable_query";
|
||||
import QueriesTable, { IQueriesTableProps } from "./QueriesTable";
|
||||
|
|
@ -207,4 +208,160 @@ describe("QueriesTable", () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("Renders an observer can run badge and tooltip for a observer can run query", async () => {
|
||||
const render = createCustomRenderer({
|
||||
context: {
|
||||
app: {
|
||||
isGlobalAdmin: true,
|
||||
currentUser: createMockUser(),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const testObserverCanRunQuery = [
|
||||
createMockQuery({
|
||||
observer_can_run: true,
|
||||
}),
|
||||
];
|
||||
const testQueries = testObserverCanRunQuery.map(enhanceQuery);
|
||||
|
||||
const { user } = render(
|
||||
<QueriesTable
|
||||
queriesList={testQueries}
|
||||
onlyInheritedQueries={false}
|
||||
isLoading={false}
|
||||
onDeleteQueryClick={jest.fn()}
|
||||
onCreateQueryClick={jest.fn()}
|
||||
isOnlyObserver={false}
|
||||
isObserverPlus={false}
|
||||
isAnyTeamObserverPlus={false}
|
||||
currentTeamId={1}
|
||||
/>
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
waitFor(() => {
|
||||
user.hover(screen.getByTestId("query-icon"));
|
||||
});
|
||||
|
||||
expect(
|
||||
screen.getByText("Observers can run this query.")
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it("Renders an inherited badge and tooltip for inherited query on a team's queries page", async () => {
|
||||
const render = createCustomRenderer({
|
||||
context: {
|
||||
app: {
|
||||
isGlobalAdmin: true,
|
||||
currentUser: createMockUser(),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const testInheritedQuery = [createMockQuery()];
|
||||
|
||||
const testQueries = testInheritedQuery.map(enhanceQuery);
|
||||
|
||||
const { user } = render(
|
||||
<QueriesTable
|
||||
queriesList={testQueries}
|
||||
onlyInheritedQueries={false}
|
||||
isLoading={false}
|
||||
onDeleteQueryClick={jest.fn()}
|
||||
onCreateQueryClick={jest.fn()}
|
||||
isOnlyObserver={false}
|
||||
isObserverPlus={false}
|
||||
isAnyTeamObserverPlus={false}
|
||||
currentTeamId={1}
|
||||
/>
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
waitFor(() => {
|
||||
user.hover(screen.getByText("Inherited"));
|
||||
});
|
||||
|
||||
expect(
|
||||
screen.getByText("This query runs on all hosts.")
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it("Does not render an inherited badge and tooltip for global query on the All team's queries page", () => {
|
||||
const render = createCustomRenderer({
|
||||
context: {
|
||||
app: {
|
||||
isGlobalAdmin: true,
|
||||
currentUser: createMockUser(),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const testGlobalQuery = [createMockQuery()];
|
||||
const testQueries = testGlobalQuery.map(enhanceQuery);
|
||||
|
||||
render(
|
||||
<QueriesTable
|
||||
queriesList={testQueries}
|
||||
onlyInheritedQueries={false}
|
||||
isLoading={false}
|
||||
onDeleteQueryClick={jest.fn()}
|
||||
onCreateQueryClick={jest.fn()}
|
||||
isOnlyObserver={false}
|
||||
isObserverPlus={false}
|
||||
isAnyTeamObserverPlus={false}
|
||||
currentTeamId={undefined}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.queryByText("Inherited")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("Renders the correct number of checkboxes for team queries and not inherited queries on a team's queries page and can check select all box", async () => {
|
||||
const render = createCustomRenderer({
|
||||
context: {
|
||||
app: {
|
||||
isGlobalAdmin: true,
|
||||
currentUser: createMockUser(),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { container, user } = render(
|
||||
<QueriesTable
|
||||
queriesList={[...testTeamQueries, ...testGlobalQueries]}
|
||||
onlyInheritedQueries={false}
|
||||
isLoading={false}
|
||||
onDeleteQueryClick={jest.fn()}
|
||||
onCreateQueryClick={jest.fn()}
|
||||
isOnlyObserver={false}
|
||||
isObserverPlus={false}
|
||||
isAnyTeamObserverPlus={false}
|
||||
currentTeamId={1}
|
||||
/>
|
||||
);
|
||||
|
||||
const numberOfCheckboxes = container.querySelectorAll(
|
||||
"input[type='checkbox']"
|
||||
).length;
|
||||
|
||||
expect(numberOfCheckboxes).toBe(
|
||||
testTeamQueries.length + 1 // +1 for Select all checkbox
|
||||
);
|
||||
|
||||
const checkbox = container.querySelectorAll(
|
||||
"input[type='checkbox']"
|
||||
)[0] as HTMLInputElement;
|
||||
|
||||
await waitFor(() => {
|
||||
waitFor(() => {
|
||||
user.click(checkbox);
|
||||
});
|
||||
|
||||
expect(checkbox.checked).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import TextCell from "components/TableContainer/DataTable/TextCell";
|
|||
import PerformanceImpactCell from "components/TableContainer/DataTable/PerformanceImpactCell";
|
||||
import TooltipWrapper from "components/TooltipWrapper";
|
||||
import InheritedBadge from "components/InheritedBadge";
|
||||
import { COLORS } from "styles/var/colors";
|
||||
import { Tooltip as ReactTooltip5 } from "react-tooltip-5";
|
||||
import QueryAutomationsStatusIndicator from "../QueryAutomationsStatusIndicator";
|
||||
|
||||
interface IQueryRow {
|
||||
|
|
@ -136,25 +136,50 @@ const generateTableHeaders = ({
|
|||
<>
|
||||
<div className="query-name-text">{cellProps.cell.value}</div>
|
||||
{!isOnlyObserver && cellProps.row.original.observer_can_run && (
|
||||
<>
|
||||
<div className="observer-can-run-badge">
|
||||
<span
|
||||
className="tooltip-base"
|
||||
data-tip
|
||||
data-for={`observer-can-run-tooltip-${cellProps.row.original.id}`}
|
||||
className="observer-can-run-icon"
|
||||
data-tooltip-id={`observer-can-run-tooltip-${cellProps.row.original.id}`}
|
||||
>
|
||||
<Icon className="query-icon" name="query" size="small" />
|
||||
<Icon
|
||||
className="observer-can-run-query-icon"
|
||||
name="query"
|
||||
size="small"
|
||||
color="core-fleet-blue"
|
||||
/>
|
||||
</span>
|
||||
<ReactTooltip
|
||||
<ReactTooltip5
|
||||
className="observer-can-run-tooltip"
|
||||
disableStyleInjection
|
||||
place="top"
|
||||
type="dark"
|
||||
effect="solid"
|
||||
opacity={1}
|
||||
id={`observer-can-run-tooltip-${cellProps.row.original.id}`}
|
||||
backgroundColor={COLORS["tooltip-bg"]}
|
||||
offset={8}
|
||||
positionStrategy="fixed"
|
||||
>
|
||||
Observers can run this query.
|
||||
</ReactTooltip>
|
||||
</>
|
||||
</ReactTooltip5>
|
||||
</div>
|
||||
|
||||
// <>
|
||||
// <span
|
||||
// className="tooltip-base"
|
||||
// data-tip
|
||||
// data-for={`observer-can-run-tooltip-${cellProps.row.original.id}`}
|
||||
// >
|
||||
// <Icon className="query-icon" name="query" size="small" />
|
||||
// </span>
|
||||
// <ReactTooltip
|
||||
// className="observer-can-run-tooltip"
|
||||
// place="top"
|
||||
// type="dark"
|
||||
// effect="solid"
|
||||
// id={`observer-can-run-tooltip-${cellProps.row.original.id}`}
|
||||
// backgroundColor={COLORS["tooltip-bg"]}
|
||||
// >
|
||||
// Observers can run this query.
|
||||
// </ReactTooltip>
|
||||
// </>
|
||||
)}
|
||||
{viewingTeamScope &&
|
||||
// inherited
|
||||
|
|
|
|||
Loading…
Reference in a new issue