diff --git a/ui/actions/providers/providers.ts b/ui/actions/providers/providers.ts index 95589eff45..6dbb3a0aee 100644 --- a/ui/actions/providers/providers.ts +++ b/ui/actions/providers/providers.ts @@ -186,6 +186,15 @@ export const addCredentialsProvider = async (formData: FormData) => { client_secret: formData.get("client_secret"), tenant_id: formData.get("tenant_id"), }; + } else if (providerType === "m365") { + // Static credentials configuration for M365 + secret = { + client_id: formData.get("client_id"), + client_secret: formData.get("client_secret"), + tenant_id: formData.get("tenant_id"), + user: formData.get("user"), + encrypted_password: formData.get("encrypted_password"), + }; } else if (providerType === "gcp") { // Static credentials configuration for GCP secret = { @@ -280,6 +289,15 @@ export const updateCredentialsProvider = async ( client_secret: formData.get("client_secret"), tenant_id: formData.get("tenant_id"), }; + } else if (providerType === "m365") { + // Static credentials configuration for M365 + secret = { + client_id: formData.get("client_id"), + client_secret: formData.get("client_secret"), + tenant_id: formData.get("tenant_id"), + user: formData.get("user"), + encrypted_password: formData.get("encrypted_password"), + }; } else if (providerType === "gcp") { // Static credentials configuration for GCP secret = { diff --git a/ui/components/icons/providers-badge/AWSProviderBadge.tsx b/ui/components/icons/providers-badge/aws-provider-badge.tsx similarity index 100% rename from ui/components/icons/providers-badge/AWSProviderBadge.tsx rename to ui/components/icons/providers-badge/aws-provider-badge.tsx diff --git a/ui/components/icons/providers-badge/AzureProviderBadge.tsx b/ui/components/icons/providers-badge/azure-provider-badge.tsx similarity index 100% rename from ui/components/icons/providers-badge/AzureProviderBadge.tsx rename to ui/components/icons/providers-badge/azure-provider-badge.tsx diff --git a/ui/components/icons/providers-badge/GCPProviderBadge.tsx b/ui/components/icons/providers-badge/gcp-provider-badge.tsx similarity index 100% rename from ui/components/icons/providers-badge/GCPProviderBadge.tsx rename to ui/components/icons/providers-badge/gcp-provider-badge.tsx diff --git a/ui/components/icons/providers-badge/index.ts b/ui/components/icons/providers-badge/index.ts index 8aa68424a0..86641d82ad 100644 --- a/ui/components/icons/providers-badge/index.ts +++ b/ui/components/icons/providers-badge/index.ts @@ -1,4 +1,5 @@ -export * from "./AWSProviderBadge"; -export * from "./AzureProviderBadge"; -export * from "./GCPProviderBadge"; -export * from "./KS8ProviderBadge"; +export * from "./aws-provider-badge"; +export * from "./azure-provider-badge"; +export * from "./gcp-provider-badge"; +export * from "./ks8-provider-badge"; +export * from "./m365-provider-badge"; diff --git a/ui/components/icons/providers-badge/KS8ProviderBadge.tsx b/ui/components/icons/providers-badge/ks8-provider-badge.tsx similarity index 100% rename from ui/components/icons/providers-badge/KS8ProviderBadge.tsx rename to ui/components/icons/providers-badge/ks8-provider-badge.tsx diff --git a/ui/components/icons/providers-badge/m365-provider-badge.tsx b/ui/components/icons/providers-badge/m365-provider-badge.tsx new file mode 100644 index 0000000000..ed5d077dcf --- /dev/null +++ b/ui/components/icons/providers-badge/m365-provider-badge.tsx @@ -0,0 +1,126 @@ +import * as React from "react"; + +import { IconSvgProps } from "@/types"; + +export const M365ProviderBadge: React.FC = ({ + size, + width, + height, + ...props +}) => ( + +); diff --git a/ui/components/providers/provider-info.tsx b/ui/components/providers/provider-info.tsx index 9eea6cdf74..f65d737f58 100644 --- a/ui/components/providers/provider-info.tsx +++ b/ui/components/providers/provider-info.tsx @@ -1,11 +1,11 @@ import React from "react"; import { ConnectionFalse, ConnectionPending, ConnectionTrue } from "../icons"; -import { getProviderLogo } from "../ui/entities"; +import { getProviderLogo, ProviderType } from "../ui/entities"; interface ProviderInfoProps { connected: boolean | null; - provider: "aws" | "azure" | "gcp" | "kubernetes"; + provider: ProviderType; providerAlias: string; providerUID?: string; } diff --git a/ui/components/providers/radio-group-provider.tsx b/ui/components/providers/radio-group-provider.tsx index e376e69ff4..ec77a148db 100644 --- a/ui/components/providers/radio-group-provider.tsx +++ b/ui/components/providers/radio-group-provider.tsx @@ -7,9 +7,13 @@ import { z } from "zod"; import { addProviderFormSchema } from "@/types"; -import { AWSProviderBadge, AzureProviderBadge } from "../icons/providers-badge"; -import { GCPProviderBadge } from "../icons/providers-badge/GCPProviderBadge"; -import { KS8ProviderBadge } from "../icons/providers-badge/KS8ProviderBadge"; +import { + AWSProviderBadge, + AzureProviderBadge, + GCPProviderBadge, + KS8ProviderBadge, + M365ProviderBadge, +} from "../icons/providers-badge"; import { CustomRadio } from "../ui/custom"; import { FormMessage } from "../ui/form"; @@ -55,6 +59,12 @@ export const RadioGroupProvider: React.FC = ({ Microsoft Azure + +
+ + Microsoft 365 +
+
diff --git a/ui/components/providers/workflow/forms/connect-account-form.tsx b/ui/components/providers/workflow/forms/connect-account-form.tsx index 597943ae36..ed59d16be0 100644 --- a/ui/components/providers/workflow/forms/connect-account-form.tsx +++ b/ui/components/providers/workflow/forms/connect-account-form.tsx @@ -24,22 +24,27 @@ const getProviderFieldDetails = (providerType?: string) => { case "aws": return { label: "Account ID", - placeholder: "123456...", + placeholder: "e.g. 123456789012", }; case "gcp": return { label: "Project ID", - placeholder: "project_id...", + placeholder: "e.g. my-gcp-project", }; case "azure": return { label: "Subscription ID", - placeholder: "fc94207a-d396-4a14-a7fd-12a...", + placeholder: "e.g. fc94207a-d396-4a14-a7fd-12ab34cd56ef", }; case "kubernetes": return { label: "Kubernetes Context", - placeholder: "context_name....", + placeholder: "e.g. my-cluster-context", + }; + case "m365": + return { + label: "Domain ID", + placeholder: "e.g. your-domain.onmicrosoft.com", }; default: return { diff --git a/ui/components/providers/workflow/forms/test-connection-form.tsx b/ui/components/providers/workflow/forms/test-connection-form.tsx index 84bd803f06..db32c4f3cf 100644 --- a/ui/components/providers/workflow/forms/test-connection-form.tsx +++ b/ui/components/providers/workflow/forms/test-connection-form.tsx @@ -18,6 +18,7 @@ import { getTask } from "@/actions/task/tasks"; import { CheckIcon, RocketIcon } from "@/components/icons"; import { useToast } from "@/components/ui"; import { CustomButton } from "@/components/ui/custom"; +import { ProviderType } from "@/components/ui/entities"; import { Form } from "@/components/ui/form"; import { checkTaskStatus } from "@/lib/helper"; import { ApiError, testConnectionFormSchema } from "@/types"; @@ -41,7 +42,7 @@ export const TestConnectionForm = ({ connected: boolean | null; last_checked_at: string | null; }; - provider: "aws" | "azure" | "gcp" | "kubernetes"; + provider: ProviderType; alias: string; scanner_args: Record; }; diff --git a/ui/components/providers/workflow/forms/via-credentials-form.tsx b/ui/components/providers/workflow/forms/via-credentials-form.tsx index 7be4a613b4..072d2f3640 100644 --- a/ui/components/providers/workflow/forms/via-credentials-form.tsx +++ b/ui/components/providers/workflow/forms/via-credentials-form.tsx @@ -19,6 +19,7 @@ import { AzureCredentials, GCPCredentials, KubernetesCredentials, + M365Credentials, } from "@/types"; import { ProviderTitleDocs } from "../provider-title-docs"; @@ -26,6 +27,7 @@ import { AWScredentialsForm } from "./via-credentials/aws-credentials-form"; import { AzureCredentialsForm } from "./via-credentials/azure-credentials-form"; import { GCPcredentialsForm } from "./via-credentials/gcp-credentials-form"; import { KubernetesCredentialsForm } from "./via-credentials/k8s-credentials-form"; +import { M365CredentialsForm } from "./via-credentials/m365-credentials-form"; type CredentialsFormSchema = z.infer< ReturnType @@ -36,7 +38,8 @@ type FormType = CredentialsFormSchema & AWSCredentials & AzureCredentials & GCPCredentials & - KubernetesCredentials; + KubernetesCredentials & + M365Credentials; export const ViaCredentialsForm = ({ searchParams, @@ -76,17 +79,25 @@ export const ViaCredentialsForm = ({ client_secret: "", tenant_id: "", } - : providerType === "gcp" + : providerType === "m365" ? { client_id: "", client_secret: "", - refresh_token: "", + tenant_id: "", + user: "", + encrypted_password: "", } - : providerType === "kubernetes" + : providerType === "gcp" ? { - kubeconfig_content: "", + client_id: "", + client_secret: "", + refresh_token: "", } - : {}), + : providerType === "kubernetes" + ? { + kubeconfig_content: "", + } + : {}), }, }); @@ -135,6 +146,18 @@ export const ViaCredentialsForm = ({ message: errorMessage, }); break; + case "/data/attributes/secret/user": + form.setError("user", { + type: "server", + message: errorMessage, + }); + break; + case "/data/attributes/secret/encrypted_password": + form.setError("encrypted_password", { + type: "server", + message: errorMessage, + }); + break; case "/data/attributes/secret/tenant_id": form.setError("tenant_id", { type: "server", @@ -191,6 +214,11 @@ export const ViaCredentialsForm = ({ control={form.control as unknown as Control} /> )} + {providerType === "m365" && ( + } + /> + )} {providerType === "gcp" && ( } diff --git a/ui/components/providers/workflow/forms/via-credentials/index.ts b/ui/components/providers/workflow/forms/via-credentials/index.ts index d3198a1d0e..88bf5587f0 100644 --- a/ui/components/providers/workflow/forms/via-credentials/index.ts +++ b/ui/components/providers/workflow/forms/via-credentials/index.ts @@ -2,3 +2,4 @@ export * from "./aws-credentials-form"; export * from "./azure-credentials-form"; export * from "./gcp-credentials-form"; export * from "./k8s-credentials-form"; +export * from "./m365-credentials-form"; diff --git a/ui/components/providers/workflow/forms/via-credentials/m365-credentials-form.tsx b/ui/components/providers/workflow/forms/via-credentials/m365-credentials-form.tsx new file mode 100644 index 0000000000..1ba6024ffc --- /dev/null +++ b/ui/components/providers/workflow/forms/via-credentials/m365-credentials-form.tsx @@ -0,0 +1,78 @@ +import { Control } from "react-hook-form"; + +import { CustomInput } from "@/components/ui/custom"; +import { M365Credentials } from "@/types"; + +export const M365CredentialsForm = ({ + control, +}: { + control: Control; +}) => { + return ( + <> +
+
+ Connect via Credentials +
+
+ Please provide the information for your Microsoft 365 credentials. +
+
+ + + + + + + ); +}; diff --git a/ui/components/ui/entities/get-provider-logo.tsx b/ui/components/ui/entities/get-provider-logo.tsx index e4bf4d0a62..4bfe7cb419 100644 --- a/ui/components/ui/entities/get-provider-logo.tsx +++ b/ui/components/ui/entities/get-provider-logo.tsx @@ -5,9 +5,10 @@ import { AzureProviderBadge, GCPProviderBadge, KS8ProviderBadge, + M365ProviderBadge, } from "@/components/icons/providers-badge"; -export type ProviderType = "aws" | "azure" | "gcp" | "kubernetes"; +export type ProviderType = "aws" | "azure" | "gcp" | "kubernetes" | "m365"; export const getProviderLogo = (provider: ProviderType) => { switch (provider) { @@ -19,6 +20,8 @@ export const getProviderLogo = (provider: ProviderType) => { return ; case "kubernetes": return ; + case "m365": + return ; default: return null; } @@ -34,6 +37,8 @@ export const getProviderName = (provider: ProviderType): string => { return "Google Cloud Platform"; case "kubernetes": return "Kubernetes"; + case "m365": + return "Microsoft 365"; default: return "Unknown Provider"; } diff --git a/ui/types/components.ts b/ui/types/components.ts index 5b2aa59437..b9a9453690 100644 --- a/ui/types/components.ts +++ b/ui/types/components.ts @@ -238,6 +238,16 @@ export type AzureCredentials = { providerId: string; }; +export type M365Credentials = { + client_id: string; + client_secret: string; + tenant_id: string; + user: string; + encrypted_password: string; + secretName: string; + providerId: string; +}; + export type GCPCredentials = { client_id: string; client_secret: string; @@ -256,7 +266,8 @@ export type CredentialsFormSchema = | AWSCredentials | AzureCredentials | GCPCredentials - | KubernetesCredentials; + | KubernetesCredentials + | M365Credentials; export interface SearchParamsProps { [key: string]: string | string[] | undefined; diff --git a/ui/types/formSchemas.ts b/ui/types/formSchemas.ts index b39a7d92a4..3fc096d03d 100644 --- a/ui/types/formSchemas.ts +++ b/ui/types/formSchemas.ts @@ -63,7 +63,7 @@ export const awsCredentialsTypeSchema = z.object({ export const addProviderFormSchema = z .object({ - providerType: z.enum(["aws", "azure", "gcp", "kubernetes"], { + providerType: z.enum(["aws", "azure", "gcp", "kubernetes", "m365"], { required_error: "Please select a provider type", }), }) @@ -80,6 +80,12 @@ export const addProviderFormSchema = z providerUid: z.string(), awsCredentialsType: z.string().optional(), }), + z.object({ + providerType: z.literal("m365"), + providerAlias: z.string(), + providerUid: z.string(), + awsCredentialsType: z.string().optional(), + }), z.object({ providerType: z.literal("gcp"), providerAlias: z.string(), @@ -128,7 +134,19 @@ export const addCredentialsFormSchema = (providerType: string) => .string() .nonempty("Kubeconfig Content is required"), } - : {}), + : providerType === "m365" + ? { + client_id: z.string().nonempty("Client ID is required"), + client_secret: z + .string() + .nonempty("Client Secret is required"), + tenant_id: z.string().nonempty("Tenant ID is required"), + user: z.string().nonempty("User is required"), + encrypted_password: z + .string() + .nonempty("Encrypted Password is required"), + } + : {}), }); export const addCredentialsRoleFormSchema = (providerType: string) =>