mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-05-06 08:47:18 +00:00
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:
committed by
GitHub
parent
786059bfb2
commit
d23c2f3b53
@@ -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"
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
3. Click "Add Cloud Provider"
|
3. Click "Add Provider"
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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"
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
3. Click "Add Cloud Provider"
|
3. Click "Add Provider"
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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`
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
3. Click on `Add Cloud Provider`
|
3. Click on `Add Provider`
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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".
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
3. Click "Add Cloud Provider".
|
3. Click "Add Provider".
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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"
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
3. Click "Add Cloud Provider"
|
3. Click "Add Provider"
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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**
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
3. Click **Add Cloud Provider**
|
3. Click **Add Provider**
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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".
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
3. Click "Add Cloud Provider".
|
3. Click "Add Provider".
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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"
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
3. Click "Add Cloud Provider"
|
3. Click "Add Provider"
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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"
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
3. Click "Add Cloud Provider"
|
3. Click "Add Provider"
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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"
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
3. Click "Add Cloud Provider"
|
3. Click "Add Provider"
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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".
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
3. Click "Add Cloud Provider".
|
3. Click "Add Provider".
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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**.
|
||||||

|

|
||||||
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**.
|
||||||

|

|
||||||
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**.
|
||||||

|

|
||||||
|
|
||||||
|
|||||||
@@ -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".
|
||||||

|

|
||||||
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".
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
3. Click "Add Cloud Provider".
|
3. Click "Add Provider".
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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
|
|||||||

|

|
||||||
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`)
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
+1
-1
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
+5
-5
@@ -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", () => {
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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",
|
||||||
|
|||||||
@@ -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,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user