Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ describe("Policies table", () => {

expect(screen.getByText("You don't have any policies")).toBeInTheDocument();
expect(screen.queryByText("Name")).toBeNull();
expect(screen.queryByPlaceholderText("Search by name")).toBeNull();
expect(screen.getByPlaceholderText("Search by name")).toBeDisabled();
});

it("Renders the page-wide empty state when no policies are present (all teams)", async () => {
Expand Down Expand Up @@ -66,7 +66,7 @@ describe("Policies table", () => {
screen.getByText("You don't have any policies that apply to all fleets")
).toBeInTheDocument();
expect(screen.queryByText("Name")).toBeNull();
expect(screen.queryByPlaceholderText("Search by name")).toBeNull();
expect(screen.getByPlaceholderText("Search by name")).toBeDisabled();
});

it("Renders the page-wide empty state when no policies are present (specific team)", async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,8 @@ const PoliciesTable = ({
emptyState.info = "No policies match the current filters.";
}

const searchable = !(
policiesList?.length === 0 &&
searchQuery === "" &&
!isFiltered
);
const isTrulyEmpty =
policiesList?.length === 0 && searchQuery === "" && !isFiltered;

const isPrimoMode = config?.partnerships?.enable_primo || false;
const viewingTeamPolicies =
Expand Down Expand Up @@ -154,8 +151,10 @@ const PoliciesTable = ({
renderCount={renderPoliciesCount}
onQueryChange={onQueryChange}
inputPlaceHolder="Search by name"
searchable={searchable}
customControl={customControl}
searchable
disableSearch={isTrulyEmpty}
disableActionButton={isTrulyEmpty}
customControl={!isTrulyEmpty ? customControl : undefined}
/>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ describe("QueriesTable", () => {
screen.getByText("You don't have any reports")
).toBeInTheDocument();
expect(screen.queryByText("Interval")).toBeNull();
expect(screen.queryByPlaceholderText("Search by name")).toBeNull();
expect(screen.getByPlaceholderText("Search by name")).toBeDisabled();
});
});

Expand All @@ -201,7 +201,7 @@ describe("QueriesTable", () => {
screen.getByText("You don't have any reports that apply to all fleets")
).toBeInTheDocument();
expect(screen.queryByText("Interval")).toBeNull();
expect(screen.queryByPlaceholderText("Search by name")).toBeNull();
expect(screen.getByPlaceholderText("Search by name")).toBeDisabled();
});
});

