refactor(ui): standardize "Providers" wording across UI and docs (#10971)

Co-authored-by: Pablo F.G <pablo.fernandez@prowler.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Pablo Fernandez Guerra (PFE)
2026-05-05 14:39:54 +02:00
committed by GitHub
parent 786059bfb2
commit d23c2f3b53
58 changed files with 191 additions and 186 deletions
+1 -1
View File
@@ -1003,7 +1003,7 @@ class ProwlerArgumentParser:
formatter_class=RawTextHelpFormatter,
usage="prowler [-h] [--version] {aws,azure,gcp,kubernetes,m365,github,nhn,dashboard,iac,your_provider} ...",
epilog="""
Available Cloud Providers:
Available Providers:
{aws,azure,gcp,kubernetes,m365,github,iac,nhn,your_provider}
aws AWS Provider
azure Azure Provider
@@ -32,11 +32,11 @@ Access Prowler App by logging in with **email and password**.
<img src="/images/log-in.png" alt="Log In" width="285" />
## Add Cloud Provider
## Add Provider
Configure a cloud provider for scanning:
Configure a provider for scanning:
1. Navigate to `Settings > Cloud Providers` and click `Add Account`.
1. Navigate to `Settings > Providers` and click `Add Provider`.
2. Select the cloud provider.
3. Enter the provider's identifier (Optional: Add an alias):
- **AWS**: Account ID
@@ -40,13 +40,13 @@ Before you begin, make sure you have:
### Step 2: Access Prowler Cloud
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app)
2. Go to "Configuration" > "Cloud Providers"
2. Go to "Configuration" > "Providers"
![Cloud Providers Page](/images/prowler-app/cloud-providers-page.png)
![Providers Page](/images/prowler-app/cloud-providers-page.png)
3. Click "Add Cloud Provider"
3. Click "Add Provider"
![Add a Cloud Provider](/images/prowler-app/add-cloud-provider.png)
![Add a Provider](/images/prowler-app/add-cloud-provider.png)
4. Select "Alibaba Cloud"
@@ -19,13 +19,13 @@ title: 'Getting Started With AWS on Prowler'
### Step 2: Access Prowler Cloud
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app)
2. Go to "Configuration" > "Cloud Providers"
2. Go to "Configuration" > "Providers"
![Cloud Providers Page](/images/prowler-app/cloud-providers-page.png)
![Providers Page](/images/prowler-app/cloud-providers-page.png)
3. Click "Add Cloud Provider"
3. Click "Add Provider"
![Add a Cloud Provider](/images/prowler-app/add-cloud-provider.png)
![Add a Provider](/images/prowler-app/add-cloud-provider.png)
4. Select "Amazon Web Services"
@@ -35,13 +35,13 @@ For detailed instructions on how to create the Service Principal and configure p
### Step 2: Access Prowler Cloud
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app)
2. Navigate to `Configuration` > `Cloud Providers`
2. Navigate to `Configuration` > `Providers`
![Cloud Providers Page](/images/prowler-app/cloud-providers-page.png)
![Providers Page](/images/prowler-app/cloud-providers-page.png)
3. Click on `Add Cloud Provider`
3. Click on `Add Provider`
![Add a Cloud Provider](/images/prowler-app/add-cloud-provider.png)
![Add a Provider](/images/prowler-app/add-cloud-provider.png)
4. Select `Microsoft Azure`
@@ -42,13 +42,13 @@ The Account ID is a 32-character hexadecimal string (e.g., `372e67954025e0ba6aaa
### Step 2: Open Prowler Cloud
1. Go to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app).
2. Navigate to "Configuration" > "Cloud Providers".
2. Navigate to "Configuration" > "Providers".
![Cloud Providers Page](/images/prowler-app/cloud-providers-page.png)
![Providers Page](/images/prowler-app/cloud-providers-page.png)
3. Click "Add Cloud Provider".
3. Click "Add Provider".
![Add a Cloud Provider](/images/prowler-app/add-cloud-provider.png)
![Add a Provider](/images/prowler-app/add-cloud-provider.png)
4. Select "Cloudflare".
@@ -14,13 +14,13 @@ title: 'Getting Started With GCP on Prowler'
### Step 2: Access Prowler Cloud
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app)
2. Go to "Configuration" > "Cloud Providers"
2. Go to "Configuration" > "Providers"
![Cloud Providers Page](/images/prowler-app/cloud-providers-page.png)
![Providers Page](/images/prowler-app/cloud-providers-page.png)
3. Click "Add Cloud Provider"
3. Click "Add Provider"
![Add a Cloud Provider](/images/prowler-app/add-cloud-provider.png)
![Add a Provider](/images/prowler-app/add-cloud-provider.png)
4. Select "Google Cloud Platform"
@@ -275,7 +275,7 @@ For step-by-step setup instructions for Prowler Cloud, see the [Getting Started
### Using Personal Access Token
1. In Prowler Cloud, navigate to **Configuration** > **Cloud Providers** > **Add Cloud Provider** > **GitHub**.
1. In Prowler Cloud, navigate to **Configuration** > **Providers** > **Add Provider** > **GitHub**.
2. Enter your GitHub Account ID (username or organization name).
@@ -49,13 +49,13 @@ Before adding GitHub to Prowler Cloud/App, ensure you have:
### Step 1: Access Prowler Cloud/App
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app)
2. Go to **Configuration** → **Cloud Providers**
2. Go to **Configuration** → **Providers**
![Cloud Providers Page](/images/prowler-app/cloud-providers-page.png)
![Providers Page](/images/prowler-app/cloud-providers-page.png)
3. Click **Add Cloud Provider**
3. Click **Add Provider**
![Add a Cloud Provider](/images/prowler-app/add-cloud-provider.png)
![Add a Provider](/images/prowler-app/add-cloud-provider.png)
4. Select **GitHub**
@@ -43,13 +43,13 @@ The Customer ID starts with the letter "C" followed by alphanumeric characters (
### Step 2: Open Prowler Cloud
1. Go to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app).
2. Navigate to "Configuration" > "Cloud Providers".
2. Navigate to "Configuration" > "Providers".
![Cloud Providers Page](/images/prowler-app/cloud-providers-page.png)
![Providers Page](/images/prowler-app/cloud-providers-page.png)
3. Click "Add Cloud Provider".
3. Click "Add Provider".
![Add a Cloud Provider](/images/prowler-app/add-cloud-provider.png)
![Add a Provider](/images/prowler-app/add-cloud-provider.png)
4. Select "Google Workspace".
@@ -42,13 +42,13 @@ Scanner selection is not configurable in Prowler App. Default scanners, misconfi
### Step 1: Access Prowler Cloud/App
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app)
2. Go to "Configuration" > "Cloud Providers"
2. Go to "Configuration" > "Providers"
![Cloud Providers Page](/images/prowler-app/cloud-providers-page.png)
![Providers Page](/images/prowler-app/cloud-providers-page.png)
3. Click "Add Cloud Provider"
3. Click "Add Provider"
![Add a Cloud Provider](/images/prowler-app/add-cloud-provider.png)
![Add a Provider](/images/prowler-app/add-cloud-provider.png)
4. Select "Infrastructure as Code"
@@ -34,13 +34,13 @@ Prowler Cloud does not support scanner selection. The vulnerability, secret, and
### Step 1: Access Prowler Cloud
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app)
2. Navigate to "Configuration" > "Cloud Providers"
2. Navigate to "Configuration" > "Providers"
![Cloud Providers Page](/images/prowler-app/cloud-providers-page.png)
![Providers Page](/images/prowler-app/cloud-providers-page.png)
3. Click "Add Cloud Provider"
3. Click "Add Provider"
![Add a Cloud Provider](/images/prowler-app/add-cloud-provider.png)
![Add a Provider](/images/prowler-app/add-cloud-provider.png)
4. Select "Container Registry"
@@ -7,13 +7,13 @@ title: 'Getting Started with Kubernetes'
### Step 1: Access Prowler Cloud/App
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app)
2. Go to "Configuration" > "Cloud Providers"
2. Go to "Configuration" > "Providers"
![Cloud Providers Page](/images/prowler-app/cloud-providers-page.png)
![Providers Page](/images/prowler-app/cloud-providers-page.png)
3. Click "Add Cloud Provider"
3. Click "Add Provider"
![Add a Cloud Provider](/images/prowler-app/add-cloud-provider.png)
![Add a Provider](/images/prowler-app/add-cloud-provider.png)
4. Select "Kubernetes"
@@ -42,13 +42,13 @@ Set up authentication for Microsoft 365 with the [Microsoft 365 Authentication](
### Step 2: Open Prowler Cloud
1. Go to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app).
2. Navigate to "Configuration" > "Cloud Providers".
2. Navigate to "Configuration" > "Providers".
![Cloud Providers Page](/images/prowler-app/cloud-providers-page.png)
![Providers Page](/images/prowler-app/cloud-providers-page.png)
3. Click "Add Cloud Provider".
3. Click "Add Provider".
![Add a Cloud Provider](/images/prowler-app/add-cloud-provider.png)
![Add a Provider](/images/prowler-app/add-cloud-provider.png)
4. Select "Microsoft 365".
@@ -38,7 +38,7 @@ If **Require IP Access List for the Atlas Administration API** is enabled in you
### Step 1: Add the provider
1. Navigate to **Cloud Providers** and click **Add Cloud Provider**.
1. Navigate to **Providers** and click **Add Provider**.
![Add provider list](./img/add-provider-list.png)
2. Select **MongoDB Atlas** from the provider list.
3. Enter your **Organization ID** (24 hex characters). This value is visible in the Atlas UI under **Organization Settings**.
@@ -16,8 +16,8 @@ The following steps apply to Prowler Cloud and the self-hosted Prowler App.
### Step 2: Access Prowler Cloud
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app).
2. Go to **Configuration** → **Cloud Providers** and click **Add Cloud Provider**.
![Add OCI Cloud Provider](./images/oci-add-cloud-provider.png)
2. Go to **Configuration** → **Providers** and click **Add Provider**.
![Add OCI Provider](./images/oci-add-cloud-provider.png)
3. Select **Oracle Cloud** and enter the **Tenancy OCID** and an optional alias, then choose **Next**.
![Add OCI Cloud Tenancy](./images/oci-add-tenancy.png)
@@ -34,7 +34,7 @@ Before running Prowler with the OpenStack provider, ensure you have:
### Step 1: Add the Provider
1. Navigate to "Cloud Providers" and click "Add Cloud Provider".
1. Navigate to "Providers" and click "Add Provider".
![Providers List](./images/select-provider.png)
2. Select "OpenStack" from the provider list.
3. Enter the "Project ID" from the OpenStack provider.
@@ -29,13 +29,13 @@ Set up authentication for Vercel with the [Vercel Authentication](/user-guide/pr
### Step 1: Add the Provider
1. Go to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app).
2. Navigate to "Configuration" > "Cloud Providers".
2. Navigate to "Configuration" > "Providers".
![Cloud Providers Page](/images/prowler-app/cloud-providers-page.png)
![Providers Page](/images/prowler-app/cloud-providers-page.png)
3. Click "Add Cloud Provider".
3. Click "Add Provider".
![Add a Cloud Provider](/images/prowler-app/add-cloud-provider.png)
![Add a Provider](/images/prowler-app/add-cloud-provider.png)
4. Select "Vercel".
@@ -123,7 +123,7 @@ The Roles section in Prowler is designed to facilitate the assignment of custom
</Note>
### Provider Groups
Provider Groups control visibility across specific providers. When creating a new role, you can assign specific groups to define their Cloud Provider visibility. This ensures that users with that role have access only to the Cloud Providers that are required.
Provider Groups control visibility across specific providers. When creating a new role, you can assign specific groups to define their Provider visibility. This ensures that users with that role have access only to the Providers that are required.
By default, a new user role does not have visibility into any group.
@@ -223,7 +223,7 @@ Assign administrative permissions by selecting from the following options:
| Invite and Manage Users | All | Invite new users and manage existing ones. |
| Manage Account | All | Adjust account settings, delete users and read/manage users permissions. |
| Manage Scans | All | Run and review scans. |
| Manage Cloud Providers | All | Add or modify connected cloud providers. |
| Manage Providers | All | Add or modify connected providers. |
| Manage Integrations | All | Add or modify the Prowler Integrations. |
| Manage Ingestions | Prowler Cloud | Allow or deny the ability to submit findings ingestion batches via the API. |
| Manage Billing | Prowler Cloud | Access and manage billing settings and subscription information. |
@@ -320,7 +320,7 @@ Once the required permissions are set up, proceed to configure the S3 integratio
![Add integration button](/images/prowler-app/s3/s3-integration-ui-3.png)
4. Complete the configuration form with the following details:
- **Cloud Providers:** Select the providers whose scan results should be exported to this S3 bucket
- **Providers:** Select the providers whose scan results should be exported to this S3 bucket
- **Bucket Name:** Enter the name of the target S3 bucket (e.g., `my-security-findings-bucket`)
- **Output Directory:** Specify the directory path within the bucket (e.g., `/prowler-findings/`, defaults to `output`)
+2 -2
View File
@@ -72,8 +72,8 @@ To perform security scans, link a cloud provider account. Prowler supports the f
Steps to add a provider:
1. Navigate to `Settings > Cloud Providers`.
2. Click `Add Account` to set up a new provider and provide your credentials.
1. Navigate to `Settings > Providers`.
2. Click `Add Provider` to set up a new provider and provide your credentials.
<img src="/images/add-provider.png" alt="Add Provider" width="700" />
@@ -246,10 +246,10 @@ Now that both roles are deployed — the management account role (Step 1) and th
### Open the Wizard
1. Navigate to **Cloud Providers** and click **Add Cloud Provider**.
1. Navigate to **Providers** and click **Add Provider**.
<Frame>
<img src="/images/organizations/cloud-providers-add.png" alt="Cloud Providers page showing the Add Cloud Provider button" />
<img src="/images/organizations/cloud-providers-add.png" alt="Providers page showing the Add Provider button" />
</Frame>
2. Select **Amazon Web Services** as the provider.
+8
View File
@@ -2,6 +2,14 @@
All notable changes to the **Prowler UI** are documented in this file.
## [1.26.0] (Prowler UNRELEASED)
### 🔄 Changed
- Standardized "Providers" wording across UI and documentation, replacing legacy "Cloud Providers" / "Accounts" / "Account Groups" copy [(#10971)](https://github.com/prowler-cloud/prowler/pull/10971)
---
## [1.25.2] (Prowler v5.25.2)
### 🔄 Changed
+3 -3
View File
@@ -23,7 +23,7 @@ export const getProviderGroups = async ({
const headers = await getAuthHeaders({ contentType: false });
if (isNaN(Number(page)) || page < 1)
redirect("/providers?tab=account-groups");
redirect("/providers?tab=provider-groups");
const url = new URL(`${apiBaseUrl}/provider-groups`);
@@ -112,7 +112,7 @@ export const createProviderGroup = async (formData: FormData) => {
body,
});
return await handleApiResponse(response, "/providers?tab=account-groups");
return await handleApiResponse(response, "/providers?tab=provider-groups");
} catch (error) {
handleApiError(error);
}
@@ -169,7 +169,7 @@ export const deleteProviderGroup = async (formData: FormData) => {
if (!providerGroupId) {
return {
errors: [{ detail: "Account Group ID is required." }],
errors: [{ detail: "Provider Group ID is required." }],
};
}
@@ -146,7 +146,7 @@ export function AccountsSelector({
const filterDescription =
selectedProviderTypes && selectedProviderTypes.length > 0
? `Accounts for ${selectedProviderTypes.map(getProviderDisplayName).join(", ")}`
: "All connected cloud provider accounts";
: "All connected provider accounts";
return (
<div className="relative">
@@ -155,8 +155,8 @@ export function AccountsSelector({
className="sr-only"
id="accounts-label"
>
Filter by cloud provider account. {filterDescription}. Select one or
more accounts to view findings.
Filter by provider account. {filterDescription}. Select one or more
accounts to view findings.
</label>
<MultiSelect values={selectedIds} onValuesChange={handleMultiValueChange}>
<MultiSelectTrigger
@@ -277,8 +277,7 @@ export const ProviderTypeSelector = ({
className="sr-only"
id="provider-type-label"
>
Filter by cloud provider type. Select one or more providers to view
findings.
Filter by provider type. Select one or more providers to view findings.
</label>
<MultiSelect
values={selectedTypes}
@@ -150,7 +150,7 @@ const getColumns = ({
{
accessorKey: "provider",
header: ({ column }) => (
<DataTableColumnHeader column={column} title="Account" />
<DataTableColumnHeader column={column} title="Provider" />
),
cell: ({ row }) => (
<EntityInfo
+2 -2
View File
@@ -11,8 +11,8 @@ export default async function ManageGroupsPage({
const groupId = resolvedSearchParams.groupId;
const target = groupId
? `/providers?tab=account-groups&groupId=${groupId}`
: "/providers?tab=account-groups";
? `/providers?tab=provider-groups&groupId=${groupId}`
: "/providers?tab=provider-groups";
redirect(target);
}
+1 -1
View File
@@ -29,7 +29,7 @@ describe("providers page", () => {
);
const source = readFileSync(columnsPath, "utf8");
// Account is fixed, Account Groups is fluid (no explicit size)
// Provider is fixed, Provider Groups is fluid (no explicit size)
expect(source).toContain("size: 420");
expect(source).toContain("size: 160");
expect(source).toContain("size: 140");
+11 -11
View File
@@ -7,7 +7,7 @@ import { ContentLayout } from "@/components/ui";
import { FilterTransitionWrapper } from "@/contexts";
import { SearchParamsProps } from "@/types";
import { AccountGroupsContent } from "./account-groups-content";
import { ProviderGroupsContent } from "./provider-groups-content";
import { ProviderPageTabs } from "./provider-page-tabs";
import { getProviderTab } from "./provider-page-tabs.shared";
import { loadProvidersAccountsViewData } from "./providers-page.utils";
@@ -25,24 +25,24 @@ export default async function Providers({
const searchParamsKey = JSON.stringify(paramsWithoutTab);
return (
<ContentLayout title="Cloud Providers" icon="lucide:cloud-cog">
<ContentLayout title="Providers" icon="lucide:cloud-cog">
<FilterTransitionWrapper>
<ProviderPageTabs
activeTab={activeTab}
accountsContent={
providersContent={
<Suspense
key={`accounts-${searchParamsKey}`}
key={`providers-${searchParamsKey}`}
fallback={<ProvidersTableFallback />}
>
<ProvidersAccountsContent searchParams={resolvedSearchParams} />
<ProvidersTabContent searchParams={resolvedSearchParams} />
</Suspense>
}
accountGroupsContent={
providerGroupsContent={
<Suspense
key={`groups-${searchParamsKey}`}
fallback={<AccountGroupsFallback />}
fallback={<ProviderGroupsFallback />}
>
<AccountGroupsContent searchParams={resolvedSearchParams} />
<ProviderGroupsContent searchParams={resolvedSearchParams} />
</Suspense>
}
/>
@@ -59,7 +59,7 @@ const ProvidersTableFallback = () => {
<Skeleton className="h-[52px] min-w-[200px] flex-1 rounded-lg md:max-w-[280px]" />
{/* Organizations filter */}
<Skeleton className="h-[52px] max-w-[240px] min-w-[180px] flex-1 rounded-lg" />
{/* Account Groups filter */}
{/* Provider Groups filter */}
<Skeleton className="h-[52px] max-w-[240px] min-w-[180px] flex-1 rounded-lg" />
{/* Status filter */}
<Skeleton className="h-[52px] max-w-[240px] min-w-[180px] flex-1 rounded-lg" />
@@ -74,7 +74,7 @@ const ProvidersTableFallback = () => {
);
};
const AccountGroupsFallback = () => {
const ProviderGroupsFallback = () => {
return (
<div className="grid min-h-[50vh] grid-cols-1 items-start gap-8 md:grid-cols-12">
<div className="col-span-1 md:col-span-4">
@@ -95,7 +95,7 @@ const AccountGroupsFallback = () => {
);
};
const ProvidersAccountsContent = async ({
const ProvidersTabContent = async ({
searchParams,
}: {
searchParams: SearchParamsProps;
@@ -9,7 +9,7 @@ import { ColumnGroups } from "@/components/manage-groups/table";
import { DataTable } from "@/components/ui/table";
import { ProviderProps, Role, SearchParamsProps } from "@/types";
export const AccountGroupsContent = async ({
export const ProviderGroupsContent = async ({
searchParams,
}: {
searchParams: SearchParamsProps;
@@ -57,10 +57,10 @@ export const AccountGroupsContent = async ({
) : (
<div className="flex flex-col">
<h1 className="mb-2 text-xl font-medium">
Create a new account group
Create a new provider group
</h1>
<p className="text-text-neutral-tertiary mb-5 text-sm">
Create a new account group to manage the providers and roles.
Create a new provider group to manage the providers and roles.
</p>
<AddGroupForm providers={providersList} roles={rolesList} />
</div>
@@ -127,9 +127,9 @@ const EditGroupSection = ({
return (
<div className="flex flex-col">
<h1 className="mb-2 text-xl font-medium">Edit account group</h1>
<h1 className="mb-2 text-xl font-medium">Edit provider group</h1>
<p className="text-text-neutral-tertiary mb-5 text-sm">
Edit the account group to manage the providers and roles.
Edit the provider group to manage the providers and roles.
</p>
<EditGroupForm
providerGroupId={providerGroupId}
@@ -1,6 +1,6 @@
const PROVIDER_TAB = {
ACCOUNTS: "accounts",
ACCOUNT_GROUPS: "account-groups",
PROVIDERS: "providers",
PROVIDER_GROUPS: "provider-groups",
} as const;
type ProviderTab = (typeof PROVIDER_TAB)[keyof typeof PROVIDER_TAB];
@@ -11,10 +11,10 @@ function isProviderTab(value: string): value is ProviderTab {
function getProviderTab(value: string | string[] | undefined): ProviderTab {
if (typeof value !== "string") {
return PROVIDER_TAB.ACCOUNTS;
return PROVIDER_TAB.PROVIDERS;
}
return isProviderTab(value) ? value : PROVIDER_TAB.ACCOUNTS;
return isProviderTab(value) ? value : PROVIDER_TAB.PROVIDERS;
}
export type { ProviderTab };
@@ -20,42 +20,41 @@ describe("ProviderPageTabs", () => {
pushMock.mockClear();
});
it("falls back to accounts when tab search params are invalid", () => {
expect(getProviderTab(undefined)).toBe(PROVIDER_TAB.ACCOUNTS);
expect(getProviderTab(["account-groups"])).toBe(PROVIDER_TAB.ACCOUNTS);
expect(getProviderTab("invalid-tab")).toBe(PROVIDER_TAB.ACCOUNTS);
expect(getProviderTab(PROVIDER_TAB.ACCOUNT_GROUPS)).toBe(
PROVIDER_TAB.ACCOUNT_GROUPS,
it("falls back to providers when tab search params are invalid", () => {
expect(getProviderTab(undefined)).toBe(PROVIDER_TAB.PROVIDERS);
expect(getProviderTab(["provider-groups"])).toBe(PROVIDER_TAB.PROVIDERS);
expect(getProviderTab("invalid-tab")).toBe(PROVIDER_TAB.PROVIDERS);
expect(getProviderTab(PROVIDER_TAB.PROVIDER_GROUPS)).toBe(
PROVIDER_TAB.PROVIDER_GROUPS,
);
});
it("shows the accounts tab when the route changes back to accounts", () => {
it("shows the providers tab when the route changes back to providers", () => {
const { rerender } = render(
<ProviderPageTabs
activeTab={PROVIDER_TAB.ACCOUNT_GROUPS}
accountsContent={<div>Accounts content</div>}
accountGroupsContent={<div>Account groups content</div>}
activeTab={PROVIDER_TAB.PROVIDER_GROUPS}
providersContent={<div>Providers content</div>}
providerGroupsContent={<div>Provider groups content</div>}
/>,
);
expect(screen.getByRole("tab", { name: "Account Groups" })).toHaveAttribute(
"data-state",
"active",
);
expect(
screen.getByRole("tab", { name: "Provider Groups" }),
).toHaveAttribute("data-state", "active");
rerender(
<ProviderPageTabs
activeTab={PROVIDER_TAB.ACCOUNTS}
accountsContent={<div>Accounts content</div>}
accountGroupsContent={<div>Account groups content</div>}
activeTab={PROVIDER_TAB.PROVIDERS}
providersContent={<div>Providers content</div>}
providerGroupsContent={<div>Provider groups content</div>}
/>,
);
expect(screen.getByRole("tab", { name: "Accounts" })).toHaveAttribute(
expect(screen.getByRole("tab", { name: "Providers" })).toHaveAttribute(
"data-state",
"active",
);
expect(screen.getByText("Accounts content")).toBeVisible();
expect(screen.getByText("Providers content")).toBeVisible();
});
it("does not switch the active tab before navigation updates the route", async () => {
@@ -63,21 +62,21 @@ describe("ProviderPageTabs", () => {
render(
<ProviderPageTabs
activeTab={PROVIDER_TAB.ACCOUNTS}
accountsContent={<div>Accounts content</div>}
accountGroupsContent={<div>Account groups content</div>}
activeTab={PROVIDER_TAB.PROVIDERS}
providersContent={<div>Providers content</div>}
providerGroupsContent={<div>Provider groups content</div>}
/>,
);
await user.click(screen.getByRole("tab", { name: "Account Groups" }));
await user.click(screen.getByRole("tab", { name: "Provider Groups" }));
expect(pushMock).toHaveBeenCalledWith("/providers?tab=account-groups");
expect(screen.getByRole("tab", { name: "Accounts" })).toHaveAttribute(
expect(pushMock).toHaveBeenCalledWith("/providers?tab=provider-groups");
expect(screen.getByRole("tab", { name: "Providers" })).toHaveAttribute(
"data-state",
"active",
);
expect(
screen.getByRole("tab", { name: "Account Groups" }),
screen.getByRole("tab", { name: "Provider Groups" }),
).not.toHaveAttribute("data-state", "active");
});
});
@@ -9,14 +9,14 @@ import { PROVIDER_TAB, type ProviderTab } from "./provider-page-tabs.shared";
interface ProviderPageTabsProps {
activeTab: ProviderTab;
accountsContent: ReactNode;
accountGroupsContent: ReactNode;
providersContent: ReactNode;
providerGroupsContent: ReactNode;
}
export const ProviderPageTabs = ({
activeTab,
accountsContent,
accountGroupsContent,
providersContent,
providerGroupsContent,
}: ProviderPageTabsProps) => {
const router = useRouter();
@@ -27,7 +27,7 @@ export const ProviderPageTabs = ({
return;
}
if (typedTab === PROVIDER_TAB.ACCOUNTS) {
if (typedTab === PROVIDER_TAB.PROVIDERS) {
router.push("/providers");
} else {
router.push(`/providers?tab=${typedTab}`);
@@ -41,18 +41,18 @@ export const ProviderPageTabs = ({
className="flex w-full flex-col gap-6"
>
<TabsList>
<TabsTrigger value={PROVIDER_TAB.ACCOUNTS}>Accounts</TabsTrigger>
<TabsTrigger value={PROVIDER_TAB.ACCOUNT_GROUPS}>
Account Groups
<TabsTrigger value={PROVIDER_TAB.PROVIDERS}>Providers</TabsTrigger>
<TabsTrigger value={PROVIDER_TAB.PROVIDER_GROUPS}>
Provider Groups
</TabsTrigger>
</TabsList>
<TabsContent value={PROVIDER_TAB.ACCOUNTS} className="mt-0">
{accountsContent}
<TabsContent value={PROVIDER_TAB.PROVIDERS} className="mt-0">
{providersContent}
</TabsContent>
<TabsContent value={PROVIDER_TAB.ACCOUNT_GROUPS} className="mt-0">
{accountGroupsContent}
<TabsContent value={PROVIDER_TAB.PROVIDER_GROUPS} className="mt-0">
{providerGroupsContent}
</TabsContent>
</Tabs>
);
@@ -13,9 +13,9 @@ describe("ComplianceCard", () => {
expect(source).toContain('variant="base"');
});
it("uses a responsive stacked layout for narrow screens", () => {
it("uses a single-column stacked layout", () => {
expect(source).toContain("flex-col");
expect(source).toContain("sm:flex-row");
expect(source).not.toContain("sm:flex-row");
});
it("uses the shadcn progress component instead of Hero UI", () => {
+2 -2
View File
@@ -24,7 +24,7 @@ export const filterProviders: FilterOption[] = [
},
{
key: "provider__in",
labelCheckboxGroup: "Cloud Provider",
labelCheckboxGroup: "Provider",
values: [...PROVIDER_TYPES],
valueLabelMapping: PROVIDER_TYPE_MAPPING,
},
@@ -34,7 +34,7 @@ export const filterProviders: FilterOption[] = [
export const filterScans = [
{
key: "provider_type__in",
labelCheckboxGroup: "Cloud Provider",
labelCheckboxGroup: "Provider",
values: [...PROVIDER_TYPES],
valueLabelMapping: PROVIDER_TYPE_MAPPING,
index: 0,
@@ -169,7 +169,7 @@ export function getStandaloneFindingColumns({
{
accessorKey: "provider",
header: ({ column }) => (
<DataTableColumnHeader column={column} title="Cloud Provider" />
<DataTableColumnHeader column={column} title="Provider" />
),
cell: ({ row }) => {
const provider = getProviderData(row, "provider");
@@ -48,7 +48,7 @@ export const DeleteGroupForm = ({
title: "Success!",
description: "The provider group was removed successfully.",
});
router.push("/providers?tab=account-groups");
router.push("/providers?tab=provider-groups");
}
setIsOpen(false); // Close the modal on success
}
@@ -130,7 +130,7 @@ export const EditGroupForm = ({
title: "Success!",
description: "The group was updated successfully.",
});
router.push("/providers?tab=account-groups");
router.push("/providers?tab=provider-groups");
}
} catch (_error) {
toast({
@@ -263,7 +263,7 @@ export const EditGroupForm = ({
type="button"
variant="ghost"
onClick={() => {
router.push("/providers?tab=account-groups");
router.push("/providers?tab=provider-groups");
}}
disabled={isLoading}
>
@@ -10,7 +10,7 @@ export const ManageGroupsButton = () => {
<Button asChild variant="outline">
<Link href="/manage-groups">
<SettingsIcon size={20} />
Account Groups
Provider Groups
</Link>
</Button>
);
@@ -41,15 +41,15 @@ export function DataTableRowActions<ProviderProps>({
<ActionDropdown>
<ActionDropdownItem
icon={<Pencil />}
label="Edit Account Group"
label="Edit Provider Group"
onSelect={() =>
router.push(`/providers?tab=account-groups&groupId=${groupId}`)
router.push(`/providers?tab=provider-groups&groupId=${groupId}`)
}
/>
<ActionDropdownDangerZone>
<ActionDropdownItem
icon={<Trash2 />}
label="Delete Account Group"
label="Delete Provider Group"
destructive
onSelect={() => setIsDeleteOpen(true)}
/>
@@ -85,7 +85,7 @@ export const SkeletonTableNewFindings = () => {
<th className="px-3 py-3 text-left">
<Skeleton className="h-4 w-16 rounded" />
</th>
{/* Cloud Provider */}
{/* Provider */}
<th className="px-3 py-3 text-left">
<Skeleton className="h-4 w-24 rounded" />
</th>
@@ -140,7 +140,7 @@ export function getColumnProviders(
<div className="ml-2">
<DataTableColumnHeader
column={column}
title="Account"
title="Provider"
param="alias"
/>
</div>
@@ -200,7 +200,7 @@ export function getColumnProviders(
accessorKey: "groupNames",
size: 160,
header: ({ column }) => (
<DataTableColumnHeader column={column} title="Account Groups" />
<DataTableColumnHeader column={column} title="Provider Groups" />
),
cell: ({ row }) => {
if (isProvidersOrganizationRow(row.original)) {
@@ -251,7 +251,7 @@ export function getColumnProviders(
if (isProvidersOrganizationRow(row.original)) {
return (
<span className="text-text-neutral-tertiary text-sm">
{row.original.providerCount} Accounts
{row.original.providerCount} Providers
</span>
);
}
@@ -3,7 +3,7 @@ import { Skeleton } from "@/components/shadcn/skeleton/skeleton";
const SkeletonTableRow = () => {
return (
<tr className="border-border-neutral-secondary border-b">
{/* Account: provider logo + alias + UID */}
{/* Provider: logo + alias + UID */}
<td className="w-[420px] px-3 py-4">
<div className="flex items-center gap-3">
<Skeleton className="size-9 rounded-lg" />
@@ -13,7 +13,7 @@ const SkeletonTableRow = () => {
</div>
</div>
</td>
{/* Account Groups: badge chips */}
{/* Provider Groups: badge chips */}
<td className="px-3 py-4">
<div className="flex items-center gap-1.5">
<Skeleton className="h-6 w-14 rounded-md" />
@@ -68,11 +68,11 @@ export const SkeletonTableProviders = () => {
<table className="w-full">
<thead>
<tr className="border-border-neutral-secondary border-b">
{/* Account */}
{/* Provider */}
<th className="w-[420px] px-3 py-3 text-left">
<Skeleton className="h-4 w-16 rounded" />
</th>
{/* Account Groups */}
{/* Provider Groups */}
<th className="px-3 py-3 text-left">
<Skeleton className="h-4 w-24 rounded" />
</th>
@@ -93,7 +93,7 @@ export function ProviderWizardModal({
</DialogTitle>
<div className="text-muted-foreground flex flex-wrap items-center gap-2 text-sm">
<Info className="size-4 shrink-0" />
<span>For assistance connecting a Cloud Provider visit</span>
<span>For assistance connecting a Provider visit</span>
<Button variant="link" size="link-sm" className="h-auto p-0" asChild>
<a href={docsLink} target="_blank" rel="noopener noreferrer">
<ExternalLink className="size-3.5 shrink-0" />
@@ -42,7 +42,7 @@ describe("getProviderWizardModalTitle", () => {
it("returns add title for add mode", () => {
const title = getProviderWizardModalTitle(PROVIDER_WIZARD_MODE.ADD);
expect(title).toBe("Adding A Cloud Provider");
expect(title).toBe("Adding A Provider");
});
it("returns update title for update mode", () => {
@@ -25,7 +25,7 @@ export function getProviderWizardModalTitle(mode: ProviderWizardMode) {
return "Update Provider Credentials";
}
return "Adding A Cloud Provider";
return "Adding A Provider";
}
export function getProviderWizardDocsDestination(docsLink: string) {
@@ -44,7 +44,7 @@ export function getProviderWizardDocsDestination(docsLink: string) {
alibabacloud: "Alibaba Cloud",
cloudflare: "Cloudflare",
openstack: "OpenStack",
help: "Cloud Provider",
help: "Provider",
};
try {
@@ -21,7 +21,7 @@ interface WizardStepperProps {
const STEPS: StepConfig[] = [
{
label: "Link a Cloud Provider",
label: "Link a Provider",
description: "Enter the provider details you would like to add in Prowler.",
icon: FolderGit2,
},
@@ -92,7 +92,7 @@ export function getColumnResources({
{
accessorKey: "provider",
header: ({ column }) => (
<DataTableColumnHeader column={column} title="Cloud Provider" />
<DataTableColumnHeader column={column} title="Provider" />
),
cell: ({ row }) => {
const provider = getProviderData(row, "provider");
@@ -47,12 +47,12 @@ export const SelectScanProvider = <
return (
<div className="flex flex-col gap-2">
<span className="text-text-neutral-primary text-sm font-medium">
Select a cloud provider to launch a scan
Select a provider to launch a scan
</span>
<FormControl>
<Select value={field.value} onValueChange={field.onChange}>
<SelectTrigger>
<SelectValue placeholder="Choose a cloud provider">
<SelectValue placeholder="Choose a provider">
{selectedItem ? (
<EntityInfo
cloudProvider={
@@ -67,7 +67,7 @@ export const SelectScanProvider = <
showCopyAction={false}
/>
) : (
"Choose a cloud provider"
"Choose a provider"
)}
</SelectValue>
</SelectTrigger>
+4 -4
View File
@@ -18,18 +18,18 @@ export const NoProvidersAdded = () => {
<div className="flex flex-col items-center gap-4">
<InfoIcon className="h-10 w-10 text-gray-800 dark:text-white" />
<h2 className="text-2xl font-bold text-gray-800 dark:text-white">
No Cloud Providers Configured
No Providers Configured
</h2>
</div>
<div className="flex flex-col items-center gap-3">
<p className="text-md leading-relaxed text-gray-600 dark:text-gray-300">
No cloud providers have been configured. Start by setting up a
cloud provider.
No providers have been configured. Start by setting up a
provider.
</p>
</div>
<Button
aria-label="Open Add Cloud Provider modal"
aria-label="Open Add Provider modal"
className="w-full max-w-xs justify-center"
size="lg"
onClick={() => setOpen(true)}
@@ -14,15 +14,15 @@ export const NoProvidersConnected = () => {
<div className="flex items-center justify-start gap-3">
<InfoIcon className="h-6 w-6 text-gray-800 dark:text-white" />
<h2 className="text-lg font-bold text-gray-800 dark:text-white">
No Connected Cloud Providers
No Connected Providers
</h2>
</div>
<p className="text-sm text-gray-600 dark:text-gray-300">
No cloud providers are currently connected. Connecting a cloud
provider is required to launch on-demand scans.
No providers are currently connected. Connecting a provider is
required to launch on-demand scans.
</p>
<p className="text-sm text-gray-600 dark:text-gray-300">
Once the cloud providers are correctly configured, this message will
Once the providers are correctly configured, this message will
disappear, and on-demand scans can be launched.
</p>
</div>
@@ -30,9 +30,9 @@ export const NoProvidersConnected = () => {
<Button
asChild
className="w-full justify-center md:w-fit"
aria-label="Go to Cloud providers page"
aria-label="Go to Providers page"
>
<Link href="/providers">Review Cloud Providers</Link>
<Link href="/providers">Review Providers</Link>
</Button>
</div>
</CardContent>
@@ -75,7 +75,7 @@ export const ColumnGetScans: ColumnDef<ScanProps>[] = [
{
accessorKey: "cloudProvider",
header: ({ column }) => (
<DataTableColumnHeader column={column} title="Cloud Provider" />
<DataTableColumnHeader column={column} title="Provider" />
),
cell: ({ row }) => {
const providerInfo = row.original.providerInfo;
+2 -3
View File
@@ -385,9 +385,8 @@ export const permissionFormFields: PermissionInfo[] = [
},
{
field: "manage_providers",
label: "Manage Cloud Providers",
description:
"Allows configuration and management of cloud provider connections",
label: "Manage Providers",
description: "Allows configuration and management of provider connections",
},
{
field: "manage_integrations",
+1 -1
View File
@@ -107,7 +107,7 @@ export const getMenuList = ({ pathname }: MenuListOptions): GroupProps[] => {
label: "Configuration",
icon: Settings,
submenus: [
{ href: "/providers", label: "Cloud Providers", icon: CloudCog },
{ href: "/providers", label: "Providers", icon: CloudCog },
{
href: "/mutelist",
label: "Mutelist",
+5 -5
View File
@@ -232,7 +232,7 @@ export class ProvidersPage extends BasePage {
// Alias input
readonly aliasInput: Locator;
// Button to add a new cloud provider
// Button to add a new provider
readonly addProviderButton: Locator;
readonly providersTable: Locator;
@@ -333,15 +333,15 @@ export class ProvidersPage extends BasePage {
.getByRole("dialog")
.filter({
has: page.getByRole("heading", {
name: /Adding A Cloud Provider|Update Provider Credentials/i,
name: /Adding A Provider|Update Provider Credentials/i,
}),
})
.first();
this.wizardTitle = page.getByRole("heading", {
name: /Adding A Cloud Provider|Update Provider Credentials/i,
name: /Adding A Provider|Update Provider Credentials/i,
});
// Button to add a new cloud provider
// Button to add a new provider
this.addProviderButton = page
.getByRole("button", {
name: "Add Provider",
@@ -357,7 +357,7 @@ export class ProvidersPage extends BasePage {
// Table displaying existing providers
this.providersTable = page.getByRole("table");
// Option buttons to select the type of cloud provider (listbox with options)
// Option buttons to select the type of provider (listbox with options)
this.awsProviderRadio = page.getByRole("option", {
name: /Amazon Web Services/i,
});
+2 -2
View File
@@ -20,7 +20,7 @@ export class ScansPage extends BasePage {
super(page);
// Scan provider selection elements
this.scanProviderSelect = page.getByRole('combobox').filter({ hasText: 'Choose a cloud provider' })
this.scanProviderSelect = page.getByRole('combobox').filter({ hasText: 'Choose a provider' })
this.scanAliasInput = page.getByRole("textbox", { name: "Scan label (optional)" });
this.startNowButton = page.getByRole("button", { name: /Start now|Start scan now/i });
@@ -107,7 +107,7 @@ export class ScansPage extends BasePage {
// Scan Table exists
await expect(this.scanTable).toBeVisible();
// Find a row that contains the account ID (provider UID in Cloud Provider column)
// Find a row that contains the account ID (provider UID in Provider column)
// Note: Use a more specific locator strategy if possible in the future
const rowWithAccountId = this.scanTable
.locator("tbody tr")
@@ -3,7 +3,7 @@ import { SignInPage } from '../sign-in-base/sign-in-base-page';
const manageCloudProvidersUserFile = 'playwright/.auth/manage_cloud_providers_user.json';
authManageCloudProvidersSetup('authenticate as manage cloud providers e2e user', async ({ page }) => {
authManageCloudProvidersSetup('authenticate as manage providers e2e user', async ({ page }) => {
const cloudProvidersEmail = process.env.E2E_MANAGE_CLOUD_PROVIDERS_USER;
const cloudProvidersPassword = process.env.E2E_MANAGE_CLOUD_PROVIDERS_PASSWORD;