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, formatter_class=RawTextHelpFormatter,
usage="prowler [-h] [--version] {aws,azure,gcp,kubernetes,m365,github,nhn,dashboard,iac,your_provider} ...", usage="prowler [-h] [--version] {aws,azure,gcp,kubernetes,m365,github,nhn,dashboard,iac,your_provider} ...",
epilog=""" epilog="""
Available Cloud Providers: Available Providers:
{aws,azure,gcp,kubernetes,m365,github,iac,nhn,your_provider} {aws,azure,gcp,kubernetes,m365,github,iac,nhn,your_provider}
aws AWS Provider aws AWS Provider
azure Azure 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" /> <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. 2. Select the cloud provider.
3. Enter the provider's identifier (Optional: Add an alias): 3. Enter the provider's identifier (Optional: Add an alias):
- **AWS**: Account ID - **AWS**: Account ID
@@ -40,13 +40,13 @@ Before you begin, make sure you have:
### Step 2: Access Prowler Cloud ### Step 2: Access Prowler Cloud
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-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 "Alibaba Cloud" 4. Select "Alibaba Cloud"
@@ -19,13 +19,13 @@ title: 'Getting Started With AWS on Prowler'
### Step 2: Access Prowler Cloud ### Step 2: Access Prowler Cloud
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-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 "Amazon Web Services" 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 ### Step 2: Access Prowler Cloud
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app) 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` 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 ### Step 2: Open Prowler Cloud
1. Go to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app). 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". 4. Select "Cloudflare".
@@ -14,13 +14,13 @@ title: 'Getting Started With GCP on Prowler'
### Step 2: Access Prowler Cloud ### Step 2: Access Prowler Cloud
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-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 "Google Cloud Platform" 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 ### 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). 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 ### Step 1: Access Prowler Cloud/App
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-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** 4. Select **GitHub**
@@ -43,13 +43,13 @@ The Customer ID starts with the letter "C" followed by alphanumeric characters (
### Step 2: Open Prowler Cloud ### Step 2: Open Prowler Cloud
1. Go to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app). 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". 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 ### Step 1: Access Prowler Cloud/App
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-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" 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 ### Step 1: Access Prowler Cloud
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app) 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" 4. Select "Container Registry"
@@ -7,13 +7,13 @@ title: 'Getting Started with Kubernetes'
### Step 1: Access Prowler Cloud/App ### Step 1: Access Prowler Cloud/App
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-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" 4. Select "Kubernetes"
@@ -42,13 +42,13 @@ Set up authentication for Microsoft 365 with the [Microsoft 365 Authentication](
### Step 2: Open Prowler Cloud ### Step 2: Open Prowler Cloud
1. Go to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app). 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". 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 ### 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) ![Add provider list](./img/add-provider-list.png)
2. Select **MongoDB Atlas** from the provider list. 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**. 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 ### Step 2: Access Prowler Cloud
1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-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** and click **Add Cloud Provider**. 2. Go to **Configuration** → **Providers** and click **Add Provider**.
![Add OCI Cloud Provider](./images/oci-add-cloud-provider.png) ![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**. 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) ![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 ### 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) ![Providers List](./images/select-provider.png)
2. Select "OpenStack" from the provider list. 2. Select "OpenStack" from the provider list.
3. Enter the "Project ID" from the OpenStack provider. 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 ### Step 1: Add the Provider
1. Go to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app). 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". 4. Select "Vercel".
@@ -123,7 +123,7 @@ The Roles section in Prowler is designed to facilitate the assignment of custom
</Note> </Note>
### Provider Groups ### 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. 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. | | 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 Account | All | Adjust account settings, delete users and read/manage users permissions. |
| Manage Scans | All | Run and review scans. | | 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 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 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. | | 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) ![Add integration button](/images/prowler-app/s3/s3-integration-ui-3.png)
4. Complete the configuration form with the following details: 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`) - **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`) - **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: Steps to add a provider:
1. Navigate to `Settings > Cloud Providers`. 1. Navigate to `Settings > Providers`.
2. Click `Add Account` to set up a new provider and provide your credentials. 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" /> <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 ### Open the Wizard
1. Navigate to **Cloud Providers** and click **Add Cloud Provider**. 1. Navigate to **Providers** and click **Add Provider**.
<Frame> <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> </Frame>
2. Select **Amazon Web Services** as the provider. 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. 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) ## [1.25.2] (Prowler v5.25.2)
### 🔄 Changed ### 🔄 Changed
+3 -3
View File
@@ -23,7 +23,7 @@ export const getProviderGroups = async ({
const headers = await getAuthHeaders({ contentType: false }); const headers = await getAuthHeaders({ contentType: false });
if (isNaN(Number(page)) || page < 1) if (isNaN(Number(page)) || page < 1)
redirect("/providers?tab=account-groups"); redirect("/providers?tab=provider-groups");
const url = new URL(`${apiBaseUrl}/provider-groups`); const url = new URL(`${apiBaseUrl}/provider-groups`);
@@ -112,7 +112,7 @@ export const createProviderGroup = async (formData: FormData) => {
body, body,
}); });
return await handleApiResponse(response, "/providers?tab=account-groups"); return await handleApiResponse(response, "/providers?tab=provider-groups");
} catch (error) { } catch (error) {
handleApiError(error); handleApiError(error);
} }
@@ -169,7 +169,7 @@ export const deleteProviderGroup = async (formData: FormData) => {
if (!providerGroupId) { if (!providerGroupId) {
return { return {
errors: [{ detail: "Account Group ID is required." }], errors: [{ detail: "Provider Group ID is required." }],
}; };
} }
@@ -146,7 +146,7 @@ export function AccountsSelector({
const filterDescription = const filterDescription =
selectedProviderTypes && selectedProviderTypes.length > 0 selectedProviderTypes && selectedProviderTypes.length > 0
? `Accounts for ${selectedProviderTypes.map(getProviderDisplayName).join(", ")}` ? `Accounts for ${selectedProviderTypes.map(getProviderDisplayName).join(", ")}`
: "All connected cloud provider accounts"; : "All connected provider accounts";
return ( return (
<div className="relative"> <div className="relative">
@@ -155,8 +155,8 @@ export function AccountsSelector({
className="sr-only" className="sr-only"
id="accounts-label" id="accounts-label"
> >
Filter by cloud provider account. {filterDescription}. Select one or Filter by provider account. {filterDescription}. Select one or more
more accounts to view findings. accounts to view findings.
</label> </label>
<MultiSelect values={selectedIds} onValuesChange={handleMultiValueChange}> <MultiSelect values={selectedIds} onValuesChange={handleMultiValueChange}>
<MultiSelectTrigger <MultiSelectTrigger
@@ -277,8 +277,7 @@ export const ProviderTypeSelector = ({
className="sr-only" className="sr-only"
id="provider-type-label" id="provider-type-label"
> >
Filter by cloud provider type. Select one or more providers to view Filter by provider type. Select one or more providers to view findings.
findings.
</label> </label>
<MultiSelect <MultiSelect
values={selectedTypes} values={selectedTypes}
@@ -150,7 +150,7 @@ const getColumns = ({
{ {
accessorKey: "provider", accessorKey: "provider",
header: ({ column }) => ( header: ({ column }) => (
<DataTableColumnHeader column={column} title="Account" /> <DataTableColumnHeader column={column} title="Provider" />
), ),
cell: ({ row }) => ( cell: ({ row }) => (
<EntityInfo <EntityInfo
+2 -2
View File
@@ -11,8 +11,8 @@ export default async function ManageGroupsPage({
const groupId = resolvedSearchParams.groupId; const groupId = resolvedSearchParams.groupId;
const target = groupId const target = groupId
? `/providers?tab=account-groups&groupId=${groupId}` ? `/providers?tab=provider-groups&groupId=${groupId}`
: "/providers?tab=account-groups"; : "/providers?tab=provider-groups";
redirect(target); redirect(target);
} }
+1 -1
View File
@@ -29,7 +29,7 @@ describe("providers page", () => {
); );
const source = readFileSync(columnsPath, "utf8"); 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: 420");
expect(source).toContain("size: 160"); expect(source).toContain("size: 160");
expect(source).toContain("size: 140"); expect(source).toContain("size: 140");
+11 -11
View File
@@ -7,7 +7,7 @@ import { ContentLayout } from "@/components/ui";
import { FilterTransitionWrapper } from "@/contexts"; import { FilterTransitionWrapper } from "@/contexts";
import { SearchParamsProps } from "@/types"; import { SearchParamsProps } from "@/types";
import { AccountGroupsContent } from "./account-groups-content"; import { ProviderGroupsContent } from "./provider-groups-content";
import { ProviderPageTabs } from "./provider-page-tabs"; import { ProviderPageTabs } from "./provider-page-tabs";
import { getProviderTab } from "./provider-page-tabs.shared"; import { getProviderTab } from "./provider-page-tabs.shared";
import { loadProvidersAccountsViewData } from "./providers-page.utils"; import { loadProvidersAccountsViewData } from "./providers-page.utils";
@@ -25,24 +25,24 @@ export default async function Providers({
const searchParamsKey = JSON.stringify(paramsWithoutTab); const searchParamsKey = JSON.stringify(paramsWithoutTab);
return ( return (
<ContentLayout title="Cloud Providers" icon="lucide:cloud-cog"> <ContentLayout title="Providers" icon="lucide:cloud-cog">
<FilterTransitionWrapper> <FilterTransitionWrapper>
<ProviderPageTabs <ProviderPageTabs
activeTab={activeTab} activeTab={activeTab}
accountsContent={ providersContent={
<Suspense <Suspense
key={`accounts-${searchParamsKey}`} key={`providers-${searchParamsKey}`}
fallback={<ProvidersTableFallback />} fallback={<ProvidersTableFallback />}
> >
<ProvidersAccountsContent searchParams={resolvedSearchParams} /> <ProvidersTabContent searchParams={resolvedSearchParams} />
</Suspense> </Suspense>
} }
accountGroupsContent={ providerGroupsContent={
<Suspense <Suspense
key={`groups-${searchParamsKey}`} key={`groups-${searchParamsKey}`}
fallback={<AccountGroupsFallback />} fallback={<ProviderGroupsFallback />}
> >
<AccountGroupsContent searchParams={resolvedSearchParams} /> <ProviderGroupsContent searchParams={resolvedSearchParams} />
</Suspense> </Suspense>
} }
/> />
@@ -59,7 +59,7 @@ const ProvidersTableFallback = () => {
<Skeleton className="h-[52px] min-w-[200px] flex-1 rounded-lg md:max-w-[280px]" /> <Skeleton className="h-[52px] min-w-[200px] flex-1 rounded-lg md:max-w-[280px]" />
{/* Organizations filter */} {/* Organizations filter */}
<Skeleton className="h-[52px] max-w-[240px] min-w-[180px] flex-1 rounded-lg" /> <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" /> <Skeleton className="h-[52px] max-w-[240px] min-w-[180px] flex-1 rounded-lg" />
{/* Status filter */} {/* Status filter */}
<Skeleton className="h-[52px] max-w-[240px] min-w-[180px] flex-1 rounded-lg" /> <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 ( return (
<div className="grid min-h-[50vh] grid-cols-1 items-start gap-8 md:grid-cols-12"> <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"> <div className="col-span-1 md:col-span-4">
@@ -95,7 +95,7 @@ const AccountGroupsFallback = () => {
); );
}; };
const ProvidersAccountsContent = async ({ const ProvidersTabContent = async ({
searchParams, searchParams,
}: { }: {
searchParams: SearchParamsProps; searchParams: SearchParamsProps;
@@ -9,7 +9,7 @@ import { ColumnGroups } from "@/components/manage-groups/table";
import { DataTable } from "@/components/ui/table"; import { DataTable } from "@/components/ui/table";
import { ProviderProps, Role, SearchParamsProps } from "@/types"; import { ProviderProps, Role, SearchParamsProps } from "@/types";
export const AccountGroupsContent = async ({ export const ProviderGroupsContent = async ({
searchParams, searchParams,
}: { }: {
searchParams: SearchParamsProps; searchParams: SearchParamsProps;
@@ -57,10 +57,10 @@ export const AccountGroupsContent = async ({
) : ( ) : (
<div className="flex flex-col"> <div className="flex flex-col">
<h1 className="mb-2 text-xl font-medium"> <h1 className="mb-2 text-xl font-medium">
Create a new account group Create a new provider group
</h1> </h1>
<p className="text-text-neutral-tertiary mb-5 text-sm"> <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> </p>
<AddGroupForm providers={providersList} roles={rolesList} /> <AddGroupForm providers={providersList} roles={rolesList} />
</div> </div>
@@ -127,9 +127,9 @@ const EditGroupSection = ({
return ( return (
<div className="flex flex-col"> <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"> <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> </p>
<EditGroupForm <EditGroupForm
providerGroupId={providerGroupId} providerGroupId={providerGroupId}
@@ -1,6 +1,6 @@
const PROVIDER_TAB = { const PROVIDER_TAB = {
ACCOUNTS: "accounts", PROVIDERS: "providers",
ACCOUNT_GROUPS: "account-groups", PROVIDER_GROUPS: "provider-groups",
} as const; } as const;
type ProviderTab = (typeof PROVIDER_TAB)[keyof typeof PROVIDER_TAB]; 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 { function getProviderTab(value: string | string[] | undefined): ProviderTab {
if (typeof value !== "string") { 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 }; export type { ProviderTab };
@@ -20,42 +20,41 @@ describe("ProviderPageTabs", () => {
pushMock.mockClear(); pushMock.mockClear();
}); });
it("falls back to accounts when tab search params are invalid", () => { it("falls back to providers when tab search params are invalid", () => {
expect(getProviderTab(undefined)).toBe(PROVIDER_TAB.ACCOUNTS); expect(getProviderTab(undefined)).toBe(PROVIDER_TAB.PROVIDERS);
expect(getProviderTab(["account-groups"])).toBe(PROVIDER_TAB.ACCOUNTS); expect(getProviderTab(["provider-groups"])).toBe(PROVIDER_TAB.PROVIDERS);
expect(getProviderTab("invalid-tab")).toBe(PROVIDER_TAB.ACCOUNTS); expect(getProviderTab("invalid-tab")).toBe(PROVIDER_TAB.PROVIDERS);
expect(getProviderTab(PROVIDER_TAB.ACCOUNT_GROUPS)).toBe( expect(getProviderTab(PROVIDER_TAB.PROVIDER_GROUPS)).toBe(
PROVIDER_TAB.ACCOUNT_GROUPS, 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( const { rerender } = render(
<ProviderPageTabs <ProviderPageTabs
activeTab={PROVIDER_TAB.ACCOUNT_GROUPS} activeTab={PROVIDER_TAB.PROVIDER_GROUPS}
accountsContent={<div>Accounts content</div>} providersContent={<div>Providers content</div>}
accountGroupsContent={<div>Account groups content</div>} providerGroupsContent={<div>Provider groups content</div>}
/>, />,
); );
expect(screen.getByRole("tab", { name: "Account Groups" })).toHaveAttribute( expect(
"data-state", screen.getByRole("tab", { name: "Provider Groups" }),
"active", ).toHaveAttribute("data-state", "active");
);
rerender( rerender(
<ProviderPageTabs <ProviderPageTabs
activeTab={PROVIDER_TAB.ACCOUNTS} activeTab={PROVIDER_TAB.PROVIDERS}
accountsContent={<div>Accounts content</div>} providersContent={<div>Providers content</div>}
accountGroupsContent={<div>Account groups content</div>} providerGroupsContent={<div>Provider groups content</div>}
/>, />,
); );
expect(screen.getByRole("tab", { name: "Accounts" })).toHaveAttribute( expect(screen.getByRole("tab", { name: "Providers" })).toHaveAttribute(
"data-state", "data-state",
"active", "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 () => { it("does not switch the active tab before navigation updates the route", async () => {
@@ -63,21 +62,21 @@ describe("ProviderPageTabs", () => {
render( render(
<ProviderPageTabs <ProviderPageTabs
activeTab={PROVIDER_TAB.ACCOUNTS} activeTab={PROVIDER_TAB.PROVIDERS}
accountsContent={<div>Accounts content</div>} providersContent={<div>Providers content</div>}
accountGroupsContent={<div>Account groups 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(pushMock).toHaveBeenCalledWith("/providers?tab=provider-groups");
expect(screen.getByRole("tab", { name: "Accounts" })).toHaveAttribute( expect(screen.getByRole("tab", { name: "Providers" })).toHaveAttribute(
"data-state", "data-state",
"active", "active",
); );
expect( expect(
screen.getByRole("tab", { name: "Account Groups" }), screen.getByRole("tab", { name: "Provider Groups" }),
).not.toHaveAttribute("data-state", "active"); ).not.toHaveAttribute("data-state", "active");
}); });
}); });
@@ -9,14 +9,14 @@ import { PROVIDER_TAB, type ProviderTab } from "./provider-page-tabs.shared";
interface ProviderPageTabsProps { interface ProviderPageTabsProps {
activeTab: ProviderTab; activeTab: ProviderTab;
accountsContent: ReactNode; providersContent: ReactNode;
accountGroupsContent: ReactNode; providerGroupsContent: ReactNode;
} }
export const ProviderPageTabs = ({ export const ProviderPageTabs = ({
activeTab, activeTab,
accountsContent, providersContent,
accountGroupsContent, providerGroupsContent,
}: ProviderPageTabsProps) => { }: ProviderPageTabsProps) => {
const router = useRouter(); const router = useRouter();
@@ -27,7 +27,7 @@ export const ProviderPageTabs = ({
return; return;
} }
if (typedTab === PROVIDER_TAB.ACCOUNTS) { if (typedTab === PROVIDER_TAB.PROVIDERS) {
router.push("/providers"); router.push("/providers");
} else { } else {
router.push(`/providers?tab=${typedTab}`); router.push(`/providers?tab=${typedTab}`);
@@ -41,18 +41,18 @@ export const ProviderPageTabs = ({
className="flex w-full flex-col gap-6" className="flex w-full flex-col gap-6"
> >
<TabsList> <TabsList>
<TabsTrigger value={PROVIDER_TAB.ACCOUNTS}>Accounts</TabsTrigger> <TabsTrigger value={PROVIDER_TAB.PROVIDERS}>Providers</TabsTrigger>
<TabsTrigger value={PROVIDER_TAB.ACCOUNT_GROUPS}> <TabsTrigger value={PROVIDER_TAB.PROVIDER_GROUPS}>
Account Groups Provider Groups
</TabsTrigger> </TabsTrigger>
</TabsList> </TabsList>
<TabsContent value={PROVIDER_TAB.ACCOUNTS} className="mt-0"> <TabsContent value={PROVIDER_TAB.PROVIDERS} className="mt-0">
{accountsContent} {providersContent}
</TabsContent> </TabsContent>
<TabsContent value={PROVIDER_TAB.ACCOUNT_GROUPS} className="mt-0"> <TabsContent value={PROVIDER_TAB.PROVIDER_GROUPS} className="mt-0">
{accountGroupsContent} {providerGroupsContent}
</TabsContent> </TabsContent>
</Tabs> </Tabs>
); );
@@ -13,9 +13,9 @@ describe("ComplianceCard", () => {
expect(source).toContain('variant="base"'); 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("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", () => { 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", key: "provider__in",
labelCheckboxGroup: "Cloud Provider", labelCheckboxGroup: "Provider",
values: [...PROVIDER_TYPES], values: [...PROVIDER_TYPES],
valueLabelMapping: PROVIDER_TYPE_MAPPING, valueLabelMapping: PROVIDER_TYPE_MAPPING,
}, },
@@ -34,7 +34,7 @@ export const filterProviders: FilterOption[] = [
export const filterScans = [ export const filterScans = [
{ {
key: "provider_type__in", key: "provider_type__in",
labelCheckboxGroup: "Cloud Provider", labelCheckboxGroup: "Provider",
values: [...PROVIDER_TYPES], values: [...PROVIDER_TYPES],
valueLabelMapping: PROVIDER_TYPE_MAPPING, valueLabelMapping: PROVIDER_TYPE_MAPPING,
index: 0, index: 0,
@@ -169,7 +169,7 @@ export function getStandaloneFindingColumns({
{ {
accessorKey: "provider", accessorKey: "provider",
header: ({ column }) => ( header: ({ column }) => (
<DataTableColumnHeader column={column} title="Cloud Provider" /> <DataTableColumnHeader column={column} title="Provider" />
), ),
cell: ({ row }) => { cell: ({ row }) => {
const provider = getProviderData(row, "provider"); const provider = getProviderData(row, "provider");
@@ -48,7 +48,7 @@ export const DeleteGroupForm = ({
title: "Success!", title: "Success!",
description: "The provider group was removed successfully.", 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 setIsOpen(false); // Close the modal on success
} }
@@ -130,7 +130,7 @@ export const EditGroupForm = ({
title: "Success!", title: "Success!",
description: "The group was updated successfully.", description: "The group was updated successfully.",
}); });
router.push("/providers?tab=account-groups"); router.push("/providers?tab=provider-groups");
} }
} catch (_error) { } catch (_error) {
toast({ toast({
@@ -263,7 +263,7 @@ export const EditGroupForm = ({
type="button" type="button"
variant="ghost" variant="ghost"
onClick={() => { onClick={() => {
router.push("/providers?tab=account-groups"); router.push("/providers?tab=provider-groups");
}} }}
disabled={isLoading} disabled={isLoading}
> >
@@ -10,7 +10,7 @@ export const ManageGroupsButton = () => {
<Button asChild variant="outline"> <Button asChild variant="outline">
<Link href="/manage-groups"> <Link href="/manage-groups">
<SettingsIcon size={20} /> <SettingsIcon size={20} />
Account Groups Provider Groups
</Link> </Link>
</Button> </Button>
); );
@@ -41,15 +41,15 @@ export function DataTableRowActions<ProviderProps>({
<ActionDropdown> <ActionDropdown>
<ActionDropdownItem <ActionDropdownItem
icon={<Pencil />} icon={<Pencil />}
label="Edit Account Group" label="Edit Provider Group"
onSelect={() => onSelect={() =>
router.push(`/providers?tab=account-groups&groupId=${groupId}`) router.push(`/providers?tab=provider-groups&groupId=${groupId}`)
} }
/> />
<ActionDropdownDangerZone> <ActionDropdownDangerZone>
<ActionDropdownItem <ActionDropdownItem
icon={<Trash2 />} icon={<Trash2 />}
label="Delete Account Group" label="Delete Provider Group"
destructive destructive
onSelect={() => setIsDeleteOpen(true)} onSelect={() => setIsDeleteOpen(true)}
/> />
@@ -85,7 +85,7 @@ export const SkeletonTableNewFindings = () => {
<th className="px-3 py-3 text-left"> <th className="px-3 py-3 text-left">
<Skeleton className="h-4 w-16 rounded" /> <Skeleton className="h-4 w-16 rounded" />
</th> </th>
{/* Cloud Provider */} {/* Provider */}
<th className="px-3 py-3 text-left"> <th className="px-3 py-3 text-left">
<Skeleton className="h-4 w-24 rounded" /> <Skeleton className="h-4 w-24 rounded" />
</th> </th>
@@ -140,7 +140,7 @@ export function getColumnProviders(
<div className="ml-2"> <div className="ml-2">
<DataTableColumnHeader <DataTableColumnHeader
column={column} column={column}
title="Account" title="Provider"
param="alias" param="alias"
/> />
</div> </div>
@@ -200,7 +200,7 @@ export function getColumnProviders(
accessorKey: "groupNames", accessorKey: "groupNames",
size: 160, size: 160,
header: ({ column }) => ( header: ({ column }) => (
<DataTableColumnHeader column={column} title="Account Groups" /> <DataTableColumnHeader column={column} title="Provider Groups" />
), ),
cell: ({ row }) => { cell: ({ row }) => {
if (isProvidersOrganizationRow(row.original)) { if (isProvidersOrganizationRow(row.original)) {
@@ -251,7 +251,7 @@ export function getColumnProviders(
if (isProvidersOrganizationRow(row.original)) { if (isProvidersOrganizationRow(row.original)) {
return ( return (
<span className="text-text-neutral-tertiary text-sm"> <span className="text-text-neutral-tertiary text-sm">
{row.original.providerCount} Accounts {row.original.providerCount} Providers
</span> </span>
); );
} }
@@ -3,7 +3,7 @@ import { Skeleton } from "@/components/shadcn/skeleton/skeleton";
const SkeletonTableRow = () => { const SkeletonTableRow = () => {
return ( return (
<tr className="border-border-neutral-secondary border-b"> <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"> <td className="w-[420px] px-3 py-4">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Skeleton className="size-9 rounded-lg" /> <Skeleton className="size-9 rounded-lg" />
@@ -13,7 +13,7 @@ const SkeletonTableRow = () => {
</div> </div>
</div> </div>
</td> </td>
{/* Account Groups: badge chips */} {/* Provider Groups: badge chips */}
<td className="px-3 py-4"> <td className="px-3 py-4">
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
<Skeleton className="h-6 w-14 rounded-md" /> <Skeleton className="h-6 w-14 rounded-md" />
@@ -68,11 +68,11 @@ export const SkeletonTableProviders = () => {
<table className="w-full"> <table className="w-full">
<thead> <thead>
<tr className="border-border-neutral-secondary border-b"> <tr className="border-border-neutral-secondary border-b">
{/* Account */} {/* Provider */}
<th className="w-[420px] px-3 py-3 text-left"> <th className="w-[420px] px-3 py-3 text-left">
<Skeleton className="h-4 w-16 rounded" /> <Skeleton className="h-4 w-16 rounded" />
</th> </th>
{/* Account Groups */} {/* Provider Groups */}
<th className="px-3 py-3 text-left"> <th className="px-3 py-3 text-left">
<Skeleton className="h-4 w-24 rounded" /> <Skeleton className="h-4 w-24 rounded" />
</th> </th>
@@ -93,7 +93,7 @@ export function ProviderWizardModal({
</DialogTitle> </DialogTitle>
<div className="text-muted-foreground flex flex-wrap items-center gap-2 text-sm"> <div className="text-muted-foreground flex flex-wrap items-center gap-2 text-sm">
<Info className="size-4 shrink-0" /> <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> <Button variant="link" size="link-sm" className="h-auto p-0" asChild>
<a href={docsLink} target="_blank" rel="noopener noreferrer"> <a href={docsLink} target="_blank" rel="noopener noreferrer">
<ExternalLink className="size-3.5 shrink-0" /> <ExternalLink className="size-3.5 shrink-0" />
@@ -42,7 +42,7 @@ describe("getProviderWizardModalTitle", () => {
it("returns add title for add mode", () => { it("returns add title for add mode", () => {
const title = getProviderWizardModalTitle(PROVIDER_WIZARD_MODE.ADD); 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", () => { it("returns update title for update mode", () => {
@@ -25,7 +25,7 @@ export function getProviderWizardModalTitle(mode: ProviderWizardMode) {
return "Update Provider Credentials"; return "Update Provider Credentials";
} }
return "Adding A Cloud Provider"; return "Adding A Provider";
} }
export function getProviderWizardDocsDestination(docsLink: string) { export function getProviderWizardDocsDestination(docsLink: string) {
@@ -44,7 +44,7 @@ export function getProviderWizardDocsDestination(docsLink: string) {
alibabacloud: "Alibaba Cloud", alibabacloud: "Alibaba Cloud",
cloudflare: "Cloudflare", cloudflare: "Cloudflare",
openstack: "OpenStack", openstack: "OpenStack",
help: "Cloud Provider", help: "Provider",
}; };
try { try {
@@ -21,7 +21,7 @@ interface WizardStepperProps {
const STEPS: StepConfig[] = [ const STEPS: StepConfig[] = [
{ {
label: "Link a Cloud Provider", label: "Link a Provider",
description: "Enter the provider details you would like to add in Prowler.", description: "Enter the provider details you would like to add in Prowler.",
icon: FolderGit2, icon: FolderGit2,
}, },
@@ -92,7 +92,7 @@ export function getColumnResources({
{ {
accessorKey: "provider", accessorKey: "provider",
header: ({ column }) => ( header: ({ column }) => (
<DataTableColumnHeader column={column} title="Cloud Provider" /> <DataTableColumnHeader column={column} title="Provider" />
), ),
cell: ({ row }) => { cell: ({ row }) => {
const provider = getProviderData(row, "provider"); const provider = getProviderData(row, "provider");
@@ -47,12 +47,12 @@ export const SelectScanProvider = <
return ( return (
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<span className="text-text-neutral-primary text-sm font-medium"> <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> </span>
<FormControl> <FormControl>
<Select value={field.value} onValueChange={field.onChange}> <Select value={field.value} onValueChange={field.onChange}>
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="Choose a cloud provider"> <SelectValue placeholder="Choose a provider">
{selectedItem ? ( {selectedItem ? (
<EntityInfo <EntityInfo
cloudProvider={ cloudProvider={
@@ -67,7 +67,7 @@ export const SelectScanProvider = <
showCopyAction={false} showCopyAction={false}
/> />
) : ( ) : (
"Choose a cloud provider" "Choose a provider"
)} )}
</SelectValue> </SelectValue>
</SelectTrigger> </SelectTrigger>
+4 -4
View File
@@ -18,18 +18,18 @@ export const NoProvidersAdded = () => {
<div className="flex flex-col items-center gap-4"> <div className="flex flex-col items-center gap-4">
<InfoIcon className="h-10 w-10 text-gray-800 dark:text-white" /> <InfoIcon className="h-10 w-10 text-gray-800 dark:text-white" />
<h2 className="text-2xl font-bold 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> </h2>
</div> </div>
<div className="flex flex-col items-center gap-3"> <div className="flex flex-col items-center gap-3">
<p className="text-md leading-relaxed text-gray-600 dark:text-gray-300"> <p className="text-md leading-relaxed text-gray-600 dark:text-gray-300">
No cloud providers have been configured. Start by setting up a No providers have been configured. Start by setting up a
cloud provider. provider.
</p> </p>
</div> </div>
<Button <Button
aria-label="Open Add Cloud Provider modal" aria-label="Open Add Provider modal"
className="w-full max-w-xs justify-center" className="w-full max-w-xs justify-center"
size="lg" size="lg"
onClick={() => setOpen(true)} onClick={() => setOpen(true)}
@@ -14,15 +14,15 @@ export const NoProvidersConnected = () => {
<div className="flex items-center justify-start gap-3"> <div className="flex items-center justify-start gap-3">
<InfoIcon className="h-6 w-6 text-gray-800 dark:text-white" /> <InfoIcon className="h-6 w-6 text-gray-800 dark:text-white" />
<h2 className="text-lg font-bold 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> </h2>
</div> </div>
<p className="text-sm text-gray-600 dark:text-gray-300"> <p className="text-sm text-gray-600 dark:text-gray-300">
No cloud providers are currently connected. Connecting a cloud No providers are currently connected. Connecting a provider is
provider is required to launch on-demand scans. required to launch on-demand scans.
</p> </p>
<p className="text-sm text-gray-600 dark:text-gray-300"> <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. disappear, and on-demand scans can be launched.
</p> </p>
</div> </div>
@@ -30,9 +30,9 @@ export const NoProvidersConnected = () => {
<Button <Button
asChild asChild
className="w-full justify-center md:w-fit" 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> </Button>
</div> </div>
</CardContent> </CardContent>
@@ -75,7 +75,7 @@ export const ColumnGetScans: ColumnDef<ScanProps>[] = [
{ {
accessorKey: "cloudProvider", accessorKey: "cloudProvider",
header: ({ column }) => ( header: ({ column }) => (
<DataTableColumnHeader column={column} title="Cloud Provider" /> <DataTableColumnHeader column={column} title="Provider" />
), ),
cell: ({ row }) => { cell: ({ row }) => {
const providerInfo = row.original.providerInfo; const providerInfo = row.original.providerInfo;
+2 -3
View File
@@ -385,9 +385,8 @@ export const permissionFormFields: PermissionInfo[] = [
}, },
{ {
field: "manage_providers", field: "manage_providers",
label: "Manage Cloud Providers", label: "Manage Providers",
description: description: "Allows configuration and management of provider connections",
"Allows configuration and management of cloud provider connections",
}, },
{ {
field: "manage_integrations", field: "manage_integrations",
+1 -1
View File
@@ -107,7 +107,7 @@ export const getMenuList = ({ pathname }: MenuListOptions): GroupProps[] => {
label: "Configuration", label: "Configuration",
icon: Settings, icon: Settings,
submenus: [ submenus: [
{ href: "/providers", label: "Cloud Providers", icon: CloudCog }, { href: "/providers", label: "Providers", icon: CloudCog },
{ {
href: "/mutelist", href: "/mutelist",
label: "Mutelist", label: "Mutelist",
+5 -5
View File
@@ -232,7 +232,7 @@ export class ProvidersPage extends BasePage {
// Alias input // Alias input
readonly aliasInput: Locator; readonly aliasInput: Locator;
// Button to add a new cloud provider // Button to add a new provider
readonly addProviderButton: Locator; readonly addProviderButton: Locator;
readonly providersTable: Locator; readonly providersTable: Locator;
@@ -333,15 +333,15 @@ export class ProvidersPage extends BasePage {
.getByRole("dialog") .getByRole("dialog")
.filter({ .filter({
has: page.getByRole("heading", { has: page.getByRole("heading", {
name: /Adding A Cloud Provider|Update Provider Credentials/i, name: /Adding A Provider|Update Provider Credentials/i,
}), }),
}) })
.first(); .first();
this.wizardTitle = page.getByRole("heading", { 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 this.addProviderButton = page
.getByRole("button", { .getByRole("button", {
name: "Add Provider", name: "Add Provider",
@@ -357,7 +357,7 @@ export class ProvidersPage extends BasePage {
// Table displaying existing providers // Table displaying existing providers
this.providersTable = page.getByRole("table"); 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", { this.awsProviderRadio = page.getByRole("option", {
name: /Amazon Web Services/i, name: /Amazon Web Services/i,
}); });
+2 -2
View File
@@ -20,7 +20,7 @@ export class ScansPage extends BasePage {
super(page); super(page);
// Scan provider selection elements // 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.scanAliasInput = page.getByRole("textbox", { name: "Scan label (optional)" });
this.startNowButton = page.getByRole("button", { name: /Start now|Start scan now/i }); this.startNowButton = page.getByRole("button", { name: /Start now|Start scan now/i });
@@ -107,7 +107,7 @@ export class ScansPage extends BasePage {
// Scan Table exists // Scan Table exists
await expect(this.scanTable).toBeVisible(); 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 // Note: Use a more specific locator strategy if possible in the future
const rowWithAccountId = this.scanTable const rowWithAccountId = this.scanTable
.locator("tbody tr") .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'; 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 cloudProvidersEmail = process.env.E2E_MANAGE_CLOUD_PROVIDERS_USER;
const cloudProvidersPassword = process.env.E2E_MANAGE_CLOUD_PROVIDERS_PASSWORD; const cloudProvidersPassword = process.env.E2E_MANAGE_CLOUD_PROVIDERS_PASSWORD;