fix(ui): polish shared table pagination and provider spacing (#10891)

This commit is contained in:
Alejandro Bailo
2026-04-24 15:40:40 +02:00
committed by GitHub
parent 22a6cc9e73
commit 4788dcade2
5 changed files with 147 additions and 18 deletions
+1
View File
@@ -17,6 +17,7 @@ All notable changes to the **Prowler UI** are documented in this file.
- Mutelist improvements: table now supports name/reason search and visual count badges for finding targets [(#10846)](https://github.com/prowler-cloud/prowler/pull/10846)
- Resources now use batch-applied filters, render metadata JSON with syntax highlighting, and more [(#10861)](https://github.com/prowler-cloud/prowler/pull/10861)
- Added knip for dead code detection with `lint:knip` and `lint:knip:fix` scripts [(#10654)](https://github.com/prowler-cloud/prowler/pull/10654)
- Table pagination controls now keep their arrows visible on hover in light theme, and more UI improvements [(#10862)](https://github.com/prowler-cloud/prowler/pull/10862)
---
@@ -0,0 +1,58 @@
import { render, screen } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import type { FilterOption, MetaDataProps, ProviderProps } from "@/types";
import type { ProvidersTableRow } from "@/types/providers-table";
vi.mock("@/components/providers/add-provider-button", () => ({
AddProviderButton: () => <button type="button">Add provider</button>,
}));
vi.mock("@/components/providers/muted-findings-config-button", () => ({
MutedFindingsConfigButton: () => (
<button type="button">Muted findings config</button>
),
}));
vi.mock("@/components/providers/providers-filters", () => ({
ProvidersFilters: () => <div data-testid="providers-filters">Filters</div>,
}));
vi.mock("@/components/providers/providers-accounts-table", () => ({
ProvidersAccountsTable: () => <div data-testid="providers-table">Table</div>,
}));
vi.mock("@/components/providers/wizard", () => ({
ProviderWizardModal: () => <div data-testid="provider-wizard-modal" />,
}));
import { ProvidersAccountsView } from "./providers-accounts-view";
const filters: FilterOption[] = [];
const providers: ProviderProps[] = [];
const rows: ProvidersTableRow[] = [];
const metadata: MetaDataProps = {
pagination: { page: 1, pages: 1, count: 0, itemsPerPage: [10] },
version: "latest",
};
describe("ProvidersAccountsView", () => {
it("keeps the same vertical spacing between filters and table as other views", () => {
render(
<ProvidersAccountsView
isCloud={false}
filters={filters}
metadata={metadata}
providers={providers}
rows={rows}
/>,
);
expect(screen.getByTestId("providers-filters").parentElement).toHaveClass(
"flex",
"flex-col",
"gap-6",
);
expect(screen.getByTestId("providers-table")).toBeInTheDocument();
});
});
@@ -60,23 +60,25 @@ export function ProvidersAccountsView({
return (
<>
<ProvidersFilters
filters={filters}
providers={providers}
actions={
<>
<MutedFindingsConfigButton />
<AddProviderButton onOpenWizard={() => openProviderWizard()} />
</>
}
/>
<ProvidersAccountsTable
isCloud={isCloud}
metadata={metadata}
rows={rows}
onOpenProviderWizard={openProviderWizard}
onOpenOrganizationWizard={openOrganizationWizard}
/>
<div className="flex flex-col gap-6">
<ProvidersFilters
filters={filters}
providers={providers}
actions={
<>
<MutedFindingsConfigButton />
<AddProviderButton onOpenWizard={() => openProviderWizard()} />
</>
}
/>
<ProvidersAccountsTable
isCloud={isCloud}
metadata={metadata}
rows={rows}
onOpenProviderWizard={openProviderWizard}
onOpenOrganizationWizard={openOrganizationWizard}
/>
</div>
<ProviderWizardModal
open={isProviderWizardOpen}
onOpenChange={handleWizardOpenChange}
@@ -0,0 +1,67 @@
import { render, screen } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import type { MetaDataProps } from "@/types";
vi.mock("next/navigation", () => ({
usePathname: () => "/providers",
useRouter: () => ({ push: vi.fn() }),
useSearchParams: () => new URLSearchParams(),
}));
vi.mock("@/lib", () => ({
getPaginationInfo: () => ({
currentPage: 2,
totalPages: 4,
totalEntries: 40,
itemsPerPageOptions: [10, 20, 50],
}),
}));
vi.mock("@/components/shadcn/select/select", () => ({
Select: ({ children }: { children: React.ReactNode }) => (
<div>{children}</div>
),
SelectContent: ({ children }: { children: React.ReactNode }) => (
<div>{children}</div>
),
SelectItem: ({
children,
value,
}: {
children: React.ReactNode;
value: string;
}) => <option value={value}>{children}</option>,
SelectTrigger: ({ children }: { children: React.ReactNode }) => (
<button type="button">{children}</button>
),
SelectValue: () => <span>10</span>,
}));
import { DataTablePagination } from "./data-table-pagination";
const metadata: MetaDataProps = {
pagination: {
page: 2,
pages: 4,
count: 40,
itemsPerPage: [10, 20, 50],
},
version: "latest",
};
describe("DataTablePagination", () => {
it("keeps navigation arrows visible on hover in light theme", () => {
render(<DataTablePagination metadata={metadata} />);
expect(screen.getByLabelText("Go to first page")).toHaveClass(
"hover:text-text-neutral-primary",
);
expect(screen.getByLabelText("Go to first page")).toHaveClass(
"hover:bg-bg-neutral-tertiary",
);
expect(screen.getByLabelText("Go to next page")).toHaveClass(
"hover:text-text-neutral-primary",
);
});
});
@@ -40,7 +40,8 @@ interface DataTablePaginationProps {
const NAV_BUTTON_STYLES = {
base: "flex items-center justify-center rounded-full p-3 transition-colors",
enabled: "text-text-neutral-secondary hover:text-white",
enabled:
"text-text-neutral-secondary hover:bg-bg-neutral-tertiary hover:text-text-neutral-primary",
disabled: "text-text-neutral-tertiary cursor-not-allowed pointer-events-none",
} as const;