Files
Pablo Fernandez Guerra (PFE) 58fd4170b5 feat(ui): support dynamic providers (#11869)
Co-authored-by: Pablo F.G <pablo.fernandez@prowler.com>
2026-07-10 13:22:41 +02:00

171 lines
3.9 KiB
TypeScript

import type { ScheduleFrequency } from "./schedules";
export const PROVIDER_TYPES = [
"aws",
"azure",
"gcp",
"kubernetes",
"m365",
"mongodbatlas",
"github",
"googleworkspace",
"iac",
"image",
"oraclecloud",
"alibabacloud",
"cloudflare",
"openstack",
"vercel",
"okta",
] as const;
/** The closed set of provider types this UI build ships bespoke assets for. */
export type KnownProviderType = (typeof PROVIDER_TYPES)[number];
// Autocomplete for predefined + open for dynamic providers
export type ProviderType = KnownProviderType | (string & {});
/** Type guard: narrows an arbitrary provider value to the known set. */
export const isKnownProviderType = (
provider: string,
): provider is KnownProviderType =>
(PROVIDER_TYPES as readonly string[]).includes(provider);
export const isConfigurableProvider = (
provider: string,
): provider is KnownProviderType => isKnownProviderType(provider);
export const PROVIDER_DISPLAY_NAMES: Record<KnownProviderType, string> = {
aws: "AWS",
azure: "Azure",
gcp: "Google Cloud",
kubernetes: "Kubernetes",
m365: "Microsoft 365",
mongodbatlas: "MongoDB Atlas",
github: "GitHub",
googleworkspace: "Google Workspace",
iac: "Infrastructure as Code",
image: "Container Registry",
oraclecloud: "Oracle Cloud Infrastructure",
alibabacloud: "Alibaba Cloud",
cloudflare: "Cloudflare",
openstack: "OpenStack",
vercel: "Vercel",
okta: "Okta",
};
/**
* Turns a raw provider id into a human-readable label: splits on `-`/`_` and
* capitalizes each word (e.g. `template` → "Template", `local-template` →
* "Local Template"). Used as the display fallback for dynamic providers
*/
export function humanizeProviderId(id: string): string {
return id
.split(/[-_]+/)
.filter(Boolean)
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
.join(" ");
}
export function getProviderDisplayName(providerId: string): string {
const normalized = providerId.toLowerCase();
return isKnownProviderType(normalized)
? PROVIDER_DISPLAY_NAMES[normalized]
: humanizeProviderId(normalized);
}
export interface ProviderProps {
id: string;
type: "providers";
attributes: {
provider: ProviderType;
is_dynamic: boolean;
uid: string;
alias: string;
status: "completed" | "pending" | "cancelled";
resources: number;
connection: {
connected: boolean;
last_checked_at: string;
};
scanner_args: {
only_logs: boolean;
excluded_checks: string[];
aws_retries_max_attempts: number;
};
inserted_at: string;
updated_at: string;
scan_frequency?: ScheduleFrequency | null;
scan_hour?: number | null;
scan_day_of_week?: number | null;
scan_day_of_month?: number | null;
scan_interval_hours?: number | null;
scan_timezone?: string | null;
scan_enabled?: boolean | null;
next_scan_at?: string | null;
last_scan_at?: string | null;
created_by: {
object: string;
id: string;
};
};
relationships: {
secret: {
data: {
type: string;
id: string;
} | null;
};
provider_groups: {
meta: {
count: number;
};
data: Array<{
type: string;
id: string;
}>;
};
};
groupNames?: string[];
}
export interface ProviderEntity {
provider: ProviderType;
uid: string;
alias: string | null;
}
export interface GroupFilterEntity {
name: string;
uid: string;
}
export interface ProviderConnectionStatus {
label: string;
value: string;
}
export interface ProvidersApiResponse {
links: {
first: string;
last: string;
next: string | null;
prev: string | null;
};
data: ProviderProps[];
included?: Array<{
type: string;
id: string;
attributes: Record<string, unknown>;
relationships?: Record<string, unknown>;
}>;
meta: {
pagination: {
page: number;
pages: number;
count: number;
};
version: string;
};
}