mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-04 02:04:06 +00:00
fix(ui): align scan filters and actions (#12781)
This commit is contained in:
@@ -0,0 +1 @@
|
||||
Scans page filter widths and action button styling, with Launch Scan and Import Findings grouped beside the tabs and sized consistently with Configure Mutelist
|
||||
@@ -223,10 +223,9 @@ export function ImportFindingsModal() {
|
||||
<>
|
||||
<Button
|
||||
type="button"
|
||||
size="lg"
|
||||
variant="secondary"
|
||||
variant="outline"
|
||||
onClick={() => handleOpenChange(true)}
|
||||
className="w-full md:w-auto"
|
||||
className="w-full sm:w-auto"
|
||||
>
|
||||
Import Findings
|
||||
</Button>
|
||||
|
||||
@@ -31,7 +31,7 @@ interface ScansFilterBarProps {
|
||||
onScanStatusChange: (value: string) => void;
|
||||
}
|
||||
|
||||
const filterItemClass = "w-full md:w-[calc(50%-0.375rem)] xl:w-60";
|
||||
const filterItemClass = "w-full sm:max-w-[240px] sm:min-w-[180px] sm:flex-1";
|
||||
|
||||
export function ScansFilterBar({
|
||||
providers,
|
||||
@@ -67,33 +67,37 @@ export function ScansFilterBar({
|
||||
</div>
|
||||
|
||||
{showScheduleTypeFilter && (
|
||||
<Select value={scheduleType} onValueChange={onScheduleTypeChange}>
|
||||
<SelectTrigger aria-label="All Types" className={filterItemClass}>
|
||||
<SelectValue placeholder="All Types" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{triggerFilterOptions.map((option) => (
|
||||
<SelectItem key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<div className={filterItemClass}>
|
||||
<Select value={scheduleType} onValueChange={onScheduleTypeChange}>
|
||||
<SelectTrigger aria-label="All Types">
|
||||
<SelectValue placeholder="All Types" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{triggerFilterOptions.map((option) => (
|
||||
<SelectItem key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showStatusFilter && (
|
||||
<Select value={scanStatus} onValueChange={onScanStatusChange}>
|
||||
<SelectTrigger aria-label="All Statuses" className={filterItemClass}>
|
||||
<SelectValue placeholder="All Statuses" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{statusFilterOptions.map((option) => (
|
||||
<SelectItem key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<div className={filterItemClass}>
|
||||
<Select value={scanStatus} onValueChange={onScanStatusChange}>
|
||||
<SelectTrigger aria-label="All Statuses">
|
||||
<SelectValue placeholder="All Statuses" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{statusFilterOptions.map((option) => (
|
||||
<SelectItem key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -336,26 +336,35 @@ describe("ScansPageShell", () => {
|
||||
expect(screen.queryByRole("alert")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("keeps launch scan with filters and mutelist with tabs", () => {
|
||||
vi.stubEnv("UI_CLOUD_ENABLED", "false");
|
||||
it("keeps launch scan, import findings, and mutelist with tabs", () => {
|
||||
// Given
|
||||
vi.stubEnv("UI_CLOUD_ENABLED", "true");
|
||||
|
||||
// When
|
||||
render(
|
||||
<ScansPageShell providers={providers} hasManageScansPermission>
|
||||
<ScansPageShell
|
||||
providers={providers}
|
||||
hasManageScansPermission
|
||||
hasManageIngestionsPermission
|
||||
>
|
||||
<div>Scans table</div>
|
||||
</ScansPageShell>,
|
||||
);
|
||||
|
||||
expect(
|
||||
screen.getByRole("group", { name: /scan filters and actions/i }),
|
||||
).toContainElement(screen.getByRole("button", { name: /launch scan/i }));
|
||||
expect(
|
||||
screen.getByRole("group", { name: /scan filters and actions/i }),
|
||||
).not.toContainElement(
|
||||
screen.getByRole("link", { name: /configure mutelist/i }),
|
||||
// Then
|
||||
const tabs = screen.getByRole("group", { name: /scan tabs/i });
|
||||
expect(tabs).toContainElement(
|
||||
screen.getByRole("button", { name: /launch scan/i }),
|
||||
);
|
||||
expect(screen.getByRole("group", { name: /scan tabs/i })).toContainElement(
|
||||
expect(tabs).toContainElement(
|
||||
screen.getByRole("button", { name: /import findings/i }),
|
||||
);
|
||||
expect(tabs).toContainElement(
|
||||
screen.getByRole("link", { name: /configure mutelist/i }),
|
||||
);
|
||||
expect(
|
||||
screen.getByRole("group", { name: /scan filters/i }),
|
||||
).toContainElement(screen.getByText("Shared scan filters"));
|
||||
});
|
||||
|
||||
it("shows the active scans count in the in progress tab", () => {
|
||||
|
||||
@@ -135,8 +135,8 @@ export function ScansPageShell({
|
||||
)}
|
||||
<div
|
||||
role="group"
|
||||
aria-label="Scan filters and actions"
|
||||
className="flex flex-wrap items-center gap-3"
|
||||
aria-label="Scan filters"
|
||||
className="flex flex-wrap items-center gap-4"
|
||||
>
|
||||
<ScansFilterBar
|
||||
providers={providers}
|
||||
@@ -148,20 +148,6 @@ export function ScansPageShell({
|
||||
onScheduleTypeChange={filters.setScheduleType}
|
||||
onScanStatusChange={filters.setScanStatus}
|
||||
/>
|
||||
|
||||
<Button
|
||||
type="button"
|
||||
size="lg"
|
||||
onClick={() => handleLaunchOpenChange(true)}
|
||||
disabled={launchDisabled}
|
||||
className="w-full md:w-auto"
|
||||
data-tour-id="view-first-scan-launch"
|
||||
>
|
||||
Launch Scan
|
||||
</Button>
|
||||
{isCloudEnvironment && hasManageIngestionsPermission && (
|
||||
<ImportFindingsModal />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{isCloudEnvironment && <CliImportBanner />}
|
||||
@@ -174,10 +160,10 @@ export function ScansPageShell({
|
||||
<div
|
||||
role="group"
|
||||
aria-label="Scan tabs"
|
||||
className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between"
|
||||
className="flex flex-wrap items-center justify-between gap-3"
|
||||
>
|
||||
<TabsList
|
||||
className="overflow-x-auto"
|
||||
className="w-full overflow-x-auto sm:w-auto"
|
||||
data-tour-id="view-first-scan-tabs"
|
||||
>
|
||||
{Object.values(SCAN_JOBS_TAB).map((tab) => (
|
||||
@@ -186,7 +172,19 @@ export function ScansPageShell({
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</TabsList>
|
||||
<div className="shrink-0">
|
||||
<div className="ml-auto flex w-full flex-wrap items-center gap-3 sm:w-auto">
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => handleLaunchOpenChange(true)}
|
||||
disabled={launchDisabled}
|
||||
className="w-full sm:w-auto"
|
||||
data-tour-id="view-first-scan-launch"
|
||||
>
|
||||
Launch Scan
|
||||
</Button>
|
||||
{isCloudEnvironment && hasManageIngestionsPermission && (
|
||||
<ImportFindingsModal />
|
||||
)}
|
||||
<MutedFindingsConfigButton />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
@@ -27,10 +27,10 @@ export class ScansPage extends BasePage {
|
||||
// The sidebar exposes its own icon-button labeled "Launch Scan"
|
||||
// (aria-label, wrapped in a Tooltip), so scoping by accessible name
|
||||
// alone hits a strict-mode duplicate. Scope to the page-shell's
|
||||
// filters-and-actions group, which only contains the visible-text
|
||||
// tabs-and-actions group, which only contains the visible-text
|
||||
// Launch Scan button.
|
||||
this.launchScanButton = page
|
||||
.getByRole("group", { name: /scan filters and actions/i })
|
||||
.getByRole("group", { name: /scan tabs/i })
|
||||
.getByRole("button", { name: /^Launch Scan$/i });
|
||||
this.launchScanDialog = page.getByRole("dialog");
|
||||
// The modal renders the providers picker as the shared MultiSelect-based
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
### Flow Steps
|
||||
|
||||
1. Navigate to Scans page
|
||||
2. Click "Launch Scan" to open the launch scan modal
|
||||
2. Click "Launch Scan" beside the scan tabs to open the launch scan modal
|
||||
3. Open the Cloud Account selector and choose the entry whose text contains E2E_AWS_PROVIDER_ACCOUNT_ID
|
||||
4. Optionally fill Scan Note
|
||||
5. Click "Launch Scan" in the modal
|
||||
@@ -46,6 +46,7 @@
|
||||
|
||||
- Scans page loads correctly
|
||||
- Launch Scan modal opens correctly
|
||||
- The page-level "Launch Scan" button is located in the "Scan tabs" group, distinct from the sidebar action
|
||||
- Cloud Account select is available and lists the configured provider UID
|
||||
- "Launch Scan" button is rendered and enabled when form is valid
|
||||
- Success toast message: "The scan was launched successfully."
|
||||
|
||||
Reference in New Issue
Block a user