Expand All @@ -228,7 +228,7 @@ describe("QueriesTable", () => {
screen.getByText("You don't have any reports that apply to this fleet")
).toBeInTheDocument();
expect(screen.queryByText("Interval")).toBeNull();
expect(screen.queryByPlaceholderText("Search by name")).toBeNull();
expect(screen.getByPlaceholderText("Search by name")).toBeDisabled();
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,8 @@ const QueriesTable = ({
[currentUser, currentTeamId, curTeamScopeQueriesPresent]
);

const searchable =
(totalQueriesCount ?? 0) > 0 || !!targetedPlatformParam || !!searchQuery;
const isTrulyEmpty =
(totalQueriesCount ?? 0) === 0 && !targetedPlatformParam && !searchQuery;

const trimmedSearchQuery = searchQuery.trim();

Expand Down Expand Up @@ -293,16 +293,15 @@ const QueriesTable = ({
onClick: onDeleteQueryClick,
}}
emptyComponent={() => <EmptyState {...emptyParams} />}
renderCount={() =>
((totalQueriesCount || searchQuery) && (
<TableCount name="reports" count={totalQueriesCount} />
)) ||
null
}
renderCount={() => (
<TableCount name="reports" count={totalQueriesCount} />
)}
inputPlaceHolder="Search by name"
onQueryChange={onQueryChange}
searchable={searchable}
customControl={searchable ? renderPlatformDropdown : undefined}
searchable
disableSearch={isTrulyEmpty}
disableActionButton={isTrulyEmpty}
customControl={!isTrulyEmpty ? renderPlatformDropdown : undefined}
disableMultiRowSelect={!curTeamScopeQueriesPresent}
onClickRow={handleRowSelect}
selectedDropdownFilter={curTargetedPlatformFilter}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,22 +235,24 @@ const QueryDetailsPage = ({
const isClipped = queryReport?.report_clipped;
const isLiveQueryDisabled = config?.server_settings.live_query_disabled;

const renderHeader = () => {
// Team admins/maintainers can only edit queries assigned to a team
const canEditQuery =
isGlobalAdmin ||
isGlobalMaintainer ||
(isTeamMaintainerOrTeamAdmin && storedQuery?.team_id);

const canLiveQuery =
lastEditedQueryObserverCanRun ||
isObserverPlus ||
isGlobalAdmin ||
isGlobalMaintainer ||
isTeamMaintainerOrTeamAdmin ||
isGlobalTechnician ||
isTeamTechnician;
const canLiveQuery =
lastEditedQueryObserverCanRun ||
isObserverPlus ||
isGlobalAdmin ||
isGlobalMaintainer ||
isTeamMaintainerOrTeamAdmin ||
isGlobalTechnician ||
isTeamTechnician;

const canRunLiveReport = canLiveQuery && !isLiveQueryDisabled;

// Team admins/maintainers can only edit queries assigned to a team
const canEditQuery =
isGlobalAdmin ||
isGlobalMaintainer ||
(isTeamMaintainerOrTeamAdmin && storedQuery?.team_id);

const renderHeader = () => {
// Function instead of constant eliminates race condition with filteredQueriesPath
const backPath = () => {
if (filteredQueriesPath) return filteredQueriesPath;
Expand Down Expand Up @@ -421,16 +423,26 @@ const QueryDetailsPage = ({
if (emptyCache || lastEditedQueryDiscardData) {
return (
<NoResults
queryId={queryId}
queryInterval={storedQuery?.interval}
queryUpdatedAt={storedQuery?.updated_at}
disabledCaching={disabledCaching}
disabledCachingGlobally={disabledCachingGlobally}
discardDataEnabled={lastEditedQueryDiscardData}
loggingSnapshot={loggingSnapshot}
canLiveQuery={canRunLiveReport}
canEditQuery={!!canEditQuery}
/>
);
}
return <QueryReport {...{ queryReport, isClipped }} />;
return (
<QueryReport
queryReport={queryReport}
queryId={queryId}
isClipped={isClipped}
canLiveQuery={canRunLiveReport}
/>
);
};

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import React from "react";
import { render, screen } from "@testing-library/react";

import NoResults from "./NoResults";

const baseProps = {
queryId: 42,
disabledCaching: false,
disabledCachingGlobally: false,
discardDataEnabled: false,
loggingSnapshot: true,
};

describe("NoResults", () => {
describe("no interval set", () => {
it("shows interval and live report text when user can edit and run live", () => {
render(
<NoResults {...baseProps} queryInterval={0} canEditQuery canLiveQuery />
);

expect(screen.getByText("Nothing to report")).toBeInTheDocument();
expect(screen.getByText(/Add an/)).toBeInTheDocument();
expect(screen.getByText("interval")).toBeInTheDocument();
expect(screen.getByText("live report")).toBeInTheDocument();
expect(screen.getByRole("link", { name: /live report/ })).toHaveAttribute(
"href",
expect.stringContaining("/reports/42/live")
);
});

it("shows only interval text when user can edit but not run live", () => {
render(
<NoResults
{...baseProps}
queryInterval={0}
canEditQuery
canLiveQuery={false}
/>
);

expect(screen.getByText(/Add an/)).toBeInTheDocument();
expect(screen.getByText("interval")).toBeInTheDocument();
expect(screen.queryByText("live report")).not.toBeInTheDocument();
});

it("shows only live report link when user can run live but not edit", () => {
render(
<NoResults
{...baseProps}
queryInterval={0}
canEditQuery={false}
canLiveQuery
/>
);

expect(screen.queryByText(/Add an/)).not.toBeInTheDocument();
expect(screen.getByText("live report")).toBeInTheDocument();
});

it("shows no actionable text when user can neither edit nor run live", () => {
render(
<NoResults
{...baseProps}
queryInterval={0}
canEditQuery={false}
canLiveQuery={false}
/>
);

expect(
screen.getByText(/does not collect data on a schedule/)
).toBeInTheDocument();
expect(screen.queryByText(/Add an/)).not.toBeInTheDocument();
expect(screen.queryByText("live report")).not.toBeInTheDocument();
});
});

describe("has interval but no results yet", () => {
it("shows live report link when user can run live", () => {
render(
<NoResults
{...baseProps}
queryInterval={3600}
queryUpdatedAt={new Date(0).toISOString()}
canLiveQuery
/>
);

expect(screen.getByText("Nothing to report yet")).toBeInTheDocument();
expect(screen.getByText("live report")).toBeInTheDocument();
});

it("does not show live report link when user cannot run live", () => {
render(
<NoResults
{...baseProps}
queryInterval={3600}
queryUpdatedAt={new Date(0).toISOString()}
canLiveQuery={false}
/>
);

expect(screen.getByText("Nothing to report yet")).toBeInTheDocument();
expect(screen.queryByText("live report")).not.toBeInTheDocument();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,35 @@ import React from "react";

import { add, differenceInSeconds, formatDistance } from "date-fns";

import PATHS from "router/paths";
import TooltipWrapper from "components/TooltipWrapper/TooltipWrapper";
import EmptyState from "components/EmptyState";
import CustomLink from "components/CustomLink";

interface INoResultsProps {
queryId: number;
queryInterval?: number;
queryUpdatedAt?: string;
disabledCaching: boolean;
disabledCachingGlobally: boolean;
discardDataEnabled: boolean;
loggingSnapshot: boolean;
canLiveQuery?: boolean;
canEditQuery?: boolean;
}

const baseClass = "no-results";

const NoResults = ({
queryId,
queryInterval,
queryUpdatedAt,
disabledCaching,
disabledCachingGlobally,
discardDataEnabled,
loggingSnapshot,
canLiveQuery,
canEditQuery,
}: INoResultsProps): JSX.Element => {
// Returns how many seconds it takes to expect a cached update
const secondsCheckbackTime = () => {
Expand Down Expand Up @@ -121,9 +129,28 @@ const NoResults = ({
return [
"Nothing to report",
<>
This report does not collect data on a schedule. Add <br />
an <strong>interval</strong> or run this as a live report to see
results.
This report does not collect data on a schedule.
{(canEditQuery || canLiveQuery) && (
<>
<br />
{canEditQuery && (
<>
Add an <strong>interval</strong>
</>
)}
{canEditQuery && canLiveQuery && " or "}
{canLiveQuery && (
<>
run a{" "}
<CustomLink
url={PATHS.LIVE_REPORT(queryId)}
text="live report"
/>
</>
)}{" "}
to see results.
</>
)}
</>,
];
}
Expand All @@ -139,10 +166,18 @@ const NoResults = ({
return [
"Nothing to report yet",
<>
This report has returned no data so far. If you&apos;re <br />
expecting to see results, try running a live report to
<br />
get diagnostics.
This report has returned no data so far.
{canLiveQuery && (
<>
<br />
Expecting to see results? Run a{" "}
<CustomLink
url={PATHS.LIVE_REPORT(queryId)}
text="live report"
/>{" "}
to troubleshoot.
</>
)}
</>,
];
};
Expand Down
Loading
Loading